VolumeTestFragment.java revision 96def40502ff34f01d11eeae49e63582ec560dda
1/* 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 */ 16package com.google.android.car.kitchensink.volume; 17 18import android.car.Car; 19import android.car.CarNotConnectedException; 20import android.car.media.CarAudioManager; 21import android.content.Context; 22import android.media.AudioManager; 23import android.media.IVolumeController; 24import android.os.Bundle; 25import android.os.Handler; 26import android.os.Message; 27import android.os.RemoteException; 28import android.support.annotation.Nullable; 29import android.support.v4.app.Fragment; 30import android.util.Log; 31import android.util.SparseIntArray; 32import android.view.KeyEvent; 33import android.view.LayoutInflater; 34import android.view.View; 35import android.view.ViewGroup; 36import android.widget.Button; 37import android.widget.ListView; 38 39import com.google.android.car.kitchensink.CarEmulator; 40import com.google.android.car.kitchensink.R; 41 42public class VolumeTestFragment extends Fragment{ 43 private static final String TAG = "CarVolumeTest"; 44 private static final int MSG_VOLUME_CHANGED = 0; 45 private static final int MSG_REQUEST_FOCUS = 1; 46 private static final int MSG_FOCUS_CHANGED= 2; 47 48 private ListView mVolumeList; 49 private Button mRefreshButton; 50 private AudioManager mAudioManager; 51 private VolumeAdapter mAdapter; 52 53 private CarAudioManager mCarAudioManager; 54 private Car mCar; 55 private CarEmulator mCarEmulator; 56 57 private Button mVolumeUp; 58 private Button mVolumeDown; 59 60 private final VolumeController mVolumeController = new VolumeController(); 61 private final Handler mHandler = new VolumeHandler(); 62 63 private class VolumeHandler extends Handler { 64 private AudioFocusListener mFocusListener; 65 66 @Override 67 public void handleMessage(Message msg) { 68 switch (msg.what) { 69 case MSG_VOLUME_CHANGED: 70 initVolumeInfo(); 71 break; 72 case MSG_REQUEST_FOCUS: 73 int stream = msg.arg1; 74 if (mFocusListener != null) { 75 mAudioManager.abandonAudioFocus(mFocusListener); 76 mVolumeInfos[mStreamIndexMap.get(stream)].mHasFocus = false; 77 mAdapter.notifyDataSetChanged(); 78 } 79 80 mFocusListener = new AudioFocusListener(stream); 81 mAudioManager.requestAudioFocus(mFocusListener, stream, 82 AudioManager.AUDIOFOCUS_GAIN); 83 break; 84 case MSG_FOCUS_CHANGED: 85 int focusStream = msg.arg1; 86 mVolumeInfos[mStreamIndexMap.get(focusStream)].mHasFocus = true; 87 mAdapter.refreshVolumes(mVolumeInfos); 88 break; 89 90 } 91 } 92 } 93 94 private VolumeInfo[] mVolumeInfos = new VolumeInfo[LOGICAL_STREAMS.length + 1]; 95 private SparseIntArray mStreamIndexMap = new SparseIntArray(LOGICAL_STREAMS.length); 96 97 private class AudioFocusListener implements AudioManager.OnAudioFocusChangeListener { 98 private final int mStream; 99 public AudioFocusListener(int stream) { 100 mStream = stream; 101 } 102 @Override 103 public void onAudioFocusChange(int focusChange) { 104 if (focusChange == AudioManager.AUDIOFOCUS_GAIN) { 105 mHandler.sendMessage(mHandler.obtainMessage(MSG_FOCUS_CHANGED, mStream, 0)); 106 } else { 107 Log.e(TAG, "Audio focus request failed"); 108 } 109 } 110 } 111 112 public static class VolumeInfo { 113 public int logicalStream; 114 public String mId; 115 public String mMax; 116 public String mCurrent; 117 public String mLogicalMax; 118 public String mLogicalCurrent; 119 public boolean mHasFocus; 120 } 121 122 private static final int LOGICAL_STREAMS[] = { 123 AudioManager.STREAM_MUSIC, 124 AudioManager.STREAM_ALARM, 125 AudioManager.STREAM_NOTIFICATION, 126 AudioManager.STREAM_RING, 127 AudioManager.STREAM_VOICE_CALL, 128 AudioManager.STREAM_SYSTEM 129 // AudioManager.STREAM_DTMF, 130 }; 131 132 private static String streamToName (int stream) { 133 switch (stream) { 134 case AudioManager.STREAM_ALARM: return "Alarm"; 135 case AudioManager.STREAM_MUSIC: return "Music"; 136 case AudioManager.STREAM_NOTIFICATION: return "Notification"; 137 case AudioManager.STREAM_RING: return "Ring"; 138 case AudioManager.STREAM_VOICE_CALL: return "Call"; 139 case AudioManager.STREAM_SYSTEM: return "System"; 140 default: return "Unknown"; 141 } 142 } 143 144 @Override 145 public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, 146 @Nullable Bundle savedInstanceState) { 147 View v = inflater.inflate(R.layout.volume_test, container, false); 148 149 mVolumeList = (ListView) v.findViewById(R.id.volume_list); 150 mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE); 151 152 mRefreshButton = (Button) v.findViewById(R.id.refresh); 153 mAdapter = new VolumeAdapter(getContext(), R.layout.volume_item, mVolumeInfos, this); 154 mVolumeList.setAdapter(mAdapter); 155 156 mRefreshButton.setOnClickListener(new View.OnClickListener() { 157 @Override 158 public void onClick(View view) { 159 initVolumeInfo(); 160 } 161 }); 162 163 mCarEmulator = CarEmulator.create(getContext()); 164 mCar = mCarEmulator.getCar(); 165 try { 166 mCarAudioManager = (CarAudioManager) mCar.getCarManager(Car.AUDIO_SERVICE); 167 initVolumeInfo(); 168 mCarAudioManager.setVolumeController(mVolumeController); 169 } catch (CarNotConnectedException e) { 170 throw new RuntimeException(e); // Should never occur in car emulator. 171 } 172 173 mVolumeUp = (Button) v.findViewById(R.id.volume_up); 174 mVolumeDown = (Button) v.findViewById(R.id.volume_down); 175 176 mVolumeUp.setOnClickListener(new View.OnClickListener() { 177 @Override 178 public void onClick(View view) { 179 mCarEmulator.injectKey(KeyEvent.KEYCODE_VOLUME_UP); 180 } 181 }); 182 183 mVolumeDown.setOnClickListener(new View.OnClickListener() { 184 @Override 185 public void onClick(View view) { 186 mCarEmulator.injectKey(KeyEvent.KEYCODE_VOLUME_DOWN); 187 } 188 }); 189 190 return v; 191 } 192 193 public void adjustVolumeByOne(int logicalStream, boolean up) { 194 if (mCarAudioManager == null) { 195 Log.e(TAG, "CarAudioManager is null"); 196 return; 197 } 198 int current = 0; 199 try { 200 current = mCarAudioManager.getStreamVolume(logicalStream); 201 } catch (CarNotConnectedException e) { 202 Log.e(TAG, "car not connected", e); 203 } 204 setStreamVolume(logicalStream, current + (up ? 1 : -1)); 205 } 206 207 public void requestFocus(int logicalStream) { 208 mHandler.sendMessage(mHandler.obtainMessage(MSG_REQUEST_FOCUS, logicalStream)); 209 } 210 211 public void setStreamVolume(int logicalStream, int volume) { 212 if (mCarAudioManager == null) { 213 Log.e(TAG, "CarAudioManager is null"); 214 return; 215 } 216 try { 217 mCarAudioManager.setStreamVolume(logicalStream, volume, 0); 218 } catch (CarNotConnectedException e) { 219 Log.e(TAG, "car not connected", e); 220 } 221 222 Log.d(TAG, "Set stream " + logicalStream + " volume " + volume); 223 } 224 225 226 private void initVolumeInfo() { 227 if (mVolumeInfos[0] == null) { 228 mVolumeInfos[0] = new VolumeInfo(); 229 mVolumeInfos[0].mId = "Stream"; 230 mVolumeInfos[0].mCurrent = "Current"; 231 mVolumeInfos[0].mMax = "Max"; 232 mVolumeInfos[0].mLogicalMax = "Android_Max"; 233 mVolumeInfos[0].mLogicalCurrent = "Android_Current"; 234 235 } 236 int i = 1; 237 for (int stream : LOGICAL_STREAMS) { 238 if (mVolumeInfos[i] == null) { 239 mVolumeInfos[i] = new VolumeInfo(); 240 } 241 mVolumeInfos[i].logicalStream = stream; 242 mStreamIndexMap.put(stream, i); 243 mVolumeInfos[i].mId = streamToName(stream); 244 245 int current = 0; 246 int max = 0; 247 try { 248 current = mCarAudioManager.getStreamVolume(stream); 249 max = mCarAudioManager.getStreamMaxVolume(stream); 250 } catch (CarNotConnectedException e) { 251 Log.e(TAG, "car not connected", e); 252 } 253 254 mVolumeInfos[i].mCurrent = String.valueOf(current); 255 mVolumeInfos[i].mMax = String.valueOf(max); 256 257 mVolumeInfos[i].mLogicalMax = String.valueOf(mAudioManager.getStreamMaxVolume(stream)); 258 mVolumeInfos[i].mLogicalCurrent = String.valueOf(mAudioManager.getStreamVolume(stream)); 259 260 Log.d(TAG, stream + " max: " + mVolumeInfos[i].mMax + " current: " 261 + mVolumeInfos[i].mCurrent); 262 i++; 263 } 264 mAdapter.refreshVolumes(mVolumeInfos); 265 } 266 267 @Override 268 public void onDestroy() { 269 if (mCar != null) { 270 mCar.disconnect(); 271 } 272 super.onDestroy(); 273 } 274 275 private class VolumeController extends IVolumeController.Stub { 276 277 @Override 278 public void displaySafeVolumeWarning(int flags) throws RemoteException {} 279 280 @Override 281 public void volumeChanged(int streamType, int flags) throws RemoteException { 282 mHandler.sendMessage(mHandler.obtainMessage(MSG_VOLUME_CHANGED, streamType)); 283 } 284 285 @Override 286 public void masterMuteChanged(int flags) throws RemoteException {} 287 288 @Override 289 public void setLayoutDirection(int layoutDirection) throws RemoteException { 290 } 291 292 @Override 293 public void dismiss() throws RemoteException { 294 } 295 296 @Override 297 public void setA11yMode(int mode) throws RemoteException { 298 } 299 } 300} 301