效果展示
主界面选择按钮
根据参数类型启动不同的fragment
package com.example.settingstest;
import android.content.Intent;
import android.media.RingtoneManager;
import android.os.Bundle;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.viewpager2.widget.ViewPager2;
import com.example.settingstest.soundpicker.SoundPickerActivity;
import com.example.settingstest.zenduration.ZenDurationPanelFragment;
import com.example.settingstest.zenduration.ZenModeEnablePanelFragment;
import com.google.android.material.tabs.TabLayout;
public class MainActivity extends AppCompatActivity implements ZenDurationPanelFragment.OnSettingsSelectedListener {
private final String TAG = "MainActivity";
private String mContent = null;
private TabLayout tabLayout;
private ViewPager2 viewPager;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.show_ringtone_fragment).setOnClickListener(v -> {
Intent intent = new Intent(MainActivity.this, SoundPickerActivity.class);
intent.putExtra("ringtone_type", RingtoneManager.TYPE_RINGTONE);
startActivity(intent);
});
findViewById(R.id.show_notification_fragment).setOnClickListener(v -> {
Intent intent = new Intent(MainActivity.this, SoundPickerActivity.class);
intent.putExtra("ringtone_type", RingtoneManager.TYPE_NOTIFICATION);
startActivity(intent);
});
findViewById(R.id.show_alarm_fragment).setOnClickListener(v -> {
Intent intent = new Intent(MainActivity.this, SoundPickerActivity.class);
intent.putExtra("ringtone_type", RingtoneManager.TYPE_ALARM);
startActivity(intent);
});
findViewById(R.id.show_bottom_sheet_dialog).setOnClickListener(view -> {
ZenDurationPanelFragment durationPanelFragment = new ZenDurationPanelFragment();
durationPanelFragment.show(getSupportFragmentManager(), "ZenDurationPanelFragment");
});
findViewById(R.id.show_bottom_sheet_dialog_enable).setOnClickListener(view -> {
ZenModeEnablePanelFragment enablePanelFragment = new ZenModeEnablePanelFragment();
enablePanelFragment.show(getSupportFragmentManager(), "ZenDurationPanelFragment");
});
}
@Override
public void onSettingsSelected(String selectedOption) {
mContent = selectedOption;
if (mContent != null)
((TextView) findViewById(R.id.show_bottom_sheet_dialog_title)).setText(mContent);
}
}
主界面对应的布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp">
<Button
android:id="@+id/show_ringtone_fragment"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="RINGTONE"
android:layout_centerInParent="true" />
<Button
android:id="@+id/show_notification_fragment"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="NOTIFICATION"
android:layout_centerInParent="true" />
<Button
android:id="@+id/show_alarm_fragment"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="ALARM"
android:layout_centerInParent="true" />
<Button
android:id="@+id/show_bottom_sheet_dialog"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="显示面板"
android:layout_centerInParent="true" />
<TextView
android:id="@+id/show_bottom_sheet_dialog_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="wu" />
<Button
android:id="@+id/show_bottom_sheet_dialog_enable"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="显示面板"
android:layout_centerInParent="true" />
<TextView
android:id="@+id/show_bottom_sheet_dialog_title_enable"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="wu" />
</LinearLayout>
SoundPickerFragment
不同的fragment
package com.example.settingstest.soundpicker;
import static android.app.Activity.RESULT_OK;
import android.content.Intent;
import android.content.res.Resources;
import android.content.res.Resources.NotFoundException;
import android.database.Cursor;
import android.database.CursorWrapper;
import android.media.AudioAttributes;
import android.media.Ringtone;
import android.media.RingtoneManager;
import android.os.Bundle;
import android.os.Handler;
import android.provider.MediaStore;
import android.util.Log;
import android.util.TypedValue;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceFragmentCompat;
import androidx.preference.PreferenceScreen;
import com.example.settingstest.R;
import com.example.settingstest.soundpicker.preference.CustomPreference;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;
public class SoundPickerFragment extends PreferenceFragmentCompat implements Runnable {
private static final String TAG = "RingtonePickerActivity";
private final String KEY_TEST_PREFERENCE_CATEGORY = "test_preference_category";
private static final String SOUND_NAME_RES_PREFIX = "sound_name_";
private static final int POS_UNKNOWN = -1;
private RingtoneManager mRingtoneManager;
private Cursor mCursor;
private Handler mHandler;
private static final String COLUMN_LABEL = MediaStore.Audio.Media.TITLE;
private int mSampleRingtonePos = POS_UNKNOWN;
private int mType;
public SoundPickerFragment(int type) {
mType = type;
}
Map<String,Integer> mRingToneMap = new HashMap<>();
@Override
public void onCreatePreferences(@Nullable Bundle savedInstanceState, @Nullable String rootKey) {
setPreferencesFromResource(R.xml.sound_picker, rootKey);
mHandler = new Handler();
initRingtoneManager();
PreferenceCategory preferenceCategory = findPreference(KEY_TEST_PREFERENCE_CATEGORY);
if (mCursor != null && mCursor.moveToFirst()) {
int i = 0;
do {
String title = mCursor.getString(RingtoneManager.TITLE_COLUMN_INDEX);
Log.d(TAG, "title = " + title);
CustomPreference customPreference = new CustomPreference(getContext());
customPreference.setTitle(title);
mRingToneMap.put("key_" + title,i);
customPreference.setKey("key_" + title);
customPreference.setSelectable(true);
customPreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(@NonNull Preference preference) {
updatePreferences(preference.getKey());
int pos = mRingToneMap.get(preference.getKey());
Bundle result = new Bundle();
result.putString("dataKey", "Hello from Fragment");
getParentFragmentManager().setFragmentResult("requestKey", result);
playRingtone(pos,0);
return true;
}
});
if (preferenceCategory != null) {
preferenceCategory.addPreference(customPreference);
}
i++;
} while (mCursor.moveToNext());
}
}
public void updatePreferences(String selectedKey) {
for (int i = 0; i < mCursor.getCount(); i++) {
String key = "key_" + i + 1;
int pos = mRingToneMap.get(selectedKey);
CustomPreference preference = findPreference(key);
if (preference != null) {
preference.setChecked(key.equals(selectedKey));
}
}
}
@Override
public PreferenceScreen getPreferenceScreen() {
return super.getPreferenceScreen();
}
private void playRingtone(int position, int delayMs) {
mHandler.removeCallbacks(this);
mSampleRingtonePos = position;
mHandler.postDelayed(this, delayMs);
}
private void initRingtoneManager() {
// Reinstantiate the RingtoneManager. Cursor.requery() was deprecated and calling it
// causes unexpected behavior.
mRingtoneManager = new RingtoneManager(getContext() /* includeParentRingtones */);
// if (mType != -1) {
// mRingtoneManager.setType(mType);
// }
mRingtoneManager.setType(mType);
mCursor = mRingtoneManager.getCursor();
mCursor = new LocalizedCursor(mRingtoneManager.getCursor(), getResources(), COLUMN_LABEL);
}
@Override
public void run() {
Ringtone ringtone;
ringtone = mRingtoneManager.getRingtone(mSampleRingtonePos);
if (ringtone != null) {
// if (mAttributesFlags != 0) {
ringtone.setAudioAttributes(
new AudioAttributes.Builder(ringtone.getAudioAttributes())
.setFlags(0x1 << 6)
.build());
// }
ringtone.play();
}
}
private static class LocalizedCursor extends CursorWrapper {
final int mTitleIndex;
final Resources mResources;
String mNamePrefix;
final Pattern mSanitizePattern;
private Cursor icursor;
LocalizedCursor(Cursor cursor, Resources resources, String columnLabel) {
super(cursor);
icursor = cursor;
mTitleIndex = cursor.getColumnIndex(columnLabel);
mResources = resources;
mSanitizePattern = Pattern.compile("[^a-zA-Z0-9]");
if (mTitleIndex == -1) {
Log.e(TAG, "No index for column " + columnLabel);
mNamePrefix = null;
} else {
try {
// Build the prefix for the name of the resource to look up
// format is: "ResourcePackageName::ResourceTypeName/"
// (the type name is expected to be "string" but let's not hardcode it).
// Here we use an existing resource "notification_sound_default" which is
// always expected to be found.
mNamePrefix = String.format("%s:%s/%s",
mResources.getResourcePackageName(R.string.notification_sound_default),
mResources.getResourceTypeName(R.string.notification_sound_default),
SOUND_NAME_RES_PREFIX);
} catch (NotFoundException e) {
mNamePrefix = null;
}
}
}
/**
* Process resource name to generate a valid resource name.
*
* @param input
* @return a non-null String
*/
private String sanitize(String input) {
if (input == null) {
return "";
}
return mSanitizePattern.matcher(input).replaceAll("_").toLowerCase();
}
@Override
public String getString(int columnIndex) {
final String defaultName = icursor.getString(columnIndex);
if ((columnIndex != mTitleIndex) || (mNamePrefix == null)) {
return defaultName;
}
TypedValue value = new TypedValue();
try {
// the name currently in the database is used to derive a name to match
// against resource names in this package
mResources.getValue(mNamePrefix + sanitize(defaultName), value, false);
} catch (NotFoundException e) {
// no localized string, use the default string
return defaultName;
}
if ((value != null) && (value.type == TypedValue.TYPE_STRING)) {
Log.d(TAG, String.format("Replacing name %s with %s",
defaultName, value.string.toString()));
return value.string.toString();
} else {
Log.e(TAG, "Invalid value when looking up localized name, using " + defaultName);
return defaultName;
}
}
}
}
fragment中preference
<?xml version="1.0" encoding="utf-8"?>
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory android:title="aaa">
<Preference android:title="@string/app_name" />
<Preference android:title="@string/app_name" />
</PreferenceCategory>
<PreferenceCategory
android:title="xxxx"
android:key="test_preference_category">
</PreferenceCategory>
</androidx.preference.PreferenceScreen>
自定义preference 布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:id="@+id/option_1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:gravity="center_vertical">
<TextView
android:id="@android:id/text1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<RadioButton
android:id="@+id/radio_group"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>
自定义preference
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:id="@+id/option_1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:gravity="center_vertical">
<TextView
android:id="@android:id/text1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<RadioButton
android:id="@+id/radio_group"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>