android 铃声设置流程
android 铃声设置流程讲解 一【最近更新】
总体思路为 :
1.截取铃声
2.保存入sd卡
3.获取铃声信息
4.将信息和文件路径写入数据库获得铃声Uri
5.将获得的Uri设置为铃声。
核心实现:在
对DefaultRingtonePreference的单机跳转到 RingtonePickerActivity.java 下篇
android 铃声设置流程讲解 二继续讲解
1.截取铃声
2.保存入sd卡
3.获取铃声信息
4.将信息和文件路径写入数据库获得铃声Uri
5.将获得的Uri设置为铃声。
核心实现:在
public class DefaultRingtonePreference extends RingtonePreference { private static final String TAG = "DefaultRingtonePreference"; public DefaultRingtonePreference(Context context, AttributeSet attrs) { super(context, attrs); } @Override protected void onPrepareRingtonePickerIntent(Intent ringtonePickerIntent) { super.onPrepareRingtonePickerIntent(ringtonePickerIntent); /* * Since this preference is for choosing the default ringtone, it * doesn't make sense to show a 'Default' item. */ ringtonePickerIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, false); } @Override protected void onSaveRingtone(Uri ringtoneUri) { //注意这个方法 他是实现铃声设置的核心方法 RingtoneManager.setActualDefaultRingtoneUri(getContext(), getRingtoneType(), ringtoneUri); } @Override protected Uri onRestoreRingtone() { return RingtoneManager.getActualDefaultRingtoneUri(getContext(), getRingtoneType()); } } DefaultRingtonePreference 单机后出现的是一个AlertDialog 但是在DefaultRingtonePreference没看见任何构造Dialog的信息 显然构建在父亲那的于是出现RingtonePreference的代码: public class RingtonePreference extends Preference implements PreferenceManager.OnActivityResultListener { private static final String TAG = "RingtonePreference"; private int mRingtoneType; private boolean mShowDefault; private boolean mShowSilent; private int mRequestCode; public RingtonePreference(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.RingtonePreference, defStyle, 0); mRingtoneType = a.getInt(com.android.internal.R.styleable.RingtonePreference_ringtoneType, RingtoneManager.TYPE_RINGTONE); mShowDefault = a.getBoolean(com.android.internal.R.styleable.RingtonePreference_showDefault, true); mShowSilent = a.getBoolean(com.android.internal.R.styleable.RingtonePreference_showSilent, true); a.recycle(); } public RingtonePreference(Context context, AttributeSet attrs) { this(context, attrs, com.android.internal.R.attr.ringtonePreferenceStyle); } public RingtonePreference(Context context) { this(context, null); } /** * Returns the sound type(s) that are shown in the picker. * * @return The sound type(s) that are shown in the picker. * @see #setRingtoneType(int) */ public int getRingtoneType() { return mRingtoneType; } /** * Sets the sound type(s) that are shown in the picker. * * @param type * The sound type(s) that are shown in the picker. * @see RingtoneManager#EXTRA_RINGTONE_TYPE */ public void setRingtoneType(int type) { mRingtoneType = type; } /** * Returns whether to a show an item for the default sound/ringtone. * * @return Whether to show an item for the default sound/ringtone. */ public boolean getShowDefault() { return mShowDefault; } /** * Sets whether to show an item for the default sound/ringtone. The default * to use will be deduced from the sound type(s) being shown. * * @param showDefault * Whether to show the default or not. * @see RingtoneManager#EXTRA_RINGTONE_SHOW_DEFAULT */ public void setShowDefault(boolean showDefault) { mShowDefault = showDefault; } /** * Returns whether to a show an item for 'Silent'. * * @return Whether to show an item for 'Silent'. */ public boolean getShowSilent() { return mShowSilent; } /** * Sets whether to show an item for 'Silent'. * * @param showSilent * Whether to show 'Silent'. * @see RingtoneManager#EXTRA_RINGTONE_SHOW_SILENT */ public void setShowSilent(boolean showSilent) { mShowSilent = showSilent; } @Override protected void onClick() { //注意这对DefaultRingtonePreference单机事件左的处理有跳转 // Launch the ringtone picker Intent intent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER); onPrepareRingtonePickerIntent(intent); getPreferenceManager().getActivity().startActivityForResult(intent, mRequestCode); } /** * Prepares the intent to launch the ringtone picker. This can be modified * to adjust the parameters of the ringtone picker. * * @param ringtonePickerIntent * The ringtone picker intent that can be modified by putting * extras. */ protected void onPrepareRingtonePickerIntent(Intent ringtonePickerIntent) { ringtonePickerIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, onRestoreRingtone()); ringtonePickerIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, mShowDefault); if (mShowDefault) { ringtonePickerIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_DEFAULT_URI, RingtoneManager.getDefaultUri(getRingtoneType())); } ringtonePickerIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT, mShowSilent); ringtonePickerIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, mRingtoneType); } /** * Called when a ringtone is chosen. * <p> * By default, this saves the ringtone URI to the persistent storage as a * string. * * @param ringtoneUri * The chosen ringtone's {@link Uri}. Can be null. */ protected void onSaveRingtone(Uri ringtoneUri) { persistString(ringtoneUri != null ? ringtoneUri.toString() : ""); } /** * Called when the chooser is about to be shown and the current ringtone * should be marked. Can return null to not mark any ringtone. * <p> * By default, this restores the previous ringtone URI from the persistent * storage. * * @return The ringtone to be marked as the current ringtone. */ protected Uri onRestoreRingtone() { final String uriString = getPersistedString(null); return !TextUtils.isEmpty(uriString) ? Uri.parse(uriString) : null; } @Override protected Object onGetDefaultValue(TypedArray a, int index) { return a.getString(index); } @Override protected void onSetInitialValue(boolean restorePersistedValue, Object defaultValueObj) { String defaultValue = (String) defaultValueObj; /* * This method is normally to make sure the internal state and UI * matches either the persisted value or the default value. Since we * don't show the current value in the UI (until the dialog is opened) * and we don't keep local state, if we are restoring the persisted * value we don't need to do anything. */ if (restorePersistedValue) { return; } // If we are setting to the default value, we should persist it. if (!TextUtils.isEmpty(defaultValue)) { onSaveRingtone(Uri.parse(defaultValue)); } } @Override protected void onAttachedToHierarchy(PreferenceManager preferenceManager) { super.onAttachedToHierarchy(preferenceManager); preferenceManager.registerOnActivityResultListener(this); mRequestCode = preferenceManager.getNextRequestCode(); } public boolean onActivityResult(int requestCode, int resultCode, Intent data) { //注意该方法回调了子类的onSaveRingtone方法 if (requestCode == mRequestCode) { if (data != null) { Uri uri = data.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI); if (callChangeListener(uri != null ? uri.toString() : "")) { onSaveRingtone(uri); } } return true; } return false; } }
android 铃声设置流程讲解 二继续讲解
android 铃声设置流程讲解 二【最近跟新】【完】
package com.android.internal.app; import com.android.internal.app.AlertActivity; import com.android.internal.app.AlertController; import android.content.DialogInterface; import android.content.Intent; import android.database.Cursor; import android.media.Ringtone; import android.media.RingtoneManager; import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.provider.MediaStore; import android.provider.Settings; import android.view.View; import android.widget.AdapterView; import android.widget.ListView; import android.widget.TextView; /** * The {@link RingtonePickerActivity} allows the user to choose one from all of * the available ringtones. The chosen ringtone's URI will be persisted as a * string. * * @see RingtoneManager#ACTION_RINGTONE_PICKER */ public final class RingtonePickerActivity extends AlertActivity implements AdapterView.OnItemSelectedListener, Runnable, DialogInterface.OnClickListener, AlertController.AlertParams.OnPrepareListViewListener { private static final String TAG = "RingtonePickerActivity"; private static final int DELAY_MS_SELECTION_PLAYED = 300; private RingtoneManager mRingtoneManager; private Cursor mCursor; private Handler mHandler; /** The position in the list of the 'Silent' item. */ private int mSilentPos = -1; /** The position in the list of the 'Default' item. */ private int mDefaultRingtonePos = -1; /** The position in the list of the last clicked item. */ private int mClickedPos = -1; /** The position in the list of the ringtone to sample. */ private int mSampleRingtonePos = -1; /** Whether this list has the 'Silent' item. */ private boolean mHasSilentItem; /** The Uri to place a checkmark next to. */ private Uri mExistingUri; /** The number of static items in the list. */ private int mStaticItemCount; /** Whether this list has the 'Default' item. */ private boolean mHasDefaultItem; /** The Uri to play when the 'Default' item is clicked. */ private Uri mUriForDefaultItem; /** * A Ringtone for the default ringtone. In most cases, the RingtoneManager * will stop the previous ringtone. However, the RingtoneManager doesn't * manage the default ringtone for us, so we should stop this one manually. */ private Ringtone mDefaultRingtone; private DialogInterface.OnClickListener mRingtoneClickListener = new DialogInterface.OnClickListener() { /* * On item clicked */ public void onClick(DialogInterface dialog, int which) { // Save the position of most recently clicked item mClickedPos = which; // Play clip playRingtone(which, 0); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mHandler = new Handler(); Intent intent = getIntent(); /* * Get whether to show the 'Default' item, and the URI to play when the * default is clicked */ mHasDefaultItem = intent.getBooleanExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, true); mUriForDefaultItem = intent.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_DEFAULT_URI); if (mUriForDefaultItem == null) { mUriForDefaultItem = Settings.System.DEFAULT_RINGTONE_URI; } // Get whether to show the 'Silent' item mHasSilentItem = intent.getBooleanExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT, true); // Give the Activity so it can do managed queries mRingtoneManager = new RingtoneManager(this); // Get whether to include DRM ringtones boolean includeDrm = intent.getBooleanExtra(RingtoneManager.EXTRA_RINGTONE_INCLUDE_DRM, true); mRingtoneManager.setIncludeDrm(includeDrm); // Get the types of ringtones to show int types = intent.getIntExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, -1); if (types != -1) { mRingtoneManager.setType(types); } mCursor = mRingtoneManager.getCursor(); // The volume keys will control the stream that we are choosing a // ringtone for setVolumeControlStream(mRingtoneManager.inferStreamType()); // Get the URI whose list item should have a checkmark mExistingUri = intent.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI); //mAlertParams 是父亲的属性 final AlertController.AlertParams p = mAlertParams; //开始构造Dailog了哦 p.mCursor = mCursor; p.mOnClickListener = mRingtoneClickListener;//这个事件是对列表选择的时候播放该歌曲 p.mLabelColumn = MediaStore.Audio.Media.TITLE; p.mIsSingleChoice = true; p.mOnItemSelectedListener = this; p.mPositiveButtonText = getString(com.android.internal.R.string.ok); p.mPositiveButtonListener = this; //选择确定后的事件 在该类onClick中实现 p.mNegativeButtonText = getString(com.android.internal.R.string.cancel); p.mPositiveButtonListener = this; //取消事件 在该类onClick中实现 p.mOnPrepareListViewListener = this; p.mTitle = intent.getCharSequenceExtra(RingtoneManager.EXTRA_RINGTONE_TITLE); if (p.mTitle == null) { p.mTitle = getString(com.android.internal.R.string.ringtone_picker_title); } setupAlert(); } public void onPrepareListView(ListView listView) { if (mHasDefaultItem) { mDefaultRingtonePos = addDefaultRingtoneItem(listView); if (RingtoneManager.isDefault(mExistingUri)) { mClickedPos = mDefaultRingtonePos; } } if (mHasSilentItem) { mSilentPos = addSilentItem(listView); // The 'Silent' item should use a null Uri if (mExistingUri == null) { mClickedPos = mSilentPos; } } if (mClickedPos == -1) { mClickedPos = getListPosition(mRingtoneManager.getRingtonePosition(mExistingUri)); } // Put a checkmark next to an item. mAlertParams.mCheckedItem = mClickedPos; } /** * Adds a static item to the top of the list. A static item is one that is * not from the RingtoneManager. * * @param listView * The ListView to add to. * @param textResId * The resource ID of the text for the item. * @return The position of the inserted item. */ private int addStaticItem(ListView listView, int textResId) { TextView textView = (TextView) getLayoutInflater().inflate(com.android.internal.R.layout.select_dialog_singlechoice, listView, false); textView.setText(textResId); listView.addHeaderView(textView); mStaticItemCount++; return listView.getHeaderViewsCount() - 1; } private int addDefaultRingtoneItem(ListView listView) { return addStaticItem(listView, com.android.internal.R.string.ringtone_default); } private int addSilentItem(ListView listView) { return addStaticItem(listView, com.android.internal.R.string.ringtone_silent); } /* * On click of Ok/Cancel buttons */ public void onClick(DialogInterface dialog, int which) { //该方法实现保存选择的音乐并放回给调用者 boolean positiveResult = which == BUTTON1; //如果悬着的int which是BUTTON1那么返回真 //意思是单机的未知==1那么就是单机了确定按钮 // Stop playing the previous ringtone mRingtoneManager.stopPreviousRingtone(); if (positiveResult) { Intent resultIntent = new Intent(); Uri uri = null; if (mClickedPos == mDefaultRingtonePos) { // Set it to the default Uri that they originally gave us uri = mUriForDefaultItem; } else if (mClickedPos == mSilentPos) { // A null Uri is for the 'Silent' item uri = null; } else { uri = mRingtoneManager.getRingtoneUri(getRingtoneManagerPosition(mClickedPos)); } resultIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI, uri); setResult(RESULT_OK, resultIntent); } else { setResult(RESULT_CANCELED); //放回该调用者的信息 } getWindow().getDecorView().post(new Runnable() { public void run() { mCursor.deactivate(); } }); finish(); } /* * On item selected via keys */ public void onItemSelected(AdapterView parent, View view, int position, long id) { playRingtone(position, DELAY_MS_SELECTION_PLAYED); } public void onNothingSelected(AdapterView parent) { } private void playRingtone(int position, int delayMs) { //播放歌曲注意mHandler会调用自己应为本类实现了 Runnable mHandler.removeCallbacks(this); mSampleRingtonePos = position; mHandler.postDelayed(this, delayMs); } public void run() { if (mSampleRingtonePos == mSilentPos) { return; } /* * Stop the default ringtone, if it's playing (other ringtones will be * stopped by the RingtoneManager when we get another Ringtone from it. */ if (mDefaultRingtone != null && mDefaultRingtone.isPlaying()) { mDefaultRingtone.stop(); mDefaultRingtone = null; } Ringtone ringtone; if (mSampleRingtonePos == mDefaultRingtonePos) { if (mDefaultRingtone == null) { mDefaultRingtone = RingtoneManager.getRingtone(this, mUriForDefaultItem); } ringtone = mDefaultRingtone; /* * Normally the non-static RingtoneManager.getRingtone stops the * previous ringtone, but we're getting the default ringtone outside * of the RingtoneManager instance, so let's stop the previous * ringtone manually. */ mRingtoneManager.stopPreviousRingtone(); } else { ringtone = mRingtoneManager.getRingtone(getRingtoneManagerPosition(mSampleRingtonePos)); } if (ringtone != null) { ringtone.play(); } } @Override protected void onStop() { super.onStop(); stopAnyPlayingRingtone(); } @Override protected void onPause() { super.onPause(); stopAnyPlayingRingtone(); } private void stopAnyPlayingRingtone() { if (mDefaultRingtone != null && mDefaultRingtone.isPlaying()) { mDefaultRingtone.stop(); } if (mRingtoneManager != null) { mRingtoneManager.stopPreviousRingtone(); } } private int getRingtoneManagerPosition(int listPos) { return listPos - mStaticItemCount; } private int getListPosition(int ringtoneManagerPos) { // If the manager position is -1 (for not found), return that if (ringtoneManagerPos < 0) return ringtoneManagerPos; return ringtoneManagerPos + mStaticItemCount; } }