Question

I'd really like to let a user pick out a vibration to use for my app, I'm already using RingtonePreference in my PreferenceScreen, is there anything similar for Vibrations, or a library that does it?

EDIT: Or, if there isn't a library or existing class that does it, is there some easy way to extend a class to do it? ListPreference looks like a good candidate but doesnt have an 'onclick' handler to play the vibration pattern chosen.

Was it helpful?

Solution

its pretty easy to set up your own, the source code for ListPreference is at http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/1.5_r4/android/preference/ListPreference.java

Here's what i eventually came up with that is working for me

VibrationPreference.java

package com.mypackagename;

import android.app.AlertDialog.Builder;
import android.content.Context;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.os.Vibrator;
import android.preference.ListPreference;
import android.util.AttributeSet;

public class VibrationPreference extends ListPreference {
    private int clickedIndex;


    // This example will cause the phone to vibrate "SOS" in Morse Code
    // In Morse Code, "s" = "dot-dot-dot", "o" = "dash-dash-dash"
    // There are pauses to separate dots/dashes, letters, and words
    // The following numbers represent millisecond lengths
    private static final int dot = 150;      // Length of a Morse Code "dot" in milliseconds
    private static final int dash = 375;     // Length of a Morse Code "dash" in milliseconds
    private static final int short_gap = 150;    // Length of Gap Between dots/dashes
    private static final int medium_gap = 375;   // Length of Gap Between Letters
    private static final int long_gap = 750;    // Length of Gap Between Words



    private static final long[] sos_pattern = {
        0,  // Start immediately
        dot, short_gap, dot, short_gap, dot,    // s
        medium_gap,
        dash, short_gap, dash, short_gap, dash, // o
        medium_gap,
        dot, short_gap, dot, short_gap, dot    // s
    };

    private static final int beat = 250;
    private static final int interbeat = 100;
    private static final int between_beat_pairs = 700;
    private static final long[] heartbeat_pattern = {
        0,  // Start immediately
        beat, interbeat, beat, // o
        between_beat_pairs,
        beat, interbeat, beat, // o
    };

    private static final long[] jackhammer_pattern = {
        0,  // Start immediately
        100, 100, 
        100, 100,
        100, 100,
        100, 100,
        100, 100,

        100, 100,
        100, 100,
        100, 100,
        100, 100,
        100, 100,

        100, 100,
        100, 100,
        100

    };


    public static final long[][] vibration_patterns = { null, sos_pattern, heartbeat_pattern, jackhammer_pattern};



    Vibrator vibrator;      

    public VibrationPreference(Context context, AttributeSet attrs) {
        super(context, attrs);
        vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
    }

    public VibrationPreference(Context context) {
        super(context);
        vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
    }

    @Override
    protected void onPrepareDialogBuilder(Builder builder) {
        super.onPrepareDialogBuilder(builder);

        if (getEntries() == null || getEntryValues() == null) {
            throw new IllegalStateException(
                    "ListPreference requires an entries array and an entryValues array.");
        }

        clickedIndex = findIndexOfValue(getValue());
        builder.setSingleChoiceItems(getEntries(), clickedIndex, 
                new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int which) {
                        clickedIndex = which;
                        vibrator.cancel();
                        if (clickedIndex > 0) vibrator.vibrate(vibration_patterns[clickedIndex], -1);
                    }
        });

        builder.setPositiveButton("OK", this).setNegativeButton("Cancel", this);
    }

    @Override
    protected void onDialogClosed(boolean positiveResult) {
        vibrator.cancel();
        super.onDialogClosed(positiveResult);

        if (positiveResult && clickedIndex >= 0 && getEntryValues() != null) {
            String value = getEntryValues()[clickedIndex].toString();
            if (callChangeListener(value)) {
                setValue(value);
            }
        }
    }
}

and then in my preference screen xml:

    <CheckBoxPreference android:title="Vibrate"
            android:key="do_vibrate" android:defaultValue="true"></CheckBoxPreference> 



    <com.mypackagename.VibrationPreference
        android:key="vibration_pattern_index"
        android:dependency="do_vibrate"
        android:title="Vibration Pattern"
        android:defaultValue="0"
        android:entries="@array/vibration_pattern_entries"
        android:entryValues="@array/vibration_pattern_values"
     />  

and don't forget to set in you manifest:

<uses-permission android:name="android.permission.VIBRATE"/>

and then just get your "vibration_pattern_index" from your prefs and use it to get the long[] out of VibrationPreference.vibration_patterns, and you'll have your user's chosen vibration! Lol i wonder if anyone will actually use or even read this:)

OTHER TIPS

If you want to use an android.support.v7.preference.ListPreference instead of an android.preference.ListPreference, you'll need to extend PreferenceDialogFragmentCompat.

VibrationPreferenceDialogFragmentCompat.java:

public class VibrationPreferenceDialogFragmentCompat extends   PreferenceDialogFragmentCompat
{

    // This example will cause the phone to vibrate "SOS" in Morse Code
    // In Morse Code, "s" = "dot-dot-dot", "o" = "dash-dash-dash"
    // There are pauses to separate dots/dashes, letters, and words
    // The following numbers represent millisecond lengths
    private static final int dot = 150;      // Length of a Morse Code "dot" in milliseconds
    private static final int dash = 375;     // Length of a Morse Code "dash" in milliseconds
    private static final int short_gap = 150;    // Length of Gap Between dots/dashes
    private static final int medium_gap = 375;   // Length of Gap Between Letters
    private static final int long_gap = 750;    // Length of Gap Between Words
    private static final long[] sos_pattern = {
        0,  // Start immediately
        dot, short_gap, dot, short_gap, dot,    // s
        medium_gap,
        dash, short_gap, dash, short_gap, dash, // o
        medium_gap,
        dot, short_gap, dot, short_gap, dot    // s
    };

    private static final int beat = 250;
    private static final int interbeat = 100;
    private static final int between_beat_pairs = 700;
    private static final long[] heartbeat_pattern = {
        0,  // Start immediately
        beat, interbeat, beat, // o
        between_beat_pairs,
        beat, interbeat, beat, // o
};

    private static final long[] jackhammer_pattern = {
        0,  // Start immediately
        100, 100,
        100, 100,
        100, 100,
        100, 100,
        100, 100,

        100, 100,
        100, 100,
        100, 100,
        100, 100,
        100, 100,

        100, 100,
        100, 100,
        100

};

    public static final long[][] VIBRATION_PATTERNS = {sos_pattern, heartbeat_pattern, jackhammer_pattern};

private int mClickedIndex;
private Vibrator mVibrator;
private ListPreference mPreference;

@Override
protected View onCreateDialogView(Context context) {
    mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
    return super.onCreateDialogView(context);
}


@Override
protected void onPrepareDialogBuilder(AlertDialog.Builder builder) {
    super.onPrepareDialogBuilder(builder);

    mPreference = (ListPreference) getPreference();

    if (mPreference.getEntries() == null || mPreference.getEntryValues() == null) {
        throw new IllegalStateException(
                "ListPreference requires an entries array and an entryValues array.");
    }

    mClickedIndex = mPreference.findIndexOfValue(mPreference.getValue());
    builder.setSingleChoiceItems(mPreference.getEntries(), mClickedIndex,
            new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int which) {
                    mClickedIndex = which;
                    mVibrator.cancel();
                    if (mClickedIndex >= 0) mVibrator.vibrate(VIBRATION_PATTERNS[mClickedIndex], -1);
                }
            });

    builder.setPositiveButton("OK", this).setNegativeButton("Cancel", this);
}

@Override
public void onDialogClosed(boolean positiveResult) {
    mVibrator.cancel();

    if (positiveResult && mClickedIndex >= 0 && mPreference.getEntryValues() != null) {
        String value = mPreference.getEntryValues()[mClickedIndex].toString();
        if (mPreference.callChangeListener(value)) {
            mPreference.setValue(value);
            mPreference.setSummary(getResources().getStringArray(R.array.vibration_pattern_entries)[mClickedIndex]);
        }
    }
}

}

SettingsFragment.java:

public class SettingsFragment extends PreferenceFragmentCompat {
...
    @Override
    public void onDisplayPreferenceDialog(Preference preference) {
        DialogFragment dialogFragment = null;
        if (preference.getKey().equals("pref_vibrate_pattern"))
        {
            dialogFragment = new VibrationPreferenceDialogFragmentCompat();
            Bundle bundle = new Bundle(1);
            bundle.putString("key", preference.getKey());
            dialogFragment.setArguments(bundle);
        }

        if (dialogFragment != null)
        {
            dialogFragment.setTargetFragment(this, 0);
            dialogFragment.show(this.getFragmentManager(), "android.support.v7.preference.PreferenceFragment.DIALOG");
        }
        else
        {
            super.onDisplayPreferenceDialog(preference);
        }
    }
...
}

settings.xml:

<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
...
        <ListPreference
            android:key="pref_vibrate_pattern"
            android:title="Vibration pattern"
            android:entries="@array/vibration_pattern_entries"
            android:entryValues="@array/vibration_pattern_values"
            android:summary="Select the vibration pattern"/>
...
</PreferenceScreen>

strings.xml:

<resources>
    <string-array name="vibration_pattern_entries">
        <item>SOS pattern</item>
        <item>Heartbeat</item>
        <item>JackHammer</item>
    </string-array>

    <string-array name="vibration_pattern_values">
        <item>0</item>
        <item>1</item>
        <item>2</item>
    </string-array>
</resources>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top