• 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 == DialogInterface.BUTTON_POSITIVE;
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             mRingtoneManager.stopPreviousRingtone();
280             return;
281         }
282 
283         /*
284          * Stop the default ringtone, if it's playing (other ringtones will be
285          * stopped by the RingtoneManager when we get another Ringtone from it.
286          */
287         if (mDefaultRingtone != null && mDefaultRingtone.isPlaying()) {
288             mDefaultRingtone.stop();
289             mDefaultRingtone = null;
290         }
291 
292         Ringtone ringtone;
293         if (mSampleRingtonePos == mDefaultRingtonePos) {
294             if (mDefaultRingtone == null) {
295                 mDefaultRingtone = RingtoneManager.getRingtone(this, mUriForDefaultItem);
296             }
297             ringtone = mDefaultRingtone;
298 
299             /*
300              * Normally the non-static RingtoneManager.getRingtone stops the
301              * previous ringtone, but we're getting the default ringtone outside
302              * of the RingtoneManager instance, so let's stop the previous
303              * ringtone manually.
304              */
305             mRingtoneManager.stopPreviousRingtone();
306 
307         } else {
308             ringtone = mRingtoneManager.getRingtone(getRingtoneManagerPosition(mSampleRingtonePos));
309         }
310 
311         if (ringtone != null) {
312             ringtone.play();
313         }
314     }
315 
316     @Override
onStop()317     protected void onStop() {
318         super.onStop();
319         stopAnyPlayingRingtone();
320     }
321 
322     @Override
onPause()323     protected void onPause() {
324         super.onPause();
325         stopAnyPlayingRingtone();
326     }
327 
stopAnyPlayingRingtone()328     private void stopAnyPlayingRingtone() {
329 
330         if (mDefaultRingtone != null && mDefaultRingtone.isPlaying()) {
331             mDefaultRingtone.stop();
332         }
333 
334         if (mRingtoneManager != null) {
335             mRingtoneManager.stopPreviousRingtone();
336         }
337     }
338 
getRingtoneManagerPosition(int listPos)339     private int getRingtoneManagerPosition(int listPos) {
340         return listPos - mStaticItemCount;
341     }
342 
getListPosition(int ringtoneManagerPos)343     private int getListPosition(int ringtoneManagerPos) {
344 
345         // If the manager position is -1 (for not found), return that
346         if (ringtoneManagerPos < 0) return ringtoneManagerPos;
347 
348         return ringtoneManagerPos + mStaticItemCount;
349     }
350 
351 }
352