diff options
author | Flamefire <alex@grundis.de> | 2014-06-05 18:00:34 +0200 |
---|---|---|
committer | Flamefire <alex@grundis.de> | 2014-10-29 14:48:54 +0100 |
commit | 951cc1efc7da193faa0769c5818f6848b9baf0dc (patch) | |
tree | 734febc3b7768fbc7a1df31cb721bb70f87328ae | |
parent | a8059acb634796c0b8d15c3bd1aed6469c763425 (diff) | |
download | android_packages_apps_DeskClock-951cc1efc7da193faa0769c5818f6848b9baf0dc.tar.gz android_packages_apps_DeskClock-951cc1efc7da193faa0769c5818f6848b9baf0dc.tar.bz2 android_packages_apps_DeskClock-951cc1efc7da193faa0769c5818f6848b9baf0dc.zip |
Add option to change timer alert sound
The default alert sound is sometimes quite annoying
PS1: Rebase and save the last picked value as default
PS6: WS fixes
Change-Id: I239e0d56a1562ba2c0fbff92fdf907d1147fb402
-rw-r--r-- | res/layout/time_setup_view.xml | 25 | ||||
-rw-r--r-- | res/values/cm_arrays.xml | 5 | ||||
-rw-r--r-- | res/values/cm_strings.xml | 1 | ||||
-rw-r--r-- | src/com/android/deskclock/TimerRingService.java | 12 | ||||
-rw-r--r-- | src/com/android/deskclock/timer/TimerFragment.java | 145 | ||||
-rw-r--r-- | src/com/android/deskclock/timer/TimerObj.java | 20 | ||||
-rw-r--r-- | src/com/android/deskclock/timer/TimerReceiver.java | 6 |
7 files changed, 201 insertions, 13 deletions
diff --git a/res/layout/time_setup_view.xml b/res/layout/time_setup_view.xml index ea3c392b7..a81026ed0 100644 --- a/res/layout/time_setup_view.xml +++ b/res/layout/time_setup_view.xml @@ -64,6 +64,31 @@ android:layout_width="match_parent" android:layout_height="1dip" android:background="@color/hairline"/> + <TextView + android:id="@+id/choose_ringtone" + android:layout_height="wrap_content" + android:layout_width="match_parent" + android:layout_marginEnd="16dp" + android:layout_marginBottom="6dp" + android:gravity="center_vertical" + android:textAlignment="viewStart" + style="@style/body" + android:background="@drawable/item_background" + android:clickable="true" + android:textColor="@color/clock_white" + android:ellipsize="marquee" + android:scrollHorizontally="true" + android:singleLine="true" + android:marqueeRepeatLimit="marquee_forever" + android:drawableStart="@drawable/ic_ringtone" + android:drawablePadding="2dp" + android:layout_alignParentStart="true" + android:layout_alignParentEnd="true" + /> + <View + android:layout_width="match_parent" + android:layout_height="1dip" + android:background="@color/hairline"/> <LinearLayout android:layout_width="match_parent" diff --git a/res/values/cm_arrays.xml b/res/values/cm_arrays.xml index 753a5b429..1584fc68c 100644 --- a/res/values/cm_arrays.xml +++ b/res/values/cm_arrays.xml @@ -34,4 +34,9 @@ <item>@string/alarm_type_ringtone</item> <item>@string/alarm_type_random</item> </string-array> + + <string-array name="timer_ringtone_picker_entries" translatable="false"> + <item>@string/alarm_type_ringtone</item> + <item>@string/alarm_type_default</item> + </string-array> </resources> diff --git a/res/values/cm_strings.xml b/res/values/cm_strings.xml index 35a6af081..f79da840f 100644 --- a/res/values/cm_strings.xml +++ b/res/values/cm_strings.xml @@ -79,6 +79,7 @@ <!-- Alarm types --> <string name="alarm_type_ringtone">Ringtone</string> <string name="alarm_type_random">Randomly</string> + <string name="alarm_type_default">Default</string> <!-- Warn Silent Alarm title --> <string name="warn_silent_alarm_title">Alarm volume is silent</string> diff --git a/src/com/android/deskclock/TimerRingService.java b/src/com/android/deskclock/TimerRingService.java index 0bc269b54..b3c8b019e 100644 --- a/src/com/android/deskclock/TimerRingService.java +++ b/src/com/android/deskclock/TimerRingService.java @@ -24,7 +24,6 @@ import android.content.res.Resources; import android.media.AudioManager; import android.media.MediaPlayer; import android.media.MediaPlayer.OnErrorListener; -import android.media.RingtoneManager; import android.net.Uri; import android.os.IBinder; import android.telephony.PhoneStateListener; @@ -40,6 +39,8 @@ public class TimerRingService extends Service implements AudioManager.OnAudioFoc private TelephonyManager mTelephonyManager; private int mInitialCallState; + public final static String RINGTONE = "RINGTONE"; + private final PhoneStateListener mPhoneStateListener = new PhoneStateListener() { @Override @@ -86,7 +87,7 @@ public class TimerRingService extends Service implements AudioManager.OnAudioFoc return START_NOT_STICKY; } - play(); + play(Uri.parse(intent.getStringExtra(RINGTONE))); // Record the initial call state here so that the new alarm has the // newest state. mInitialCallState = mTelephonyManager.getCallState(); @@ -97,7 +98,7 @@ public class TimerRingService extends Service implements AudioManager.OnAudioFoc // Volume suggested by media team for in-call alarms. private static final float IN_CALL_VOLUME = 0.125f; - private void play() { + private void play(Uri ringtone) { if (mPlaying) { return; @@ -130,10 +131,13 @@ public class TimerRingService extends Service implements AudioManager.OnAudioFoc mMediaPlayer.setVolume(IN_CALL_VOLUME, IN_CALL_VOLUME); setDataSourceFromResource(getResources(), mMediaPlayer, R.raw.in_call_alarm); - } else { + } else if (ringtone.equals(Uri.EMPTY)) { + // Default sound AssetFileDescriptor afd = getAssets().openFd("sounds/Timer_Expire.ogg"); mMediaPlayer.setDataSource( afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength()); + } else { + mMediaPlayer.setDataSource(getApplication(), ringtone); } startAlarm(mMediaPlayer); } catch (Exception ex) { diff --git a/src/com/android/deskclock/timer/TimerFragment.java b/src/com/android/deskclock/timer/TimerFragment.java index 700168bec..4efc9065e 100644 --- a/src/com/android/deskclock/timer/TimerFragment.java +++ b/src/com/android/deskclock/timer/TimerFragment.java @@ -19,15 +19,21 @@ package com.android.deskclock.timer; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; +import android.app.Activity; +import android.app.AlertDialog; import android.app.Fragment; import android.app.FragmentTransaction; import android.app.NotificationManager; import android.content.Context; +import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.content.SharedPreferences.OnSharedPreferenceChangeListener; import android.content.res.Configuration; import android.content.res.Resources; +import android.media.Ringtone; +import android.media.RingtoneManager; +import android.net.Uri; import android.os.Bundle; import android.preference.PreferenceManager; import android.util.Log; @@ -52,25 +58,27 @@ import com.android.deskclock.LabelDialogFragment; import com.android.deskclock.R; import com.android.deskclock.TimerSetupView; import com.android.deskclock.Utils; +import com.android.deskclock.widget.sgv.GridAdapter; +import com.android.deskclock.widget.sgv.SgvAnimationHelper.AnimationIn; +import com.android.deskclock.widget.sgv.SgvAnimationHelper.AnimationOut; +import com.android.deskclock.widget.sgv.StaggeredGridView; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.LinkedList; -import com.android.deskclock.widget.sgv.SgvAnimationHelper.AnimationIn; -import com.android.deskclock.widget.sgv.SgvAnimationHelper.AnimationOut; -import com.android.deskclock.widget.sgv.StaggeredGridView; -import com.android.deskclock.widget.sgv.GridAdapter; - public class TimerFragment extends DeskClockFragment implements OnClickListener, OnSharedPreferenceChangeListener { private static final String TAG = "TimerFragment"; private static final String KEY_SETUP_SELECTED = "_setup_selected"; private static final String KEY_ENTRY_STATE = "entry_state"; + public static final String KEY_TIMER_SOUND = "timer_sound"; public static final String GOTO_SETUP_VIEW = "deskclock.timers.gotosetup"; + private static final int REQUEST_CODE_RINGTONE = 1; + private Bundle mViewState = null; private StaggeredGridView mTimersList; private View mTimersListPage; @@ -86,6 +94,10 @@ public class TimerFragment extends DeskClockFragment private NotificationManager mNotificationManager; private OnEmptyListListener mOnEmptyListListener; private View mLastVisibleView = null; // used to decide if to set the view or animate to it. + private TextView mRingtone; + + private Uri mRingtoneUri = null; + private Bundle mRingtoneTitleCache = new Bundle(); public TimerFragment() { } @@ -487,6 +499,7 @@ public class TimerFragment extends DeskClockFragment } TimerObj t = new TimerObj(timerLength * 1000); t.mState = TimerObj.STATE_RUNNING; + t.setRingtone(mRingtoneUri); mAdapter.addTimer(t); updateTimersState(t, Timers.START_TIMER); gotoTimersView(); @@ -524,9 +537,128 @@ public class TimerFragment extends DeskClockFragment mNotificationManager = (NotificationManager) getActivity().getSystemService(Context.NOTIFICATION_SERVICE); + mRingtone = (TextView) v.findViewById(R.id.choose_ringtone); + mRingtone.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + launchRingTonePicker(); + } + }); + String ringtone = mPrefs.getString(KEY_TIMER_SOUND, ""); + if (ringtone == null || ringtone.isEmpty()) + mRingtoneUri = null; + else + mRingtoneUri = Uri.parse(ringtone); + updateRingtoneText(); + return v; } + private void updateRingtoneText() { + String ringtone; + if (mRingtoneUri == null) { + ringtone = getResources().getString(R.string.alarm_type_default); + } else { + ringtone = getRingToneTitle(mRingtoneUri); + if (ringtone == null) { + ringtone = getResources().getString(R.string.alarm_type_default); + } + } + mRingtone.setText(ringtone); + mRingtone.setContentDescription( + getResources().getString(R.string.ringtone_description) + " " + ringtone); + } + + /** + * Does a read-through cache for ringtone titles. + * + * @param uri The uri of the ringtone. + * @return The ringtone title. {@literal null} if no matching ringtone + * found. + */ + private String getRingToneTitle(Uri uri) { + // Try the cache first + String title = mRingtoneTitleCache.getString(uri.toString()); + if (title == null) { + // This is slow because a media player is created during Ringtone + // object creation. + Ringtone ringTone = RingtoneManager.getRingtone(getActivity(), uri); + if (ringTone != null) { + title = ringTone.getTitle(getActivity()); + } + if (title != null) { + mRingtoneTitleCache.putString(uri.toString(), title); + } + } + return title; + } + + private void launchRingTonePicker() { + AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); + builder.setTitle(R.string.alarm_picker_title).setItems( + R.array.timer_ringtone_picker_entries, + + new DialogInterface.OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, int which) { + switch (which) { + case 0: + launchSingleRingTonePicker(); + break; + case 1: + mRingtoneUri = null; + SharedPreferences.Editor editor = mPrefs.edit(); + editor.putString(KEY_TIMER_SOUND, ""); + editor.apply(); + updateRingtoneText(); + break; + } + } + }); + AlertDialog d = builder.create(); + d.show(); + } + + private void launchSingleRingTonePicker() { + // Save current view state + mViewState = new Bundle(); + saveViewState(mViewState); + + final Intent intent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER); + intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, mRingtoneUri); + intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, RingtoneManager.TYPE_ALARM); + intent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, false); + startActivityForResult(intent, REQUEST_CODE_RINGTONE); + } + + private void saveRingtoneUri(Intent intent) { + mRingtoneUri = intent.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI); + + // Save the last selected ringtone as the default for new alarms + if (mRingtoneUri != null) { + RingtoneManager.setActualDefaultRingtoneUri( + getActivity(), RingtoneManager.TYPE_ALARM, mRingtoneUri); + } + SharedPreferences.Editor editor = mPrefs.edit(); + editor.putString(KEY_TIMER_SOUND, mRingtoneUri == null ? "" : mRingtoneUri.toString()); + editor.apply(); + updateRingtoneText(); + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + if (resultCode == Activity.RESULT_OK) { + switch (requestCode) { + case REQUEST_CODE_RINGTONE: + saveRingtoneUri(data); + break; + default: + Log.w(TAG, "Unhandled request code in onActivityResult: " + requestCode); + } + } + } + @Override public void onDestroyView() { mViewState = new Bundle(); @@ -606,7 +738,7 @@ public class TimerFragment extends DeskClockFragment super.onPause(); stopClockTicks(); if (mAdapter != null) { - mAdapter.saveGlobalState (); + mAdapter.saveGlobalState(); } mPrefs.unregisterOnSharedPreferenceChangeListener(this); // This is called because the lock screen was activated, the window stay @@ -721,6 +853,7 @@ public class TimerFragment extends DeskClockFragment mTimerSetup.updateDeleteButton(); mLastVisibleView = mTimerSetup; } + private void gotoTimersView() { if (mLastVisibleView == null || mLastVisibleView.getId() == R.id.timers_list_page) { mTimerSetup.setVisibility(View.GONE); diff --git a/src/com/android/deskclock/timer/TimerObj.java b/src/com/android/deskclock/timer/TimerObj.java index 66aee5952..506a5deea 100644 --- a/src/com/android/deskclock/timer/TimerObj.java +++ b/src/com/android/deskclock/timer/TimerObj.java @@ -18,6 +18,7 @@ package com.android.deskclock.timer; import android.content.Context; import android.content.SharedPreferences; +import android.net.Uri; import android.os.Parcel; import android.os.Parcelable; import android.util.Log; @@ -49,6 +50,7 @@ public class TimerObj implements Parcelable { public int mState; public String mLabel; public boolean mDeleteAfterUse; + private Uri mRingtone; public static final int STATE_RUNNING = 1; public static final int STATE_STOPPED = 2; @@ -65,6 +67,7 @@ public class TimerObj implements Parcelable { private static final String PREF_STATE = "timer_state_"; private static final String PREF_LABEL = "timer_label_"; private static final String PREF_DELETE_AFTER_USE = "delete_after_use_"; + private static final String PREF_RINGTONE = "ringtone_"; private static final String PREF_TIMERS_LIST = "timers_list"; @@ -102,6 +105,8 @@ public class TimerObj implements Parcelable { editor.putString(key, mLabel); key = PREF_DELETE_AFTER_USE + id; editor.putBoolean(key, mDeleteAfterUse); + key = PREF_RINGTONE + id; + editor.putString(key, mRingtone.toString()); editor.apply(); } @@ -122,6 +127,8 @@ public class TimerObj implements Parcelable { mLabel = prefs.getString(key, ""); key = PREF_DELETE_AFTER_USE + id; mDeleteAfterUse = prefs.getBoolean(key, false); + key = PREF_RINGTONE + id; + mRingtone = Uri.parse(prefs.getString(key, "")); } public void deleteFromSharedPref(SharedPreferences prefs) { @@ -146,6 +153,8 @@ public class TimerObj implements Parcelable { editor.remove(key); key = PREF_DELETE_AFTER_USE + id; editor.remove(key); + key = PREF_RINGTONE + id; + editor.remove(key); editor.commit(); //dumpTimersFromSharedPrefs(prefs); } @@ -165,6 +174,7 @@ public class TimerObj implements Parcelable { dest.writeLong(mSetupLength); dest.writeInt(mState); dest.writeString(mLabel); + dest.writeString(mRingtone.toString()); } public TimerObj(Parcel p) { @@ -175,6 +185,7 @@ public class TimerObj implements Parcelable { mSetupLength = p.readLong(); mState = p.readInt(); mLabel = p.readString(); + mRingtone = Uri.parse(p.readString()); } public TimerObj() { @@ -198,6 +209,7 @@ public class TimerObj implements Parcelable { mStartTime = Utils.getTimeNow(); mTimeLeft = mOriginalLength = mSetupLength = length; mLabel = ""; + mRingtone = Uri.EMPTY; } public long updateTimeLeft(boolean forceUpdate) { @@ -237,6 +249,13 @@ public class TimerObj implements Parcelable { return mStartTime + mOriginalLength; } + public Uri getRingtone() { + return mRingtone; + } + + public void setRingtone(Uri ringTone) { + mRingtone = ringTone == null ? Uri.EMPTY : ringTone; + } public static void getTimersFromSharedPrefs( SharedPreferences prefs, ArrayList<TimerObj> timers) { @@ -278,7 +297,6 @@ public class TimerObj implements Parcelable { SharedPreferences prefs, ArrayList<TimerObj> timers) { if (timers.size() > 0) { for (int i = 0; i < timers.size(); i++) { - TimerObj t = timers.get(i); timers.get(i).writeToSharedPref(prefs); } } diff --git a/src/com/android/deskclock/timer/TimerReceiver.java b/src/com/android/deskclock/timer/TimerReceiver.java index 86cdb04e6..28c60085b 100644 --- a/src/com/android/deskclock/timer/TimerReceiver.java +++ b/src/com/android/deskclock/timer/TimerReceiver.java @@ -99,10 +99,12 @@ public class TimerReceiver extends BroadcastReceiver { t.mState = TimerObj.STATE_TIMESUP; t.writeToSharedPref(prefs); - // Play ringtone by using TimerRingService service with a default alarm. + // Play ringtone by using TimerRingService service with the selected + // alarm. Log.d(TAG, "playing ringtone"); Intent si = new Intent(); si.setClass(context, TimerRingService.class); + si.putExtra(TimerRingService.RINGTONE, t.getRingtone().toString()); context.startService(si); // Update the in-use notification @@ -348,7 +350,7 @@ public class TimerReceiver extends BroadcastReceiver { return null; } - long hundreds, seconds, minutes, hours; + long seconds, minutes, hours; seconds = timeLeft / 1000; minutes = seconds / 60; seconds = seconds - minutes * 60; |