blob: 385438c65ba7cf279e5d7c028dd4d3c4b3ebe3f0 [file] [log] [blame]
John Spurlockf88d8082015-03-25 18:09:51 -04001/*
2 * Copyright (C) 2015 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
17package com.android.systemui.volume;
18
Jason Monk782cd672017-03-22 12:50:57 -040019import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_ALL_MASK;
20import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_GENERIC;
21
Julia Reynoldsfba474a82017-12-13 15:35:54 -050022import static com.android.systemui.volume.Events.DISMISS_REASON_OUTPUT_CHOOSER;
Julia Reynolds0a228562018-01-10 12:53:40 -050023import static com.android.systemui.volume.Events.DISMISS_REASON_SETTINGS_CLICKED;
Julia Reynolds42411922017-11-08 11:19:09 -050024import static com.android.systemui.volume.Events.DISMISS_REASON_TOUCH_OUTSIDE;
25
John Spurlock5adeabc2015-05-05 14:50:43 -040026import android.accessibilityservice.AccessibilityServiceInfo;
Julia Reynolds4b006a82016-04-20 16:09:06 -040027import android.animation.ObjectAnimator;
Julia Reynolds2feab162016-04-21 14:58:52 -040028import android.annotation.NonNull;
John Spurlockf88d8082015-03-25 18:09:51 -040029import android.annotation.SuppressLint;
30import android.app.Dialog;
31import android.app.KeyguardManager;
32import android.content.Context;
Julia Reynolds42411922017-11-08 11:19:09 -050033import android.content.DialogInterface;
Julia Reynolds0a228562018-01-10 12:53:40 -050034import android.content.Intent;
Julia Reynoldsedb2e7c2017-12-11 13:18:03 -050035import android.content.pm.PackageManager;
John Spurlock77bb25af2015-05-11 12:12:07 -040036import android.content.res.ColorStateList;
John Spurlockf88d8082015-03-25 18:09:51 -040037import android.content.res.Resources;
Jason Monk98ad83c2017-06-13 14:03:45 -040038import android.graphics.Color;
John Spurlockf88d8082015-03-25 18:09:51 -040039import android.graphics.Rect;
Jason Monk98ad83c2017-06-13 14:03:45 -040040import android.graphics.drawable.ColorDrawable;
John Spurlockf88d8082015-03-25 18:09:51 -040041import android.media.AudioManager;
42import android.media.AudioSystem;
John Spurlock5adeabc2015-05-05 14:50:43 -040043import android.os.Debug;
John Spurlockf88d8082015-03-25 18:09:51 -040044import android.os.Handler;
45import android.os.Looper;
46import android.os.Message;
47import android.os.SystemClock;
Julia Reynolds0a228562018-01-10 12:53:40 -050048import android.provider.Settings;
John Spurlockf88d8082015-03-25 18:09:51 -040049import android.provider.Settings.Global;
Julia Reynolds5daa4722017-12-20 09:53:59 -050050import android.support.v7.media.MediaRouter;
John Spurlockf88d8082015-03-25 18:09:51 -040051import android.util.Log;
Julia Reynolds03c548f2016-12-14 15:02:38 -050052import android.util.Slog;
John Spurlockf88d8082015-03-25 18:09:51 -040053import android.util.SparseBooleanArray;
Lucas Dupin448786c2017-07-24 17:44:25 -070054import android.view.ContextThemeWrapper;
John Spurlockf88d8082015-03-25 18:09:51 -040055import android.view.MotionEvent;
56import android.view.View;
John Spurlock5adeabc2015-05-05 14:50:43 -040057import android.view.View.AccessibilityDelegate;
58import android.view.View.OnAttachStateChangeListener;
John Spurlockf88d8082015-03-25 18:09:51 -040059import android.view.View.OnClickListener;
John Spurlockf88d8082015-03-25 18:09:51 -040060import android.view.View.OnTouchListener;
61import android.view.ViewGroup;
John Spurlockf88d8082015-03-25 18:09:51 -040062import android.view.Window;
63import android.view.WindowManager;
John Spurlock5adeabc2015-05-05 14:50:43 -040064import android.view.accessibility.AccessibilityEvent;
65import android.view.accessibility.AccessibilityManager;
66import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener;
Julia Reynolds4b006a82016-04-20 16:09:06 -040067import android.view.animation.DecelerateInterpolator;
John Spurlockf88d8082015-03-25 18:09:51 -040068import android.widget.ImageButton;
John Spurlockf88d8082015-03-25 18:09:51 -040069import android.widget.SeekBar;
70import android.widget.SeekBar.OnSeekBarChangeListener;
71import android.widget.TextView;
Lucas Dupin7224c1e2017-07-06 14:35:30 -070072
Andrew Sapperstein5c373442016-06-12 13:17:16 -070073import com.android.settingslib.Utils;
Jason Monkde850bb2017-02-01 19:26:30 -050074import com.android.systemui.Dependency;
John Spurlockf88d8082015-03-25 18:09:51 -040075import com.android.systemui.R;
Rajeev Kumar5c964a42017-06-13 19:41:35 -070076import com.android.systemui.plugins.VolumeDialog;
Jason Monk782cd672017-03-22 12:50:57 -040077import com.android.systemui.plugins.VolumeDialogController;
78import com.android.systemui.plugins.VolumeDialogController.State;
79import com.android.systemui.plugins.VolumeDialogController.StreamState;
Lucas Dupin7224c1e2017-07-06 14:35:30 -070080
John Spurlockf88d8082015-03-25 18:09:51 -040081import java.io.PrintWriter;
82import java.util.ArrayList;
83import java.util.List;
84
85/**
86 * Visual presentation of the volume dialog.
87 *
Jason Monk782cd672017-03-22 12:50:57 -040088 * A client of VolumeDialogControllerImpl and its state model.
John Spurlockf88d8082015-03-25 18:09:51 -040089 *
90 * Methods ending in "H" must be called on the (ui) handler.
91 */
Julia Reynolds66d28942017-11-07 09:43:54 -050092public class VolumeDialogImpl implements VolumeDialog {
Jason Monk782cd672017-03-22 12:50:57 -040093 private static final String TAG = Util.logTag(VolumeDialogImpl.class);
John Spurlockf88d8082015-03-25 18:09:51 -040094
95 private static final long USER_ATTEMPT_GRACE_PERIOD = 1000;
Julia Reynolds4b006a82016-04-20 16:09:06 -040096 private static final int UPDATE_ANIMATION_DURATION = 80;
John Spurlockf88d8082015-03-25 18:09:51 -040097
98 private final Context mContext;
99 private final H mHandler = new H();
Rajeev Kumar5c964a42017-06-13 19:41:35 -0700100 private final VolumeDialogController mController;
John Spurlockf88d8082015-03-25 18:09:51 -0400101
Julia Reynolds568585b2016-07-25 08:55:15 -0400102 private Window mWindow;
Julia Reynoldsc791e052016-02-19 16:02:01 -0500103 private CustomDialog mDialog;
104 private ViewGroup mDialogView;
Julia Reynolds568585b2016-07-25 08:55:15 -0400105 private ViewGroup mDialogRowsView;
Julia Reynolds36dd4f12017-12-06 15:47:46 -0500106 private ImageButton mRingerIcon;
107 private TextView mRingerStatus;
Julia Reynoldsc791e052016-02-19 16:02:01 -0500108 private final List<VolumeRow> mRows = new ArrayList<>();
Julia Reynolds03c548f2016-12-14 15:02:38 -0500109 private ConfigurableTexts mConfigurableTexts;
John Spurlockf88d8082015-03-25 18:09:51 -0400110 private final SparseBooleanArray mDynamic = new SparseBooleanArray();
111 private final KeyguardManager mKeyguard;
Julia Reynolds2feab162016-04-21 14:58:52 -0400112 private final AccessibilityManager mAccessibilityMgr;
John Spurlock76b52b32015-04-03 00:00:12 -0400113 private final Object mSafetyWarningLock = new Object();
Julia Reynoldsfba474a82017-12-13 15:35:54 -0500114 private final Object mOutputChooserLock = new Object();
John Spurlock5adeabc2015-05-05 14:50:43 -0400115 private final Accessibility mAccessibility = new Accessibility();
John Spurlock77bb25af2015-05-11 12:12:07 -0400116 private final ColorStateList mActiveSliderTint;
117 private final ColorStateList mInactiveSliderTint;
John Spurlockf88d8082015-03-25 18:09:51 -0400118
119 private boolean mShowing;
Julia Reynoldsdbfb40f2017-01-23 11:05:57 -0500120 private boolean mShowA11yStream;
Julia Reynoldsc791e052016-02-19 16:02:01 -0500121
John Spurlockf88d8082015-03-25 18:09:51 -0400122 private int mActiveStream;
Beverlyfa4c8e72017-08-10 14:55:34 -0400123 private int mPrevActiveStream;
John Spurlockf55b7f22015-04-13 19:21:26 -0400124 private boolean mAutomute = VolumePrefs.DEFAULT_ENABLE_AUTOMUTE;
125 private boolean mSilentMode = VolumePrefs.DEFAULT_ENABLE_SILENT_MODE;
John Spurlockf88d8082015-03-25 18:09:51 -0400126 private State mState;
John Spurlock76b52b32015-04-03 00:00:12 -0400127 private SafetyWarningDialog mSafetyWarning;
Julia Reynoldsfba474a82017-12-13 15:35:54 -0500128 private OutputChooserDialog mOutputChooserDialog;
Jun Mukai3f5d7132015-07-21 14:10:09 -0700129 private boolean mHovering = false;
John Spurlockf88d8082015-03-25 18:09:51 -0400130
Jason Monk782cd672017-03-22 12:50:57 -0400131 public VolumeDialogImpl(Context context) {
Lucas Dupin448786c2017-07-24 17:44:25 -0700132 mContext = new ContextThemeWrapper(context, com.android.systemui.R.style.qs_theme);
Jason Monk782cd672017-03-22 12:50:57 -0400133 mController = Dependency.get(VolumeDialogController.class);
134 mKeyguard = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
Julia Reynolds568585b2016-07-25 08:55:15 -0400135 mAccessibilityMgr =
136 (AccessibilityManager) mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
Andrew Sapperstein5c373442016-06-12 13:17:16 -0700137 mActiveSliderTint = ColorStateList.valueOf(Utils.getColorAccent(mContext));
Julia Reynoldsc791e052016-02-19 16:02:01 -0500138 mInactiveSliderTint = loadColorStateList(R.color.volume_slider_inactive);
Jason Monk782cd672017-03-22 12:50:57 -0400139 }
140
141 public void init(int windowType, Callback callback) {
Julia Reynoldsc791e052016-02-19 16:02:01 -0500142 initDialog();
143
144 mAccessibility.init();
145
Jason Monk782cd672017-03-22 12:50:57 -0400146 mController.addCallback(mControllerCallbackH, mHandler);
147 mController.getState();
Julia Reynoldsc791e052016-02-19 16:02:01 -0500148 }
149
Jason Monk782cd672017-03-22 12:50:57 -0400150 @Override
151 public void destroy() {
Jason Monk3b9357f2017-07-14 09:40:54 -0400152 mAccessibility.destroy();
Jason Monk782cd672017-03-22 12:50:57 -0400153 mController.removeCallback(mControllerCallbackH);
Jason Monk3b9357f2017-07-14 09:40:54 -0400154 mHandler.removeCallbacksAndMessages(null);
Jason Monk782cd672017-03-22 12:50:57 -0400155 }
156
Julia Reynoldsc791e052016-02-19 16:02:01 -0500157 private void initDialog() {
John Spurlockf88d8082015-03-25 18:09:51 -0400158 mDialog = new CustomDialog(mContext);
159
Julia Reynolds03c548f2016-12-14 15:02:38 -0500160 mConfigurableTexts = new ConfigurableTexts(mContext);
Julia Reynoldsc791e052016-02-19 16:02:01 -0500161 mHovering = false;
162 mShowing = false;
Julia Reynolds568585b2016-07-25 08:55:15 -0400163 mWindow = mDialog.getWindow();
164 mWindow.requestFeature(Window.FEATURE_NO_TITLE);
Jason Monk98ad83c2017-06-13 14:03:45 -0400165 mWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
Julia Reynolds42411922017-11-08 11:19:09 -0500166 mWindow.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND
167 | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR);
Julia Reynolds36dd4f12017-12-06 15:47:46 -0500168 mWindow.addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
169 | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
170 | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
171 | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
172 | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
173 | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
174 mWindow.setTitle(VolumeDialogImpl.class.getSimpleName());
Julia Reynolds42411922017-11-08 11:19:09 -0500175 mWindow.setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY);
176 mWindow.setWindowAnimations(com.android.internal.R.style.Animation_Toast);
Julia Reynoldsc791e052016-02-19 16:02:01 -0500177
Jason Monk98ad83c2017-06-13 14:03:45 -0400178 mDialog.setContentView(R.layout.volume_dialog);
Julia Reynoldsedb2e7c2017-12-11 13:18:03 -0500179 mDialog.setOnShowListener(dialog -> {
Julia Reynolds0a228562018-01-10 12:53:40 -0500180 mDialogView.setTranslationX(mDialogView.getWidth() / 2);
Julia Reynoldsedb2e7c2017-12-11 13:18:03 -0500181 mDialogView.setAlpha(0);
182 mDialogView.animate()
183 .alpha(1)
Julia Reynolds0a228562018-01-10 12:53:40 -0500184 .translationX(0)
Julia Reynoldsedb2e7c2017-12-11 13:18:03 -0500185 .setDuration(300)
186 .setInterpolator(new SystemUIInterpolators.LogDecelerateInterpolator())
187 .withEndAction(() -> {
188 mWindow.getDecorView().requestAccessibilityFocus();
189 })
190 .start();
Julia Reynolds36dd4f12017-12-06 15:47:46 -0500191 });
192 mDialogView = mDialog.findViewById(R.id.volume_dialog);
Julia Reynoldsedb2e7c2017-12-11 13:18:03 -0500193 mDialogView.setOnHoverListener((v, event) -> {
194 int action = event.getActionMasked();
195 mHovering = (action == MotionEvent.ACTION_HOVER_ENTER)
196 || (action == MotionEvent.ACTION_HOVER_MOVE);
197 rescheduleTimeoutH();
198 return true;
Jun Mukai3f5d7132015-07-21 14:10:09 -0700199 });
Julia Reynoldsedb2e7c2017-12-11 13:18:03 -0500200 VolumeUiLayout hardwareLayout = VolumeUiLayout.get(mDialogView);
201 hardwareLayout.setOutsideTouchListener(view -> dismiss(DISMISS_REASON_TOUCH_OUTSIDE));
Lucas Dupinc1cc7592017-05-22 15:56:16 -0700202
Julia Reynolds0a228562018-01-10 12:53:40 -0500203 mDialogRowsView = mDialog.findViewById(R.id.volume_dialog_rows);
Julia Reynoldsedb2e7c2017-12-11 13:18:03 -0500204 mRingerIcon = mDialog.findViewById(R.id.ringer_icon);
205 mRingerStatus = mDialog.findViewById(R.id.ringer_status);
206
Julia Reynoldsc791e052016-02-19 16:02:01 -0500207 if (mRows.isEmpty()) {
Julia Reynoldsc791e052016-02-19 16:02:01 -0500208 addRow(AudioManager.STREAM_MUSIC,
Julia Reynoldsedb2e7c2017-12-11 13:18:03 -0500209 R.drawable.ic_volume_media, R.drawable.ic_volume_media_mute, true, true);
Muyuan Li36007d22016-06-21 14:21:48 -0700210 if (!AudioSystem.isSingleVolume(mContext)) {
211 addRow(AudioManager.STREAM_RING,
Julia Reynoldsedb2e7c2017-12-11 13:18:03 -0500212 R.drawable.ic_volume_ringer, R.drawable.ic_volume_ringer_mute, true, false);
Muyuan Li36007d22016-06-21 14:21:48 -0700213 addRow(AudioManager.STREAM_ALARM,
Julia Reynoldsedb2e7c2017-12-11 13:18:03 -0500214 R.drawable.ic_volume_alarm, R.drawable.ic_volume_alarm_mute, true, false);
Muyuan Li36007d22016-06-21 14:21:48 -0700215 addRow(AudioManager.STREAM_VOICE_CALL,
Julia Reynoldsedb2e7c2017-12-11 13:18:03 -0500216 R.drawable.ic_volume_voice, R.drawable.ic_volume_voice, false, false);
Muyuan Li36007d22016-06-21 14:21:48 -0700217 addRow(AudioManager.STREAM_BLUETOOTH_SCO,
Julia Reynoldsedb2e7c2017-12-11 13:18:03 -0500218 R.drawable.ic_volume_bt_sco, R.drawable.ic_volume_bt_sco, false, false);
219 addRow(AudioManager.STREAM_SYSTEM, R.drawable.ic_volume_system,
220 R.drawable.ic_volume_system_mute, false, false);
Julia Reynoldsdbfb40f2017-01-23 11:05:57 -0500221 addRow(AudioManager.STREAM_ACCESSIBILITY, R.drawable.ic_volume_accessibility,
Julia Reynoldsedb2e7c2017-12-11 13:18:03 -0500222 R.drawable.ic_volume_accessibility, true, false);
Muyuan Li36007d22016-06-21 14:21:48 -0700223 }
Julia Reynoldsc791e052016-02-19 16:02:01 -0500224 } else {
225 addExistingRows();
226 }
Julia Reynolds0a228562018-01-10 12:53:40 -0500227
Julia Reynolds08ce3102017-11-16 09:29:55 -0500228 updateRowsH(getActiveRow());
Julia Reynolds36dd4f12017-12-06 15:47:46 -0500229 initRingerH();
John Spurlockf88d8082015-03-25 18:09:51 -0400230 }
231
John Spurlock77bb25af2015-05-11 12:12:07 -0400232 private ColorStateList loadColorStateList(int colorResId) {
233 return ColorStateList.valueOf(mContext.getColor(colorResId));
234 }
235
John Spurlockf88d8082015-03-25 18:09:51 -0400236 public void setStreamImportant(int stream, boolean important) {
237 mHandler.obtainMessage(H.SET_STREAM_IMPORTANT, stream, important ? 1 : 0).sendToTarget();
238 }
239
John Spurlockf88d8082015-03-25 18:09:51 -0400240 public void setAutomute(boolean automute) {
241 if (mAutomute == automute) return;
242 mAutomute = automute;
243 mHandler.sendEmptyMessage(H.RECHECK_ALL);
244 }
245
246 public void setSilentMode(boolean silentMode) {
247 if (mSilentMode == silentMode) return;
248 mSilentMode = silentMode;
249 mHandler.sendEmptyMessage(H.RECHECK_ALL);
250 }
251
Julia Reynoldsedb2e7c2017-12-11 13:18:03 -0500252 private void addRow(int stream, int iconRes, int iconMuteRes, boolean important,
253 boolean defaultStream) {
254 addRow(stream, iconRes, iconMuteRes, important, defaultStream, false);
Julia Reynoldsdbfb40f2017-01-23 11:05:57 -0500255 }
256
257 private void addRow(int stream, int iconRes, int iconMuteRes, boolean important,
Julia Reynoldsedb2e7c2017-12-11 13:18:03 -0500258 boolean defaultStream, boolean dynamic) {
Julia Reynoldsc791e052016-02-19 16:02:01 -0500259 VolumeRow row = new VolumeRow();
Julia Reynoldsedb2e7c2017-12-11 13:18:03 -0500260 initRow(row, stream, iconRes, iconMuteRes, important, defaultStream);
Julia Reynoldsdbfb40f2017-01-23 11:05:57 -0500261 int rowSize;
Julia Reynolds0a228562018-01-10 12:53:40 -0500262 if (mShowA11yStream && dynamic && (rowSize = mRows.size()) > 1) {
263 // A11y Stream should be the first in the list, so it's shown to start of other rows
264 mDialogRowsView.addView(row.view, 0);
Julia Reynoldsdbfb40f2017-01-23 11:05:57 -0500265 mRows.add(rowSize - 2, row);
266 } else {
267 mDialogRowsView.addView(row.view);
268 mRows.add(row);
269 }
John Spurlockf88d8082015-03-25 18:09:51 -0400270 }
271
Julia Reynoldsc791e052016-02-19 16:02:01 -0500272 private void addExistingRows() {
273 int N = mRows.size();
274 for (int i = 0; i < N; i++) {
275 final VolumeRow row = mRows.get(i);
Julia Reynoldsedb2e7c2017-12-11 13:18:03 -0500276 initRow(row, row.stream, row.iconRes, row.iconMuteRes, row.important,
277 row.defaultStream);
Julia Reynolds568585b2016-07-25 08:55:15 -0400278 mDialogRowsView.addView(row.view);
Julia Reynolds42411922017-11-08 11:19:09 -0500279 updateVolumeRowH(row);
Julia Reynoldsc791e052016-02-19 16:02:01 -0500280 }
281 }
282
John Spurlockf88d8082015-03-25 18:09:51 -0400283 private VolumeRow getActiveRow() {
284 for (VolumeRow row : mRows) {
285 if (row.stream == mActiveStream) {
286 return row;
287 }
288 }
289 return mRows.get(0);
290 }
291
292 private VolumeRow findRow(int stream) {
293 for (VolumeRow row : mRows) {
294 if (row.stream == stream) return row;
295 }
296 return null;
297 }
298
John Spurlockf88d8082015-03-25 18:09:51 -0400299 public void dump(PrintWriter writer) {
Jason Monk782cd672017-03-22 12:50:57 -0400300 writer.println(VolumeDialogImpl.class.getSimpleName() + " state:");
John Spurlockf88d8082015-03-25 18:09:51 -0400301 writer.print(" mShowing: "); writer.println(mShowing);
John Spurlockf88d8082015-03-25 18:09:51 -0400302 writer.print(" mActiveStream: "); writer.println(mActiveStream);
303 writer.print(" mDynamic: "); writer.println(mDynamic);
John Spurlockf88d8082015-03-25 18:09:51 -0400304 writer.print(" mAutomute: "); writer.println(mAutomute);
305 writer.print(" mSilentMode: "); writer.println(mSilentMode);
John Spurlock84ee67c2015-05-20 23:33:43 -0400306 writer.print(" mAccessibility.mFeedbackEnabled: ");
307 writer.println(mAccessibility.mFeedbackEnabled);
John Spurlockf88d8082015-03-25 18:09:51 -0400308 }
309
Julia Reynolds4b006a82016-04-20 16:09:06 -0400310 private static int getImpliedLevel(SeekBar seekBar, int progress) {
311 final int m = seekBar.getMax();
312 final int n = m / 100 - 1;
313 final int level = progress == 0 ? 0
314 : progress == m ? (m / 100) : (1 + (int)((progress / (float) m) * n));
315 return level;
316 }
317
John Spurlockf88d8082015-03-25 18:09:51 -0400318 @SuppressLint("InflateParams")
Julia Reynoldsc791e052016-02-19 16:02:01 -0500319 private void initRow(final VolumeRow row, final int stream, int iconRes, int iconMuteRes,
Julia Reynoldsedb2e7c2017-12-11 13:18:03 -0500320 boolean important, boolean defaultStream) {
John Spurlockf88d8082015-03-25 18:09:51 -0400321 row.stream = stream;
322 row.iconRes = iconRes;
323 row.iconMuteRes = iconMuteRes;
324 row.important = important;
Julia Reynoldsedb2e7c2017-12-11 13:18:03 -0500325 row.defaultStream = defaultStream;
John Spurlockf88d8082015-03-25 18:09:51 -0400326 row.view = mDialog.getLayoutInflater().inflate(R.layout.volume_dialog_row, null);
Julia Reynolds568585b2016-07-25 08:55:15 -0400327 row.view.setId(row.stream);
John Spurlockf88d8082015-03-25 18:09:51 -0400328 row.view.setTag(row);
Julia Reynolds42411922017-11-08 11:19:09 -0500329 row.header = row.view.findViewById(R.id.volume_row_header);
Julia Reynolds568585b2016-07-25 08:55:15 -0400330 row.header.setId(20 * row.stream);
Julia Reynolds42411922017-11-08 11:19:09 -0500331 row.slider = row.view.findViewById(R.id.volume_row_slider);
John Spurlockf88d8082015-03-25 18:09:51 -0400332 row.slider.setOnSeekBarChangeListener(new VolumeSeekBarChangeListener(row));
Julia Reynolds5774cf02016-05-26 13:43:38 -0400333 row.anim = null;
John Spurlockf88d8082015-03-25 18:09:51 -0400334
Julia Reynolds4f9750c2018-01-18 11:43:53 -0500335 ImageButton outputChooser = row.view.findViewById(R.id.output_chooser);
336 outputChooser.setOnClickListener(mClickOutputChooser);
337
John Spurlockf88d8082015-03-25 18:09:51 -0400338 // forward events above the slider into the slider
339 row.view.setOnTouchListener(new OnTouchListener() {
340 private final Rect mSliderHitRect = new Rect();
341 private boolean mDragging;
342
343 @SuppressLint("ClickableViewAccessibility")
344 @Override
345 public boolean onTouch(View v, MotionEvent event) {
346 row.slider.getHitRect(mSliderHitRect);
347 if (!mDragging && event.getActionMasked() == MotionEvent.ACTION_DOWN
348 && event.getY() < mSliderHitRect.top) {
349 mDragging = true;
350 }
351 if (mDragging) {
352 event.offsetLocation(-mSliderHitRect.left, -mSliderHitRect.top);
353 row.slider.dispatchTouchEvent(event);
354 if (event.getActionMasked() == MotionEvent.ACTION_UP
355 || event.getActionMasked() == MotionEvent.ACTION_CANCEL) {
356 mDragging = false;
357 }
358 return true;
359 }
360 return false;
361 }
362 });
Julia Reynoldse2503dd2017-04-18 11:21:13 -0400363 row.icon = row.view.findViewById(R.id.volume_row_icon);
John Spurlockf88d8082015-03-25 18:09:51 -0400364 row.icon.setImageResource(iconRes);
Julia Reynolds7c502e02017-03-06 10:19:10 -0500365 if (row.stream != AudioSystem.STREAM_ACCESSIBILITY) {
Julia Reynoldsedb2e7c2017-12-11 13:18:03 -0500366 row.icon.setOnClickListener(v -> {
367 Events.writeEvent(mContext, Events.EVENT_ICON_CLICK, row.stream, row.iconState);
368 mController.setActiveStream(row.stream);
369 if (row.stream == AudioManager.STREAM_RING) {
370 final boolean hasVibrator = mController.hasVibrator();
Julia Reynolds229b3002018-01-23 09:30:09 -0500371 if (mState.ringerModeInternal == AudioManager.RINGER_MODE_NORMAL) {
Julia Reynoldsedb2e7c2017-12-11 13:18:03 -0500372 if (hasVibrator) {
Julia Reynolds229b3002018-01-23 09:30:09 -0500373 mController.setRingerMode(AudioManager.RINGER_MODE_VIBRATE, false);
John Spurlockf88d8082015-03-25 18:09:51 -0400374 } else {
Julia Reynoldsedb2e7c2017-12-11 13:18:03 -0500375 final boolean wasZero = row.ss.level == 0;
376 mController.setStreamVolume(stream,
377 wasZero ? row.lastAudibleLevel : 0);
John Spurlockf88d8082015-03-25 18:09:51 -0400378 }
379 } else {
Julia Reynolds229b3002018-01-23 09:30:09 -0500380 mController.setRingerMode(AudioManager.RINGER_MODE_NORMAL, false);
Julia Reynoldsedb2e7c2017-12-11 13:18:03 -0500381 if (row.ss.level == 0) {
382 mController.setStreamVolume(stream, 1);
383 }
John Spurlockf88d8082015-03-25 18:09:51 -0400384 }
Julia Reynoldsedb2e7c2017-12-11 13:18:03 -0500385 } else {
386 final boolean vmute = row.ss.level == row.ss.levelMin;
387 mController.setStreamVolume(stream,
388 vmute ? row.lastAudibleLevel : row.ss.levelMin);
John Spurlockf88d8082015-03-25 18:09:51 -0400389 }
Julia Reynoldsedb2e7c2017-12-11 13:18:03 -0500390 row.userAttempt = 0; // reset the grace period, slider updates immediately
Julia Reynolds7c502e02017-03-06 10:19:10 -0500391 });
Julia Reynoldse2503dd2017-04-18 11:21:13 -0400392 } else {
393 row.icon.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
Julia Reynolds7c502e02017-03-06 10:19:10 -0500394 }
John Spurlockf88d8082015-03-25 18:09:51 -0400395 }
396
Julia Reynolds36dd4f12017-12-06 15:47:46 -0500397 public void initRingerH() {
398 mRingerIcon.setOnClickListener(v -> {
399 Events.writeEvent(mContext, Events.EVENT_ICON_CLICK, AudioManager.STREAM_RING,
400 mRingerIcon.getTag());
401 final StreamState ss = mState.states.get(AudioManager.STREAM_RING);
Julia Reynolds41eae632018-01-09 09:21:44 -0500402 if (ss == null) {
403 return;
404 }
Julia Reynolds36dd4f12017-12-06 15:47:46 -0500405 final boolean hasVibrator = mController.hasVibrator();
Julia Reynolds229b3002018-01-23 09:30:09 -0500406 if (mState.ringerModeInternal == AudioManager.RINGER_MODE_NORMAL) {
Julia Reynolds36dd4f12017-12-06 15:47:46 -0500407 if (hasVibrator) {
Julia Reynolds229b3002018-01-23 09:30:09 -0500408 mController.setRingerMode(AudioManager.RINGER_MODE_VIBRATE, false);
Julia Reynolds36dd4f12017-12-06 15:47:46 -0500409 } else {
410 final boolean wasZero = ss.level == 0;
411 mController.setStreamVolume(AudioManager.STREAM_RING, wasZero ? 1 : 0);
412 }
413 } else {
Julia Reynolds229b3002018-01-23 09:30:09 -0500414 mController.setRingerMode(AudioManager.RINGER_MODE_NORMAL, false);
Julia Reynolds36dd4f12017-12-06 15:47:46 -0500415 if (ss.level == 0) {
416 mController.setStreamVolume(AudioManager.STREAM_RING, 1);
417 }
418 }
419 updateRingerH();
420 });
Julia Reynolds0a228562018-01-10 12:53:40 -0500421 mRingerIcon.setOnLongClickListener(v -> {
422 Intent intent = new Intent(Settings.ACTION_SOUND_SETTINGS);
423 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
424 dismissH(DISMISS_REASON_SETTINGS_CLICKED);
425 mContext.startActivity(intent);
426 return true;
427 });
Julia Reynolds36dd4f12017-12-06 15:47:46 -0500428 updateRingerH();
429 }
430
John Spurlockf88d8082015-03-25 18:09:51 -0400431 public void show(int reason) {
432 mHandler.obtainMessage(H.SHOW, reason, 0).sendToTarget();
433 }
434
435 public void dismiss(int reason) {
436 mHandler.obtainMessage(H.DISMISS, reason, 0).sendToTarget();
437 }
438
John Spurlockf88d8082015-03-25 18:09:51 -0400439 private void showH(int reason) {
John Spurlock22def3d2015-06-17 11:56:12 -0400440 if (D.BUG) Log.d(TAG, "showH r=" + Events.DISMISS_REASONS[reason]);
John Spurlockf88d8082015-03-25 18:09:51 -0400441 mHandler.removeMessages(H.SHOW);
442 mHandler.removeMessages(H.DISMISS);
443 rescheduleTimeoutH();
444 if (mShowing) return;
445 mShowing = true;
Julia Reynolds36dd4f12017-12-06 15:47:46 -0500446
447 mDialog.show();
Chris Wrene565ee62015-06-17 15:24:56 -0400448 Events.writeEvent(mContext, Events.EVENT_SHOW_DIALOG, reason, mKeyguard.isKeyguardLocked());
John Spurlockf88d8082015-03-25 18:09:51 -0400449 mController.notifyVisible(true);
450 }
451
452 protected void rescheduleTimeoutH() {
453 mHandler.removeMessages(H.DISMISS);
John Spurlockf09838b2015-06-11 16:14:44 -0400454 final int timeout = computeTimeoutH();
455 mHandler.sendMessageDelayed(mHandler
456 .obtainMessage(H.DISMISS, Events.DISMISS_REASON_TIMEOUT, 0), timeout);
John Spurlock5adeabc2015-05-05 14:50:43 -0400457 if (D.BUG) Log.d(TAG, "rescheduleTimeout " + timeout + " " + Debug.getCaller());
John Spurlockf88d8082015-03-25 18:09:51 -0400458 mController.userActivity();
459 }
460
461 private int computeTimeoutH() {
John Spurlockf09838b2015-06-11 16:14:44 -0400462 if (mAccessibility.mFeedbackEnabled) return 20000;
Jun Mukai3f5d7132015-07-21 14:10:09 -0700463 if (mHovering) return 16000;
John Spurlock76b52b32015-04-03 00:00:12 -0400464 if (mSafetyWarning != null) return 5000;
John Spurlockf88d8082015-03-25 18:09:51 -0400465 return 3000;
466 }
467
468 protected void dismissH(int reason) {
469 mHandler.removeMessages(H.DISMISS);
470 mHandler.removeMessages(H.SHOW);
471 if (!mShowing) return;
Julia Reynolds36dd4f12017-12-06 15:47:46 -0500472 mDialogView.animate().cancel();
John Spurlockf88d8082015-03-25 18:09:51 -0400473 mShowing = false;
Julia Reynolds36dd4f12017-12-06 15:47:46 -0500474
Julia Reynolds0a228562018-01-10 12:53:40 -0500475 mDialogView.setTranslationX(0);
Julia Reynolds36dd4f12017-12-06 15:47:46 -0500476 mDialogView.setAlpha(1);
477 mDialogView.animate()
Julia Reynolds42411922017-11-08 11:19:09 -0500478 .alpha(0)
Julia Reynolds0a228562018-01-10 12:53:40 -0500479 .translationX(mDialogView.getWidth() / 2)
Julia Reynolds36dd4f12017-12-06 15:47:46 -0500480 .setDuration(250)
Julia Reynolds42411922017-11-08 11:19:09 -0500481 .setInterpolator(new SystemUIInterpolators.LogAccelerateInterpolator())
Julia Reynolds36dd4f12017-12-06 15:47:46 -0500482 .withEndAction(() -> mHandler.postDelayed(() -> {
483 if (D.BUG) Log.d(TAG, "mDialog.dismiss()");
484 mDialog.dismiss();
485 }, 50))
Julia Reynolds42411922017-11-08 11:19:09 -0500486 .start();
Julia Reynolds36dd4f12017-12-06 15:47:46 -0500487
Julia Reynolds86cd5512017-12-05 10:20:39 -0500488 if (mAccessibilityMgr.isEnabled()) {
Julia Reynolds2feab162016-04-21 14:58:52 -0400489 AccessibilityEvent event =
490 AccessibilityEvent.obtain(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
491 event.setPackageName(mContext.getPackageName());
492 event.setClassName(CustomDialog.class.getSuperclass().getName());
493 event.getText().add(mContext.getString(
494 R.string.volume_dialog_accessibility_dismissed_message));
495 mAccessibilityMgr.sendAccessibilityEvent(event);
496 }
Chris Wrene565ee62015-06-17 15:24:56 -0400497 Events.writeEvent(mContext, Events.EVENT_DISMISS_DIALOG, reason);
John Spurlockf88d8082015-03-25 18:09:51 -0400498 mController.notifyVisible(false);
John Spurlock76b52b32015-04-03 00:00:12 -0400499 synchronized (mSafetyWarningLock) {
500 if (mSafetyWarning != null) {
501 if (D.BUG) Log.d(TAG, "SafetyWarning dismissed");
502 mSafetyWarning.dismiss();
503 }
504 }
John Spurlockf88d8082015-03-25 18:09:51 -0400505 }
506
Julia Reynoldsedb2e7c2017-12-11 13:18:03 -0500507 private boolean isAttached() {
508 return mDialogView != null && mDialogView.isAttachedToWindow();
509 }
510
511 private boolean hasTouchFeature() {
512 final PackageManager pm = mContext.getPackageManager();
513 return pm.hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN);
514 }
515
Beverlyfa4c8e72017-08-10 14:55:34 -0400516 private boolean shouldBeVisibleH(VolumeRow row, VolumeRow activeRow) {
517 boolean isActive = row == activeRow;
Julia Reynoldsdbfb40f2017-01-23 11:05:57 -0500518 if (row.stream == AudioSystem.STREAM_ACCESSIBILITY) {
519 return mShowA11yStream;
520 }
Beverlyfa4c8e72017-08-10 14:55:34 -0400521
522 // if the active row is accessibility, then continue to display previous
Julia Reynolds66d28942017-11-07 09:43:54 -0500523 // active row since accessibility is displayed under it
Beverlyfa4c8e72017-08-10 14:55:34 -0400524 if (activeRow.stream == AudioSystem.STREAM_ACCESSIBILITY &&
525 row.stream == mPrevActiveStream) {
526 return true;
527 }
528
Julia Reynolds0a228562018-01-10 12:53:40 -0500529 return row.defaultStream || isActive;
John Spurlockf88d8082015-03-25 18:09:51 -0400530 }
531
Julia Reynolds568585b2016-07-25 08:55:15 -0400532 private void updateRowsH(final VolumeRow activeRow) {
John Spurlock22def3d2015-06-17 11:56:12 -0400533 if (D.BUG) Log.d(TAG, "updateRowsH");
John Spurlockf88d8082015-03-25 18:09:51 -0400534 if (!mShowing) {
535 trimObsoleteH();
536 }
John Spurlockf88d8082015-03-25 18:09:51 -0400537 // apply changes to all rows
Julia Reynolds568585b2016-07-25 08:55:15 -0400538 for (final VolumeRow row : mRows) {
John Spurlockf88d8082015-03-25 18:09:51 -0400539 final boolean isActive = row == activeRow;
Beverlyfa4c8e72017-08-10 14:55:34 -0400540 final boolean shouldBeVisible = shouldBeVisibleH(row, activeRow);
Julia Reynolds568585b2016-07-25 08:55:15 -0400541 Util.setVisOrGone(row.view, shouldBeVisible);
Jason Monk98ad83c2017-06-13 14:03:45 -0400542 Util.setVisOrGone(row.header, shouldBeVisible);
Julia Reynolds568585b2016-07-25 08:55:15 -0400543 if (row.view.isShown()) {
Julia Reynolds568585b2016-07-25 08:55:15 -0400544 updateVolumeRowSliderTintH(row, isActive);
545 }
John Spurlockf88d8082015-03-25 18:09:51 -0400546 }
547 }
548
Julia Reynolds36dd4f12017-12-06 15:47:46 -0500549 protected void updateRingerH() {
550 if (mState != null) {
551 final StreamState ss = mState.states.get(AudioManager.STREAM_RING);
Julia Reynolds41eae632018-01-09 09:21:44 -0500552 if (ss == null) {
553 return;
554 }
Julia Reynolds229b3002018-01-23 09:30:09 -0500555 switch (mState.ringerModeInternal) {
Julia Reynolds36dd4f12017-12-06 15:47:46 -0500556 case AudioManager.RINGER_MODE_VIBRATE:
557 mRingerStatus.setText(R.string.volume_ringer_status_vibrate);
558 mRingerIcon.setImageResource(R.drawable.ic_volume_ringer_vibrate);
559 mRingerIcon.setTag(Events.ICON_STATE_VIBRATE);
560 break;
561 case AudioManager.RINGER_MODE_SILENT:
562 mRingerStatus.setText(R.string.volume_ringer_status_silent);
563 mRingerIcon.setImageResource(R.drawable.ic_volume_ringer_mute);
564 mRingerIcon.setContentDescription(mContext.getString(
565 R.string.volume_stream_content_description_unmute,
566 getStreamLabelH(ss)));
567 mRingerIcon.setTag(Events.ICON_STATE_MUTE);
568 break;
569 case AudioManager.RINGER_MODE_NORMAL:
570 default:
Julia Reynoldsedb2e7c2017-12-11 13:18:03 -0500571 boolean muted = (mAutomute && ss.level == 0) || ss.muted;
Julia Reynolds36dd4f12017-12-06 15:47:46 -0500572 if (muted) {
573 mRingerStatus.setText(R.string.volume_ringer_status_silent);
574 mRingerIcon.setImageResource(R.drawable.ic_volume_ringer_mute);
575 mRingerIcon.setContentDescription(mContext.getString(
576 R.string.volume_stream_content_description_unmute,
577 getStreamLabelH(ss)));
578 mRingerIcon.setTag(Events.ICON_STATE_MUTE);
579 } else {
580 mRingerStatus.setText(R.string.volume_ringer_status_normal);
581 mRingerIcon.setImageResource(R.drawable.ic_volume_ringer);
582 if (mController.hasVibrator()) {
583 mRingerIcon.setContentDescription(mContext.getString(
584 mShowA11yStream
585 ? R.string.volume_stream_content_description_vibrate_a11y
586 : R.string.volume_stream_content_description_vibrate,
587 getStreamLabelH(ss)));
588
589 } else {
590 mRingerIcon.setContentDescription(getStreamLabelH(ss));
591 }
592 mRingerIcon.setTag(Events.ICON_STATE_UNMUTE);
593 }
594 break;
595 }
596 }
597 }
598
John Spurlockf88d8082015-03-25 18:09:51 -0400599 private void trimObsoleteH() {
John Spurlock22def3d2015-06-17 11:56:12 -0400600 if (D.BUG) Log.d(TAG, "trimObsoleteH");
Julia Reynolds568585b2016-07-25 08:55:15 -0400601 for (int i = mRows.size() - 1; i >= 0; i--) {
John Spurlockf88d8082015-03-25 18:09:51 -0400602 final VolumeRow row = mRows.get(i);
603 if (row.ss == null || !row.ss.dynamic) continue;
604 if (!mDynamic.get(row.stream)) {
605 mRows.remove(i);
Julia Reynolds568585b2016-07-25 08:55:15 -0400606 mDialogRowsView.removeView(row.view);
John Spurlockf88d8082015-03-25 18:09:51 -0400607 }
608 }
609 }
610
611 private void onStateChangedH(State state) {
612 mState = state;
613 mDynamic.clear();
614 // add any new dynamic rows
615 for (int i = 0; i < state.states.size(); i++) {
616 final int stream = state.states.keyAt(i);
617 final StreamState ss = state.states.valueAt(i);
618 if (!ss.dynamic) continue;
619 mDynamic.put(stream, true);
620 if (findRow(stream) == null) {
Julia Reynoldsdbfb40f2017-01-23 11:05:57 -0500621 addRow(stream, R.drawable.ic_volume_remote, R.drawable.ic_volume_remote_mute, true,
Julia Reynoldsedb2e7c2017-12-11 13:18:03 -0500622 false, true);
John Spurlockf88d8082015-03-25 18:09:51 -0400623 }
624 }
625
626 if (mActiveStream != state.activeStream) {
Beverlyfa4c8e72017-08-10 14:55:34 -0400627 mPrevActiveStream = mActiveStream;
John Spurlockf88d8082015-03-25 18:09:51 -0400628 mActiveStream = state.activeStream;
Julia Reynolds568585b2016-07-25 08:55:15 -0400629 updateRowsH(getActiveRow());
John Spurlockf88d8082015-03-25 18:09:51 -0400630 rescheduleTimeoutH();
631 }
632 for (VolumeRow row : mRows) {
633 updateVolumeRowH(row);
634 }
Julia Reynolds36dd4f12017-12-06 15:47:46 -0500635 updateRingerH();
John Spurlockf88d8082015-03-25 18:09:51 -0400636 }
637
638 private void updateVolumeRowH(VolumeRow row) {
John Spurlock22def3d2015-06-17 11:56:12 -0400639 if (D.BUG) Log.d(TAG, "updateVolumeRowH s=" + row.stream);
John Spurlockf88d8082015-03-25 18:09:51 -0400640 if (mState == null) return;
641 final StreamState ss = mState.states.get(row.stream);
642 if (ss == null) return;
643 row.ss = ss;
644 if (ss.level > 0) {
645 row.lastAudibleLevel = ss.level;
646 }
John Spurlockb0a2e5f2015-06-09 14:41:52 -0400647 if (ss.level == row.requestedLevel) {
648 row.requestedLevel = -1;
649 }
Julia Reynolds7c502e02017-03-06 10:19:10 -0500650 final boolean isA11yStream = row.stream == AudioManager.STREAM_ACCESSIBILITY;
John Spurlockf88d8082015-03-25 18:09:51 -0400651 final boolean isRingStream = row.stream == AudioManager.STREAM_RING;
652 final boolean isSystemStream = row.stream == AudioManager.STREAM_SYSTEM;
John Spurlockd9c75db2015-04-28 11:19:13 -0400653 final boolean isAlarmStream = row.stream == AudioManager.STREAM_ALARM;
654 final boolean isMusicStream = row.stream == AudioManager.STREAM_MUSIC;
John Spurlockf88d8082015-03-25 18:09:51 -0400655 final boolean isRingVibrate = isRingStream
Julia Reynolds229b3002018-01-23 09:30:09 -0500656 && mState.ringerModeInternal == AudioManager.RINGER_MODE_VIBRATE;
John Spurlockd9c75db2015-04-28 11:19:13 -0400657 final boolean isRingSilent = isRingStream
Julia Reynolds229b3002018-01-23 09:30:09 -0500658 && mState.ringerModeInternal == AudioManager.RINGER_MODE_SILENT;
John Spurlockd9c75db2015-04-28 11:19:13 -0400659 final boolean isZenAlarms = mState.zenMode == Global.ZEN_MODE_ALARMS;
660 final boolean isZenNone = mState.zenMode == Global.ZEN_MODE_NO_INTERRUPTIONS;
John Spurlockd9c75db2015-04-28 11:19:13 -0400661 final boolean zenMuted = isZenAlarms ? (isRingStream || isSystemStream)
662 : isZenNone ? (isRingStream || isSystemStream || isAlarmStream || isMusicStream)
663 : false;
John Spurlockf88d8082015-03-25 18:09:51 -0400664
665 // update slider max
Julia Reynolds4b006a82016-04-20 16:09:06 -0400666 final int max = ss.levelMax * 100;
John Spurlockf88d8082015-03-25 18:09:51 -0400667 if (max != row.slider.getMax()) {
668 row.slider.setMax(max);
669 }
670
John Spurlockf88d8082015-03-25 18:09:51 -0400671 // update header text
Julia Reynolds03c548f2016-12-14 15:02:38 -0500672 Util.setText(row.header, getStreamLabelH(ss));
Lucas Dupin421b20c2017-08-01 10:36:10 -0700673 row.slider.setContentDescription(row.header.getText());
Julia Reynolds03c548f2016-12-14 15:02:38 -0500674 mConfigurableTexts.add(row.header, ss.name);
John Spurlockf88d8082015-03-25 18:09:51 -0400675
676 // update icon
John Spurlockd9c75db2015-04-28 11:19:13 -0400677 final boolean iconEnabled = (mAutomute || ss.muteSupported) && !zenMuted;
John Spurlockf88d8082015-03-25 18:09:51 -0400678 row.icon.setEnabled(iconEnabled);
679 row.icon.setAlpha(iconEnabled ? 1 : 0.5f);
680 final int iconRes =
John Spurlock76b52b32015-04-03 00:00:12 -0400681 isRingVibrate ? R.drawable.ic_volume_ringer_vibrate
Julia Reynolds42411922017-11-08 11:19:09 -0500682 : isRingSilent || zenMuted ? row.iconMuteRes
John Spurlockf88d8082015-03-25 18:09:51 -0400683 : ss.routedToBluetooth ?
John Spurlockf15ef112015-04-09 22:04:14 -0400684 (ss.muted ? R.drawable.ic_volume_media_bt_mute
685 : R.drawable.ic_volume_media_bt)
John Spurlock76b52b32015-04-03 00:00:12 -0400686 : mAutomute && ss.level == 0 ? row.iconMuteRes
John Spurlockf88d8082015-03-25 18:09:51 -0400687 : (ss.muted ? row.iconMuteRes : row.iconRes);
Julia Reynolds42411922017-11-08 11:19:09 -0500688 row.icon.setImageResource(iconRes);
John Spurlockf88d8082015-03-25 18:09:51 -0400689 row.iconState =
690 iconRes == R.drawable.ic_volume_ringer_vibrate ? Events.ICON_STATE_VIBRATE
John Spurlockf15ef112015-04-09 22:04:14 -0400691 : (iconRes == R.drawable.ic_volume_media_bt_mute || iconRes == row.iconMuteRes)
John Spurlockf88d8082015-03-25 18:09:51 -0400692 ? Events.ICON_STATE_MUTE
John Spurlockf15ef112015-04-09 22:04:14 -0400693 : (iconRes == R.drawable.ic_volume_media_bt || iconRes == row.iconRes)
John Spurlockf88d8082015-03-25 18:09:51 -0400694 ? Events.ICON_STATE_UNMUTE
695 : Events.ICON_STATE_UNKNOWN;
Julia Reynoldsdfe0b4d2016-04-08 17:14:15 -0400696 if (iconEnabled) {
697 if (isRingStream) {
698 if (isRingVibrate) {
699 row.icon.setContentDescription(mContext.getString(
700 R.string.volume_stream_content_description_unmute,
Julia Reynolds03c548f2016-12-14 15:02:38 -0500701 getStreamLabelH(ss)));
Julia Reynoldsdfe0b4d2016-04-08 17:14:15 -0400702 } else {
703 if (mController.hasVibrator()) {
704 row.icon.setContentDescription(mContext.getString(
Julia Reynolds7c502e02017-03-06 10:19:10 -0500705 mShowA11yStream
706 ? R.string.volume_stream_content_description_vibrate_a11y
707 : R.string.volume_stream_content_description_vibrate,
Julia Reynolds03c548f2016-12-14 15:02:38 -0500708 getStreamLabelH(ss)));
Julia Reynoldsdfe0b4d2016-04-08 17:14:15 -0400709 } else {
710 row.icon.setContentDescription(mContext.getString(
Julia Reynolds7c502e02017-03-06 10:19:10 -0500711 mShowA11yStream
712 ? R.string.volume_stream_content_description_mute_a11y
713 : R.string.volume_stream_content_description_mute,
Julia Reynolds03c548f2016-12-14 15:02:38 -0500714 getStreamLabelH(ss)));
Julia Reynoldsdfe0b4d2016-04-08 17:14:15 -0400715 }
716 }
Julia Reynolds7c502e02017-03-06 10:19:10 -0500717 } else if (isA11yStream) {
718 row.icon.setContentDescription(getStreamLabelH(ss));
Julia Reynoldsdfe0b4d2016-04-08 17:14:15 -0400719 } else {
720 if (ss.muted || mAutomute && ss.level == 0) {
721 row.icon.setContentDescription(mContext.getString(
722 R.string.volume_stream_content_description_unmute,
Julia Reynolds03c548f2016-12-14 15:02:38 -0500723 getStreamLabelH(ss)));
Julia Reynoldsdfe0b4d2016-04-08 17:14:15 -0400724 } else {
725 row.icon.setContentDescription(mContext.getString(
Julia Reynolds7c502e02017-03-06 10:19:10 -0500726 mShowA11yStream
727 ? R.string.volume_stream_content_description_mute_a11y
728 : R.string.volume_stream_content_description_mute,
Julia Reynolds03c548f2016-12-14 15:02:38 -0500729 getStreamLabelH(ss)));
Julia Reynoldsdfe0b4d2016-04-08 17:14:15 -0400730 }
731 }
732 } else {
Julia Reynolds03c548f2016-12-14 15:02:38 -0500733 row.icon.setContentDescription(getStreamLabelH(ss));
Julia Reynoldsdfe0b4d2016-04-08 17:14:15 -0400734 }
John Spurlockf88d8082015-03-25 18:09:51 -0400735
Beverlye421abe2017-08-22 14:47:28 -0400736 // ensure tracking is disabled if zenMuted
737 if (zenMuted) {
738 row.tracking = false;
739 }
740
John Spurlockf88d8082015-03-25 18:09:51 -0400741 // update slider
John Spurlockb0a2e5f2015-06-09 14:41:52 -0400742 final boolean enableSlider = !zenMuted;
Julia Reynolds5f84c192016-11-14 13:13:08 -0500743 final int vlevel = row.ss.muted && (!isRingStream && !zenMuted) ? 0
John Spurlockb0a2e5f2015-06-09 14:41:52 -0400744 : row.ss.level;
745 updateVolumeRowSliderH(row, enableSlider, vlevel);
John Spurlockf88d8082015-03-25 18:09:51 -0400746 }
747
John Spurlockecc80582015-05-13 16:23:14 -0400748 private void updateVolumeRowSliderTintH(VolumeRow row, boolean isActive) {
Julia Reynolds66d28942017-11-07 09:43:54 -0500749 if (isActive) {
John Spurlock67a0f852015-06-15 15:35:47 -0400750 row.slider.requestFocus();
John Spurlock67a0f852015-06-15 15:35:47 -0400751 }
John Spurlockecc80582015-05-13 16:23:14 -0400752 final ColorStateList tint = isActive && row.slider.isEnabled() ? mActiveSliderTint
753 : mInactiveSliderTint;
754 if (tint == row.cachedSliderTint) return;
755 row.cachedSliderTint = tint;
756 row.slider.setProgressTintList(tint);
757 row.slider.setThumbTintList(tint);
758 }
759
John Spurlockb0a2e5f2015-06-09 14:41:52 -0400760 private void updateVolumeRowSliderH(VolumeRow row, boolean enable, int vlevel) {
761 row.slider.setEnabled(enable);
John Spurlockecc80582015-05-13 16:23:14 -0400762 updateVolumeRowSliderTintH(row, row.stream == mActiveStream);
John Spurlockf88d8082015-03-25 18:09:51 -0400763 if (row.tracking) {
764 return; // don't update if user is sliding
765 }
Julia Reynolds4b006a82016-04-20 16:09:06 -0400766 final int progress = row.slider.getProgress();
767 final int level = getImpliedLevel(row.slider, progress);
John Spurlockf88d8082015-03-25 18:09:51 -0400768 final boolean rowVisible = row.view.getVisibility() == View.VISIBLE;
769 final boolean inGracePeriod = (SystemClock.uptimeMillis() - row.userAttempt)
770 < USER_ATTEMPT_GRACE_PERIOD;
771 mHandler.removeMessages(H.RECHECK, row);
772 if (mShowing && rowVisible && inGracePeriod) {
773 if (D.BUG) Log.d(TAG, "inGracePeriod");
774 mHandler.sendMessageAtTime(mHandler.obtainMessage(H.RECHECK, row),
775 row.userAttempt + USER_ATTEMPT_GRACE_PERIOD);
776 return; // don't update if visible and in grace period
777 }
John Spurlockf88d8082015-03-25 18:09:51 -0400778 if (vlevel == level) {
779 if (mShowing && rowVisible) {
780 return; // don't clamp if visible
781 }
782 }
Julia Reynolds4b006a82016-04-20 16:09:06 -0400783 final int newProgress = vlevel * 100;
784 if (progress != newProgress) {
785 if (mShowing && rowVisible) {
786 // animate!
787 if (row.anim != null && row.anim.isRunning()
788 && row.animTargetProgress == newProgress) {
789 return; // already animating to the target progress
790 }
791 // start/update animation
792 if (row.anim == null) {
793 row.anim = ObjectAnimator.ofInt(row.slider, "progress", progress, newProgress);
794 row.anim.setInterpolator(new DecelerateInterpolator());
795 } else {
796 row.anim.cancel();
797 row.anim.setIntValues(progress, newProgress);
798 }
799 row.animTargetProgress = newProgress;
800 row.anim.setDuration(UPDATE_ANIMATION_DURATION);
801 row.anim.start();
802 } else {
803 // update slider directly to clamped value
804 if (row.anim != null) {
805 row.anim.cancel();
806 }
Julia Reynolds88dabde2016-08-09 13:59:44 -0400807 row.slider.setProgress(newProgress, true);
Julia Reynolds4b006a82016-04-20 16:09:06 -0400808 }
809 }
John Spurlockf88d8082015-03-25 18:09:51 -0400810 }
811
812 private void recheckH(VolumeRow row) {
813 if (row == null) {
814 if (D.BUG) Log.d(TAG, "recheckH ALL");
815 trimObsoleteH();
816 for (VolumeRow r : mRows) {
817 updateVolumeRowH(r);
818 }
819 } else {
820 if (D.BUG) Log.d(TAG, "recheckH " + row.stream);
821 updateVolumeRowH(row);
822 }
823 }
824
825 private void setStreamImportantH(int stream, boolean important) {
826 for (VolumeRow row : mRows) {
827 if (row.stream == stream) {
828 row.important = important;
829 return;
830 }
831 }
832 }
833
John Spurlock76b52b32015-04-03 00:00:12 -0400834 private void showSafetyWarningH(int flags) {
835 if ((flags & (AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_SHOW_UI_WARNINGS)) != 0
836 || mShowing) {
837 synchronized (mSafetyWarningLock) {
838 if (mSafetyWarning != null) {
839 return;
840 }
841 mSafetyWarning = new SafetyWarningDialog(mContext, mController.getAudioManager()) {
842 @Override
843 protected void cleanUp() {
844 synchronized (mSafetyWarningLock) {
845 mSafetyWarning = null;
846 }
847 recheckH(null);
848 }
849 };
850 mSafetyWarning.show();
851 }
852 recheckH(null);
853 }
854 rescheduleTimeoutH();
855 }
856
Julia Reynoldsfba474a82017-12-13 15:35:54 -0500857 private void showOutputChooserH() {
858 synchronized (mOutputChooserLock) {
859 if (mOutputChooserDialog != null) {
860 return;
861 }
Julia Reynolds5daa4722017-12-20 09:53:59 -0500862 mOutputChooserDialog = new OutputChooserDialog(mContext,
863 new MediaRouterWrapper(MediaRouter.getInstance(mContext))) {
Julia Reynoldsfba474a82017-12-13 15:35:54 -0500864 @Override
865 protected void cleanUp() {
866 synchronized (mOutputChooserLock) {
867 mOutputChooserDialog = null;
868 }
869 }
870 };
871 mOutputChooserDialog.show();
872 }
873 }
874
Julia Reynolds03c548f2016-12-14 15:02:38 -0500875 private String getStreamLabelH(StreamState ss) {
876 if (ss.remoteLabel != null) {
877 return ss.remoteLabel;
878 }
879 try {
880 return mContext.getString(ss.name);
881 } catch (Resources.NotFoundException e) {
882 Slog.e(TAG, "Can't find translation for stream " + ss);
883 return "";
884 }
885 }
886
Julia Reynoldsfba474a82017-12-13 15:35:54 -0500887 private final OnClickListener mClickOutputChooser = new OnClickListener() {
888 @Override
889 public void onClick(View v) {
890 // TODO: log
891 dismissH(DISMISS_REASON_OUTPUT_CHOOSER);
892 showOutputChooserH();
893 }
894 };
895
John Spurlockf88d8082015-03-25 18:09:51 -0400896 private final VolumeDialogController.Callbacks mControllerCallbackH
897 = new VolumeDialogController.Callbacks() {
898 @Override
899 public void onShowRequested(int reason) {
900 showH(reason);
901 }
902
903 @Override
904 public void onDismissRequested(int reason) {
905 dismissH(reason);
906 }
907
John Spurlock76b52b32015-04-03 00:00:12 -0400908 @Override
John Spurlockf88d8082015-03-25 18:09:51 -0400909 public void onScreenOff() {
910 dismissH(Events.DISMISS_REASON_SCREEN_OFF);
911 }
912
913 @Override
914 public void onStateChanged(State state) {
915 onStateChangedH(state);
916 }
917
918 @Override
919 public void onLayoutDirectionChanged(int layoutDirection) {
920 mDialogView.setLayoutDirection(layoutDirection);
921 }
922
923 @Override
924 public void onConfigurationChanged() {
Julia Reynolds42411922017-11-08 11:19:09 -0500925 mDialog.dismiss();
926 initDialog();
Julia Reynolds03c548f2016-12-14 15:02:38 -0500927 mConfigurableTexts.update();
John Spurlockf88d8082015-03-25 18:09:51 -0400928 }
929
930 @Override
931 public void onShowVibrateHint() {
932 if (mSilentMode) {
933 mController.setRingerMode(AudioManager.RINGER_MODE_SILENT, false);
934 }
935 }
936
John Spurlock76b52b32015-04-03 00:00:12 -0400937 @Override
John Spurlockf88d8082015-03-25 18:09:51 -0400938 public void onShowSilentHint() {
939 if (mSilentMode) {
940 mController.setRingerMode(AudioManager.RINGER_MODE_NORMAL, false);
941 }
942 }
John Spurlock76b52b32015-04-03 00:00:12 -0400943
944 @Override
945 public void onShowSafetyWarning(int flags) {
946 showSafetyWarningH(flags);
947 }
Julia Reynoldsdbfb40f2017-01-23 11:05:57 -0500948
949 @Override
950 public void onAccessibilityModeChanged(Boolean showA11yStream) {
Julia Reynoldsedb2e7c2017-12-11 13:18:03 -0500951 mShowA11yStream = showA11yStream == null ? false : showA11yStream;
Julia Reynolds74cc6502017-08-08 12:41:04 -0400952 VolumeRow activeRow = getActiveRow();
953 if (!mShowA11yStream && AudioManager.STREAM_ACCESSIBILITY == activeRow.stream) {
954 dismissH(Events.DISMISS_STREAM_GONE);
955 } else {
956 updateRowsH(activeRow);
957 }
Julia Reynoldsdbfb40f2017-01-23 11:05:57 -0500958
959 }
John Spurlockf88d8082015-03-25 18:09:51 -0400960 };
961
John Spurlockf88d8082015-03-25 18:09:51 -0400962 private final class H extends Handler {
963 private static final int SHOW = 1;
964 private static final int DISMISS = 2;
965 private static final int RECHECK = 3;
966 private static final int RECHECK_ALL = 4;
967 private static final int SET_STREAM_IMPORTANT = 5;
968 private static final int RESCHEDULE_TIMEOUT = 6;
John Spurlock22def3d2015-06-17 11:56:12 -0400969 private static final int STATE_CHANGED = 7;
John Spurlockf88d8082015-03-25 18:09:51 -0400970
971 public H() {
972 super(Looper.getMainLooper());
973 }
974
975 @Override
976 public void handleMessage(Message msg) {
977 switch (msg.what) {
978 case SHOW: showH(msg.arg1); break;
979 case DISMISS: dismissH(msg.arg1); break;
980 case RECHECK: recheckH((VolumeRow) msg.obj); break;
981 case RECHECK_ALL: recheckH(null); break;
982 case SET_STREAM_IMPORTANT: setStreamImportantH(msg.arg1, msg.arg2 != 0); break;
983 case RESCHEDULE_TIMEOUT: rescheduleTimeoutH(); break;
John Spurlock22def3d2015-06-17 11:56:12 -0400984 case STATE_CHANGED: onStateChangedH(mState); break;
John Spurlockf88d8082015-03-25 18:09:51 -0400985 }
986 }
987 }
988
Julia Reynolds42411922017-11-08 11:19:09 -0500989 private final class CustomDialog extends Dialog implements DialogInterface {
John Spurlockf88d8082015-03-25 18:09:51 -0400990 public CustomDialog(Context context) {
Julia Reynolds42411922017-11-08 11:19:09 -0500991 super(context, com.android.systemui.R.style.qs_theme);
John Spurlockf88d8082015-03-25 18:09:51 -0400992 }
993
994 @Override
995 public boolean dispatchTouchEvent(MotionEvent ev) {
996 rescheduleTimeoutH();
997 return super.dispatchTouchEvent(ev);
998 }
999
1000 @Override
Julia Reynolds42411922017-11-08 11:19:09 -05001001 protected void onStart() {
1002 super.setCanceledOnTouchOutside(true);
1003 super.onStart();
John Spurlockf88d8082015-03-25 18:09:51 -04001004 }
1005
1006 @Override
Julia Reynolds42411922017-11-08 11:19:09 -05001007 protected void onStop() {
1008 super.onStop();
1009 mHandler.sendEmptyMessage(H.RECHECK_ALL);
John Spurlockf88d8082015-03-25 18:09:51 -04001010 }
Julia Reynolds2feab162016-04-21 14:58:52 -04001011
1012 @Override
1013 public boolean dispatchPopulateAccessibilityEvent(@NonNull AccessibilityEvent event) {
1014 event.setClassName(getClass().getSuperclass().getName());
1015 event.setPackageName(mContext.getPackageName());
1016
1017 ViewGroup.LayoutParams params = getWindow().getAttributes();
Jason Monk98ad83c2017-06-13 14:03:45 -04001018 boolean isFullScreen = (params.width == ViewGroup.LayoutParams.MATCH_PARENT) &&
1019 (params.height == ViewGroup.LayoutParams.MATCH_PARENT);
Julia Reynolds2feab162016-04-21 14:58:52 -04001020 event.setFullScreen(isFullScreen);
1021
1022 if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
1023 if (mShowing) {
1024 event.getText().add(mContext.getString(
1025 R.string.volume_dialog_accessibility_shown_message,
Julia Reynolds03c548f2016-12-14 15:02:38 -05001026 getStreamLabelH(getActiveRow().ss)));
Julia Reynolds2feab162016-04-21 14:58:52 -04001027 return true;
1028 }
1029 }
1030 return false;
1031 }
John Spurlockf88d8082015-03-25 18:09:51 -04001032 }
1033
1034 private final class VolumeSeekBarChangeListener implements OnSeekBarChangeListener {
1035 private final VolumeRow mRow;
1036
1037 private VolumeSeekBarChangeListener(VolumeRow row) {
1038 mRow = row;
1039 }
1040
1041 @Override
1042 public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
1043 if (mRow.ss == null) return;
1044 if (D.BUG) Log.d(TAG, AudioSystem.streamToString(mRow.stream)
1045 + " onProgressChanged " + progress + " fromUser=" + fromUser);
1046 if (!fromUser) return;
1047 if (mRow.ss.levelMin > 0) {
Julia Reynolds4b006a82016-04-20 16:09:06 -04001048 final int minProgress = mRow.ss.levelMin * 100;
John Spurlockf88d8082015-03-25 18:09:51 -04001049 if (progress < minProgress) {
1050 seekBar.setProgress(minProgress);
Julia Reynolds798b0c32015-09-01 14:35:53 -04001051 progress = minProgress;
John Spurlockf88d8082015-03-25 18:09:51 -04001052 }
1053 }
Julia Reynolds4b006a82016-04-20 16:09:06 -04001054 final int userLevel = getImpliedLevel(seekBar, progress);
1055 if (mRow.ss.level != userLevel || mRow.ss.muted && userLevel > 0) {
John Spurlockf88d8082015-03-25 18:09:51 -04001056 mRow.userAttempt = SystemClock.uptimeMillis();
Julia Reynolds4b006a82016-04-20 16:09:06 -04001057 if (mRow.requestedLevel != userLevel) {
1058 mController.setStreamVolume(mRow.stream, userLevel);
1059 mRow.requestedLevel = userLevel;
Chris Wrene565ee62015-06-17 15:24:56 -04001060 Events.writeEvent(mContext, Events.EVENT_TOUCH_LEVEL_CHANGED, mRow.stream,
Julia Reynolds4b006a82016-04-20 16:09:06 -04001061 userLevel);
John Spurlockf88d8082015-03-25 18:09:51 -04001062 }
1063 }
1064 }
1065
1066 @Override
1067 public void onStartTrackingTouch(SeekBar seekBar) {
1068 if (D.BUG) Log.d(TAG, "onStartTrackingTouch"+ " " + mRow.stream);
1069 mController.setActiveStream(mRow.stream);
1070 mRow.tracking = true;
1071 }
1072
1073 @Override
1074 public void onStopTrackingTouch(SeekBar seekBar) {
1075 if (D.BUG) Log.d(TAG, "onStopTrackingTouch"+ " " + mRow.stream);
1076 mRow.tracking = false;
1077 mRow.userAttempt = SystemClock.uptimeMillis();
Julia Reynolds4b006a82016-04-20 16:09:06 -04001078 final int userLevel = getImpliedLevel(seekBar, seekBar.getProgress());
Chris Wrene565ee62015-06-17 15:24:56 -04001079 Events.writeEvent(mContext, Events.EVENT_TOUCH_LEVEL_DONE, mRow.stream, userLevel);
John Spurlockf88d8082015-03-25 18:09:51 -04001080 if (mRow.ss.level != userLevel) {
1081 mHandler.sendMessageDelayed(mHandler.obtainMessage(H.RECHECK, mRow),
1082 USER_ATTEMPT_GRACE_PERIOD);
1083 }
1084 }
1085 }
1086
John Spurlockf09838b2015-06-11 16:14:44 -04001087 private final class Accessibility extends AccessibilityDelegate {
John Spurlock5adeabc2015-05-05 14:50:43 -04001088 private boolean mFeedbackEnabled;
1089
1090 public void init() {
John Spurlock5adeabc2015-05-05 14:50:43 -04001091 mDialogView.addOnAttachStateChangeListener(new OnAttachStateChangeListener() {
1092 @Override
1093 public void onViewDetachedFromWindow(View v) {
John Spurlock22def3d2015-06-17 11:56:12 -04001094 if (D.BUG) Log.d(TAG, "onViewDetachedFromWindow");
John Spurlock5adeabc2015-05-05 14:50:43 -04001095 }
1096
1097 @Override
1098 public void onViewAttachedToWindow(View v) {
John Spurlock22def3d2015-06-17 11:56:12 -04001099 if (D.BUG) Log.d(TAG, "onViewAttachedToWindow");
John Spurlock5adeabc2015-05-05 14:50:43 -04001100 updateFeedbackEnabled();
1101 }
1102 });
John Spurlockf09838b2015-06-11 16:14:44 -04001103 mDialogView.setAccessibilityDelegate(this);
Jason Monk3b9357f2017-07-14 09:40:54 -04001104 mAccessibilityMgr.addAccessibilityStateChangeListener(mListener);
John Spurlock5adeabc2015-05-05 14:50:43 -04001105 updateFeedbackEnabled();
1106 }
1107
Jason Monk3b9357f2017-07-14 09:40:54 -04001108 public void destroy() {
1109 mAccessibilityMgr.removeAccessibilityStateChangeListener(mListener);
1110 }
1111
John Spurlockf09838b2015-06-11 16:14:44 -04001112 @Override
1113 public boolean onRequestSendAccessibilityEvent(ViewGroup host, View child,
1114 AccessibilityEvent event) {
1115 rescheduleTimeoutH();
1116 return super.onRequestSendAccessibilityEvent(host, child, event);
1117 }
1118
John Spurlock5adeabc2015-05-05 14:50:43 -04001119 private void updateFeedbackEnabled() {
1120 mFeedbackEnabled = computeFeedbackEnabled();
1121 }
1122
1123 private boolean computeFeedbackEnabled() {
John Spurlockf09838b2015-06-11 16:14:44 -04001124 // are there any enabled non-generic a11y services?
John Spurlock5adeabc2015-05-05 14:50:43 -04001125 final List<AccessibilityServiceInfo> services =
Julia Reynolds2feab162016-04-21 14:58:52 -04001126 mAccessibilityMgr.getEnabledAccessibilityServiceList(FEEDBACK_ALL_MASK);
John Spurlock5adeabc2015-05-05 14:50:43 -04001127 for (AccessibilityServiceInfo asi : services) {
John Spurlockf09838b2015-06-11 16:14:44 -04001128 if (asi.feedbackType != 0 && asi.feedbackType != FEEDBACK_GENERIC) {
John Spurlock5adeabc2015-05-05 14:50:43 -04001129 return true;
1130 }
1131 }
1132 return false;
1133 }
Jason Monk3b9357f2017-07-14 09:40:54 -04001134
1135 private final AccessibilityStateChangeListener mListener =
1136 enabled -> updateFeedbackEnabled();
John Spurlock5adeabc2015-05-05 14:50:43 -04001137 }
1138
John Spurlockf88d8082015-03-25 18:09:51 -04001139 private static class VolumeRow {
1140 private View view;
John Spurlockf88d8082015-03-25 18:09:51 -04001141 private TextView header;
1142 private ImageButton icon;
1143 private SeekBar slider;
John Spurlockf88d8082015-03-25 18:09:51 -04001144 private int stream;
1145 private StreamState ss;
1146 private long userAttempt; // last user-driven slider change
1147 private boolean tracking; // tracking slider touch
John Spurlockb0a2e5f2015-06-09 14:41:52 -04001148 private int requestedLevel = -1; // pending user-requested level via progress changed
John Spurlockf88d8082015-03-25 18:09:51 -04001149 private int iconRes;
1150 private int iconMuteRes;
1151 private boolean important;
Julia Reynoldsedb2e7c2017-12-11 13:18:03 -05001152 private boolean defaultStream;
John Spurlockecc80582015-05-13 16:23:14 -04001153 private ColorStateList cachedSliderTint;
John Spurlockf88d8082015-03-25 18:09:51 -04001154 private int iconState; // from Events
Julia Reynolds4b006a82016-04-20 16:09:06 -04001155 private ObjectAnimator anim; // slider progress animation for non-touch-related updates
1156 private int animTargetProgress;
John Spurlockf88d8082015-03-25 18:09:51 -04001157 private int lastAudibleLevel = 1;
1158 }
John Spurlockf88d8082015-03-25 18:09:51 -04001159}