1 /* 2 * Copyright 2019 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 android.media.cts; 18 19 import static org.junit.Assert.assertNotEquals; 20 import static org.junit.Assert.fail; 21 22 import android.app.Instrumentation; 23 import android.content.Context; 24 import android.content.Intent; 25 import android.content.res.Resources; 26 import android.media.AudioAttributes; 27 import android.media.AudioManager; 28 import android.media.session.MediaSession; 29 import android.os.SystemClock; 30 import android.view.KeyEvent; 31 32 import androidx.test.InstrumentationRegistry; 33 import androidx.test.filters.MediumTest; 34 import androidx.test.rule.ActivityTestRule; 35 import androidx.test.runner.AndroidJUnit4; 36 37 import org.junit.After; 38 import org.junit.Before; 39 import org.junit.Rule; 40 import org.junit.Test; 41 import org.junit.runner.RunWith; 42 43 import java.util.ArrayList; 44 import java.util.HashMap; 45 import java.util.List; 46 import java.util.Map; 47 48 /** 49 * Test media activity which has called {@link Activity#setMediaController}. 50 */ 51 @MediumTest 52 @RunWith(AndroidJUnit4.class) 53 public class MediaActivityTest { 54 private static final String TAG = "MediaActivityTest"; 55 private static final int WAIT_TIME_MS = 500; 56 private static final List<Integer> ALL_VOLUME_STREAMS = new ArrayList(); 57 static { 58 ALL_VOLUME_STREAMS.add(AudioManager.STREAM_ACCESSIBILITY); 59 ALL_VOLUME_STREAMS.add(AudioManager.STREAM_ALARM); 60 ALL_VOLUME_STREAMS.add(AudioManager.STREAM_DTMF); 61 ALL_VOLUME_STREAMS.add(AudioManager.STREAM_MUSIC); 62 ALL_VOLUME_STREAMS.add(AudioManager.STREAM_NOTIFICATION); 63 ALL_VOLUME_STREAMS.add(AudioManager.STREAM_RING); 64 ALL_VOLUME_STREAMS.add(AudioManager.STREAM_SYSTEM); 65 ALL_VOLUME_STREAMS.add(AudioManager.STREAM_VOICE_CALL); 66 } 67 68 private Instrumentation mInstrumentation; 69 private Context mContext; 70 private boolean mUseFixedVolume; 71 private AudioManager mAudioManager; 72 private Map<Integer, Integer> mStreamVolumeMap = new HashMap<>(); 73 private MediaSession mSession; 74 75 @Rule 76 public ActivityTestRule<MediaSessionTestActivity> mActivityRule = 77 new ActivityTestRule<>(MediaSessionTestActivity.class, false, false); 78 79 @Before 80 public void setUp() throws Exception { 81 mInstrumentation = InstrumentationRegistry.getInstrumentation(); 82 mContext = mInstrumentation.getContext(); 83 mUseFixedVolume = mContext.getResources().getBoolean( 84 Resources.getSystem().getIdentifier("config_useFixedVolume", "bool", "android")); 85 mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); 86 87 mStreamVolumeMap.clear(); 88 for (Integer stream : ALL_VOLUME_STREAMS) { 89 mStreamVolumeMap.put(stream, mAudioManager.getStreamVolume(stream)); 90 } 91 92 mSession = new MediaSession(mContext, TAG); 93 mSession.setPlaybackToLocal(new AudioAttributes.Builder() 94 .setLegacyStreamType(AudioManager.STREAM_MUSIC).build()); 95 96 Intent intent = new Intent(Intent.ACTION_MAIN); 97 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 98 intent.putExtra(MediaSessionTestActivity.KEY_SESSION_TOKEN, mSession.getSessionToken()); 99 mActivityRule.launchActivity(intent); 100 } 101 102 @After 103 public void cleanUp() { 104 if (mSession != null) { 105 mSession.release(); 106 mSession = null; 107 } 108 109 for (int stream : mStreamVolumeMap.keySet()) { 110 int volume = mStreamVolumeMap.get(stream); 111 mAudioManager.setStreamVolume(stream, volume, 0); 112 } 113 } 114 115 /** 116 * Tests whether volume key changes volume with the session's stream. 117 */ 118 @Test 119 public void testVolumeKey_whileSessionAlive() throws InterruptedException { 120 if (mUseFixedVolume) { 121 return; 122 } 123 124 final int testStream = mSession.getController().getPlaybackInfo().getAudioAttributes() 125 .getVolumeControlStream(); 126 final int testKeyCode; 127 if (mStreamVolumeMap.get(testStream) == mAudioManager.getStreamMinVolume(testStream)) { 128 testKeyCode = KeyEvent.KEYCODE_VOLUME_UP; 129 } else { 130 testKeyCode = KeyEvent.KEYCODE_VOLUME_DOWN; 131 } 132 133 // The first event can be ignored and show volume panel instead. Use double tap. 134 sendKeyEvent(testKeyCode); 135 sendKeyEvent(testKeyCode); 136 137 Thread.sleep(WAIT_TIME_MS); 138 assertNotEquals((int) mStreamVolumeMap.get(testStream), 139 mAudioManager.getStreamVolume(testStream)); 140 } 141 142 /** 143 * Tests whether volume key changes volume even after the session is released. 144 */ 145 @Test 146 public void testVolumeKey_afterSessionReleased() throws InterruptedException { 147 if (mUseFixedVolume) { 148 return; 149 } 150 151 mSession.release(); 152 153 // The first event can be ignored and show volume panel instead. Use double tap. 154 sendKeyEvent(KeyEvent.KEYCODE_VOLUME_DOWN); 155 sendKeyEvent(KeyEvent.KEYCODE_VOLUME_DOWN); 156 157 // We cannot know which stream is changed. Need to monitor all streams. 158 Thread.sleep(WAIT_TIME_MS); 159 for (int stream : mStreamVolumeMap.keySet()) { 160 int volume = mStreamVolumeMap.get(stream); 161 if (mAudioManager.getStreamVolume(stream) != volume) { 162 return; 163 } 164 } 165 166 // Volume can be already zero for the target stream, so try again with the volume up. 167 sendKeyEvent(KeyEvent.KEYCODE_VOLUME_UP); 168 sendKeyEvent(KeyEvent.KEYCODE_VOLUME_UP); 169 170 Thread.sleep(WAIT_TIME_MS); 171 for (int stream : mStreamVolumeMap.keySet()) { 172 int volume = mStreamVolumeMap.get(stream); 173 if (mAudioManager.getStreamVolume(stream) != volume) { 174 return; 175 } 176 } 177 fail("Volume keys were ignored"); 178 } 179 180 private void sendKeyEvent(int keyCode) { 181 final long downTime = SystemClock.uptimeMillis(); 182 final KeyEvent down = new KeyEvent(downTime, downTime, KeyEvent.ACTION_DOWN, keyCode, 0); 183 final long upTime = SystemClock.uptimeMillis(); 184 final KeyEvent up = new KeyEvent(downTime, upTime, KeyEvent.ACTION_UP, keyCode, 0); 185 mInstrumentation.sendKeySync(down); 186 mInstrumentation.sendKeySync(up); 187 } 188 } 189