diff options
author | Wilhelm Fitzpatrick <rafial@cyngn.com> | 2015-12-15 13:45:06 -0800 |
---|---|---|
committer | Gerrit Code Review <gerrit@cyanogenmod.org> | 2015-12-16 17:00:38 -0800 |
commit | aba22b8d30283c159ffcb2e06d894a7bc89d9559 (patch) | |
tree | ef6297ba3aece3510ff71190dd5fbe6490dacd5d | |
parent | 421038c8924178f951fdcdbfadaa9c778868a3d1 (diff) | |
download | android_packages_apps_DeskClock-aba22b8d30283c159ffcb2e06d894a7bc89d9559.tar.gz android_packages_apps_DeskClock-aba22b8d30283c159ffcb2e06d894a7bc89d9559.tar.bz2 android_packages_apps_DeskClock-aba22b8d30283c159ffcb2e06d894a7bc89d9559.zip |
DeskClock: add increasing volume option for alarm clocks
Based on CM12 feature:
https://github.com/CyanogenMod/android_packages_apps_DeskClock/commit/7fc93e1b93b0e9e56a8426a6201a26c2bfca90ba
http://review.cyanogenmod.org/#/c/82967/
Change-Id: I090c76bd773e419f10e1e02bcf3c40ad04d6a988
-rw-r--r-- | res/layout/alarm_time.xml | 29 | ||||
-rw-r--r-- | res/values/cm_strings.xml | 3 | ||||
-rw-r--r-- | src/com/android/deskclock/AlarmClockFragment.java | 13 | ||||
-rw-r--r-- | src/com/android/deskclock/AsyncRingtonePlayer.java | 122 | ||||
-rw-r--r-- | src/com/android/deskclock/alarms/AlarmKlaxon.java | 2 |
5 files changed, 139 insertions, 30 deletions
diff --git a/res/layout/alarm_time.xml b/res/layout/alarm_time.xml index fb2fe9a11..fee4ccb98 100644 --- a/res/layout/alarm_time.xml +++ b/res/layout/alarm_time.xml @@ -74,7 +74,7 @@ <CheckBox android:id="@+id/repeat_onoff" android:layout_width="wrap_content" - android:layout_height="48dip" + android:layout_height="@dimen/touch_target_min_size" android:layout_gravity="center_vertical|start" android:text="@string/alarm_repeat" android:textSize="16sp" @@ -84,7 +84,7 @@ <LinearLayout android:id="@+id/repeat_days" android:layout_width="match_parent" - android:layout_height="48dip" + android:layout_height="@dimen/touch_target_min_size" android:layout_gravity="top" android:orientation="horizontal" android:visibility="gone"> @@ -95,18 +95,16 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_vertical" - android:orientation="horizontal" > + android:orientation="vertical" > <TextView android:id="@+id/choose_ringtone" - android:layout_width="0dip" - android:layout_height="48dip" - android:layout_weight="1" - android:layout_alignParentStart="true" + android:layout_width="match_parent" + android:layout_height="@dimen/touch_target_min_size" android:background="?android:attr/selectableItemBackground" android:clickable="true" android:paddingStart="4dip" - android:drawablePadding="16dp" + android:drawablePadding="20dp" android:drawableStart="@drawable/ic_ringtone" android:ellipsize="marquee" android:gravity="center_vertical" @@ -119,11 +117,20 @@ /> <CheckBox + android:id="@+id/increasing_volume_onoff" + android:layout_width="wrap_content" + android:layout_height="@dimen/touch_target_min_size" + android:includeFontPadding="false" + android:text="@string/alarm_increasing_volume" + android:paddingStart="16dip" + android:textSize="16sp" + android:textColor="@color/white" + style="@style/body" /> + + <CheckBox android:id="@+id/vibrate_onoff" android:layout_width="wrap_content" - android:layout_height="48dip" - android:layout_alignParentEnd="true" - android:layout_centerVertical="true" + android:layout_height="@dimen/touch_target_min_size" android:includeFontPadding="false" android:text="@string/alarm_vibrate" android:paddingStart="16dip" diff --git a/res/values/cm_strings.xml b/res/values/cm_strings.xml index c5fba1c65..067fedd6e 100644 --- a/res/values/cm_strings.xml +++ b/res/values/cm_strings.xml @@ -20,4 +20,7 @@ <!-- Setting summary for showing/hiding the alarm statusbar icon --> <string name="show_status_bar_icon_summary">Show an icon in the status bar when an alarm is set</string> + + <!-- Setting labels on Set alarm screen: Increasing volume on or off --> + <string name="alarm_increasing_volume">Increasing volume</string> </resources> diff --git a/src/com/android/deskclock/AlarmClockFragment.java b/src/com/android/deskclock/AlarmClockFragment.java index 9cee1af06..14906d870 100644 --- a/src/com/android/deskclock/AlarmClockFragment.java +++ b/src/com/android/deskclock/AlarmClockFragment.java @@ -573,6 +573,7 @@ public abstract class AlarmClockFragment extends DeskClockFragment implements LinearLayout repeatDays; CompoundButton[] dayButtons = new CompoundButton[7]; CheckBox vibrate; + CheckBox increasingVolume; TextView ringtone; View hairLine; View arrow; @@ -713,6 +714,7 @@ public abstract class AlarmClockFragment extends DeskClockFragment implements holder.dayButtons[i] = dayButton; } holder.vibrate = (CheckBox) view.findViewById(R.id.vibrate_onoff); + holder.increasingVolume = (CheckBox) view.findViewById(R.id.increasing_volume_onoff); holder.ringtone = (TextView) view.findViewById(R.id.choose_ringtone); view.setTag(holder); @@ -1052,6 +1054,17 @@ public abstract class AlarmClockFragment extends DeskClockFragment implements launchRingTonePicker(alarm); } }); + + itemHolder.increasingVolume.setVisibility(View.VISIBLE); + itemHolder.increasingVolume.setChecked(alarm.increasingVolume); + itemHolder.increasingVolume.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + final boolean checked = ((CheckBox) v).isChecked(); + alarm.increasingVolume = checked; + asyncUpdateAlarm(alarm, false); + } + }); } // Sets the alpha of the digital time display. This gives a visual effect diff --git a/src/com/android/deskclock/AsyncRingtonePlayer.java b/src/com/android/deskclock/AsyncRingtonePlayer.java index 4416aab79..af98e892e 100644 --- a/src/com/android/deskclock/AsyncRingtonePlayer.java +++ b/src/com/android/deskclock/AsyncRingtonePlayer.java @@ -46,9 +46,15 @@ public class AsyncRingtonePlayer { // Volume suggested by media team for in-call alarms. private static final float IN_CALL_VOLUME = 0.125f; + // Constants for increasing volume alarms + private static final long INCREASING_VOLUME_DELAY = 4000; + private static final float INCREASING_VOLUME_START = 0.05f; + private static final float INCREASING_VOLUME_DELTA = 0.05f; + // Message codes used with the ringtone thread. private static final int EVENT_PLAY = 1; private static final int EVENT_STOP = 2; + private static final int EVENT_INCREASE_VOLUME = 3; private static final String RINGTONE_URI_KEY = "RINGTONE_URI_KEY"; /** Handler running on the ringtone thread. */ @@ -65,15 +71,15 @@ public class AsyncRingtonePlayer { } /** Plays the ringtone. */ - public void play(Uri ringtoneUri) { + public void play(Uri ringtoneUri, boolean increasingVolume) { LogUtils.d(TAG, "Posting play."); - postMessage(EVENT_PLAY, ringtoneUri); + postMessage(EVENT_PLAY, ringtoneUri, increasingVolume); } /** Stops playing the ringtone. */ public void stop() { LogUtils.d(TAG, "Posting stop."); - postMessage(EVENT_STOP, null); + postMessage(EVENT_STOP, null, false); } /** @@ -81,7 +87,7 @@ public class AsyncRingtonePlayer { * * @param messageCode The message to post. */ - private void postMessage(int messageCode, Uri ringtoneUri) { + private void postMessage(int messageCode, Uri ringtoneUri, boolean increasingVolume) { synchronized (this) { if (mHandler == null) { mHandler = getNewHandler(); @@ -93,10 +99,17 @@ public class AsyncRingtonePlayer { bundle.putParcelable(RINGTONE_URI_KEY, ringtoneUri); message.setData(bundle); } + message.arg1 = increasingVolume ? 1 : 0; message.sendToTarget(); } } + private void delayedMessage(int messageCode, long delay) { + synchronized (this) { + mHandler.sendEmptyMessageDelayed(messageCode, delay); + } + } + /** * Creates a new ringtone Handler running in its own thread. */ @@ -110,18 +123,29 @@ public class AsyncRingtonePlayer { switch (msg.what) { case EVENT_PLAY: final Uri ringtoneUri = msg.getData().getParcelable(RINGTONE_URI_KEY); - getPlaybackDelegate().play(mContext, ringtoneUri); + final boolean increasingVolume = msg.arg1 == 1; + getPlaybackDelegate().play(mContext, ringtoneUri, increasingVolume); + if (increasingVolume) { + delayedMessage(EVENT_INCREASE_VOLUME, INCREASING_VOLUME_DELAY); + } break; case EVENT_STOP: + removeMessages(EVENT_INCREASE_VOLUME); getPlaybackDelegate().stop(mContext); break; + case EVENT_INCREASE_VOLUME: + PlaybackDelegate pd = getPlaybackDelegate(); + if (pd.isPlaying() && pd.increaseVolume()) { + delayedMessage(EVENT_INCREASE_VOLUME, INCREASING_VOLUME_DELAY); + } + break; } } }; } /** - * @return <code>true</code> iff the device is currently in a telephone call + * @return <code>true</code> if the device is currently in a telephone call */ private static boolean isInTelephoneCall(Context context) { final TelephonyManager tm = (TelephonyManager) @@ -169,8 +193,10 @@ public class AsyncRingtonePlayer { * vs {@link MediaPlayer}. */ private interface PlaybackDelegate { - void play(Context context, Uri ringtoneUri); + void play(Context context, Uri ringtoneUri, boolean increasingVolume); void stop(Context context); + boolean isPlaying(); + boolean increaseVolume(); } /** @@ -184,11 +210,14 @@ public class AsyncRingtonePlayer { /** Non-{@code null} while playing a ringtone; {@code null} otherwise. */ private MediaPlayer mMediaPlayer; + private float mMaxVolume; + private float mCurrentVolume; + /** * Starts the actual playback of the ringtone. Executes on ringtone-thread. */ @Override - public void play(final Context context, Uri ringtoneUri) { + public void play(final Context context, Uri ringtoneUri, boolean increasingVolume) { if (Looper.getMainLooper() == Looper.myLooper()) { LogUtils.e(TAG, "Must not be on the main thread!", new IllegalStateException()); } @@ -217,11 +246,12 @@ public class AsyncRingtonePlayer { }); try { + mMaxVolume = 1f; // Check if we are in a call. If we are, use the in-call alarm resource at a // low volume to not disrupt the call. if (isInTelephoneCall(context)) { LogUtils.v("Using the in-call alarm"); - mMediaPlayer.setVolume(IN_CALL_VOLUME, IN_CALL_VOLUME); + mMaxVolume = IN_CALL_VOLUME; alarmNoise = getInCallRingtoneUri(context); } @@ -230,7 +260,7 @@ public class AsyncRingtonePlayer { // installation time. M+, this permission can be revoked by the user any time. mMediaPlayer.setDataSource(context, alarmNoise); - startAlarm(mMediaPlayer); + startAlarm(mMediaPlayer, increasingVolume); } catch (Throwable t) { LogUtils.e("Use the fallback ringtone, original was " + alarmNoise, t); // The alarmNoise may be on the sd card which could be busy right now. @@ -239,7 +269,7 @@ public class AsyncRingtonePlayer { // Must reset the media player to clear the error state. mMediaPlayer.reset(); mMediaPlayer.setDataSource(context, getFallbackRingtoneUri(context)); - startAlarm(mMediaPlayer); + startAlarm(mMediaPlayer, increasingVolume); } catch (Throwable t2) { // At this point we just don't play anything. LogUtils.e("Failed to play fallback ringtone", t2); @@ -250,7 +280,7 @@ public class AsyncRingtonePlayer { /** * Do the common stuff when starting the alarm. */ - private void startAlarm(MediaPlayer player) throws IOException { + private void startAlarm(MediaPlayer player, boolean increasingVolume) throws IOException { // do not play alarms if stream volume is 0 (typically because ringer mode is silent). if (mAudioManager.getStreamVolume(AudioManager.STREAM_ALARM) != 0) { if (Utils.isLOrLater()) { @@ -260,6 +290,8 @@ public class AsyncRingtonePlayer { .build()); } + mCurrentVolume = increasingVolume ? INCREASING_VOLUME_START : mMaxVolume; + player.setVolume(mCurrentVolume, mCurrentVolume); player.setAudioStreamType(AudioManager.STREAM_ALARM); player.setLooping(true); player.prepare(); @@ -288,6 +320,27 @@ public class AsyncRingtonePlayer { mMediaPlayer = null; } } + + @Override + public boolean isPlaying() { + return mMediaPlayer != null && mMediaPlayer.isPlaying(); + } + + /** + * @return <code>true</code> if volume should continue to be increased + */ + @Override + public boolean increaseVolume() { + if (mMediaPlayer != null) { + mCurrentVolume += INCREASING_VOLUME_DELTA; + if (mCurrentVolume > mMaxVolume) { + mCurrentVolume = mMaxVolume; + } + mMediaPlayer.setVolume(mCurrentVolume, mCurrentVolume); + return mCurrentVolume < mMaxVolume; + } + return false; + } } /** @@ -307,6 +360,9 @@ public class AsyncRingtonePlayer { /** The method to adjust playback looping; cannot be null. */ private Method mSetLoopingMethod; + private float mMaxVolume; + private float mCurrentVolume; + private RingtonePlaybackDelegate() { try { mSetVolumeMethod = Ringtone.class.getDeclaredMethod("setVolume", float.class); @@ -325,7 +381,7 @@ public class AsyncRingtonePlayer { * Starts the actual playback of the ringtone. Executes on ringtone-thread. */ @Override - public void play(Context context, Uri ringtoneUri) { + public void play(Context context, Uri ringtoneUri, boolean increasingVolume) { if (Looper.getMainLooper() == Looper.myLooper()) { LogUtils.e(TAG, "Must not be on the main thread!", new IllegalStateException()); } @@ -374,21 +430,29 @@ public class AsyncRingtonePlayer { .build()); } + mMaxVolume = 1f; // Attempt to adjust the ringtone volume if the user is in a telephone call. if (inTelephoneCall) { LogUtils.v("Using the in-call alarm"); - try { - mSetVolumeMethod.invoke(mRingtone, IN_CALL_VOLUME); - } catch (Exception e) { - LogUtils.e(TAG, "Unable to set in-call volume for android.media.Ringtone", e); - } + mMaxVolume = IN_CALL_VOLUME; } + mCurrentVolume = increasingVolume ? INCREASING_VOLUME_START : mMaxVolume; + mAudioManager.requestAudioFocus(null, AudioManager.STREAM_ALARM, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT); + setVolume(mCurrentVolume); mRingtone.play(); } + private void setVolume(float volume) { + try { + mSetVolumeMethod.invoke(mRingtone, volume); + } catch (Exception e) { + LogUtils.e(TAG, "Unable to set in-call volume for android.media.Ringtone", e); + } + } + /** * Stops the playback of the ringtone. Executes on the ringtone-thread. */ @@ -403,12 +467,34 @@ public class AsyncRingtonePlayer { if (mRingtone != null && mRingtone.isPlaying()) { LogUtils.d(TAG, "Ringtone.stop() invoked."); mRingtone.stop(); + mRingtone = null; } if (mAudioManager != null) { mAudioManager.abandonAudioFocus(null); } } + + @Override + public boolean isPlaying() { + return mRingtone != null && mRingtone.isPlaying(); + } + + /** + * @return <code>true</code> if volume should continue to be increased + */ + @Override + public boolean increaseVolume() { + if (mRingtone != null && mSetVolumeMethod != null) { + mCurrentVolume += INCREASING_VOLUME_DELTA; + if (mCurrentVolume > mMaxVolume) { + mCurrentVolume = mMaxVolume; + } + setVolume(mCurrentVolume); + return mCurrentVolume < mMaxVolume; + } + return false; + } } } diff --git a/src/com/android/deskclock/alarms/AlarmKlaxon.java b/src/com/android/deskclock/alarms/AlarmKlaxon.java index c286f459b..8b31cfb72 100644 --- a/src/com/android/deskclock/alarms/AlarmKlaxon.java +++ b/src/com/android/deskclock/alarms/AlarmKlaxon.java @@ -52,7 +52,7 @@ public final class AlarmKlaxon { stop(context); if (!AlarmInstance.NO_RINGTONE_URI.equals(instance.mRingtone)) { - getAsyncRingtonePlayer(context).play(instance.mRingtone); + getAsyncRingtonePlayer(context).play(instance.mRingtone, instance.mIncreasingVolume); } if (instance.mVibrate) { |