19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2006 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.media;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.ContentResolver;
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context;
211c25a21ffcfbc78a0edced4076d533f34902428aOscar Rydhéimport android.content.res.AssetFileDescriptor;
221c25a21ffcfbc78a0edced4076d533f34902428aOscar Rydhéimport android.content.res.Resources.NotFoundException;
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.database.Cursor;
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.net.Uri;
25098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkeyimport android.os.Binder;
26098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkeyimport android.os.RemoteException;
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.MediaStore;
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.Settings;
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log;
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.IOException;
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Ringtone provides a quick method for playing a ringtone, notification, or
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * other similar types of sounds.
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * For ways of retrieving {@link Ringtone} objects or to show a ringtone
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * picker, see {@link RingtoneManager}.
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see RingtoneManager
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class Ringtone {
43098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    private static final String TAG = "Ringtone";
44098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    private static final boolean LOGD = true;
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String[] MEDIA_COLUMNS = new String[] {
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        MediaStore.Audio.Media._ID,
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        MediaStore.Audio.Media.DATA,
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        MediaStore.Audio.Media.TITLE
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    };
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
52098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    private final Context mContext;
53098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    private final AudioManager mAudioManager;
54098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    private final boolean mAllowRemote;
55098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    private final IRingtonePlayer mRemotePlayer;
56098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    private final Binder mRemoteToken;
57098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey
58098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    private MediaPlayer mLocalPlayer;
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private Uri mUri;
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private String mTitle;
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mStreamType = AudioManager.STREAM_RING;
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
65098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    /** {@hide} */
66098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    public Ringtone(Context context, boolean allowRemote) {
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext = context;
68524dc046b1225087f481878a5c3ae7f733c9f0e2Eric Laurent        mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
69098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey        mAllowRemote = allowRemote;
70098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey        mRemotePlayer = allowRemote ? mAudioManager.getRingtonePlayer() : null;
71098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey        mRemoteToken = allowRemote ? new Binder() : null;
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Sets the stream type where this ringtone will be played.
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param streamType The stream, see {@link AudioManager}.
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setStreamType(int streamType) {
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mStreamType = streamType;
81098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey
82098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey        // The stream type has to be set before the media player is prepared.
83098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey        // Re-initialize it.
84098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey        setUri(mUri);
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Gets the stream type where this ringtone will be played.
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The stream type, see {@link AudioManager}.
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getStreamType() {
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mStreamType;
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
97853ad6fbe34fa26e81e4b7325309a034d7a1b038Mike Lockwood     * Returns a human-presentable title for ringtone. Looks in media
98853ad6fbe34fa26e81e4b7325309a034d7a1b038Mike Lockwood     * content provider. If not in either, uses the filename
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param context A context used for querying.
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public String getTitle(Context context) {
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mTitle != null) return mTitle;
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mTitle = getTitle(context, mUri, true);
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static String getTitle(Context context, Uri uri, boolean followSettingsUri) {
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Cursor cursor = null;
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ContentResolver res = context.getContentResolver();
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String title = null;
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (uri != null) {
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            String authority = uri.getAuthority();
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (Settings.AUTHORITY.equals(authority)) {
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (followSettingsUri) {
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    Uri actualUri = RingtoneManager.getActualDefaultRingtoneUri(context,
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            RingtoneManager.getDefaultType(uri));
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    String actualTitle = getTitle(context, actualUri, false);
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    title = context
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            .getString(com.android.internal.R.string.ringtone_default_with_actual,
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                    actualTitle);
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
1261d8e5c588035550293ecd2558a2e285ee2789d38Jeff Sharkey                try {
127853ad6fbe34fa26e81e4b7325309a034d7a1b038Mike Lockwood                    if (MediaStore.AUTHORITY.equals(authority)) {
1281d8e5c588035550293ecd2558a2e285ee2789d38Jeff Sharkey                        cursor = res.query(uri, MEDIA_COLUMNS, null, null, null);
1291d8e5c588035550293ecd2558a2e285ee2789d38Jeff Sharkey                    }
1301d8e5c588035550293ecd2558a2e285ee2789d38Jeff Sharkey                } catch (SecurityException e) {
1311d8e5c588035550293ecd2558a2e285ee2789d38Jeff Sharkey                    // missing cursor is handled below
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
1331d8e5c588035550293ecd2558a2e285ee2789d38Jeff Sharkey
1346b51a98acbc710a4e1a1656d85bb5d3c92f82fe9Josh Guilfoyle                try {
1356b51a98acbc710a4e1a1656d85bb5d3c92f82fe9Josh Guilfoyle                    if (cursor != null && cursor.getCount() == 1) {
1366b51a98acbc710a4e1a1656d85bb5d3c92f82fe9Josh Guilfoyle                        cursor.moveToFirst();
1376b51a98acbc710a4e1a1656d85bb5d3c92f82fe9Josh Guilfoyle                        return cursor.getString(2);
1386b51a98acbc710a4e1a1656d85bb5d3c92f82fe9Josh Guilfoyle                    } else {
1396b51a98acbc710a4e1a1656d85bb5d3c92f82fe9Josh Guilfoyle                        title = uri.getLastPathSegment();
1406b51a98acbc710a4e1a1656d85bb5d3c92f82fe9Josh Guilfoyle                    }
1416b51a98acbc710a4e1a1656d85bb5d3c92f82fe9Josh Guilfoyle                } finally {
1426b51a98acbc710a4e1a1656d85bb5d3c92f82fe9Josh Guilfoyle                    if (cursor != null) {
1436b51a98acbc710a4e1a1656d85bb5d3c92f82fe9Josh Guilfoyle                        cursor.close();
1446b51a98acbc710a4e1a1656d85bb5d3c92f82fe9Josh Guilfoyle                    }
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (title == null) {
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            title = context.getString(com.android.internal.R.string.ringtone_unknown);
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (title == null) {
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                title = "";
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return title;
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
159098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey
160098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    /**
161098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey     * Set {@link Uri} to be used for ringtone playback. Attempts to open
162098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey     * locally, otherwise will delegate playback to remote
163098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey     * {@link IRingtonePlayer}.
164098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey     *
165098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey     * @hide
166098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey     */
167098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    public void setUri(Uri uri) {
168098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey        destroyLocalPlayer();
169098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey
170098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey        mUri = uri;
171098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey        if (mUri == null) {
172098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey            return;
173e1bd048cf2af24cbd93e549875c875239e5f4829Marco Nelissen        }
174098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey
175098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey        // TODO: detect READ_EXTERNAL and specific content provider case, instead of relying on throwing
176098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey
177098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey        // try opening uri locally before delegating to remote player
178098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey        mLocalPlayer = new MediaPlayer();
179098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey        try {
180098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey            mLocalPlayer.setDataSource(mContext, mUri);
181098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey            mLocalPlayer.setAudioStreamType(mStreamType);
182098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey            mLocalPlayer.prepare();
183098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey
184098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey        } catch (SecurityException e) {
185098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey            destroyLocalPlayer();
186098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey            if (!mAllowRemote) {
1871d8e5c588035550293ecd2558a2e285ee2789d38Jeff Sharkey                Log.w(TAG, "Remote playback not allowed: " + e);
188098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey            }
189098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey        } catch (IOException e) {
190098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey            destroyLocalPlayer();
191098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey            if (!mAllowRemote) {
1921d8e5c588035550293ecd2558a2e285ee2789d38Jeff Sharkey                Log.w(TAG, "Remote playback not allowed: " + e);
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
196098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey        if (LOGD) {
197098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey            if (mLocalPlayer != null) {
198098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey                Log.d(TAG, "Successfully created local player");
199098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey            } else {
200098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey                Log.d(TAG, "Problem opening; delegating to remote player");
201098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey            }
202098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey        }
2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
205098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    /** {@hide} */
206098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    public Uri getUri() {
207098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey        return mUri;
2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
209e47e8520fa48bd014287eda94ea39927de73d6bcDianne Hackborn
2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Plays the ringtone.
2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void play() {
214098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey        if (mLocalPlayer != null) {
215098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey            // do not play ringtones if stream volume is 0
216524dc046b1225087f481878a5c3ae7f733c9f0e2Eric Laurent            // (typically because ringer mode is silent).
217524dc046b1225087f481878a5c3ae7f733c9f0e2Eric Laurent            if (mAudioManager.getStreamVolume(mStreamType) != 0) {
218098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey                mLocalPlayer.start();
219098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey            }
220098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey        } else if (mAllowRemote) {
22165c4a2b26cd8776b0927e9b0e07ecf53bd31b627Jeff Sharkey            final Uri canonicalUri = mUri.getCanonicalUri();
222098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey            try {
22365c4a2b26cd8776b0927e9b0e07ecf53bd31b627Jeff Sharkey                mRemotePlayer.play(mRemoteToken, canonicalUri, mStreamType);
224098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey            } catch (RemoteException e) {
2251c25a21ffcfbc78a0edced4076d533f34902428aOscar Rydhé                if (!playFallbackRingtone()) {
2261c25a21ffcfbc78a0edced4076d533f34902428aOscar Rydhé                    Log.w(TAG, "Problem playing ringtone: " + e);
2271c25a21ffcfbc78a0edced4076d533f34902428aOscar Rydhé                }
228524dc046b1225087f481878a5c3ae7f733c9f0e2Eric Laurent            }
229098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey        } else {
2301c25a21ffcfbc78a0edced4076d533f34902428aOscar Rydhé            if (!playFallbackRingtone()) {
2311c25a21ffcfbc78a0edced4076d533f34902428aOscar Rydhé                Log.w(TAG, "Neither local nor remote playback available");
2321c25a21ffcfbc78a0edced4076d533f34902428aOscar Rydhé            }
2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Stops a playing ringtone.
2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void stop() {
240098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey        if (mLocalPlayer != null) {
241098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey            destroyLocalPlayer();
242098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey        } else if (mAllowRemote) {
243098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey            try {
244098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey                mRemotePlayer.stop(mRemoteToken);
245098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey            } catch (RemoteException e) {
246098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey                Log.w(TAG, "Problem stopping ringtone: " + e);
247098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey            }
248098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey        }
249098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    }
250098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey
251098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    private void destroyLocalPlayer() {
252098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey        if (mLocalPlayer != null) {
253098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey            mLocalPlayer.reset();
254098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey            mLocalPlayer.release();
255098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey            mLocalPlayer = null;
2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Whether this ringtone is currently playing.
2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return True if playing, false otherwise.
2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean isPlaying() {
265098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey        if (mLocalPlayer != null) {
266098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey            return mLocalPlayer.isPlaying();
267098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey        } else if (mAllowRemote) {
268098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey            try {
269098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey                return mRemotePlayer.isPlaying(mRemoteToken);
270098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey            } catch (RemoteException e) {
271098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey                Log.w(TAG, "Problem checking ringtone: " + e);
272098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey                return false;
273098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey            }
274098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey        } else {
2751d8e5c588035550293ecd2558a2e285ee2789d38Jeff Sharkey            Log.w(TAG, "Neither local nor remote playback available");
2761d8e5c588035550293ecd2558a2e285ee2789d38Jeff Sharkey            return false;
277098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey        }
2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2801c25a21ffcfbc78a0edced4076d533f34902428aOscar Rydhé    private boolean playFallbackRingtone() {
2811c25a21ffcfbc78a0edced4076d533f34902428aOscar Rydhé        if (mAudioManager.getStreamVolume(mStreamType) != 0) {
2821c25a21ffcfbc78a0edced4076d533f34902428aOscar Rydhé            int ringtoneType = RingtoneManager.getDefaultType(mUri);
28319a4671b10e7d07309f1d427e1d81b87d5bbca18Marco Nelissen            if (ringtoneType == -1 ||
2841c25a21ffcfbc78a0edced4076d533f34902428aOscar Rydhé                    RingtoneManager.getActualDefaultRingtoneUri(mContext, ringtoneType) != null) {
2851c25a21ffcfbc78a0edced4076d533f34902428aOscar Rydhé                // Default ringtone, try fallback ringtone.
2861c25a21ffcfbc78a0edced4076d533f34902428aOscar Rydhé                try {
2871c25a21ffcfbc78a0edced4076d533f34902428aOscar Rydhé                    AssetFileDescriptor afd = mContext.getResources().openRawResourceFd(
2881c25a21ffcfbc78a0edced4076d533f34902428aOscar Rydhé                            com.android.internal.R.raw.fallbackring);
2891c25a21ffcfbc78a0edced4076d533f34902428aOscar Rydhé                    if (afd != null) {
2901c25a21ffcfbc78a0edced4076d533f34902428aOscar Rydhé                        mLocalPlayer = new MediaPlayer();
2911c25a21ffcfbc78a0edced4076d533f34902428aOscar Rydhé                        if (afd.getDeclaredLength() < 0) {
2921c25a21ffcfbc78a0edced4076d533f34902428aOscar Rydhé                            mLocalPlayer.setDataSource(afd.getFileDescriptor());
2931c25a21ffcfbc78a0edced4076d533f34902428aOscar Rydhé                        } else {
2941c25a21ffcfbc78a0edced4076d533f34902428aOscar Rydhé                            mLocalPlayer.setDataSource(afd.getFileDescriptor(),
2951c25a21ffcfbc78a0edced4076d533f34902428aOscar Rydhé                                    afd.getStartOffset(),
2961c25a21ffcfbc78a0edced4076d533f34902428aOscar Rydhé                                    afd.getDeclaredLength());
2971c25a21ffcfbc78a0edced4076d533f34902428aOscar Rydhé                        }
2981c25a21ffcfbc78a0edced4076d533f34902428aOscar Rydhé                        mLocalPlayer.setAudioStreamType(mStreamType);
2991c25a21ffcfbc78a0edced4076d533f34902428aOscar Rydhé                        mLocalPlayer.prepare();
3001c25a21ffcfbc78a0edced4076d533f34902428aOscar Rydhé                        mLocalPlayer.start();
3011c25a21ffcfbc78a0edced4076d533f34902428aOscar Rydhé                        afd.close();
3021c25a21ffcfbc78a0edced4076d533f34902428aOscar Rydhé                        return true;
3031c25a21ffcfbc78a0edced4076d533f34902428aOscar Rydhé                    } else {
3041c25a21ffcfbc78a0edced4076d533f34902428aOscar Rydhé                        Log.e(TAG, "Could not load fallback ringtone");
3051c25a21ffcfbc78a0edced4076d533f34902428aOscar Rydhé                    }
3061c25a21ffcfbc78a0edced4076d533f34902428aOscar Rydhé                } catch (IOException ioe) {
3071c25a21ffcfbc78a0edced4076d533f34902428aOscar Rydhé                    destroyLocalPlayer();
3081c25a21ffcfbc78a0edced4076d533f34902428aOscar Rydhé                    Log.e(TAG, "Failed to open fallback ringtone");
3091c25a21ffcfbc78a0edced4076d533f34902428aOscar Rydhé                } catch (NotFoundException nfe) {
3101c25a21ffcfbc78a0edced4076d533f34902428aOscar Rydhé                    Log.e(TAG, "Fallback ringtone does not exist");
3111c25a21ffcfbc78a0edced4076d533f34902428aOscar Rydhé                }
31219a4671b10e7d07309f1d427e1d81b87d5bbca18Marco Nelissen            } else {
31319a4671b10e7d07309f1d427e1d81b87d5bbca18Marco Nelissen                Log.w(TAG, "not playing fallback for " + mUri);
3141c25a21ffcfbc78a0edced4076d533f34902428aOscar Rydhé            }
3151c25a21ffcfbc78a0edced4076d533f34902428aOscar Rydhé        }
3161c25a21ffcfbc78a0edced4076d533f34902428aOscar Rydhé        return false;
3171c25a21ffcfbc78a0edced4076d533f34902428aOscar Rydhé    }
3181c25a21ffcfbc78a0edced4076d533f34902428aOscar Rydhé
3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    void setTitle(String title) {
3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mTitle = title;
3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
323