1 /* 2 * Copyright (C) 2009 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 package android.media.audio.cts; 17 18 import static org.junit.Assert.assertEquals; 19 import static org.junit.Assert.assertFalse; 20 import static org.junit.Assert.assertNotNull; 21 import static org.junit.Assert.assertTrue; 22 import static org.junit.Assert.fail; 23 24 import android.app.Instrumentation; 25 import android.content.ContentProvider; 26 import android.content.ContentResolver; 27 import android.content.Context; 28 import android.content.pm.PackageManager; 29 import android.content.res.AssetFileDescriptor; 30 import android.database.Cursor; 31 import android.media.AudioManager; 32 import android.media.Ringtone; 33 import android.media.RingtoneManager; 34 import android.media.cts.Utils; 35 import android.net.Uri; 36 import android.os.ConditionVariable; 37 import android.platform.test.annotations.AppModeFull; 38 import android.provider.Settings; 39 40 import androidx.test.core.app.ActivityScenario; 41 import androidx.test.ext.junit.runners.AndroidJUnit4; 42 import androidx.test.platform.app.InstrumentationRegistry; 43 44 import org.junit.After; 45 import org.junit.Before; 46 import org.junit.Test; 47 import org.junit.runner.RunWith; 48 49 import java.io.IOException; 50 51 @AppModeFull(reason = "TODO: evaluate and port to instant") 52 @RunWith(AndroidJUnit4.class) 53 public class RingtoneManagerTest { 54 55 private static final String PKG = "android.media.audio.cts"; 56 private static final String TAG = "RingtoneManagerTest"; 57 58 private RingtonePickerActivity mActivity; 59 private ActivityScenario<RingtonePickerActivity> mActivityScenario; 60 private Instrumentation mInstrumentation; 61 private Context mContext; 62 private RingtoneManager mRingtoneManager; 63 private AudioManager mAudioManager; 64 private int mOriginalRingerMode; 65 private Uri mDefaultUri; 66 67 @Before setUp()68 public void setUp() throws Exception { 69 mActivityScenario = ActivityScenario.launch(RingtonePickerActivity.class); 70 ConditionVariable activityReferenceObtained = new ConditionVariable(); 71 mActivityScenario.onActivity(activity -> { 72 mActivity = activity; 73 activityReferenceObtained.open(); 74 }); 75 activityReferenceObtained.block(10000); 76 assertNotNull("Failed to acquire activity reference.", mActivity); 77 78 mInstrumentation = InstrumentationRegistry.getInstrumentation(); 79 mContext = mInstrumentation.getTargetContext(); 80 mInstrumentation.waitForIdleSync(); 81 82 Utils.enableAppOps(mContext.getPackageName(), "android:write_settings", mInstrumentation); 83 mRingtoneManager = new RingtoneManager(mActivity); 84 mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); 85 // backup ringer settings 86 mDefaultUri = ContentProvider.maybeAddUserId( 87 RingtoneManager.getActualDefaultRingtoneUri( 88 mContext, RingtoneManager.TYPE_RINGTONE), mContext.getUserId()); 89 90 mOriginalRingerMode = mAudioManager.getRingerMode(); 91 if (mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_NORMAL) { 92 try { 93 Utils.toggleNotificationPolicyAccess( 94 mContext.getPackageName(), mInstrumentation, true); 95 mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL); 96 } finally { 97 Utils.toggleNotificationPolicyAccess( 98 mContext.getPackageName(), mInstrumentation, false); 99 } 100 } 101 } 102 103 @After tearDown()104 public void tearDown() throws Exception { 105 try { 106 Utils.toggleNotificationPolicyAccess( 107 mContext.getPackageName(), mInstrumentation, true); 108 // restore original ringer settings 109 if (mAudioManager != null) { 110 mAudioManager.setRingerMode(mOriginalRingerMode); 111 } 112 } finally { 113 Utils.toggleNotificationPolicyAccess( 114 mContext.getPackageName(), mInstrumentation, false); 115 } 116 RingtoneManager.setActualDefaultRingtoneUri(mContext, RingtoneManager.TYPE_RINGTONE, 117 mDefaultUri); 118 Utils.disableAppOps(mContext.getPackageName(), "android:write_settings", mInstrumentation); 119 } 120 isSupportedDevice()121 private boolean isSupportedDevice() { 122 final PackageManager pm = mContext.getPackageManager(); 123 return pm.hasSystemFeature(PackageManager.FEATURE_AUDIO_OUTPUT) 124 && !pm.hasSystemFeature(PackageManager.FEATURE_LEANBACK_ONLY); 125 } 126 127 @Test testConstructors()128 public void testConstructors() { 129 if (!isSupportedDevice()) return; 130 131 new RingtoneManager(mActivity); 132 new RingtoneManager(mContext); 133 } 134 135 @Test testAccessMethods()136 public void testAccessMethods() { 137 if (!isSupportedDevice()) return; 138 139 Cursor c = mRingtoneManager.getCursor(); 140 assertTrue("Must have at least one ring tone available", c.getCount() > 0); 141 142 assertNotNull(mRingtoneManager.getRingtone(0)); 143 assertNotNull(RingtoneManager.getRingtone(mContext, Settings.System.DEFAULT_RINGTONE_URI)); 144 int expectedPosition = 0; 145 Uri uri = mRingtoneManager.getRingtoneUri(expectedPosition); 146 assertEquals(expectedPosition, mRingtoneManager.getRingtonePosition(uri)); 147 assertNotNull(RingtoneManager.getValidRingtoneUri(mContext)); 148 uri = ContentProvider.maybeAddUserId(uri, mContext.getUserId()); 149 150 RingtoneManager.setActualDefaultRingtoneUri(mContext, RingtoneManager.TYPE_RINGTONE, uri); 151 152 Uri actualDefaultRingtoneUri = ContentProvider.maybeAddUserId( 153 RingtoneManager.getActualDefaultRingtoneUri( 154 mContext, RingtoneManager.TYPE_RINGTONE), mContext.getUserId()); 155 156 assertEquals(uri, actualDefaultRingtoneUri); 157 158 try (AssetFileDescriptor afd = RingtoneManager.openDefaultRingtoneUri( 159 mActivity, RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE))) { 160 assertNotNull(afd); 161 } catch (IOException e) { 162 fail(e.getMessage()); 163 } 164 165 Uri bogus = Uri.parse("content://a_bogus_uri"); 166 RingtoneManager.setActualDefaultRingtoneUri(mContext, RingtoneManager.TYPE_RINGTONE, bogus); 167 // not testing the matching getter after setting a bogus URI as ringtone 168 //assertNotEquals(bogus, RingtoneManager.getActualDefaultRingtoneUri(mContext, 169 // RingtoneManager.TYPE_RINGTONE)); 170 171 assertEquals(Settings.System.DEFAULT_RINGTONE_URI, 172 RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE)); 173 assertEquals(Settings.System.DEFAULT_NOTIFICATION_URI, 174 RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)); 175 assertEquals(RingtoneManager.TYPE_RINGTONE, 176 RingtoneManager.getDefaultType(Settings.System.DEFAULT_RINGTONE_URI)); 177 assertEquals(RingtoneManager.TYPE_NOTIFICATION, 178 RingtoneManager.getDefaultType(Settings.System.DEFAULT_NOTIFICATION_URI)); 179 assertTrue(RingtoneManager.isDefault(Settings.System.DEFAULT_RINGTONE_URI)); 180 } 181 182 @Test testSetType()183 public void testSetType() { 184 if (!isSupportedDevice()) return; 185 186 mRingtoneManager.setType(RingtoneManager.TYPE_ALARM); 187 assertEquals(AudioManager.STREAM_ALARM, mRingtoneManager.inferStreamType()); 188 Cursor c = mRingtoneManager.getCursor(); 189 assertTrue("Must have at least one alarm tone available", c.getCount() > 0); 190 Ringtone r = mRingtoneManager.getRingtone(0); 191 assertEquals(RingtoneManager.TYPE_ALARM, r.getStreamType()); 192 } 193 194 @Test testStopPreviousRingtone()195 public void testStopPreviousRingtone() { 196 if (!isSupportedDevice()) return; 197 198 Cursor c = mRingtoneManager.getCursor(); 199 assertTrue("Must have at least one ring tone available", c.getCount() > 0); 200 201 mRingtoneManager.setStopPreviousRingtone(true); 202 assertTrue(mRingtoneManager.getStopPreviousRingtone()); 203 Uri uri = Uri.parse("android.resource://" + PKG + "/" + R.raw.john_cage); 204 Ringtone ringtone = RingtoneManager.getRingtone(mContext, uri); 205 ringtone.play(); 206 assertTrue(ringtone.isPlaying()); 207 ringtone.stop(); 208 assertFalse(ringtone.isPlaying()); 209 Ringtone newRingtone = mRingtoneManager.getRingtone(0); 210 assertFalse(ringtone.isPlaying()); 211 newRingtone.play(); 212 assertTrue(newRingtone.isPlaying()); 213 mRingtoneManager.stopPreviousRingtone(); 214 assertFalse(newRingtone.isPlaying()); 215 } 216 217 @Test testQuery()218 public void testQuery() { 219 if (!isSupportedDevice()) return; 220 221 final Cursor c = mRingtoneManager.getCursor(); 222 assertTrue(c.moveToFirst()); 223 assertTrue(c.getInt(RingtoneManager.ID_COLUMN_INDEX) >= 0); 224 assertTrue(c.getString(RingtoneManager.TITLE_COLUMN_INDEX) != null); 225 assertTrue(c.getString(RingtoneManager.URI_COLUMN_INDEX), 226 c.getString(RingtoneManager.URI_COLUMN_INDEX).startsWith("content://")); 227 } 228 229 @Test testHasHapticChannels()230 public void testHasHapticChannels() { 231 if (!isSupportedDevice()) return; 232 233 Cursor c = mRingtoneManager.getCursor(); 234 assertTrue("Must have at lease one ringtone available", c.getCount() > 0); 235 mRingtoneManager.hasHapticChannels(0); 236 237 final String uriPrefix = ContentResolver.SCHEME_ANDROID_RESOURCE + "://" + 238 mContext.getPackageName() + "/raw/"; 239 assertTrue(RingtoneManager.hasHapticChannels(Uri.parse(uriPrefix + "a_4_haptic"))); 240 assertFalse(RingtoneManager.hasHapticChannels(Uri.parse(uriPrefix + "a_4"))); 241 242 assertTrue(RingtoneManager.hasHapticChannels( 243 mContext, Uri.parse(uriPrefix + "a_4_haptic"))); 244 assertFalse(RingtoneManager.hasHapticChannels(mContext, Uri.parse(uriPrefix + "a_4"))); 245 } 246 } 247