DeskClock: fix setting alarm volume

Minimum volume for a STREAM_ALARM is 1 (or 4, if caller is unprivile-
ged). Substract the minimum volume from Seekbar's value in order to set
proper volume. Also add permission MODIFY_AUDIO_SETTINGS to be able to
set the volume to 1.

Test: Open DeskClock settings, set alarm volume to 1.
      Reopen app, verify volume is still at 1 (minimum).
      Verify alarm volume is at 1 in settings (minimum).
Signed-off-by: Timi Rautamäki <timi.rautamaki@gmail.com>
Change-Id: Icdb5bf7ebc0daefa12edcd28d03c444709cf75c6
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 27da155..aa784bb 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -31,6 +31,7 @@
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
     <uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" />
+    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
     <uses-permission android:name="org.codeaurora.permission.POWER_OFF_ALARM" />
 
     <!-- WRITE_SETTINGS is required to record the upcoming alarm prior to L -->
diff --git a/src/com/android/deskclock/Utils.java b/src/com/android/deskclock/Utils.java
index 6d97912..348c795 100644
--- a/src/com/android/deskclock/Utils.java
+++ b/src/com/android/deskclock/Utils.java
@@ -164,6 +164,13 @@
     }
 
     /**
+     * @return {@code true} if the device is {@link Build.VERSION_CODES#P} or later
+     */
+    public static boolean isPOrLater() {
+        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.P;
+    }
+
+    /**
      * @param resourceId identifies an application resource
      * @return the Uri by which the application resource is accessed
      */
diff --git a/src/com/android/deskclock/settings/AlarmVolumePreference.java b/src/com/android/deskclock/settings/AlarmVolumePreference.java
index c6510db..92edd9e 100644
--- a/src/com/android/deskclock/settings/AlarmVolumePreference.java
+++ b/src/com/android/deskclock/settings/AlarmVolumePreference.java
@@ -44,7 +44,6 @@
     private static final long ALARM_PREVIEW_DURATION_MS = 2000;
 
     private SeekBar mSeekbar;
-    private ImageView mAlarmIcon;
     private boolean mPreviewPlaying;
 
     public AlarmVolumePreference(Context context, AttributeSet attrs) {
@@ -61,10 +60,14 @@
         // Disable click feedback for this preference.
         holder.itemView.setClickable(false);
 
+        // Minimum volume for alarm is not 0, calculate it.
+        int maxVolume = audioManager.getStreamMaxVolume(STREAM_ALARM) - getMinVolume(audioManager);
         mSeekbar = (SeekBar) holder.findViewById(R.id.seekbar);
-        mSeekbar.setMax(audioManager.getStreamMaxVolume(STREAM_ALARM));
-        mSeekbar.setProgress(audioManager.getStreamVolume(STREAM_ALARM));
-        mAlarmIcon = (ImageView) holder.findViewById(android.R.id.icon);
+        mSeekbar.setMax(maxVolume);
+        mSeekbar.setProgress(audioManager.getStreamVolume(STREAM_ALARM) -
+                getMinVolume(audioManager));
+        ((ImageView) holder.findViewById(android.R.id.icon))
+                .setImageResource(R.drawable.ic_alarm_small);
 
         onSeekbarChanged();
 
@@ -72,7 +75,8 @@
             @Override
             public void onChange(boolean selfChange) {
                 // Volume was changed elsewhere, update our slider.
-                mSeekbar.setProgress(audioManager.getStreamVolume(STREAM_ALARM));
+                mSeekbar.setProgress(audioManager.getStreamVolume(STREAM_ALARM) -
+                        getMinVolume(audioManager));
             }
         };
 
@@ -93,7 +97,8 @@
             @Override
             public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                 if (fromUser) {
-                    audioManager.setStreamVolume(STREAM_ALARM, progress, 0);
+                    int newVolume = progress + getMinVolume(audioManager);
+                    audioManager.setStreamVolume(STREAM_ALARM, newVolume, 0);
                 }
                 onSeekbarChanged();
             }
@@ -104,8 +109,8 @@
 
             @Override
             public void onStopTrackingTouch(SeekBar seekBar) {
-                if (!mPreviewPlaying && seekBar.getProgress() != 0) {
-                    // If we are not currently playing and progress is set to non-zero, start.
+                if (!mPreviewPlaying) {
+                    // If we are not currently playing, start.
                     RingtonePreviewKlaxon.start(
                             context, DataModel.getDataModel().getDefaultAlarmRingtoneUri());
                     mPreviewPlaying = true;
@@ -123,8 +128,6 @@
 
     private void onSeekbarChanged() {
         mSeekbar.setEnabled(doesDoNotDisturbAllowAlarmPlayback());
-        mAlarmIcon.setImageResource(mSeekbar.getProgress() == 0 ?
-                R.drawable.ic_alarm_off_24dp : R.drawable.ic_alarm_small);
     }
 
     private boolean doesDoNotDisturbAllowAlarmPlayback() {
@@ -138,4 +141,8 @@
         return notificationManager.getCurrentInterruptionFilter() !=
                 NotificationManager.INTERRUPTION_FILTER_NONE;
     }
+
+    private int getMinVolume(AudioManager audioManager) {
+        return (Utils.isPOrLater()) ? audioManager.getStreamMinVolume(STREAM_ALARM) : 0;
+    }
 }
\ No newline at end of file