Ringtone.java revision 1d8e5c588035550293ecd2558a2e285ee2789d38
1/* 2 * Copyright (C) 2006 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 17package android.media; 18 19import android.content.ContentResolver; 20import android.content.Context; 21import android.database.Cursor; 22import android.net.Uri; 23import android.os.Binder; 24import android.os.RemoteException; 25import android.provider.DrmStore; 26import android.provider.MediaStore; 27import android.provider.Settings; 28import android.util.Log; 29 30import java.io.IOException; 31 32/** 33 * Ringtone provides a quick method for playing a ringtone, notification, or 34 * other similar types of sounds. 35 * <p> 36 * For ways of retrieving {@link Ringtone} objects or to show a ringtone 37 * picker, see {@link RingtoneManager}. 38 * 39 * @see RingtoneManager 40 */ 41public class Ringtone { 42 private static final String TAG = "Ringtone"; 43 private static final boolean LOGD = true; 44 45 private static final String[] MEDIA_COLUMNS = new String[] { 46 MediaStore.Audio.Media._ID, 47 MediaStore.Audio.Media.DATA, 48 MediaStore.Audio.Media.TITLE 49 }; 50 51 private static final String[] DRM_COLUMNS = new String[] { 52 DrmStore.Audio._ID, 53 DrmStore.Audio.DATA, 54 DrmStore.Audio.TITLE 55 }; 56 57 private final Context mContext; 58 private final AudioManager mAudioManager; 59 private final boolean mAllowRemote; 60 private final IRingtonePlayer mRemotePlayer; 61 private final Binder mRemoteToken; 62 63 private MediaPlayer mLocalPlayer; 64 65 private Uri mUri; 66 private String mTitle; 67 68 private int mStreamType = AudioManager.STREAM_RING; 69 70 /** {@hide} */ 71 public Ringtone(Context context, boolean allowRemote) { 72 mContext = context; 73 mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); 74 mAllowRemote = allowRemote; 75 mRemotePlayer = allowRemote ? mAudioManager.getRingtonePlayer() : null; 76 mRemoteToken = allowRemote ? new Binder() : null; 77 } 78 79 /** 80 * Sets the stream type where this ringtone will be played. 81 * 82 * @param streamType The stream, see {@link AudioManager}. 83 */ 84 public void setStreamType(int streamType) { 85 mStreamType = streamType; 86 87 // The stream type has to be set before the media player is prepared. 88 // Re-initialize it. 89 setUri(mUri); 90 } 91 92 /** 93 * Gets the stream type where this ringtone will be played. 94 * 95 * @return The stream type, see {@link AudioManager}. 96 */ 97 public int getStreamType() { 98 return mStreamType; 99 } 100 101 /** 102 * Returns a human-presentable title for ringtone. Looks in media and DRM 103 * content providers. If not in either, uses the filename 104 * 105 * @param context A context used for querying. 106 */ 107 public String getTitle(Context context) { 108 if (mTitle != null) return mTitle; 109 return mTitle = getTitle(context, mUri, true); 110 } 111 112 private static String getTitle(Context context, Uri uri, boolean followSettingsUri) { 113 Cursor cursor = null; 114 ContentResolver res = context.getContentResolver(); 115 116 String title = null; 117 118 if (uri != null) { 119 String authority = uri.getAuthority(); 120 121 if (Settings.AUTHORITY.equals(authority)) { 122 if (followSettingsUri) { 123 Uri actualUri = RingtoneManager.getActualDefaultRingtoneUri(context, 124 RingtoneManager.getDefaultType(uri)); 125 String actualTitle = getTitle(context, actualUri, false); 126 title = context 127 .getString(com.android.internal.R.string.ringtone_default_with_actual, 128 actualTitle); 129 } 130 } else { 131 try { 132 if (DrmStore.AUTHORITY.equals(authority)) { 133 cursor = res.query(uri, DRM_COLUMNS, null, null, null); 134 } else if (MediaStore.AUTHORITY.equals(authority)) { 135 cursor = res.query(uri, MEDIA_COLUMNS, null, null, null); 136 } 137 } catch (SecurityException e) { 138 // missing cursor is handled below 139 } 140 141 try { 142 if (cursor != null && cursor.getCount() == 1) { 143 cursor.moveToFirst(); 144 return cursor.getString(2); 145 } else { 146 title = uri.getLastPathSegment(); 147 } 148 } finally { 149 if (cursor != null) { 150 cursor.close(); 151 } 152 } 153 } 154 } 155 156 if (title == null) { 157 title = context.getString(com.android.internal.R.string.ringtone_unknown); 158 159 if (title == null) { 160 title = ""; 161 } 162 } 163 164 return title; 165 } 166 167 /** 168 * Set {@link Uri} to be used for ringtone playback. Attempts to open 169 * locally, otherwise will delegate playback to remote 170 * {@link IRingtonePlayer}. 171 * 172 * @hide 173 */ 174 public void setUri(Uri uri) { 175 destroyLocalPlayer(); 176 177 mUri = uri; 178 if (mUri == null) { 179 return; 180 } 181 182 // TODO: detect READ_EXTERNAL and specific content provider case, instead of relying on throwing 183 184 // try opening uri locally before delegating to remote player 185 mLocalPlayer = new MediaPlayer(); 186 try { 187 mLocalPlayer.setDataSource(mContext, mUri); 188 mLocalPlayer.setAudioStreamType(mStreamType); 189 mLocalPlayer.prepare(); 190 191 } catch (SecurityException e) { 192 destroyLocalPlayer(); 193 if (!mAllowRemote) { 194 Log.w(TAG, "Remote playback not allowed: " + e); 195 } 196 } catch (IOException e) { 197 destroyLocalPlayer(); 198 if (!mAllowRemote) { 199 Log.w(TAG, "Remote playback not allowed: " + e); 200 } 201 } 202 203 if (LOGD) { 204 if (mLocalPlayer != null) { 205 Log.d(TAG, "Successfully created local player"); 206 } else { 207 Log.d(TAG, "Problem opening; delegating to remote player"); 208 } 209 } 210 } 211 212 /** {@hide} */ 213 public Uri getUri() { 214 return mUri; 215 } 216 217 /** 218 * Plays the ringtone. 219 */ 220 public void play() { 221 if (mLocalPlayer != null) { 222 // do not play ringtones if stream volume is 0 223 // (typically because ringer mode is silent). 224 if (mAudioManager.getStreamVolume(mStreamType) != 0) { 225 mLocalPlayer.start(); 226 } 227 } else if (mAllowRemote) { 228 try { 229 mRemotePlayer.play(mRemoteToken, mUri, mStreamType); 230 } catch (RemoteException e) { 231 Log.w(TAG, "Problem playing ringtone: " + e); 232 } 233 } else { 234 Log.w(TAG, "Neither local nor remote playback available"); 235 } 236 } 237 238 /** 239 * Stops a playing ringtone. 240 */ 241 public void stop() { 242 if (mLocalPlayer != null) { 243 destroyLocalPlayer(); 244 } else if (mAllowRemote) { 245 try { 246 mRemotePlayer.stop(mRemoteToken); 247 } catch (RemoteException e) { 248 Log.w(TAG, "Problem stopping ringtone: " + e); 249 } 250 } 251 } 252 253 private void destroyLocalPlayer() { 254 if (mLocalPlayer != null) { 255 mLocalPlayer.reset(); 256 mLocalPlayer.release(); 257 mLocalPlayer = null; 258 } 259 } 260 261 /** 262 * Whether this ringtone is currently playing. 263 * 264 * @return True if playing, false otherwise. 265 */ 266 public boolean isPlaying() { 267 if (mLocalPlayer != null) { 268 return mLocalPlayer.isPlaying(); 269 } else if (mAllowRemote) { 270 try { 271 return mRemotePlayer.isPlaying(mRemoteToken); 272 } catch (RemoteException e) { 273 Log.w(TAG, "Problem checking ringtone: " + e); 274 return false; 275 } 276 } else { 277 Log.w(TAG, "Neither local nor remote playback available"); 278 return false; 279 } 280 } 281 282 void setTitle(String title) { 283 mTitle = title; 284 } 285} 286