SoundPicker 铃声选择定制化

效果展示
在这里插入图片描述

主界面选择按钮

根据参数类型启动不同的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>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值