1 /*
2  * Copyright (C) 2008 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.audio.cts;
18 
19 import android.content.ContentProvider;
20 import android.content.Context;
21 import android.content.pm.PackageManager;
22 import android.media.AudioAttributes;
23 import android.media.AudioManager;
24 import android.media.Ringtone;
25 import android.media.RingtoneManager;
26 import android.media.audiofx.HapticGenerator;
27 import android.media.cts.Utils;
28 import android.net.Uri;
29 import android.os.Build;
30 import android.platform.test.annotations.AppModeFull;
31 import android.provider.Settings;
32 import android.test.InstrumentationTestCase;
33 import android.util.Log;
34 
35 import com.android.compatibility.common.util.ApiLevelUtil;
36 
37 @AppModeFull(reason = "TODO: evaluate and port to instant")
38 public class RingtoneTest extends InstrumentationTestCase {
39     private static final String TAG = "RingtoneTest";
40 
41     private Context mContext;
42     private Ringtone mRingtone;
43     private AudioManager mAudioManager;
44     private int mOriginalVolume;
45     private int mOriginalRingerMode;
46     private int mOriginalStreamType;
47     private Uri mDefaultRingUri;
48 
49     private static boolean sIsAtLeastS = ApiLevelUtil.isAtLeast(Build.VERSION_CODES.S);
50 
51     @Override
setUp()52     protected void setUp() throws Exception {
53         super.setUp();
54         enableAppOps();
55         mContext = getInstrumentation().getContext();
56         mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
57         mRingtone = RingtoneManager.getRingtone(mContext, Settings.System.DEFAULT_RINGTONE_URI);
58         // backup ringer settings
59         mOriginalRingerMode = mAudioManager.getRingerMode();
60         mOriginalVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_RING);
61         mOriginalStreamType = mRingtone.getStreamType();
62 
63         int maxVolume = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_RING);
64 
65         if (mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_VIBRATE) {
66             mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
67             mAudioManager.setStreamVolume(AudioManager.STREAM_RING, maxVolume / 2,
68                     AudioManager.FLAG_ALLOW_RINGER_MODES);
69         } else if (mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_NORMAL) {
70             mAudioManager.setStreamVolume(AudioManager.STREAM_RING, maxVolume / 2,
71                     AudioManager.FLAG_ALLOW_RINGER_MODES);
72         } else {
73             try {
74                 Utils.toggleNotificationPolicyAccess(
75                         mContext.getPackageName(), getInstrumentation(), true);
76                 // set ringer to a reasonable volume
77                 mAudioManager.setStreamVolume(AudioManager.STREAM_RING, maxVolume / 2,
78                         AudioManager.FLAG_ALLOW_RINGER_MODES);
79                 // make sure that we are not in silent mode
80                 mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
81             } finally {
82                 Utils.toggleNotificationPolicyAccess(
83                         mContext.getPackageName(), getInstrumentation(), false);
84             }
85         }
86 
87         mDefaultRingUri = RingtoneManager.getActualDefaultRingtoneUri(mContext,
88                 RingtoneManager.TYPE_RINGTONE);
89     }
90 
enableAppOps()91     private void enableAppOps() {
92         StringBuilder cmd = new StringBuilder();
93         cmd.append("appops set ");
94         cmd.append(getInstrumentation().getContext().getPackageName());
95         cmd.append(" android:write_settings allow");
96         getInstrumentation().getUiAutomation().executeShellCommand(cmd.toString());
97         try {
98             Thread.sleep(2200);
99         } catch (InterruptedException e) {
100         }
101     }
102 
103     @Override
tearDown()104     protected void tearDown() throws Exception {
105         // restore original settings
106         if (mRingtone != null) {
107             if (mRingtone.isPlaying()) mRingtone.stop();
108             mRingtone.setStreamType(mOriginalStreamType);
109         }
110         if (mAudioManager != null) {
111             try {
112                 Utils.toggleNotificationPolicyAccess(
113                         mContext.getPackageName(), getInstrumentation(), true);
114                 mAudioManager.setRingerMode(mOriginalRingerMode);
115                 mAudioManager.setStreamVolume(AudioManager.STREAM_RING, mOriginalVolume,
116                         AudioManager.FLAG_ALLOW_RINGER_MODES);
117             } finally {
118                 Utils.toggleNotificationPolicyAccess(
119                         mContext.getPackageName(), getInstrumentation(), false);
120             }
121         }
122         RingtoneManager.setActualDefaultRingtoneUri(mContext, RingtoneManager.TYPE_RINGTONE,
123                 mDefaultRingUri);
124         super.tearDown();
125     }
126 
hasAudioOutput()127     private boolean hasAudioOutput() {
128         return getInstrumentation().getContext().getPackageManager()
129                 .hasSystemFeature(PackageManager.FEATURE_AUDIO_OUTPUT);
130     }
131 
isTV()132     private boolean isTV() {
133         return getInstrumentation().getContext().getPackageManager()
134                 .hasSystemFeature(PackageManager.FEATURE_LEANBACK_ONLY);
135     }
136 
testRingtone()137     public void testRingtone() {
138         if (isTV()) {
139             return;
140         }
141         if (!hasAudioOutput()) {
142             Log.i(TAG, "Skipping testRingtone(): device doesn't have audio output.");
143             return;
144         }
145 
146         assertNotNull(mRingtone.getTitle(mContext));
147         assertTrue(mOriginalStreamType >= 0);
148 
149         mRingtone.setStreamType(AudioManager.STREAM_MUSIC);
150         assertEquals(AudioManager.STREAM_MUSIC, mRingtone.getStreamType());
151         mRingtone.setStreamType(AudioManager.STREAM_ALARM);
152         assertEquals(AudioManager.STREAM_ALARM, mRingtone.getStreamType());
153         // make sure we play on STREAM_RING because we the volume on this stream is not 0
154         mRingtone.setStreamType(AudioManager.STREAM_RING);
155         assertEquals(AudioManager.STREAM_RING, mRingtone.getStreamType());
156 
157         // Some releases, such as Wear R can return a null ringtone when its badly formed, this
158         // assumption may change on T+ so if it does, update this test accordingly
159         Ringtone badRingtone =
160             RingtoneManager.getRingtone(mContext, Uri.parse("content://fakeuri"));
161         boolean nullForBadRingtonesSupported = badRingtone == null;
162         if (!nullForBadRingtonesSupported) {
163             // test the "None" ringtone
164             RingtoneManager.setActualDefaultRingtoneUri(
165                 mContext, RingtoneManager.TYPE_RINGTONE, null);
166             mRingtone = RingtoneManager.getRingtone(mContext, Settings.System.DEFAULT_RINGTONE_URI);
167             assertTrue(mRingtone.getStreamType() == AudioManager.STREAM_RING);
168             mRingtone.play();
169             assertFalse(mRingtone.isPlaying());
170         }
171 
172         // Test an actual ringtone
173         Uri uri = RingtoneManager.getValidRingtoneUri(mContext);
174         assertNotNull("ringtone was unexpectedly null", uri);
175         Uri uriWithUser = ContentProvider.maybeAddUserId(uri, mContext.getUserId());
176         RingtoneManager.setActualDefaultRingtoneUri(mContext, RingtoneManager.TYPE_RINGTONE,
177                 uriWithUser);
178         mRingtone = RingtoneManager.getRingtone(mContext, Settings.System.DEFAULT_RINGTONE_URI);
179         assertTrue(mRingtone.getStreamType() == AudioManager.STREAM_RING);
180         mRingtone.play();
181         assertTrue("couldn't play ringtone " + uriWithUser, mRingtone.isPlaying());
182         mRingtone.stop();
183         assertFalse(mRingtone.isPlaying());
184     }
185 
testPlaybackProperties()186     public void testPlaybackProperties() {
187         if (isTV()) {
188             return;
189         }
190         if (!hasAudioOutput()) {
191             Log.i(TAG, "Skipping testRingtone(): device doesn't have audio output.");
192             return;
193         }
194 
195         Uri uri = RingtoneManager.getValidRingtoneUri(mContext);
196         assertNotNull("ringtone was unexpectedly null", uri);
197         RingtoneManager.setActualDefaultRingtoneUri(mContext, RingtoneManager.TYPE_RINGTONE, uri);
198         assertNotNull(mRingtone.getTitle(mContext));
199         final AudioAttributes ringtoneAa = new AudioAttributes.Builder()
200                 .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE).
201                 build();
202         mRingtone.setAudioAttributes(ringtoneAa);
203         assertEquals(ringtoneAa, mRingtone.getAudioAttributes());
204         mRingtone.setLooping(true);
205         mRingtone.setVolume(0.5f);
206         if (sIsAtLeastS) {
207             assertEquals(HapticGenerator.isAvailable(), mRingtone.setHapticGeneratorEnabled(true));
208         }
209         mRingtone.play();
210         assertTrue("couldn't play ringtone " + uri, mRingtone.isPlaying());
211         assertTrue(mRingtone.isLooping());
212         if (sIsAtLeastS) {
213             assertEquals(HapticGenerator.isAvailable(), mRingtone.isHapticGeneratorEnabled());
214         }
215         assertEquals("invalid ringtone player volume", 0.5f, mRingtone.getVolume());
216         mRingtone.stop();
217         assertFalse(mRingtone.isPlaying());
218     }
219 }
220