Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Custom Vibrations (1/6)

Frameworks part.

- added new VibrationPattern class for storing & handling vibration patterns
- added contact related provider columns
- added custom vibrations to the CallerInfo class
- necessary layouts & changes

PS6: rebase

Change-Id: I314abc4fec70e85f2b1b93bacb6ddf43301d42ec
Signed-off-by: sethyx <sethyx@gmail.com>
  • Loading branch information...
commit 747980a4b17fb47aa7b1418ede0ac69795195a46 1 parent c31d0c7
@sethyx sethyx authored
View
190 core/java/android/app/VibrationPickerDialog.java
@@ -0,0 +1,190 @@
+
+package android.app;
+
+import android.app.Activity;
+import android.app.DialogFragment;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.database.Cursor;
+import android.media.VibrationPattern;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.os.Vibrator;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.ListView;
+import android.widget.SimpleCursorAdapter;
+import android.widget.TextView;
+
+import java.io.Serializable;
+
+import com.android.internal.R;
+
+public class VibrationPickerDialog extends DialogFragment {
+
+ private static final String TAG = "VibrationPickerDialog";
+
+ private final int VIB_OK = 10;
+ private final int VIB_CANCEL = 11;
+ private final int VIB_DEL = 12;
+
+ private boolean mIsDel;
+ private Context mContext;
+ private Handler mHandler;
+ private Vibrator mVibrator;
+ private AlertDialog.Builder mBuilder;
+ private VibrationPattern mPattern;
+
+ public static VibrationPickerDialog newInstance(Handler handler, boolean isDel,
+ String selectedUri) {
+ VibrationPickerDialog vpd = new VibrationPickerDialog();
+
+ Bundle args = new Bundle();
+ args.putBoolean("isdel", isDel);
+ if (selectedUri == null) {
+ args.putString("uri", "");
+ } else {
+ args.putString("uri", selectedUri);
+ }
+ args.putSerializable("handler", new HandlerHolder(handler));
+ vpd.setArguments(args);
+ return vpd;
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ mIsDel = getArguments().getBoolean("isdel");
+ String mUriString = getArguments().getString("uri");
+ mHandler = ((HandlerHolder) getArguments().getSerializable("handler")).getHandler();
+ mContext = getActivity();
+ mVibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
+
+ final Uri allVibrations = Uri.parse(VibrationPattern.URI);
+ final Cursor vibrations = mContext.getContentResolver().
+ query(allVibrations, null, null, null, null);
+
+ vibrations.moveToFirst();
+ int ID = -1;
+ if (!mUriString.isEmpty()) {
+ Uri mUri = Uri.parse(mUriString);
+ do {
+ try {
+ if (Integer.parseInt(mUri.getLastPathSegment()) == vibrations.getInt(0)) {
+ ID = vibrations.getPosition();
+ }
+ } catch (Exception ex) {
+ // nothing to do here
+ }
+ } while (vibrations.moveToNext());
+ }
+ final int selectedID = ID;
+ final SimpleCursorAdapter adapter = new SimpleCursorAdapter(mContext,
+ android.R.layout.simple_list_item_single_choice,
+ vibrations,
+ new String[] {
+ "name"
+ },
+ new int[] {
+ android.R.id.text1
+ }, 0) {
+
+ @Override
+ public Object getItem(int pos) {
+ vibrations.moveToPosition(pos);
+ int id = vibrations.getInt(0);
+ setSelectedVibration(new VibrationPattern(
+ Uri.parse(VibrationPattern.URI + "/" + id), mContext));
+ return getSelectedVibration();
+ }
+ };
+
+ LayoutInflater factory = LayoutInflater.from(mContext);
+ final View vibListView = factory.inflate(R.layout.vibration_picker_dialog, null);
+
+ return new AlertDialog.Builder(mContext)
+ .setTitle(
+ mIsDel ? R.string.vibration_picker_del_title
+ : R.string.vibration_picker_title)
+ .setIcon(
+ mIsDel ? R.drawable.ic_dialog_alert
+ : 0)
+ .setView(vibListView)
+ .setSingleChoiceItems(adapter, selectedID,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ ((VibrationPattern) adapter.getItem(which)).play();
+ }
+ })
+ .setPositiveButton(mIsDel ? R.string.delete : R.string.ok,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int whichButton) {
+ if (mIsDel) {
+ delVib(getSelectedVibration());
+ adapter.notifyDataSetChanged();
+ } else {
+ selectVib(getSelectedVibration());
+ }
+ stopAllVibrations();
+ }
+ })
+ .setNegativeButton(R.string.cancel,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int whichButton) {
+ stopAllVibrations();
+ sendCancel();
+ }
+ })
+ .create();
+ }
+
+ private void selectVib(VibrationPattern vib) {
+ final Message m = new Message();
+ m.obj = vib;
+ m.what = VIB_OK;
+ mHandler.sendMessage(m);
+ }
+
+ private void sendCancel() {
+ final Message m = new Message();
+ m.what = VIB_CANCEL;
+ mHandler.sendMessage(m);
+ }
+
+ private void delVib(VibrationPattern vib) {
+ final Message m = new Message();
+ m.obj = vib;
+ m.what = VIB_DEL;
+ mHandler.sendMessage(m);
+ }
+
+ public void stopAllVibrations() {
+ if (mVibrator != null) {
+ mVibrator.cancel();
+ }
+ }
+
+ private void setSelectedVibration(VibrationPattern pattern) {
+ mPattern = pattern;
+ }
+
+ private VibrationPattern getSelectedVibration() {
+ return mPattern;
+ }
+
+ static class HandlerHolder implements Serializable {
+ Handler tHandler;
+
+ public HandlerHolder(Handler handler) {
+ tHandler = handler;
+ }
+
+ public Handler getHandler() {
+ return tHandler;
+ }
+ }
+}
View
8 core/java/android/provider/Contacts.java
@@ -308,6 +308,14 @@ public static void setSetting(ContentResolver cr, String account, String key,
public static final String CUSTOM_RINGTONE = "custom_ringtone";
/**
+ * A custom vibration associated with a person. Not always present.
+ * <P>Type: TEXT (URI to the vibration)</P>
+ * @deprecated see {@link android.provider.ContactsContract}
+ */
+ @Deprecated
+ public static final String CUSTOM_VIBRATION = "custom_vibration";
+
+ /**
* Whether the person should always be sent to voicemail. Not always
* present.
* <P>Type: INTEGER (0 for false, 1 for true)</P>
View
7 core/java/android/provider/ContactsContract.java
@@ -833,6 +833,13 @@ public static ContentProviderOperation newSetOperation(Account account, byte[] d
public static final String CUSTOM_RINGTONE = "custom_ringtone";
/**
+ * URI for a custom vibration associated with the contact. If null or missing,
+ * the default vibration is used.
+ * <P>Type: TEXT (URI to the vibration)</P>
+ */
+ public static final String CUSTOM_VIBRATION = "custom_vibration";
+
+ /**
* Whether the contact should always be sent to voicemail. If missing,
* defaults to false.
* <P>Type: INTEGER (0 for false, 1 for true)</P>
View
4 core/java/android/provider/Settings.java
@@ -1793,6 +1793,10 @@ public static void setShowGTalkServiceStatus(ContentResolver cr, boolean flag) {
*/
public static final Uri DEFAULT_RINGTONE_URI = getUriFor(RINGTONE);
+ public static final Uri DEFAULT_VIBRATION_URI = Uri.parse("content://com.aokp.romcontrol.Vibrations/vibrations/0");
+
+ public static final String PHONE_VIBRATION = "phone_vibration";
+
/**
* Persistent store for the system-wide default notification sound.
*
View
12 core/res/res/layout/vibration_picker_dialog.xml
@@ -0,0 +1,12 @@
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical" >
+
+ <ListView
+ android:id="@+id/vibration_picker_list"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" >
+ </ListView>
+
+</LinearLayout>
View
5 core/res/res/values/public.xml
@@ -3802,4 +3802,9 @@
<java-symbol type="id" name="title_aokp" />
<java-symbol type="id" name="title_stock" />
+ <!-- Custom Vibrations -->
+ <java-symbol type="string" name="vibration_picker_title"/>
+ <java-symbol type="string" name="vibration_picker_del_title"/>
+ <java-symbol type="layout" name="vibration_picker_dialog"/>
+
</resources>
View
4 core/res/res/values/strings.xml
@@ -3617,4 +3617,8 @@
<!-- Lockscreen weather slash string -->
<string name="weatherpanel_slash">/</string>
+ <!-- Vibration picker dialog title -->
+ <string name="vibration_picker_title">Select vibration</string>
+ <string name="vibration_picker_del_title">Delete vibration</string>
+
</resources>
View
141 media/java/android/media/VibrationPattern.java
@@ -0,0 +1,141 @@
+
+package android.media;
+
+import java.util.ArrayList;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Vibrator;
+import android.provider.Settings;
+import android.util.Log;
+
+public class VibrationPattern {
+ public static final String URI = "content://com.aokp.romcontrol.Vibrations/vibrations";
+ public static final String FALLBACK_NAME = "FALLBACK";
+ public static final String FALLBACK_PATTERN = "500,1000,1000,1000,1000";
+
+ private static final String TAG = "VibrationPattern";
+ private Context mContext = null;
+ private String mName;
+ private Uri mUri;
+ private long[] mPattern;
+ private Vibrator mVibrator = null;
+
+ public VibrationPattern(String name, ArrayList<Long> pattern, Context context) {
+ mContext = context;
+ mVibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
+ mName = name;
+ mPattern = new long[pattern.size()];
+ for (int i = 0; i < pattern.size() - 1; i++) {
+ mPattern[i] = (pattern.get(i + 1) - pattern.get(i));
+ }
+ }
+
+ public VibrationPattern(String name, String patternString, Context context) {
+ mContext = context;
+ mVibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
+ mName = name;
+ setPatternFromString(patternString);
+ }
+
+ public VibrationPattern(Uri uri, Context context) {
+ if (uri != null) {
+ mUri = uri;
+ mContext = context;
+ mVibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
+ try {
+ Cursor vibCursor = context.getContentResolver()
+ .query(mUri, null, null, null, null);
+ vibCursor.moveToFirst();
+ mName = vibCursor.getString(1);
+ setPatternFromString(vibCursor.getString(2));
+ vibCursor.close();
+ } catch (Exception e) {
+ Log.d(TAG, "No vibration matching, cloning default vibration");
+ VibrationPattern def = new VibrationPattern(Uri.parse(VibrationPattern
+ .getPhoneVibration(context)), context);
+ mUri = def.getUri();
+ mName = def.getName();
+ mPattern = def.getPattern();
+ }
+ }
+ }
+
+ public void setName(String newName) {
+ mName = newName;
+ }
+
+ public String getName() {
+ return mName;
+ }
+
+ public long[] getPattern() {
+ return mPattern;
+ }
+
+ public void setUri(Uri uri) {
+ mUri = uri;
+ }
+
+ public Uri getUri() {
+ return mUri;
+ }
+
+ public int getLength() {
+ int sum = 0;
+ for (int i = 0; i < mPattern.length; i++) {
+ sum += (int) mPattern[i];
+ }
+ return sum;
+ }
+
+ public String getPatternString() {
+ String result = "";
+ for (int i = 0; i < mPattern.length; i++) {
+ result = result.concat(Long.toString(mPattern[i]) + ",");
+ }
+ return result.substring(0, result.length() - 1);
+ }
+
+ public void setPatternFromString(String patternString) {
+ String[] split = patternString.split(",");
+ Log.d(TAG, patternString);
+ mPattern = new long[split.length];
+ for (int i = 0; i < split.length; i++) {
+ mPattern[i] = Long.parseLong(split[i]);
+ }
+ }
+
+ public void play() {
+ if (mVibrator != null) {
+ mVibrator.vibrate(mPattern, -1);
+ }
+ }
+
+ public void stop() {
+ if (mVibrator != null) {
+ mVibrator.cancel();
+ }
+ }
+
+ public static String getPhoneVibration(Context context) {
+ ContentResolver cr = context.getContentResolver();
+ String defVibration = Settings.System.getString(cr, Settings.System.PHONE_VIBRATION);
+ if (defVibration == null) {
+ // first time setup
+ Settings.System.putString(cr, Settings.System.PHONE_VIBRATION,
+ Settings.System.DEFAULT_VIBRATION_URI.toString());
+ return Settings.System.DEFAULT_VIBRATION_URI.toString();
+ }
+ return defVibration;
+ }
+
+ // If something goes wrong with the provider.
+ // This is used only by the Phone app's Ringer.java, if the loaded pattern
+ // is corrupt.
+ public static VibrationPattern getFallbackVibration(Context context) {
+ return new VibrationPattern(FALLBACK_NAME, FALLBACK_PATTERN, context);
+ }
+}
View
13 telephony/java/com/android/internal/telephony/CallerInfo.java
@@ -103,6 +103,7 @@
// including the send to voicemail flag and the ringtone
// uri reference.
public Uri contactRingtoneUri;
+ public Uri contactVibrationUri;
public boolean shouldSendToVoicemail;
/**
@@ -227,6 +228,15 @@ public static CallerInfo getCallerInfo(Context context, Uri contactRef, Cursor c
info.contactRingtoneUri = null;
}
+ // look for the custom vibration, create from the string stored
+ // in the database.
+ columnIndex = cursor.getColumnIndex(PhoneLookup.CUSTOM_VIBRATION);
+ if ((columnIndex != -1) && (cursor.getString(columnIndex) != null)) {
+ info.contactVibrationUri = Uri.parse(cursor.getString(columnIndex));
+ } else {
+ info.contactVibrationUri = null;
+ }
+
// look for the send to voicemail flag, set it to true only
// under certain circumstances.
columnIndex = cursor.getColumnIndex(PhoneLookup.SEND_TO_VOICEMAIL);
@@ -603,7 +613,8 @@ public String toString() {
.append("\nperson_id: " + person_id)
.append("\nneedUpdate: " + needUpdate)
.append("\ncontactRefUri: " + contactRefUri)
- .append("\ncontactRingtoneUri: " + contactRefUri)
+ .append("\ncontactRingtoneUri: " + contactRingtoneUri)
+ .append("\ncontactVibrationUri: " + contactVibrationUri)
.append("\nshouldSendToVoicemail: " + shouldSendToVoicemail)
.append("\ncachedPhoto: " + cachedPhoto)
.append("\nisCachedPhotoCurrent: " + isCachedPhotoCurrent)
Please sign in to comment.
Something went wrong with that request. Please try again.