blob: db5e865415b37b45293820a9be0c672f8703d234 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
John Spurlock3346a802014-05-20 16:25:37 -040017package com.android.systemui.volume;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080018
Eric Laurentc34dcc12012-09-10 13:51:52 -070019import android.app.AlertDialog;
Amith Yamasani2bbdd772011-02-02 18:54:13 -080020import android.app.Dialog;
Amith Yamasani2bbdd772011-02-02 18:54:13 -080021import android.content.BroadcastReceiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080022import android.content.Context;
Amith Yamasani2bbdd772011-02-02 18:54:13 -080023import android.content.DialogInterface;
John Spurlock86005342014-05-23 11:58:00 -040024import android.content.DialogInterface.OnDismissListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080025import android.content.Intent;
Amith Yamasani2bbdd772011-02-02 18:54:13 -080026import android.content.IntentFilter;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080027import android.content.res.Resources;
John Spurlock2078caf2014-05-29 22:20:14 -040028import android.graphics.PixelFormat;
29import android.graphics.drawable.ColorDrawable;
John Spurlock7b414672014-07-18 13:02:39 -040030import android.media.AudioAttributes;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080031import android.media.AudioManager;
32import android.media.AudioService;
33import android.media.AudioSystem;
Marco Nelissen69f593c2009-07-28 09:55:04 -070034import android.media.RingtoneManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080035import android.media.ToneGenerator;
RoboErik19c95182014-06-23 15:38:48 -070036import android.media.VolumeProvider;
37import android.media.session.MediaController;
38import android.media.session.MediaController.VolumeInfo;
Marco Nelissen69f593c2009-07-28 09:55:04 -070039import android.net.Uri;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040import android.os.Handler;
41import android.os.Message;
42import android.os.Vibrator;
John Spurlockae641c92014-06-30 18:11:40 -040043import android.provider.Settings.Global;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044import android.util.Log;
John Spurlock3346a802014-05-20 16:25:37 -040045import android.view.Gravity;
46import android.view.LayoutInflater;
47import android.view.MotionEvent;
48import android.view.View;
John Spurlock7f1df5e2014-05-31 19:11:40 -040049import android.view.View.OnClickListener;
John Spurlock3346a802014-05-20 16:25:37 -040050import android.view.ViewGroup;
John Spurlock86005342014-05-23 11:58:00 -040051import android.view.ViewStub;
John Spurlock3346a802014-05-20 16:25:37 -040052import android.view.Window;
53import android.view.WindowManager;
Amith Yamasani284e6302011-09-16 18:24:47 -070054import android.view.WindowManager.LayoutParams;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055import android.widget.ImageView;
Amith Yamasani2bbdd772011-02-02 18:54:13 -080056import android.widget.SeekBar;
Amith Yamasani2bbdd772011-02-02 18:54:13 -080057import android.widget.SeekBar.OnSeekBarChangeListener;
58
John Spurlock86005342014-05-23 11:58:00 -040059import com.android.internal.R;
60import com.android.systemui.statusbar.policy.ZenModeController;
61
Amith Yamasani2bbdd772011-02-02 18:54:13 -080062import java.util.HashMap;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080063
64/**
John Spurlock3346a802014-05-20 16:25:37 -040065 * Handles the user interface for the volume keys.
Dianne Hackborne8ecde12011-08-03 18:55:19 -070066 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080067 * @hide
68 */
John Spurlock3346a802014-05-20 16:25:37 -040069public class VolumePanel extends Handler {
John Spurlockae641c92014-06-30 18:11:40 -040070 private static final String TAG = "VolumePanel";
71 private static boolean LOGD = Log.isLoggable(TAG, Log.DEBUG);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080072
John Spurlock3346a802014-05-20 16:25:37 -040073 private static final int PLAY_SOUND_DELAY = AudioService.PLAY_SOUND_DELAY;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080074
75 /**
76 * The delay before vibrating. This small period exists so if the user is
77 * moving to silent mode, it will not emit a short vibrate (it normally
78 * would since vibrate is between normal mode and silent mode using hardware
79 * keys).
80 */
81 public static final int VIBRATE_DELAY = 300;
82
83 private static final int VIBRATE_DURATION = 300;
84 private static final int BEEP_DURATION = 150;
85 private static final int MAX_VOLUME = 100;
86 private static final int FREE_DELAY = 10000;
Amith Yamasani2bbdd772011-02-02 18:54:13 -080087 private static final int TIMEOUT_DELAY = 3000;
John Spurlock8845da72014-07-07 21:29:48 -040088 private static final int TIMEOUT_DELAY_SHORT = 1500;
John Spurlockea9938c2014-07-11 18:51:32 -040089 private static final int TIMEOUT_DELAY_COLLAPSED = 4500;
John Spurlock3bd4fee2014-05-29 20:51:09 -040090 private static final int TIMEOUT_DELAY_EXPANDED = 10000;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080091
92 private static final int MSG_VOLUME_CHANGED = 0;
93 private static final int MSG_FREE_RESOURCES = 1;
94 private static final int MSG_PLAY_SOUND = 2;
95 private static final int MSG_STOP_SOUNDS = 3;
96 private static final int MSG_VIBRATE = 4;
Amith Yamasani2bbdd772011-02-02 18:54:13 -080097 private static final int MSG_TIMEOUT = 5;
98 private static final int MSG_RINGER_MODE_CHANGED = 6;
Mike Lockwoodce952c82011-11-14 10:47:42 -080099 private static final int MSG_MUTE_CHANGED = 7;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700100 private static final int MSG_REMOTE_VOLUME_CHANGED = 8;
101 private static final int MSG_REMOTE_VOLUME_UPDATE_IF_SHOWN = 9;
102 private static final int MSG_SLIDER_VISIBILITY_CHANGED = 10;
Eric Laurentc34dcc12012-09-10 13:51:52 -0700103 private static final int MSG_DISPLAY_SAFE_VOLUME_WARNING = 11;
John Spurlock86005342014-05-23 11:58:00 -0400104 private static final int MSG_LAYOUT_DIRECTION = 12;
105 private static final int MSG_ZEN_MODE_CHANGED = 13;
John Spurlockae641c92014-06-30 18:11:40 -0400106 private static final int MSG_USER_ACTIVITY = 14;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800107
Mike Lockwood8dc1dab2011-10-27 09:52:41 -0400108 // Pseudo stream type for master volume
Mike Lockwood47676902011-11-08 10:31:21 -0800109 private static final int STREAM_MASTER = -100;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700110 // Pseudo stream type for remote volume is defined in AudioService.STREAM_REMOTE_MUSIC
Mike Lockwood8dc1dab2011-10-27 09:52:41 -0400111
John Spurlock7b414672014-07-18 13:02:39 -0400112 private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder()
113 .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
114 .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
115 .build();
116
John Spurlock86005342014-05-23 11:58:00 -0400117 private final String mTag;
John Spurlock3346a802014-05-20 16:25:37 -0400118 protected final Context mContext;
119 private final AudioManager mAudioManager;
John Spurlock86005342014-05-23 11:58:00 -0400120 private final ZenModeController mZenController;
Marco Nelissen69f593c2009-07-28 09:55:04 -0700121 private boolean mRingIsSilent;
Amith Yamasani71def772011-10-12 12:25:24 -0700122 private boolean mVoiceCapable;
John Spurlock86005342014-05-23 11:58:00 -0400123 private boolean mZenModeCapable;
John Spurlock8845da72014-07-07 21:29:48 -0400124 private boolean mZenPanelExpanded;
John Spurlock3bd4fee2014-05-29 20:51:09 -0400125 private int mTimeoutDelay = TIMEOUT_DELAY;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800126
Christopher Tatec4b78d22012-05-22 13:57:58 -0700127 // True if we want to play tones on the system stream when the master stream is specified.
128 private final boolean mPlayMasterStreamTones;
129
John Spurlock86005342014-05-23 11:58:00 -0400130
131 /** Volume panel content view */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800132 private final View mView;
John Spurlockeb2727b2014-07-19 23:11:36 -0400133 /** Dialog hosting the panel */
John Spurlock86005342014-05-23 11:58:00 -0400134 private final Dialog mDialog;
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800135
Amith Yamasanibaf6dbf2011-08-18 17:40:29 -0700136 /** The visible portion of the volume overlay */
137 private final ViewGroup mPanel;
John Spurlock86005342014-05-23 11:58:00 -0400138 /** Contains the slider and its touchable icons */
139 private final ViewGroup mSliderPanel;
John Spurlockeb2727b2014-07-19 23:11:36 -0400140 /** The zen mode configuration panel view */
John Spurlock86005342014-05-23 11:58:00 -0400141 private ZenModePanel mZenPanel;
John Spurlock86005342014-05-23 11:58:00 -0400142
John Spurlockae641c92014-06-30 18:11:40 -0400143 private Callback mCallback;
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800144
145 /** Currently active stream that shows up at the top of the list of sliders */
146 private int mActiveStreamType = -1;
147 /** All the slider controls mapped by stream type */
148 private HashMap<Integer,StreamControl> mStreamControls;
149
Amith Yamasani71def772011-10-12 12:25:24 -0700150 private enum StreamResources {
151 BluetoothSCOStream(AudioManager.STREAM_BLUETOOTH_SCO,
152 R.string.volume_icon_description_bluetooth,
153 R.drawable.ic_audio_bt,
154 R.drawable.ic_audio_bt,
155 false),
156 RingerStream(AudioManager.STREAM_RING,
157 R.string.volume_icon_description_ringer,
John Spurlock86005342014-05-23 11:58:00 -0400158 com.android.systemui.R.drawable.ic_ringer_audible,
159 com.android.systemui.R.drawable.ic_ringer_silent,
Amith Yamasani71def772011-10-12 12:25:24 -0700160 false),
161 VoiceStream(AudioManager.STREAM_VOICE_CALL,
162 R.string.volume_icon_description_incall,
163 R.drawable.ic_audio_phone,
164 R.drawable.ic_audio_phone,
165 false),
Amith Yamasani92e1b2d2011-10-14 17:24:47 -0700166 AlarmStream(AudioManager.STREAM_ALARM,
167 R.string.volume_alarm,
168 R.drawable.ic_audio_alarm,
169 R.drawable.ic_audio_alarm_mute,
170 false),
Amith Yamasani71def772011-10-12 12:25:24 -0700171 MediaStream(AudioManager.STREAM_MUSIC,
172 R.string.volume_icon_description_media,
173 R.drawable.ic_audio_vol,
174 R.drawable.ic_audio_vol_mute,
175 true),
176 NotificationStream(AudioManager.STREAM_NOTIFICATION,
177 R.string.volume_icon_description_notification,
John Spurlock86005342014-05-23 11:58:00 -0400178 com.android.systemui.R.drawable.ic_ringer_audible,
179 com.android.systemui.R.drawable.ic_ringer_silent,
Mike Lockwood8dc1dab2011-10-27 09:52:41 -0400180 true),
181 // for now, use media resources for master volume
182 MasterStream(STREAM_MASTER,
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700183 R.string.volume_icon_description_media, //FIXME should have its own description
Mike Lockwood8dc1dab2011-10-27 09:52:41 -0400184 R.drawable.ic_audio_vol,
185 R.drawable.ic_audio_vol_mute,
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700186 false),
187 RemoteStream(AudioService.STREAM_REMOTE_MUSIC,
188 R.string.volume_icon_description_media, //FIXME should have its own description
189 R.drawable.ic_media_route_on_holo_dark,
190 R.drawable.ic_media_route_disabled_holo_dark,
191 false);// will be dynamically updated
Amith Yamasani71def772011-10-12 12:25:24 -0700192
193 int streamType;
194 int descRes;
195 int iconRes;
196 int iconMuteRes;
197 // RING, VOICE_CALL & BLUETOOTH_SCO are hidden unless explicitly requested
198 boolean show;
199
200 StreamResources(int streamType, int descRes, int iconRes, int iconMuteRes, boolean show) {
201 this.streamType = streamType;
202 this.descRes = descRes;
203 this.iconRes = iconRes;
204 this.iconMuteRes = iconMuteRes;
205 this.show = show;
206 }
Alan Viverettee8ebaf32014-04-11 15:44:15 -0700207 }
Amith Yamasani71def772011-10-12 12:25:24 -0700208
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800209 // List of stream types and their order
Amith Yamasani71def772011-10-12 12:25:24 -0700210 private static final StreamResources[] STREAMS = {
211 StreamResources.BluetoothSCOStream,
212 StreamResources.RingerStream,
213 StreamResources.VoiceStream,
214 StreamResources.MediaStream,
Amith Yamasani92e1b2d2011-10-14 17:24:47 -0700215 StreamResources.NotificationStream,
Mike Lockwood8dc1dab2011-10-27 09:52:41 -0400216 StreamResources.AlarmStream,
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700217 StreamResources.MasterStream,
218 StreamResources.RemoteStream
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800219 };
220
221 /** Object that contains data for each slider */
222 private class StreamControl {
223 int streamType;
RoboErik19c95182014-06-23 15:38:48 -0700224 MediaController controller;
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800225 ViewGroup group;
226 ImageView icon;
227 SeekBar seekbarView;
228 int iconRes;
229 int iconMuteRes;
230 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800231
232 // Synchronize when accessing this
233 private ToneGenerator mToneGenerators[];
234 private Vibrator mVibrator;
235
Eric Laurentc34dcc12012-09-10 13:51:52 -0700236 private static AlertDialog sConfirmSafeVolumeDialog;
Eric Laurent0516a9e2012-09-19 11:53:03 -0700237 private static Object sConfirmSafeVolumeLock = new Object();
Eric Laurentc34dcc12012-09-10 13:51:52 -0700238
239 private static class WarningDialogReceiver extends BroadcastReceiver
240 implements DialogInterface.OnDismissListener {
Eric Laurentfde16d52012-12-03 14:42:39 -0800241 private final Context mContext;
242 private final Dialog mDialog;
243 private final VolumePanel mVolumePanel;
Eric Laurentc34dcc12012-09-10 13:51:52 -0700244
Eric Laurentfde16d52012-12-03 14:42:39 -0800245 WarningDialogReceiver(Context context, Dialog dialog, VolumePanel volumePanel) {
Eric Laurentc34dcc12012-09-10 13:51:52 -0700246 mContext = context;
247 mDialog = dialog;
Eric Laurentfde16d52012-12-03 14:42:39 -0800248 mVolumePanel = volumePanel;
Eric Laurentc34dcc12012-09-10 13:51:52 -0700249 IntentFilter filter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
250 context.registerReceiver(this, filter);
251 }
252
253 @Override
254 public void onReceive(Context context, Intent intent) {
255 mDialog.cancel();
Eric Laurentfde16d52012-12-03 14:42:39 -0800256 cleanUp();
Eric Laurentc34dcc12012-09-10 13:51:52 -0700257 }
258
Alan Viverette494fb7b2014-04-10 18:12:56 -0700259 @Override
Eric Laurentc34dcc12012-09-10 13:51:52 -0700260 public void onDismiss(DialogInterface unused) {
261 mContext.unregisterReceiver(this);
Eric Laurentfde16d52012-12-03 14:42:39 -0800262 cleanUp();
263 }
264
265 private void cleanUp() {
Eric Laurent0516a9e2012-09-19 11:53:03 -0700266 synchronized (sConfirmSafeVolumeLock) {
267 sConfirmSafeVolumeDialog = null;
268 }
John Spurlock1dad2722014-07-11 11:07:53 -0400269 mVolumePanel.forceTimeout(0);
Eric Laurentfde16d52012-12-03 14:42:39 -0800270 mVolumePanel.updateStates();
Eric Laurentc34dcc12012-09-10 13:51:52 -0700271 }
272 }
273
274
John Spurlockeb2727b2014-07-19 23:11:36 -0400275 public VolumePanel(Context context, ZenModeController zenController) {
276 mTag = String.format("%s.%08x", TAG, hashCode());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800277 mContext = context;
John Spurlock86005342014-05-23 11:58:00 -0400278 mZenController = zenController;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800279 mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800280
Mike Lockwood8dc1dab2011-10-27 09:52:41 -0400281 // For now, only show master volume if master volume is supported
Alan Viverettee8ebaf32014-04-11 15:44:15 -0700282 final Resources res = context.getResources();
283 final boolean useMasterVolume = res.getBoolean(R.bool.config_useMasterVolume);
Mike Lockwood8dc1dab2011-10-27 09:52:41 -0400284 if (useMasterVolume) {
285 for (int i = 0; i < STREAMS.length; i++) {
286 StreamResources streamRes = STREAMS[i];
287 streamRes.show = (streamRes.streamType == STREAM_MASTER);
288 }
289 }
John Spurlockeb2727b2014-07-19 23:11:36 -0400290 if (LOGD) Log.d(mTag, "new VolumePanel");
291
292 mDialog = new Dialog(context) {
293 @Override
294 public boolean onTouchEvent(MotionEvent event) {
295 if (isShowing() && event.getAction() == MotionEvent.ACTION_OUTSIDE &&
296 sConfirmSafeVolumeDialog == null) {
297 forceTimeout(0);
298 return true;
Amith Yamasani284e6302011-09-16 18:24:47 -0700299 }
John Spurlockeb2727b2014-07-19 23:11:36 -0400300 return false;
301 }
302 };
Alan Viverettee8ebaf32014-04-11 15:44:15 -0700303
John Spurlockeb2727b2014-07-19 23:11:36 -0400304 // Change some window properties
305 final Window window = mDialog.getWindow();
306 final LayoutParams lp = window.getAttributes();
307 lp.token = null;
308 // Offset from the top
309 lp.y = res.getDimensionPixelOffset(com.android.systemui.R.dimen.volume_panel_top);
310 lp.type = LayoutParams.TYPE_STATUS_BAR_PANEL;
311 lp.format = PixelFormat.TRANSLUCENT;
312 lp.windowAnimations = com.android.systemui.R.style.VolumePanelAnimation;
313 lp.gravity = Gravity.TOP;
314 window.setAttributes(lp);
315 window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
316 window.requestFeature(Window.FEATURE_NO_TITLE);
317 window.addFlags(LayoutParams.FLAG_NOT_FOCUSABLE
318 | LayoutParams.FLAG_NOT_TOUCH_MODAL
319 | LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
320 | LayoutParams.FLAG_HARDWARE_ACCELERATED);
321 mDialog.setCanceledOnTouchOutside(true);
322 mDialog.setContentView(com.android.systemui.R.layout.volume_dialog);
323 mDialog.setOnDismissListener(new OnDismissListener() {
324 @Override
325 public void onDismiss(DialogInterface dialog) {
326 mActiveStreamType = -1;
327 mAudioManager.forceVolumeControlStream(mActiveStreamType);
328 setZenPanelVisible(false);
329 }
330 });
Alan Viverettee8ebaf32014-04-11 15:44:15 -0700331
John Spurlockeb2727b2014-07-19 23:11:36 -0400332 mDialog.create();
333 // temporary workaround, until we support window-level shadows
334 mDialog.getWindow().setBackgroundDrawable(new ColorDrawable(0x00000000));
Alan Viverette494fb7b2014-04-10 18:12:56 -0700335
John Spurlockeb2727b2014-07-19 23:11:36 -0400336 mView = window.findViewById(R.id.content);
337 mView.setOnTouchListener(new View.OnTouchListener() {
338 @Override
339 public boolean onTouch(View v, MotionEvent event) {
340 resetTimeout();
341 return false;
342 }
343 });
Alan Viverette494fb7b2014-04-10 18:12:56 -0700344
John Spurlock86005342014-05-23 11:58:00 -0400345 mPanel = (ViewGroup) mView.findViewById(com.android.systemui.R.id.visible_panel);
346 mSliderPanel = (ViewGroup) mView.findViewById(com.android.systemui.R.id.slider_panel);
John Spurlockeb2727b2014-07-19 23:11:36 -0400347 mZenPanel = (ZenModePanel) mView.findViewById(com.android.systemui.R.id.zen_mode_panel);
348 initZenModePanel();
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800349
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800350 mToneGenerators = new ToneGenerator[AudioSystem.getNumStreamTypes()];
Alan Viverettee8ebaf32014-04-11 15:44:15 -0700351 mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
Amith Yamasani71def772011-10-12 12:25:24 -0700352 mVoiceCapable = context.getResources().getBoolean(R.bool.config_voice_capable);
Alan Viverettee8ebaf32014-04-11 15:44:15 -0700353
John Spurlock86005342014-05-23 11:58:00 -0400354 mZenModeCapable = !useMasterVolume && mZenController != null;
John Spurlockae641c92014-06-30 18:11:40 -0400355 updateZenMode(mZenController != null ? mZenController.getZen() : Global.ZEN_MODE_OFF);
John Spurlock86005342014-05-23 11:58:00 -0400356 mZenController.addCallback(mZenCallback);
Amith Yamasani42722bf2011-07-22 10:34:27 -0700357
Alan Viverettee8ebaf32014-04-11 15:44:15 -0700358 final boolean masterVolumeOnly = res.getBoolean(R.bool.config_useMasterVolume);
359 final boolean masterVolumeKeySounds = res.getBoolean(R.bool.config_useVolumeKeySounds);
Christopher Tatec4b78d22012-05-22 13:57:58 -0700360 mPlayMasterStreamTones = masterVolumeOnly && masterVolumeKeySounds;
361
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800362 listenToRingerMode();
363 }
364
John Spurlockeb2727b2014-07-19 23:11:36 -0400365 private void initZenModePanel() {
366 mZenPanel.init(mZenController);
367 mZenPanel.setCallback(new ZenModePanel.Callback() {
368 @Override
369 public void onMoreSettings() {
370 if (mCallback != null) {
371 mCallback.onZenSettings();
372 }
373 }
374
375 @Override
376 public void onInteraction() {
377 resetTimeout();
378 }
379
380 @Override
381 public void onExpanded(boolean expanded) {
382 if (mZenPanelExpanded == expanded) return;
383 mZenPanelExpanded = expanded;
384 updateTimeoutDelay();
385 resetTimeout();
386 }
387 });
John Spurlock7f8f22a2014-07-02 18:54:17 -0400388 }
389
John Spurlock86005342014-05-23 11:58:00 -0400390 private void setLayoutDirection(int layoutDirection) {
Fabrice Di Meglio8c028842013-01-09 18:20:38 -0800391 mPanel.setLayoutDirection(layoutDirection);
392 updateStates();
393 }
394
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800395 private void listenToRingerMode() {
396 final IntentFilter filter = new IntentFilter();
397 filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
398 mContext.registerReceiver(new BroadcastReceiver() {
Alan Viverette494fb7b2014-04-10 18:12:56 -0700399 @Override
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800400 public void onReceive(Context context, Intent intent) {
401 final String action = intent.getAction();
402
403 if (AudioManager.RINGER_MODE_CHANGED_ACTION.equals(action)) {
404 removeMessages(MSG_RINGER_MODE_CHANGED);
405 sendMessage(obtainMessage(MSG_RINGER_MODE_CHANGED));
406 }
407 }
408 }, filter);
409 }
410
411 private boolean isMuted(int streamType) {
Mike Lockwood8dc1dab2011-10-27 09:52:41 -0400412 if (streamType == STREAM_MASTER) {
Eric Laurent8c787522012-05-14 14:09:43 -0700413 return mAudioManager.isMasterMute();
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700414 } else if (streamType == AudioService.STREAM_REMOTE_MUSIC) {
RoboErik19c95182014-06-23 15:38:48 -0700415 // TODO do we need to support a distinct mute property for remote?
416 return false;
Mike Lockwood8dc1dab2011-10-27 09:52:41 -0400417 } else {
Eric Laurent8c787522012-05-14 14:09:43 -0700418 return mAudioManager.isStreamMute(streamType);
Mike Lockwood8dc1dab2011-10-27 09:52:41 -0400419 }
420 }
421
422 private int getStreamMaxVolume(int streamType) {
Mike Lockwood8dc1dab2011-10-27 09:52:41 -0400423 if (streamType == STREAM_MASTER) {
Eric Laurent8c787522012-05-14 14:09:43 -0700424 return mAudioManager.getMasterMaxVolume();
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700425 } else if (streamType == AudioService.STREAM_REMOTE_MUSIC) {
RoboErik19c95182014-06-23 15:38:48 -0700426 if (mStreamControls != null) {
427 StreamControl sc = mStreamControls.get(streamType);
428 if (sc != null && sc.controller != null) {
429 VolumeInfo vi = sc.controller.getVolumeInfo();
430 return vi.getMaxVolume();
431 }
432 }
433 return -1;
Mike Lockwood8dc1dab2011-10-27 09:52:41 -0400434 } else {
Eric Laurent8c787522012-05-14 14:09:43 -0700435 return mAudioManager.getStreamMaxVolume(streamType);
Mike Lockwood8dc1dab2011-10-27 09:52:41 -0400436 }
437 }
438
439 private int getStreamVolume(int streamType) {
Mike Lockwood8dc1dab2011-10-27 09:52:41 -0400440 if (streamType == STREAM_MASTER) {
Eric Laurent8c787522012-05-14 14:09:43 -0700441 return mAudioManager.getMasterVolume();
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700442 } else if (streamType == AudioService.STREAM_REMOTE_MUSIC) {
RoboErik19c95182014-06-23 15:38:48 -0700443 if (mStreamControls != null) {
444 StreamControl sc = mStreamControls.get(streamType);
445 if (sc != null && sc.controller != null) {
446 VolumeInfo vi = sc.controller.getVolumeInfo();
447 return vi.getCurrentVolume();
448 }
449 }
450 return -1;
Mike Lockwood8dc1dab2011-10-27 09:52:41 -0400451 } else {
Eric Laurent8c787522012-05-14 14:09:43 -0700452 return mAudioManager.getStreamVolume(streamType);
Mike Lockwood8dc1dab2011-10-27 09:52:41 -0400453 }
454 }
455
RoboErik19c95182014-06-23 15:38:48 -0700456 private void setStreamVolume(StreamControl sc, int index, int flags) {
457 if (sc.streamType == AudioService.STREAM_REMOTE_MUSIC) {
458 if (sc.controller != null) {
459 sc.controller.setVolumeTo(index, flags);
460 } else {
Jean-Michel Trivi65820412014-06-30 12:10:44 -0700461 Log.w(mTag, "Adjusting remote volume without a controller!");
RoboErik19c95182014-06-23 15:38:48 -0700462 }
463 } else if (getStreamVolume(sc.streamType) != index) {
464 if (sc.streamType == STREAM_MASTER) {
465 mAudioManager.setMasterVolume(index, flags);
466 } else {
467 mAudioManager.setStreamVolume(sc.streamType, index, flags);
468 }
Mike Lockwood8dc1dab2011-10-27 09:52:41 -0400469 }
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800470 }
471
472 private void createSliders() {
Alan Viverette494fb7b2014-04-10 18:12:56 -0700473 final Resources res = mContext.getResources();
474 final LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
475 Context.LAYOUT_INFLATER_SERVICE);
476
Amith Yamasani71def772011-10-12 12:25:24 -0700477 mStreamControls = new HashMap<Integer, StreamControl>(STREAMS.length);
Alan Viverette494fb7b2014-04-10 18:12:56 -0700478
Amith Yamasani71def772011-10-12 12:25:24 -0700479 for (int i = 0; i < STREAMS.length; i++) {
480 StreamResources streamRes = STREAMS[i];
Alan Viverette494fb7b2014-04-10 18:12:56 -0700481
482 final int streamType = streamRes.streamType;
Alan Viverette494fb7b2014-04-10 18:12:56 -0700483
484 final StreamControl sc = new StreamControl();
Amith Yamasanid47a3aee2011-08-23 11:11:35 -0700485 sc.streamType = streamType;
John Spurlock86005342014-05-23 11:58:00 -0400486 sc.group = (ViewGroup) inflater.inflate(
487 com.android.systemui.R.layout.volume_panel_item, null);
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800488 sc.group.setTag(sc);
John Spurlock86005342014-05-23 11:58:00 -0400489 sc.icon = (ImageView) sc.group.findViewById(com.android.systemui.R.id.stream_icon);
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800490 sc.icon.setTag(sc);
Amith Yamasani71def772011-10-12 12:25:24 -0700491 sc.icon.setContentDescription(res.getString(streamRes.descRes));
492 sc.iconRes = streamRes.iconRes;
493 sc.iconMuteRes = streamRes.iconMuteRes;
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800494 sc.icon.setImageResource(sc.iconRes);
John Spurlock7f1df5e2014-05-31 19:11:40 -0400495 sc.icon.setClickable(isNotificationOrRing(streamType));
496 if (sc.icon.isClickable()) {
John Spurlockab4ea762014-07-19 18:50:16 -0400497 sc.icon.setSoundEffectsEnabled(false);
John Spurlock7f1df5e2014-05-31 19:11:40 -0400498 sc.icon.setOnClickListener(new OnClickListener() {
499 @Override
500 public void onClick(View v) {
501 resetTimeout();
502 toggle(sc);
503 }
504 });
John Spurlock7f1df5e2014-05-31 19:11:40 -0400505 }
John Spurlock86005342014-05-23 11:58:00 -0400506 sc.seekbarView = (SeekBar) sc.group.findViewById(com.android.systemui.R.id.seekbar);
Alan Viverette494fb7b2014-04-10 18:12:56 -0700507 final int plusOne = (streamType == AudioSystem.STREAM_BLUETOOTH_SCO ||
Amith Yamasanid47a3aee2011-08-23 11:11:35 -0700508 streamType == AudioSystem.STREAM_VOICE_CALL) ? 1 : 0;
Mike Lockwood8dc1dab2011-10-27 09:52:41 -0400509 sc.seekbarView.setMax(getStreamMaxVolume(streamType) + plusOne);
Alan Viverettee8ebaf32014-04-11 15:44:15 -0700510 sc.seekbarView.setOnSeekBarChangeListener(mSeekListener);
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800511 sc.seekbarView.setTag(sc);
Amith Yamasanid47a3aee2011-08-23 11:11:35 -0700512 mStreamControls.put(streamType, sc);
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800513 }
514 }
515
John Spurlock7f1df5e2014-05-31 19:11:40 -0400516 private void toggle(StreamControl sc) {
517 if (mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_NORMAL) {
518 mAudioManager.setRingerMode(AudioManager.RINGER_MODE_VIBRATE);
519 postVolumeChanged(sc.streamType, AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_VIBRATE);
520 } else {
521 mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
522 postVolumeChanged(sc.streamType, AudioManager.FLAG_PLAY_SOUND);
523 }
524 }
525
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800526 private void reorderSliders(int activeStreamType) {
John Spurlock86005342014-05-23 11:58:00 -0400527 mSliderPanel.removeAllViews();
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800528
Alan Viverette494fb7b2014-04-10 18:12:56 -0700529 final StreamControl active = mStreamControls.get(activeStreamType);
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800530 if (active == null) {
John Spurlockae641c92014-06-30 18:11:40 -0400531 Log.e(TAG, "Missing stream type! - " + activeStreamType);
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800532 mActiveStreamType = -1;
533 } else {
John Spurlock86005342014-05-23 11:58:00 -0400534 mSliderPanel.addView(active.group);
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800535 mActiveStreamType = activeStreamType;
536 active.group.setVisibility(View.VISIBLE);
537 updateSlider(active);
John Spurlock8845da72014-07-07 21:29:48 -0400538 updateTimeoutDelay();
John Spurlockae641c92014-06-30 18:11:40 -0400539 setZenPanelVisible(isNotificationOrRing(mActiveStreamType));
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800540 }
541 }
542
543 /** Update the mute and progress state of a slider */
544 private void updateSlider(StreamControl sc) {
Eric Laurent8c787522012-05-14 14:09:43 -0700545 sc.seekbarView.setProgress(getStreamVolume(sc.streamType));
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800546 final boolean muted = isMuted(sc.streamType);
Fabrice Di Meglio8c028842013-01-09 18:20:38 -0800547 // Force reloading the image resource
548 sc.icon.setImageDrawable(null);
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800549 sc.icon.setImageResource(muted ? sc.iconMuteRes : sc.iconRes);
John Spurlock7f1df5e2014-05-31 19:11:40 -0400550 if (isNotificationOrRing(sc.streamType) &&
Eric Laurent8c787522012-05-14 14:09:43 -0700551 mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_VIBRATE) {
John Spurlock86005342014-05-23 11:58:00 -0400552 sc.icon.setImageResource(com.android.systemui.R.drawable.ic_ringer_vibrate);
Amith Yamasanic696a532011-10-28 17:02:37 -0700553 }
John Spurlock7f1df5e2014-05-31 19:11:40 -0400554 updateSliderEnabled(sc, muted, false);
555 }
556
John Spurlock5f640e42014-05-31 20:15:59 -0400557 private void updateSliderEnabled(final StreamControl sc, boolean muted, boolean fixedVolume) {
558 final boolean wasEnabled = sc.seekbarView.isEnabled();
John Spurlockae641c92014-06-30 18:11:40 -0400559 final boolean isRinger = isNotificationOrRing(sc.streamType);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700560 if (sc.streamType == AudioService.STREAM_REMOTE_MUSIC) {
561 // never disable touch interactions for remote playback, the muting is not tied to
562 // the state of the phone.
RoboErik19c95182014-06-23 15:38:48 -0700563 sc.seekbarView.setEnabled(!fixedVolume);
John Spurlock7f1df5e2014-05-31 19:11:40 -0400564 } else if (fixedVolume ||
565 (sc.streamType != mAudioManager.getMasterStreamType() && muted) ||
Eric Laurentfde16d52012-12-03 14:42:39 -0800566 (sConfirmSafeVolumeDialog != null)) {
Eric Laurent8c787522012-05-14 14:09:43 -0700567 sc.seekbarView.setEnabled(false);
John Spurlockae641c92014-06-30 18:11:40 -0400568 } else if (isRinger && mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_SILENT) {
John Spurlock7f1df5e2014-05-31 19:11:40 -0400569 sc.seekbarView.setEnabled(false);
John Spurlockae641c92014-06-30 18:11:40 -0400570 sc.icon.setEnabled(false);
571 sc.icon.setClickable(false);
Eric Laurent8c787522012-05-14 14:09:43 -0700572 } else {
573 sc.seekbarView.setEnabled(true);
John Spurlockae641c92014-06-30 18:11:40 -0400574 sc.icon.setEnabled(true);
Eric Laurent8c787522012-05-14 14:09:43 -0700575 }
John Spurlockae641c92014-06-30 18:11:40 -0400576 // show the silent hint when the disabled slider is touched in silent mode
577 if (isRinger && wasEnabled != sc.seekbarView.isEnabled()) {
John Spurlock5f640e42014-05-31 20:15:59 -0400578 if (sc.seekbarView.isEnabled()) {
John Spurlockae641c92014-06-30 18:11:40 -0400579 sc.group.setOnTouchListener(null);
580 sc.icon.setClickable(true);
John Spurlock5f640e42014-05-31 20:15:59 -0400581 } else {
John Spurlockae641c92014-06-30 18:11:40 -0400582 final View.OnTouchListener showHintOnTouch = new View.OnTouchListener() {
John Spurlock5f640e42014-05-31 20:15:59 -0400583 @Override
584 public boolean onTouch(View v, MotionEvent event) {
585 resetTimeout();
John Spurlockae641c92014-06-30 18:11:40 -0400586 showSilentHint();
John Spurlock5f640e42014-05-31 20:15:59 -0400587 return false;
588 }
John Spurlockae641c92014-06-30 18:11:40 -0400589 };
590 sc.group.setOnTouchListener(showHintOnTouch);
John Spurlock5f640e42014-05-31 20:15:59 -0400591 }
592 }
593 }
594
John Spurlockae641c92014-06-30 18:11:40 -0400595 private void showSilentHint() {
596 if (mZenPanel != null) {
597 mZenPanel.showSilentHint();
598 }
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800599 }
600
John Spurlock7f1df5e2014-05-31 19:11:40 -0400601 private static boolean isNotificationOrRing(int streamType) {
602 return streamType == AudioManager.STREAM_RING
603 || streamType == AudioManager.STREAM_NOTIFICATION;
604 }
605
John Spurlockae641c92014-06-30 18:11:40 -0400606 public void setCallback(Callback callback) {
607 mCallback = callback;
John Spurlock86005342014-05-23 11:58:00 -0400608 }
609
John Spurlock8845da72014-07-07 21:29:48 -0400610 private void updateTimeoutDelay() {
611 mTimeoutDelay = mActiveStreamType == AudioManager.STREAM_MUSIC ? TIMEOUT_DELAY_SHORT
John Spurlockea9938c2014-07-11 18:51:32 -0400612 : mZenPanelExpanded ? TIMEOUT_DELAY_EXPANDED
613 : isZenPanelVisible() ? TIMEOUT_DELAY_COLLAPSED
614 : TIMEOUT_DELAY;
615 }
616
617 private boolean isZenPanelVisible() {
618 return mZenPanel != null && mZenPanel.getVisibility() == View.VISIBLE;
John Spurlock8845da72014-07-07 21:29:48 -0400619 }
620
John Spurlockae641c92014-06-30 18:11:40 -0400621 private void setZenPanelVisible(boolean visible) {
622 if (LOGD) Log.d(mTag, "setZenPanelVisible " + visible + " mZenPanel=" + mZenPanel);
John Spurlockea9938c2014-07-11 18:51:32 -0400623 final boolean changing = visible != isZenPanelVisible();
John Spurlockae641c92014-06-30 18:11:40 -0400624 if (visible) {
John Spurlockeb2727b2014-07-19 23:11:36 -0400625 mZenPanel.setHidden(false);
John Spurlockae641c92014-06-30 18:11:40 -0400626 resetTimeout();
627 } else {
John Spurlockeb2727b2014-07-19 23:11:36 -0400628 mZenPanel.setHidden(true);
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800629 }
John Spurlockea9938c2014-07-11 18:51:32 -0400630 if (changing) {
631 updateTimeoutDelay();
632 resetTimeout();
633 }
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800634 }
635
Eric Laurentfde16d52012-12-03 14:42:39 -0800636 public void updateStates() {
John Spurlock86005342014-05-23 11:58:00 -0400637 final int count = mSliderPanel.getChildCount();
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800638 for (int i = 0; i < count; i++) {
John Spurlock86005342014-05-23 11:58:00 -0400639 StreamControl sc = (StreamControl) mSliderPanel.getChildAt(i).getTag();
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800640 updateSlider(sc);
641 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800642 }
643
John Spurlockae641c92014-06-30 18:11:40 -0400644 private void updateZenMode(int zen) {
645 final boolean show = mZenModeCapable && isNotificationOrRing(mActiveStreamType);
646 setZenPanelVisible(show);
John Spurlock86005342014-05-23 11:58:00 -0400647 }
648
John Spurlockae641c92014-06-30 18:11:40 -0400649 public void postZenModeChanged(int zen) {
John Spurlock86005342014-05-23 11:58:00 -0400650 removeMessages(MSG_ZEN_MODE_CHANGED);
John Spurlockae641c92014-06-30 18:11:40 -0400651 obtainMessage(MSG_ZEN_MODE_CHANGED, zen).sendToTarget();
John Spurlock86005342014-05-23 11:58:00 -0400652 }
653
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800654 public void postVolumeChanged(int streamType, int flags) {
655 if (hasMessages(MSG_VOLUME_CHANGED)) return;
Amith Yamasania6549862012-05-30 17:29:28 -0700656 synchronized (this) {
657 if (mStreamControls == null) {
658 createSliders();
659 }
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800660 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800661 removeMessages(MSG_FREE_RESOURCES);
662 obtainMessage(MSG_VOLUME_CHANGED, streamType, flags).sendToTarget();
663 }
664
RoboErik19c95182014-06-23 15:38:48 -0700665 public void postRemoteVolumeChanged(MediaController controller, int flags) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700666 if (hasMessages(MSG_REMOTE_VOLUME_CHANGED)) return;
667 synchronized (this) {
668 if (mStreamControls == null) {
669 createSliders();
670 }
671 }
672 removeMessages(MSG_FREE_RESOURCES);
RoboErik19c95182014-06-23 15:38:48 -0700673 obtainMessage(MSG_REMOTE_VOLUME_CHANGED, flags, 0, controller).sendToTarget();
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700674 }
675
676 public void postRemoteSliderVisibility(boolean visible) {
677 obtainMessage(MSG_SLIDER_VISIBILITY_CHANGED,
678 AudioService.STREAM_REMOTE_MUSIC, visible ? 1 : 0).sendToTarget();
679 }
680
681 /**
682 * Called by AudioService when it has received new remote playback information that
683 * would affect the VolumePanel display (mainly volumes). The difference with
684 * {@link #postRemoteVolumeChanged(int, int)} is that the handling of the posted message
685 * (MSG_REMOTE_VOLUME_UPDATE_IF_SHOWN) will only update the volume slider if it is being
686 * displayed.
687 * This special code path is due to the fact that remote volume updates arrive to AudioService
688 * asynchronously. So after AudioService has sent the volume update (which should be treated
689 * as a request to update the volume), the application will likely set a new volume. If the UI
690 * is still up, we need to refresh the display to show this new value.
691 */
692 public void postHasNewRemotePlaybackInfo() {
693 if (hasMessages(MSG_REMOTE_VOLUME_UPDATE_IF_SHOWN)) return;
694 // don't create or prevent resources to be freed, if they disappear, this update came too
695 // late and shouldn't warrant the panel to be displayed longer
696 obtainMessage(MSG_REMOTE_VOLUME_UPDATE_IF_SHOWN).sendToTarget();
697 }
698
Mike Lockwood8dc1dab2011-10-27 09:52:41 -0400699 public void postMasterVolumeChanged(int flags) {
700 postVolumeChanged(STREAM_MASTER, flags);
701 }
702
Mike Lockwoodce952c82011-11-14 10:47:42 -0800703 public void postMuteChanged(int streamType, int flags) {
704 if (hasMessages(MSG_VOLUME_CHANGED)) return;
Amith Yamasania6549862012-05-30 17:29:28 -0700705 synchronized (this) {
706 if (mStreamControls == null) {
707 createSliders();
708 }
Mike Lockwoodce952c82011-11-14 10:47:42 -0800709 }
710 removeMessages(MSG_FREE_RESOURCES);
711 obtainMessage(MSG_MUTE_CHANGED, streamType, flags).sendToTarget();
712 }
713
714 public void postMasterMuteChanged(int flags) {
715 postMuteChanged(STREAM_MASTER, flags);
716 }
717
Eric Laurentfde16d52012-12-03 14:42:39 -0800718 public void postDisplaySafeVolumeWarning(int flags) {
Eric Laurent0516a9e2012-09-19 11:53:03 -0700719 if (hasMessages(MSG_DISPLAY_SAFE_VOLUME_WARNING)) return;
Eric Laurentfde16d52012-12-03 14:42:39 -0800720 obtainMessage(MSG_DISPLAY_SAFE_VOLUME_WARNING, flags, 0).sendToTarget();
Eric Laurentc34dcc12012-09-10 13:51:52 -0700721 }
722
John Spurlock1dad2722014-07-11 11:07:53 -0400723 public void postDismiss(long delay) {
724 forceTimeout(delay);
John Spurlock86005342014-05-23 11:58:00 -0400725 }
726
727 public void postLayoutDirection(int layoutDirection) {
728 removeMessages(MSG_LAYOUT_DIRECTION);
John Spurlock84da84c2014-05-31 22:21:52 -0400729 obtainMessage(MSG_LAYOUT_DIRECTION, layoutDirection, 0).sendToTarget();
John Spurlock3346a802014-05-20 16:25:37 -0400730 }
731
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800732 /**
733 * Override this if you have other work to do when the volume changes (for
734 * example, vibrating, playing a sound, etc.). Make sure to call through to
735 * the superclass implementation.
736 */
737 protected void onVolumeChanged(int streamType, int flags) {
738
John Spurlock86005342014-05-23 11:58:00 -0400739 if (LOGD) Log.d(mTag, "onVolumeChanged(streamType: " + streamType + ", flags: " + flags + ")");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800740
741 if ((flags & AudioManager.FLAG_SHOW_UI) != 0) {
Amith Yamasania6549862012-05-30 17:29:28 -0700742 synchronized (this) {
743 if (mActiveStreamType != streamType) {
744 reorderSliders(streamType);
745 }
RoboErik19c95182014-06-23 15:38:48 -0700746 onShowVolumeChanged(streamType, flags, null);
Amith Yamasanie3361b82011-02-10 18:20:50 -0800747 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800748 }
749
Marco Nelissen69f593c2009-07-28 09:55:04 -0700750 if ((flags & AudioManager.FLAG_PLAY_SOUND) != 0 && ! mRingIsSilent) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800751 removeMessages(MSG_PLAY_SOUND);
752 sendMessageDelayed(obtainMessage(MSG_PLAY_SOUND, streamType, flags), PLAY_SOUND_DELAY);
753 }
754
755 if ((flags & AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE) != 0) {
756 removeMessages(MSG_PLAY_SOUND);
757 removeMessages(MSG_VIBRATE);
758 onStopSounds();
759 }
760
761 removeMessages(MSG_FREE_RESOURCES);
762 sendMessageDelayed(obtainMessage(MSG_FREE_RESOURCES), FREE_DELAY);
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800763 resetTimeout();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800764 }
765
Mike Lockwoodce952c82011-11-14 10:47:42 -0800766 protected void onMuteChanged(int streamType, int flags) {
767
John Spurlock86005342014-05-23 11:58:00 -0400768 if (LOGD) Log.d(mTag, "onMuteChanged(streamType: " + streamType + ", flags: " + flags + ")");
Mike Lockwoodce952c82011-11-14 10:47:42 -0800769
770 StreamControl sc = mStreamControls.get(streamType);
771 if (sc != null) {
772 sc.icon.setImageResource(isMuted(sc.streamType) ? sc.iconMuteRes : sc.iconRes);
773 }
774
775 onVolumeChanged(streamType, flags);
776 }
777
RoboErik19c95182014-06-23 15:38:48 -0700778 protected void onShowVolumeChanged(int streamType, int flags, MediaController controller) {
Eric Laurent8c787522012-05-14 14:09:43 -0700779 int index = getStreamVolume(streamType);
Eric Laurentd72d51c2011-02-03 18:47:47 -0800780
Marco Nelissen69f593c2009-07-28 09:55:04 -0700781 mRingIsSilent = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800782
783 if (LOGD) {
John Spurlock86005342014-05-23 11:58:00 -0400784 Log.d(mTag, "onShowVolumeChanged(streamType: " + streamType
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800785 + ", flags: " + flags + "), index: " + index);
786 }
787
788 // get max volume for progress bar
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800789
Mike Lockwood8dc1dab2011-10-27 09:52:41 -0400790 int max = getStreamMaxVolume(streamType);
RoboErik19c95182014-06-23 15:38:48 -0700791 StreamControl sc = mStreamControls.get(streamType);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800792
793 switch (streamType) {
794
795 case AudioManager.STREAM_RING: {
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800796// setRingerIcon();
Marco Nelissen69f593c2009-07-28 09:55:04 -0700797 Uri ringuri = RingtoneManager.getActualDefaultRingtoneUri(
798 mContext, RingtoneManager.TYPE_RINGTONE);
799 if (ringuri == null) {
Marco Nelissen69f593c2009-07-28 09:55:04 -0700800 mRingIsSilent = true;
801 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800802 break;
803 }
804
805 case AudioManager.STREAM_MUSIC: {
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800806 // Special case for when Bluetooth is active for music
Glenn Kasten8b4b97a2011-02-04 13:54:26 -0800807 if ((mAudioManager.getDevicesForStream(AudioManager.STREAM_MUSIC) &
808 (AudioManager.DEVICE_OUT_BLUETOOTH_A2DP |
809 AudioManager.DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
810 AudioManager.DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER)) != 0) {
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800811 setMusicIcon(R.drawable.ic_audio_bt, R.drawable.ic_audio_bt_mute);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800812 } else {
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800813 setMusicIcon(R.drawable.ic_audio_vol, R.drawable.ic_audio_vol_mute);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800814 }
815 break;
816 }
817
818 case AudioManager.STREAM_VOICE_CALL: {
819 /*
820 * For in-call voice call volume, there is no inaudible volume.
821 * Rescale the UI control so the progress bar doesn't go all
822 * the way to zero and don't show the mute icon.
823 */
824 index++;
825 max++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800826 break;
827 }
828
829 case AudioManager.STREAM_ALARM: {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800830 break;
831 }
832
833 case AudioManager.STREAM_NOTIFICATION: {
Marco Nelissen69f593c2009-07-28 09:55:04 -0700834 Uri ringuri = RingtoneManager.getActualDefaultRingtoneUri(
835 mContext, RingtoneManager.TYPE_NOTIFICATION);
836 if (ringuri == null) {
Marco Nelissen69f593c2009-07-28 09:55:04 -0700837 mRingIsSilent = true;
838 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800839 break;
840 }
841
842 case AudioManager.STREAM_BLUETOOTH_SCO: {
843 /*
844 * For in-call voice call volume, there is no inaudible volume.
845 * Rescale the UI control so the progress bar doesn't go all
846 * the way to zero and don't show the mute icon.
847 */
848 index++;
849 max++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800850 break;
851 }
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700852
853 case AudioService.STREAM_REMOTE_MUSIC: {
RoboErik19c95182014-06-23 15:38:48 -0700854 if (controller == null && sc != null) {
855 // If we weren't passed one try using the last one set.
856 controller = sc.controller;
857 }
858 if (controller == null) {
859 // We still don't have one, ignore the command.
860 Log.w(mTag, "sent remote volume change without a controller!");
861 } else {
862 VolumeInfo vi = controller.getVolumeInfo();
863 index = vi.getCurrentVolume();
864 max = vi.getMaxVolume();
865 if ((vi.getVolumeControl() & VolumeProvider.VOLUME_CONTROL_FIXED) != 0) {
866 // if the remote volume is fixed add the flag for the UI
867 flags |= AudioManager.FLAG_FIXED_VOLUME;
868 }
869 }
John Spurlock86005342014-05-23 11:58:00 -0400870 if (LOGD) { Log.d(mTag, "showing remote volume "+index+" over "+ max); }
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700871 break;
872 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800873 }
874
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800875 if (sc != null) {
RoboErik19c95182014-06-23 15:38:48 -0700876 if (streamType == AudioService.STREAM_REMOTE_MUSIC && controller != sc.controller) {
877 if (sc.controller != null) {
878 sc.controller.removeCallback(mMediaControllerCb);
879 }
880 sc.controller = controller;
881 if (controller != null) {
882 sc.controller.addCallback(mMediaControllerCb);
883 }
884 }
Amith Yamasanid47a3aee2011-08-23 11:11:35 -0700885 if (sc.seekbarView.getMax() != max) {
886 sc.seekbarView.setMax(max);
887 }
Eric Laurent4bbcc652012-09-24 14:26:30 -0700888
Amith Yamasani2bbdd772011-02-02 18:54:13 -0800889 sc.seekbarView.setProgress(index);
John Spurlock7f1df5e2014-05-31 19:11:40 -0400890 updateSliderEnabled(sc, isMuted(streamType),
891 (flags & AudioManager.FLAG_FIXED_VOLUME) != 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800892 }
893
John Spurlock86005342014-05-23 11:58:00 -0400894 if (!isShowing()) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700895 int stream = (streamType == AudioService.STREAM_REMOTE_MUSIC) ? -1 : streamType;
896 // when the stream is for remote playback, use -1 to reset the stream type evaluation
897 mAudioManager.forceVolumeControlStream(stream);
Alan Viverettee8ebaf32014-04-11 15:44:15 -0700898
John Spurlockeb2727b2014-07-19 23:11:36 -0400899 mDialog.show();
900 if (mCallback != null) {
901 mCallback.onVisible(true);
John Spurlock86005342014-05-23 11:58:00 -0400902 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800903 }
904
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800905 // Do a little vibrate if applicable (only when going into vibrate mode)
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700906 if ((streamType != AudioService.STREAM_REMOTE_MUSIC) &&
907 ((flags & AudioManager.FLAG_VIBRATE) != 0) &&
John Spurlock3346a802014-05-20 16:25:37 -0400908 mAudioManager.isStreamAffectedByRingerMode(streamType) &&
Eric Laurent8c787522012-05-14 14:09:43 -0700909 mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_VIBRATE) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800910 sendMessageDelayed(obtainMessage(MSG_VIBRATE), VIBRATE_DELAY);
911 }
John Spurlocka11b4af2014-06-01 11:52:23 -0400912
913 // Pulse the slider icon if an adjustment was suppressed due to silent mode.
John Spurlockae641c92014-06-30 18:11:40 -0400914 if ((flags & AudioManager.FLAG_SHOW_SILENT_HINT) != 0) {
915 showSilentHint();
John Spurlocka11b4af2014-06-01 11:52:23 -0400916 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800917 }
918
John Spurlock86005342014-05-23 11:58:00 -0400919 private boolean isShowing() {
John Spurlockeb2727b2014-07-19 23:11:36 -0400920 return mDialog.isShowing();
John Spurlock86005342014-05-23 11:58:00 -0400921 }
922
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800923 protected void onPlaySound(int streamType, int flags) {
924
925 if (hasMessages(MSG_STOP_SOUNDS)) {
926 removeMessages(MSG_STOP_SOUNDS);
927 // Force stop right now
928 onStopSounds();
929 }
930
931 synchronized (this) {
932 ToneGenerator toneGen = getOrCreateToneGenerator(streamType);
Eric Laurent733a42b2011-01-19 10:41:57 -0800933 if (toneGen != null) {
934 toneGen.startTone(ToneGenerator.TONE_PROP_BEEP);
935 sendMessageDelayed(obtainMessage(MSG_STOP_SOUNDS), BEEP_DURATION);
936 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800937 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800938 }
939
940 protected void onStopSounds() {
941
942 synchronized (this) {
943 int numStreamTypes = AudioSystem.getNumStreamTypes();
944 for (int i = numStreamTypes - 1; i >= 0; i--) {
945 ToneGenerator toneGen = mToneGenerators[i];
946 if (toneGen != null) {
947 toneGen.stopTone();
948 }
949 }
950 }
951 }
952
953 protected void onVibrate() {
954
955 // Make sure we ended up in vibrate ringer mode
Eric Laurent8c787522012-05-14 14:09:43 -0700956 if (mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_VIBRATE) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800957 return;
958 }
959
John Spurlock7b414672014-07-18 13:02:39 -0400960 mVibrator.vibrate(VIBRATE_DURATION, VIBRATION_ATTRIBUTES);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800961 }
962
RoboErik19c95182014-06-23 15:38:48 -0700963 protected void onRemoteVolumeChanged(MediaController controller, int flags) {
964 if (LOGD) Log.d(mTag, "onRemoteVolumeChanged(controller:" + controller + ", flags: " + flags
965 + ")");
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700966
John Spurlock86005342014-05-23 11:58:00 -0400967 if (((flags & AudioManager.FLAG_SHOW_UI) != 0) || isShowing()) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700968 synchronized (this) {
969 if (mActiveStreamType != AudioService.STREAM_REMOTE_MUSIC) {
970 reorderSliders(AudioService.STREAM_REMOTE_MUSIC);
971 }
RoboErik19c95182014-06-23 15:38:48 -0700972 onShowVolumeChanged(AudioService.STREAM_REMOTE_MUSIC, flags, controller);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700973 }
974 } else {
John Spurlock86005342014-05-23 11:58:00 -0400975 if (LOGD) Log.d(mTag, "not calling onShowVolumeChanged(), no FLAG_SHOW_UI or no UI");
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700976 }
977
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700978 removeMessages(MSG_FREE_RESOURCES);
979 sendMessageDelayed(obtainMessage(MSG_FREE_RESOURCES), FREE_DELAY);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700980 resetTimeout();
981 }
982
983 protected void onRemoteVolumeUpdateIfShown() {
John Spurlock86005342014-05-23 11:58:00 -0400984 if (LOGD) Log.d(mTag, "onRemoteVolumeUpdateIfShown()");
985 if (isShowing()
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700986 && (mActiveStreamType == AudioService.STREAM_REMOTE_MUSIC)
987 && (mStreamControls != null)) {
RoboErik19c95182014-06-23 15:38:48 -0700988 onShowVolumeChanged(AudioService.STREAM_REMOTE_MUSIC, 0, null);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700989 }
990 }
991
RoboErik19c95182014-06-23 15:38:48 -0700992 /**
993 * Clear the current remote stream controller.
994 */
995 private void clearRemoteStreamController() {
996 if (mStreamControls != null) {
997 StreamControl sc = mStreamControls.get(AudioService.STREAM_REMOTE_MUSIC);
998 if (sc != null) {
999 if (sc.controller != null) {
1000 sc.controller.removeCallback(mMediaControllerCb);
1001 sc.controller = null;
1002 }
1003 }
1004 }
1005 }
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07001006
1007 /**
1008 * Handler for MSG_SLIDER_VISIBILITY_CHANGED
1009 * Hide or show a slider
1010 * @param streamType can be a valid stream type value, or VolumePanel.STREAM_MASTER,
1011 * or AudioService.STREAM_REMOTE_MUSIC
1012 * @param visible
1013 */
1014 synchronized protected void onSliderVisibilityChanged(int streamType, int visible) {
John Spurlock86005342014-05-23 11:58:00 -04001015 if (LOGD) Log.d(mTag, "onSliderVisibilityChanged(stream="+streamType+", visi="+visible+")");
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07001016 boolean isVisible = (visible == 1);
1017 for (int i = STREAMS.length - 1 ; i >= 0 ; i--) {
1018 StreamResources streamRes = STREAMS[i];
1019 if (streamRes.streamType == streamType) {
1020 streamRes.show = isVisible;
1021 if (!isVisible && (mActiveStreamType == streamType)) {
1022 mActiveStreamType = -1;
1023 }
1024 break;
1025 }
1026 }
1027 }
1028
Eric Laurentfde16d52012-12-03 14:42:39 -08001029 protected void onDisplaySafeVolumeWarning(int flags) {
John Spurlock86005342014-05-23 11:58:00 -04001030 if ((flags & AudioManager.FLAG_SHOW_UI) != 0 || isShowing()) {
Eric Laurentfde16d52012-12-03 14:42:39 -08001031 synchronized (sConfirmSafeVolumeLock) {
1032 if (sConfirmSafeVolumeDialog != null) {
1033 return;
1034 }
1035 sConfirmSafeVolumeDialog = new AlertDialog.Builder(mContext)
1036 .setMessage(com.android.internal.R.string.safe_media_volume_warning)
1037 .setPositiveButton(com.android.internal.R.string.yes,
1038 new DialogInterface.OnClickListener() {
Alan Viverettee8ebaf32014-04-11 15:44:15 -07001039 @Override
Eric Laurentfde16d52012-12-03 14:42:39 -08001040 public void onClick(DialogInterface dialog, int which) {
John Spurlock3346a802014-05-20 16:25:37 -04001041 mAudioManager.disableSafeMediaVolume();
Eric Laurentfde16d52012-12-03 14:42:39 -08001042 }
1043 })
1044 .setNegativeButton(com.android.internal.R.string.no, null)
1045 .setIconAttribute(android.R.attr.alertDialogIcon)
1046 .create();
1047 final WarningDialogReceiver warning = new WarningDialogReceiver(mContext,
1048 sConfirmSafeVolumeDialog, this);
Eric Laurent0516a9e2012-09-19 11:53:03 -07001049
Eric Laurentfde16d52012-12-03 14:42:39 -08001050 sConfirmSafeVolumeDialog.setOnDismissListener(warning);
1051 sConfirmSafeVolumeDialog.getWindow().setType(
1052 WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
1053 sConfirmSafeVolumeDialog.show();
1054 }
1055 updateStates();
Eric Laurentc34dcc12012-09-10 13:51:52 -07001056 }
Eric Laurentfde16d52012-12-03 14:42:39 -08001057 resetTimeout();
Eric Laurentc34dcc12012-09-10 13:51:52 -07001058 }
1059
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001060 /**
1061 * Lock on this VolumePanel instance as long as you use the returned ToneGenerator.
1062 */
1063 private ToneGenerator getOrCreateToneGenerator(int streamType) {
Christopher Tatec4b78d22012-05-22 13:57:58 -07001064 if (streamType == STREAM_MASTER) {
1065 // For devices that use the master volume setting only but still want to
1066 // play a volume-changed tone, direct the master volume pseudostream to
1067 // the system stream's tone generator.
1068 if (mPlayMasterStreamTones) {
1069 streamType = AudioManager.STREAM_SYSTEM;
1070 } else {
1071 return null;
1072 }
1073 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001074 synchronized (this) {
1075 if (mToneGenerators[streamType] == null) {
Eric Laurent733a42b2011-01-19 10:41:57 -08001076 try {
1077 mToneGenerators[streamType] = new ToneGenerator(streamType, MAX_VOLUME);
1078 } catch (RuntimeException e) {
1079 if (LOGD) {
John Spurlock86005342014-05-23 11:58:00 -04001080 Log.d(mTag, "ToneGenerator constructor failed with "
Eric Laurent733a42b2011-01-19 10:41:57 -08001081 + "RuntimeException: " + e);
1082 }
1083 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001084 }
Eric Laurent733a42b2011-01-19 10:41:57 -08001085 return mToneGenerators[streamType];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001086 }
1087 }
1088
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001089
1090 /**
Amith Yamasani2bbdd772011-02-02 18:54:13 -08001091 * Switch between icons because Bluetooth music is same as music volume, but with
1092 * different icons.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001093 */
Amith Yamasani2bbdd772011-02-02 18:54:13 -08001094 private void setMusicIcon(int resId, int resMuteId) {
1095 StreamControl sc = mStreamControls.get(AudioManager.STREAM_MUSIC);
1096 if (sc != null) {
1097 sc.iconRes = resId;
1098 sc.iconMuteRes = resMuteId;
1099 sc.icon.setImageResource(isMuted(sc.streamType) ? sc.iconMuteRes : sc.iconRes);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001100 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001101 }
1102
1103 protected void onFreeResources() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001104 synchronized (this) {
1105 for (int i = mToneGenerators.length - 1; i >= 0; i--) {
1106 if (mToneGenerators[i] != null) {
1107 mToneGenerators[i].release();
1108 }
1109 mToneGenerators[i] = null;
1110 }
1111 }
1112 }
1113
1114 @Override
1115 public void handleMessage(Message msg) {
1116 switch (msg.what) {
1117
1118 case MSG_VOLUME_CHANGED: {
1119 onVolumeChanged(msg.arg1, msg.arg2);
1120 break;
1121 }
1122
Mike Lockwoodce952c82011-11-14 10:47:42 -08001123 case MSG_MUTE_CHANGED: {
1124 onMuteChanged(msg.arg1, msg.arg2);
1125 break;
1126 }
1127
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001128 case MSG_FREE_RESOURCES: {
1129 onFreeResources();
1130 break;
1131 }
1132
1133 case MSG_STOP_SOUNDS: {
1134 onStopSounds();
1135 break;
1136 }
1137
1138 case MSG_PLAY_SOUND: {
1139 onPlaySound(msg.arg1, msg.arg2);
1140 break;
1141 }
1142
1143 case MSG_VIBRATE: {
1144 onVibrate();
1145 break;
1146 }
1147
Amith Yamasani2bbdd772011-02-02 18:54:13 -08001148 case MSG_TIMEOUT: {
John Spurlock86005342014-05-23 11:58:00 -04001149 if (isShowing()) {
John Spurlockeb2727b2014-07-19 23:11:36 -04001150 mDialog.dismiss();
1151 clearRemoteStreamController();
1152 mActiveStreamType = -1;
1153 if (mCallback != null) {
1154 mCallback.onVisible(false);
John Spurlock86005342014-05-23 11:58:00 -04001155 }
Amith Yamasani2bbdd772011-02-02 18:54:13 -08001156 }
Eric Laurentfde16d52012-12-03 14:42:39 -08001157 synchronized (sConfirmSafeVolumeLock) {
1158 if (sConfirmSafeVolumeDialog != null) {
1159 sConfirmSafeVolumeDialog.dismiss();
1160 }
1161 }
Amith Yamasani2bbdd772011-02-02 18:54:13 -08001162 break;
1163 }
1164 case MSG_RINGER_MODE_CHANGED: {
John Spurlock86005342014-05-23 11:58:00 -04001165 if (isShowing()) {
Amith Yamasani2bbdd772011-02-02 18:54:13 -08001166 updateStates();
1167 }
1168 break;
1169 }
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07001170
1171 case MSG_REMOTE_VOLUME_CHANGED: {
RoboErik19c95182014-06-23 15:38:48 -07001172 onRemoteVolumeChanged((MediaController) msg.obj, msg.arg1);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07001173 break;
1174 }
1175
1176 case MSG_REMOTE_VOLUME_UPDATE_IF_SHOWN:
1177 onRemoteVolumeUpdateIfShown();
1178 break;
1179
1180 case MSG_SLIDER_VISIBILITY_CHANGED:
1181 onSliderVisibilityChanged(msg.arg1, msg.arg2);
1182 break;
Eric Laurentc34dcc12012-09-10 13:51:52 -07001183
1184 case MSG_DISPLAY_SAFE_VOLUME_WARNING:
Eric Laurentfde16d52012-12-03 14:42:39 -08001185 onDisplaySafeVolumeWarning(msg.arg1);
Eric Laurentc34dcc12012-09-10 13:51:52 -07001186 break;
John Spurlock86005342014-05-23 11:58:00 -04001187
1188 case MSG_LAYOUT_DIRECTION:
1189 setLayoutDirection(msg.arg1);
1190 break;
1191
1192 case MSG_ZEN_MODE_CHANGED:
John Spurlockae641c92014-06-30 18:11:40 -04001193 updateZenMode(msg.arg1);
1194 break;
1195
1196 case MSG_USER_ACTIVITY:
1197 if (mCallback != null) {
1198 mCallback.onInteraction();
1199 }
John Spurlock86005342014-05-23 11:58:00 -04001200 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001201 }
1202 }
1203
John Spurlockae641c92014-06-30 18:11:40 -04001204 private void resetTimeout() {
John Spurlockea9938c2014-07-11 18:51:32 -04001205 if (LOGD) Log.d(mTag, "resetTimeout at " + System.currentTimeMillis()
1206 + " delay=" + mTimeoutDelay);
Amith Yamasani2bbdd772011-02-02 18:54:13 -08001207 removeMessages(MSG_TIMEOUT);
John Spurlock3bd4fee2014-05-29 20:51:09 -04001208 sendEmptyMessageDelayed(MSG_TIMEOUT, mTimeoutDelay);
John Spurlockae641c92014-06-30 18:11:40 -04001209 removeMessages(MSG_USER_ACTIVITY);
1210 sendEmptyMessage(MSG_USER_ACTIVITY);
Amith Yamasani2bbdd772011-02-02 18:54:13 -08001211 }
1212
John Spurlock1dad2722014-07-11 11:07:53 -04001213 private void forceTimeout(long delay) {
Amith Yamasanibaf6dbf2011-08-18 17:40:29 -07001214 removeMessages(MSG_TIMEOUT);
John Spurlock1dad2722014-07-11 11:07:53 -04001215 sendEmptyMessageDelayed(MSG_TIMEOUT, delay);
John Spurlock86005342014-05-23 11:58:00 -04001216 }
1217
1218 public ZenModeController getZenController() {
1219 return mZenController;
Amith Yamasanibaf6dbf2011-08-18 17:40:29 -07001220 }
1221
Alan Viverettee8ebaf32014-04-11 15:44:15 -07001222 private final OnSeekBarChangeListener mSeekListener = new OnSeekBarChangeListener() {
1223 @Override
1224 public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
1225 final Object tag = seekBar.getTag();
1226 if (fromUser && tag instanceof StreamControl) {
1227 StreamControl sc = (StreamControl) tag;
John Spurlockac9ab5b2014-07-20 13:09:44 -04001228 setStreamVolume(sc, progress,
1229 AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_VIBRATE);
Alan Viverettee8ebaf32014-04-11 15:44:15 -07001230 }
1231 resetTimeout();
1232 }
1233
1234 @Override
1235 public void onStartTrackingTouch(SeekBar seekBar) {
1236 }
1237
1238 @Override
1239 public void onStopTrackingTouch(SeekBar seekBar) {
Amith Yamasani2bbdd772011-02-02 18:54:13 -08001240 }
Alan Viverettee8ebaf32014-04-11 15:44:15 -07001241 };
Amith Yamasani2bbdd772011-02-02 18:54:13 -08001242
John Spurlock86005342014-05-23 11:58:00 -04001243 private final ZenModeController.Callback mZenCallback = new ZenModeController.Callback() {
John Spurlockae641c92014-06-30 18:11:40 -04001244 public void onZenChanged(int zen) {
John Spurlock7f1df5e2014-05-31 19:11:40 -04001245 postZenModeChanged(zen);
John Spurlock86005342014-05-23 11:58:00 -04001246 }
1247 };
RoboErik19c95182014-06-23 15:38:48 -07001248
1249 private final MediaController.Callback mMediaControllerCb = new MediaController.Callback() {
1250 public void onVolumeInfoChanged(VolumeInfo info) {
1251 onRemoteVolumeUpdateIfShown();
1252 }
1253 };
John Spurlockae641c92014-06-30 18:11:40 -04001254
1255 public interface Callback {
1256 void onZenSettings();
1257 void onInteraction();
John Spurlock33f4e042014-07-11 13:10:58 -04001258 void onVisible(boolean visible);
John Spurlockae641c92014-06-30 18:11:40 -04001259 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001260}