Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a6d1c00a authored by James Lemieux's avatar James Lemieux Committed by Android Git Automerger
Browse files

am 5b762a5c: Prompt for READ_EXTERNAL_STORAGE perm on custom ringtone selection

* commit '5b762a5c':
  Prompt for READ_EXTERNAL_STORAGE perm on custom ringtone selection
parents ce3f6f3f 5b762a5c
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@
    <!-- READ_PHONE_STATE is required to determine when a phone call exists prior to M -->
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <!-- READ_EXTERNAL_STORAGE is required to play custom ringtones from the SD card prior to M -->
    <!-- It is also required to display user-friendly names for custom ringtones in the UI. -->
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

    <application android:label="@string/app_label"
+3 −0
Original line number Diff line number Diff line
@@ -70,6 +70,9 @@
    <!-- Setting labels on Set alarm screen: Select alarm ringtone  -->
    <string name="alert">Alarm Ringtone</string>

    <!-- Label on expanded alarm edit view indicating the ringtone is custom. -->
    <string name="custom_ringtone">Custom Ringtone</string>

    <!-- Label on expanded alarm edit view. -->
    <string name="ringtone">Ringtone</string>

+30 −6
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.deskclock;

import android.Manifest;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
@@ -105,6 +106,7 @@ public abstract class AlarmClockFragment extends DeskClockFragment implements
    private static final String KEY_SELECTED_ALARM = "selectedAlarm";

    private static final int REQUEST_CODE_RINGTONE = 1;
    private static final int REQUEST_CODE_PERMISSIONS = 2;
    private static final long INVALID_ID = -1;
    private static final String PREF_KEY_DEFAULT_ALARM_RINGTONE_URI = "default_alarm_ringtone_uri";

@@ -473,6 +475,13 @@ public abstract class AlarmClockFragment extends DeskClockFragment implements
        setDefaultRingtoneUri(uri);

        asyncUpdateAlarm(mSelectedAlarm, false);

        // If the user chose an external ringtone and has not yet granted the permission to read
        // external storage, ask them for that permission now.
        if (!AlarmUtils.hasPermissionToDisplayRingtoneTitle(getActivity(), uri)) {
            final String[] perms = {Manifest.permission.READ_EXTERNAL_STORAGE};
            requestPermissions(perms, REQUEST_CODE_PERMISSIONS);
        }
    }

    private Uri getDefaultRingtoneUri() {
@@ -512,6 +521,14 @@ public abstract class AlarmClockFragment extends DeskClockFragment implements
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions,
            int[] grantResults) {
        // The permission change may alter the cached ringtone titles so clear them.
        // (e.g. READ_EXTERNAL_STORAGE is granted or revoked)
        mRingtoneTitleCache.clear();
    }

    private class AlarmItemAdapter extends CursorAdapter {
        private final Context mContext;
        private final LayoutInflater mFactory;
@@ -1083,13 +1100,20 @@ public abstract class AlarmClockFragment extends DeskClockFragment implements
            // Try the cache first
            String title = mRingtoneTitleCache.getString(uri.toString());
            if (title == null) {
                // If the user cannot read the ringtone file, insert our own name rather than the
                // ugly one returned by Ringtone.getTitle().
                if (!AlarmUtils.hasPermissionToDisplayRingtoneTitle(mContext, uri)) {
                    title = getString(R.string.custom_ringtone);
                } else {
                    // This is slow because a media player is created during Ringtone object creation.
                Ringtone ringTone = RingtoneManager.getRingtone(mContext, uri);
                    final Ringtone ringTone = RingtoneManager.getRingtone(mContext, uri);
                    if (ringTone == null) {
                        LogUtils.i("No ringtone for uri %s", uri.toString());
                        return null;
                    }
                    title = ringTone.getTitle(mContext);
                }

                if (title != null) {
                    mRingtoneTitleCache.putString(uri.toString(), title);
                }
+27 −0
Original line number Diff line number Diff line
@@ -16,12 +16,15 @@

package com.android.deskclock;

import android.Manifest;
import android.annotation.TargetApi;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.app.TimePickerDialog;
import android.content.Context;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.support.annotation.VisibleForTesting;
import android.text.format.DateFormat;
@@ -117,6 +120,30 @@ public class AlarmUtils {
        timePickerFragment.show(manager, FRAG_TAG_TIME_PICKER);
    }

    /**
     * @return {@code true} iff the user has granted permission to read the ringtone at the given
     *      uri or no permission is required to read the ringtone
     */
    public static boolean hasPermissionToDisplayRingtoneTitle(Context context, Uri ringtoneUri) {
        final PackageManager pm = context.getPackageManager();
        final String packageName = context.getPackageName();

        // If no ringtone is specified, return true.
        if (ringtoneUri == null || ringtoneUri == Alarm.NO_RINGTONE_URI) {
            return true;
        }

        // If the permission is already granted, return true.
        if (pm.checkPermission(Manifest.permission.READ_EXTERNAL_STORAGE, packageName)
                == PackageManager.PERMISSION_GRANTED) {
            return true;
        }

        // If the ringtone is internal, return true;
        // external ringtones require the permission to see their title
        return ringtoneUri.toString().startsWith("content://media/internal/");
    }

    /**
     * format "Alarm set for 2 days, 7 hours, and 53 minutes from now."
     */