• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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 
17 package com.android.car.settings.sound;
18 
19 import android.annotation.DrawableRes;
20 import android.annotation.StringRes;
21 import android.car.CarNotConnectedException;
22 import android.car.media.CarAudioManager;
23 import android.content.Context;
24 import android.media.AudioAttributes;
25 import android.media.Ringtone;
26 import android.media.RingtoneManager;
27 import android.net.Uri;
28 import android.os.Handler;
29 import android.os.Looper;
30 import android.provider.Settings;
31 import android.widget.SeekBar;
32 
33 import androidx.car.widget.SeekbarListItem;
34 
35 import com.android.car.settings.common.Logger;
36 
37 /**
38  * Contains logic about volume controller UI.
39  */
40 public class VolumeLineItem extends SeekbarListItem implements SeekBar.OnSeekBarChangeListener {
41     private static final Logger LOG = new Logger(VolumeLineItem.class);
42     private static final int AUDIO_FEEDBACK_DURATION_MS = 1000;
43 
44     private final Handler mUiHandler;
45     private final Ringtone mRingtone;
46     private final int mVolumeGroupId;
47     private final CarAudioManager mCarAudioManager;
48 
VolumeLineItem( Context context, CarAudioManager carAudioManager, int volumeGroupId, @AudioAttributes.AttributeUsage int usage, @DrawableRes int iconResId, @StringRes int titleId)49     public VolumeLineItem(
50             Context context,
51             CarAudioManager carAudioManager,
52             int volumeGroupId,
53             @AudioAttributes.AttributeUsage int usage,
54             @DrawableRes int iconResId,
55             @StringRes int titleId) throws CarNotConnectedException {
56         super(context);
57         mCarAudioManager = carAudioManager;
58         mUiHandler = new Handler(Looper.getMainLooper());
59         mRingtone = RingtoneManager.getRingtone(context, getRingtoneUri(usage));
60         mRingtone.setAudioAttributes(new AudioAttributes.Builder().setUsage(usage).build());
61         mVolumeGroupId = volumeGroupId;
62         setMax(getMaxSeekbarValue());
63         updateProgress();
64         setOnSeekBarChangeListener(this);
65         setText(context.getString(titleId));
66         setPrimaryActionIcon(iconResId);
67     }
68 
69     @Override
onStartTrackingTouch(SeekBar seekBar)70     public void onStartTrackingTouch(SeekBar seekBar) {
71         // no-op
72     }
73 
74     @Override
onStopTrackingTouch(SeekBar seekBar)75     public void onStopTrackingTouch(SeekBar seekBar) {
76         // no-op
77     }
78 
79     @Override
onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)80     public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
81         if (!fromUser) {
82             // For instance, if this event is originated from AudioService,
83             // we can ignore it as it has already been handled and doesn't need to be
84             // sent back down again.
85             return;
86         }
87         try {
88             if (mCarAudioManager == null) {
89                 LOG.w("Ignoring volume change event because the car isn't connected");
90                 return;
91             }
92             // AudioManager.FLAG_PLAY_SOUND does not guarantee play sound, use our own
93             // playback here instead.
94             mCarAudioManager.setGroupVolume(mVolumeGroupId, progress, 0);
95             playAudioFeedback();
96         } catch (CarNotConnectedException e) {
97             LOG.e("Car is not connected!", e);
98         }
99     }
100 
101     /**
102      * Clean ups
103      */
stop()104     public void stop() {
105         mUiHandler.removeCallbacksAndMessages(null);
106         mRingtone.stop();
107     }
108 
getVolumeGroupId()109     public int getVolumeGroupId() {
110         return mVolumeGroupId;
111     }
112 
113     /**
114      * Gets the latest progress.
115      */
updateProgress()116     public void updateProgress() {
117         setProgress(getSeekbarValue());
118     }
119 
playAudioFeedback()120     private void playAudioFeedback() {
121         mUiHandler.removeCallbacksAndMessages(null);
122         mRingtone.play();
123         mUiHandler.postDelayed(() -> {
124             if (mRingtone.isPlaying()) {
125                 mRingtone.stop();
126             }
127         }, AUDIO_FEEDBACK_DURATION_MS);
128     }
129 
130     // TODO: bundle car-specific audio sample assets in res/raw by usage
getRingtoneUri(@udioAttributes.AttributeUsage int usage)131     private Uri getRingtoneUri(@AudioAttributes.AttributeUsage int usage) {
132         switch (usage) {
133             case AudioAttributes.USAGE_NOTIFICATION:
134                 return Settings.System.DEFAULT_NOTIFICATION_URI;
135             case AudioAttributes.USAGE_ALARM:
136                 return Settings.System.DEFAULT_ALARM_ALERT_URI;
137             default:
138                 return Settings.System.DEFAULT_RINGTONE_URI;
139         }
140     }
141 
getSeekbarValue()142     private int getSeekbarValue() {
143         try {
144             return mCarAudioManager.getGroupVolume(mVolumeGroupId);
145         } catch (CarNotConnectedException e) {
146             LOG.e("Car is not connected!", e);
147         }
148         return 0;
149     }
150 
getMaxSeekbarValue()151     private int getMaxSeekbarValue() {
152         try {
153             return mCarAudioManager.getGroupMaxVolume(mVolumeGroupId);
154         } catch (CarNotConnectedException e) {
155             LOG.e("Car is not connected!", e);
156         }
157         return 0;
158     }
159 }
160