• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 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 com.android.internal.app;
18 
19 import com.android.internal.app.AlertActivity;
20 import com.android.internal.app.AlertController;
21 
22 import android.content.DialogInterface;
23 import android.content.Intent;
24 import android.database.Cursor;
25 import android.media.Ringtone;
26 import android.media.RingtoneManager;
27 import android.net.Uri;
28 import android.os.Bundle;
29 import android.os.Handler;
30 import android.provider.MediaStore;
31 import android.provider.Settings;
32 import android.view.View;
33 import android.widget.AdapterView;
34 import android.widget.ListView;
35 import android.widget.TextView;
36 
37 /**
38  * The {@link RingtonePickerActivity} allows the user to choose one from all of the
39  * available ringtones. The chosen ringtone's URI will be persisted as a string.
40  *
41  * @see RingtoneManager#ACTION_RINGTONE_PICKER
42  */
43 public final class RingtonePickerActivity extends AlertActivity implements
44         AdapterView.OnItemSelectedListener, Runnable, DialogInterface.OnClickListener,
45         AlertController.AlertParams.OnPrepareListViewListener {
46 
47     private static final String TAG = "RingtonePickerActivity";
48 
49     private static final int DELAY_MS_SELECTION_PLAYED = 300;
50 
51     private RingtoneManager mRingtoneManager;
52 
53     private Cursor mCursor;
54     private Handler mHandler;
55 
56     /** The position in the list of the 'Silent' item. */
57     private int mSilentPos = -1;
58 
59     /** The position in the list of the 'Default' item. */
60     private int mDefaultRingtonePos = -1;
61 
62     /** The position in the list of the last clicked item. */
63     private int mClickedPos = -1;
64 
65     /** The position in the list of the ringtone to sample. */
66     private int mSampleRingtonePos = -1;
67 
68     /** Whether this list has the 'Silent' item. */
69     private boolean mHasSilentItem;
70 
71     /** The Uri to place a checkmark next to. */
72     private Uri mExistingUri;
73 
74     /** The number of static items in the list. */
75     private int mStaticItemCount;
76 
77     /** Whether this list has the 'Default' item. */
78     private boolean mHasDefaultItem;
79 
80     /** The Uri to play when the 'Default' item is clicked. */
81     private Uri mUriForDefaultItem;
82 
83     /**
84      * A Ringtone for the default ringtone. In most cases, the RingtoneManager
85      * will stop the previous ringtone. However, the RingtoneManager doesn't
86      * manage the default ringtone for us, so we should stop this one manually.
87      */
88     private Ringtone mDefaultRingtone;
89 
90     private DialogInterface.OnClickListener mRingtoneClickListener =
91             new DialogInterface.OnClickListener() {
92 
93         /*
94          * On item clicked
95          */
96         public void onClick(DialogInterface dialog, int which) {
97             // Save the position of most recently clicked item
98             mClickedPos = which;
99 
100             // Play clip
101             playRingtone(which, 0);
102         }
103 
104     };
105 
106     @Override
onCreate(Bundle savedInstanceState)107     protected void onCreate(Bundle savedInstanceState) {
108         super.onCreate(savedInstanceState);
109 
110         mHandler = new Handler();
111 
112         Intent intent = getIntent();
113 
114         /*
115          * Get whether to show the 'Default' item, and the URI to play when the
116          * default is clicked
117          */
118         mHasDefaultItem = intent.getBooleanExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, true);
119         mUriForDefaultItem = intent.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_DEFAULT_URI);
120         if (mUriForDefaultItem == null) {
121             mUriForDefaultItem = Settings.System.DEFAULT_RINGTONE_URI;
122         }
123 
124         // Get whether to show the 'Silent' item
125         mHasSilentItem = intent.getBooleanExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT, true);
126 
127         // Give the Activity so it can do managed queries
128         mRingtoneManager = new RingtoneManager(this);
129 
130         // Get whether to include DRM ringtones
131         boolean includeDrm = intent.getBooleanExtra(RingtoneManager.EXTRA_RINGTONE_INCLUDE_DRM,
132                 true);
133         mRingtoneManager.setIncludeDrm(includeDrm);
134 
135         // Get the types of ringtones to show
136         int types = intent.getIntExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, -1);
137         if (types != -1) {
138             mRingtoneManager.setType(types);
139         }
140 
141         mCursor = mRingtoneManager.getCursor();
142 
143         // The volume keys will control the stream that we are choosing a ringtone for
144         setVolumeControlStream(mRingtoneManager.inferStreamType());
145 
146         // Get the URI whose list item should have a checkmark
147         mExistingUri = intent
148                 .getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI);
149 
150         final AlertController.AlertParams p = mAlertParams;
151         p.mCursor = mCursor;
152         p.mOnClickListener = mRingtoneClickListener;
153         p.mLabelColumn = MediaStore.Audio.Media.TITLE;
154         p.mIsSingleChoice = true;
155         p.mOnItemSelectedListener = this;
156         p.mPositiveButtonText = getString(com.android.internal.R.string.ok);
157         p.mPositiveButtonListener = this;
158         p.mNegativeButtonText = getString(com.android.internal.R.string.cancel);
159         p.mPositiveButtonListener = this;
160         p.mOnPrepareListViewListener = this;
161 
162         p.mTitle = intent.getCharSequenceExtra(RingtoneManager.EXTRA_RINGTONE_TITLE);
163         if (p.mTitle == null) {
164             p.mTitle = getString(com.android.internal.R.string.ringtone_picker_title);
165         }
166 
167         setupAlert();
168     }
169 
onPrepareListView(ListView listView)170     public void onPrepareListView(ListView listView) {
171 
172         if (mHasDefaultItem) {
173             mDefaultRingtonePos = addDefaultRingtoneItem(listView);
174 
175             if (RingtoneManager.isDefault(mExistingUri)) {
176                 mClickedPos = mDefaultRingtonePos;
177             }
178         }
179 
180         if (mHasSilentItem) {
181             mSilentPos = addSilentItem(listView);
182 
183             // The 'Silent' item should use a null Uri
184             if (mExistingUri == null) {
185                 mClickedPos = mSilentPos;
186             }
187         }
188 
189         if (mClickedPos == -1) {
190             mClickedPos = getListPosition(mRingtoneManager.getRingtonePosition(mExistingUri));
191         }
192 
193         // Put a checkmark next to an item.
194         mAlertParams.mCheckedItem = mClickedPos;
195     }
196 
197     /**
198      * Adds a static item to the top of the list. A static item is one that is not from the
199      * RingtoneManager.
200      *
201      * @param listView The ListView to add to.
202      * @param textResId The resource ID of the text for the item.
203      * @return The position of the inserted item.
204      */
addStaticItem(ListView listView, int textResId)205     private int addStaticItem(ListView listView, int textResId) {
206         TextView textView = (TextView) getLayoutInflater().inflate(
207                 com.android.internal.R.layout.select_dialog_singlechoice, listView, false);
208         textView.setText(textResId);
209         listView.addHeaderView(textView);
210         mStaticItemCount++;
211         return listView.getHeaderViewsCount() - 1;
212     }
213 
addDefaultRingtoneItem(ListView listView)214     private int addDefaultRingtoneItem(ListView listView) {
215         return addStaticItem(listView, com.android.internal.R.string.ringtone_default);
216     }
217 
addSilentItem(ListView listView)218     private int addSilentItem(ListView listView) {
219         return addStaticItem(listView, com.android.internal.R.string.ringtone_silent);
220     }
221 
222     /*
223      * On click of Ok/Cancel buttons
224      */
onClick(DialogInterface dialog, int which)225     public void onClick(DialogInterface dialog, int which) {
226         boolean positiveResult = which == BUTTON1;
227 
228         // Stop playing the previous ringtone
229         mRingtoneManager.stopPreviousRingtone();
230 
231         if (positiveResult) {
232             Intent resultIntent = new Intent();
233             Uri uri = null;
234 
235             if (mClickedPos == mDefaultRingtonePos) {
236                 // Set it to the default Uri that they originally gave us
237                 uri = mUriForDefaultItem;
238             } else if (mClickedPos == mSilentPos) {
239                 // A null Uri is for the 'Silent' item
240                 uri = null;
241             } else {
242                 uri = mRingtoneManager.getRingtoneUri(getRingtoneManagerPosition(mClickedPos));
243             }
244 
245             resultIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI, uri);
246             setResult(RESULT_OK, resultIntent);
247         } else {
248             setResult(RESULT_CANCELED);
249         }
250 
251         getWindow().getDecorView().post(new Runnable() {
252             public void run() {
253                 mCursor.deactivate();
254             }
255         });
256 
257         finish();
258     }
259 
260     /*
261      * On item selected via keys
262      */
onItemSelected(AdapterView parent, View view, int position, long id)263     public void onItemSelected(AdapterView parent, View view, int position, long id) {
264         playRingtone(position, DELAY_MS_SELECTION_PLAYED);
265     }
266 
onNothingSelected(AdapterView parent)267     public void onNothingSelected(AdapterView parent) {
268     }
269 
playRingtone(int position, int delayMs)270     private void playRingtone(int position, int delayMs) {
271         mHandler.removeCallbacks(this);
272         mSampleRingtonePos = position;
273         mHandler.postDelayed(this, delayMs);
274     }
275 
run()276     public void run() {
277 
278         if (mSampleRingtonePos == mSilentPos) {
279             return;
280         }
281 
282         /*
283          * Stop the default ringtone, if it's playing (other ringtones will be
284          * stopped by the RingtoneManager when we get another Ringtone from it.
285          */
286         if (mDefaultRingtone != null && mDefaultRingtone.isPlaying()) {
287             mDefaultRingtone.stop();
288             mDefaultRingtone = null;
289         }
290 
291         Ringtone ringtone;
292         if (mSampleRingtonePos == mDefaultRingtonePos) {
293             if (mDefaultRingtone == null) {
294                 mDefaultRingtone = RingtoneManager.getRingtone(this, mUriForDefaultItem);
295             }
296             ringtone = mDefaultRingtone;
297 
298             /*
299              * Normally the non-static RingtoneManager.getRingtone stops the
300              * previous ringtone, but we're getting the default ringtone outside
301              * of the RingtoneManager instance, so let's stop the previous
302              * ringtone manually.
303              */
304             mRingtoneManager.stopPreviousRingtone();
305 
306         } else {
307             ringtone = mRingtoneManager.getRingtone(getRingtoneManagerPosition(mSampleRingtonePos));
308         }
309 
310         if (ringtone != null) {
311             ringtone.play();
312         }
313     }
314 
315     @Override
onStop()316     protected void onStop() {
317         super.onStop();
318         stopAnyPlayingRingtone();
319     }
320 
321     @Override
onPause()322     protected void onPause() {
323         super.onPause();
324         stopAnyPlayingRingtone();
325     }
326 
stopAnyPlayingRingtone()327     private void stopAnyPlayingRingtone() {
328 
329         if (mDefaultRingtone != null && mDefaultRingtone.isPlaying()) {
330             mDefaultRingtone.stop();
331         }
332 
333         if (mRingtoneManager != null) {
334             mRingtoneManager.stopPreviousRingtone();
335         }
336     }
337 
getRingtoneManagerPosition(int listPos)338     private int getRingtoneManagerPosition(int listPos) {
339         return listPos - mStaticItemCount;
340     }
341 
getListPosition(int ringtoneManagerPos)342     private int getListPosition(int ringtoneManagerPos) {
343 
344         // If the manager position is -1 (for not found), return that
345         if (ringtoneManagerPos < 0) return ringtoneManagerPos;
346 
347         return ringtoneManagerPos + mStaticItemCount;
348     }
349 
350 }
351