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

Commit dc50b548 authored by Andre Lago's avatar Andre Lago Committed by Robin Lee
Browse files

[RingtoneManager] Option for cursor to list parent sounds

Modify RingtoneManager.getCursor so that the cursor returned also
retrieves the parent profile's ringtones, adding the parent's id to
those ringtones

Test: manual (use ringtone picker in associated CL)
Bug: 30658854
Change-Id: I3b52b0dc41a5a3ff1a71a89fd8a0d33023021aba
parent 178693a5
Loading
Loading
Loading
Loading
+46 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.media;

import android.content.ContentProvider;
import android.database.Cursor;
import android.database.CursorWrapper;
import android.net.Uri;

/**
 * Cursor that adds the user id to fetched URIs. This is especially useful for {@link getCursor} as
 * a managed profile should also list its parent's ringtones
 *
 * @hide
 */
public class ExternalRingtonesCursorWrapper extends CursorWrapper {

    private int mUserId;

    public ExternalRingtonesCursorWrapper(Cursor cursor, int userId) {
        super(cursor);
        mUserId = userId;
    }

    public String getString(int index) {
        String result = super.getString(index);
        if (index == RingtoneManager.URI_COLUMN_INDEX) {
            result = ContentProvider.maybeAddUserId(Uri.parse(result), mUserId).toString();
        }
        return result;
    }
}
+94 −13
Original line number Diff line number Diff line
@@ -261,6 +261,8 @@ public class RingtoneManager {
    private boolean mStopPreviousRingtone = true;
    private Ringtone mPreviousRingtone;

    private boolean mIncludeParentRingtones;

    /**
     * Constructs a RingtoneManager. This constructor is recommended as its
     * constructed instance manages cursor(s).
@@ -268,9 +270,24 @@ public class RingtoneManager {
     * @param activity The activity used to get a managed cursor.
     */
    public RingtoneManager(Activity activity) {
        this(activity, /* includeParentRingtones */ false);
    }

    /**
     * Constructs a RingtoneManager. This constructor is recommended if there's the need to also
     * list ringtones from the user's parent.
     *
     * @param activity The activity used to get a managed cursor.
     * @param includeParentRingtones if true, this ringtone manager's cursor will also retrieve
     *            ringtones from the parent of the user specified in the given activity
     *
     * @hide
     */
    public RingtoneManager(Activity activity, boolean includeParentRingtones) {
        mActivity = activity;
        mContext = activity;
        setType(mType);
        mIncludeParentRingtones = includeParentRingtones;
    }

    /**
@@ -281,9 +298,23 @@ public class RingtoneManager {
     * @param context The context to used to get a cursor.
     */
    public RingtoneManager(Context context) {
        this(context, /* includeParentRingtones */ false);
    }

    /**
     * Constructs a RingtoneManager.
     *
     * @param context The context to used to get a cursor.
     * @param includeParentRingtones if true, this ringtone manager's cursor will also retrieve
     *            ringtones from the parent of the user specified in the given context
     *
     * @hide
     */
    public RingtoneManager(Context context, boolean includeParentRingtones) {
        mActivity = null;
        mContext = context;
        setType(mType);
        mIncludeParentRingtones = includeParentRingtones;
    }

    /**
@@ -404,13 +435,37 @@ public class RingtoneManager {
            return mCursor;
        }

        final Cursor internalCursor = getInternalRingtones();
        final Cursor mediaCursor = getMediaRingtones();
        ArrayList<Cursor> ringtoneCursors = new ArrayList<Cursor>();
        ringtoneCursors.add(getInternalRingtones());
        ringtoneCursors.add(getMediaRingtones());

        return mCursor = new SortCursor(new Cursor[] { internalCursor, mediaCursor },
        if (mIncludeParentRingtones) {
            Cursor parentRingtonesCursor = getParentProfileRingtones();
            if (parentRingtonesCursor != null) {
                ringtoneCursors.add(parentRingtonesCursor);
            }
        }

        return mCursor = new SortCursor(ringtoneCursors.toArray(new Cursor[ringtoneCursors.size()]),
                MediaStore.Audio.Media.DEFAULT_SORT_ORDER);
    }

    private Cursor getParentProfileRingtones() {
        final UserManager um = UserManager.get(mContext);
        final UserInfo parentInfo = um.getProfileParent(mContext.getUserId());
        if (parentInfo != null && parentInfo.id != mContext.getUserId()) {
            final Context parentContext = createPackageContextAsUser(mContext, parentInfo.id);
            if (parentContext != null) {
                // We don't need to re-add the internal ringtones for the work profile since
                // they are the same as the personal profile. We just need the external
                // ringtones.
                return new ExternalRingtonesCursorWrapper(getMediaRingtones(parentContext),
                        parentInfo.id);
            }
        }
        return null;
    }

    /**
     * Gets a {@link Ringtone} for the ringtone at the given position in the
     * {@link Cursor}.
@@ -559,7 +614,11 @@ public class RingtoneManager {
    }

    private Cursor getMediaRingtones() {
        if (PackageManager.PERMISSION_GRANTED != mContext.checkPermission(
        return getMediaRingtones(mContext);
    }

    private Cursor getMediaRingtones(Context context) {
        if (PackageManager.PERMISSION_GRANTED != context.checkPermission(
                android.Manifest.permission.READ_EXTERNAL_STORAGE,
                Process.myPid(), Process.myUid())) {
            Log.w(TAG, "No READ_EXTERNAL_STORAGE permission, ignoring ringtones on ext storage");
@@ -573,7 +632,7 @@ public class RingtoneManager {
                ? query(
                    MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, MEDIA_COLUMNS,
                    constructBooleanTrueWhereClause(mFilterColumns), null,
                    MediaStore.Audio.Media.DEFAULT_SORT_ORDER)
                    MediaStore.Audio.Media.DEFAULT_SORT_ORDER, context)
                : null;
    }
    
@@ -628,10 +687,19 @@ public class RingtoneManager {
            String selection,
            String[] selectionArgs,
            String sortOrder) {
        return query(uri, projection, selection, selectionArgs, sortOrder, mContext);
    }

    private Cursor query(Uri uri,
            String[] projection,
            String selection,
            String[] selectionArgs,
            String sortOrder,
            Context context) {
        if (mActivity != null) {
            return mActivity.managedQuery(uri, projection, selection, selectionArgs, sortOrder);
        } else {
            return mContext.getContentResolver().query(uri, projection, selection, selectionArgs,
            return context.getContentResolver().query(uri, projection, selection, selectionArgs,
                    sortOrder);
        }
    }
@@ -717,17 +785,14 @@ public class RingtoneManager {
        UserManager um = UserManager.get(userContext);
        UserInfo parentInfo = um.getProfileParent(userContext.getUserId());
        if (parentInfo != null) {
            try {
                Context targetContext = userContext.createPackageContextAsUser(
                        userContext.getPackageName(), 0 /* flags */, UserHandle.of(parentInfo.id));
            final Context targetContext = createPackageContextAsUser(userContext, parentInfo.id);
            if (targetContext != null) {
                for (int ringtoneType : RINGTONE_TYPES) {
                    Uri ringtoneUri = getActualDefaultRingtoneUri(targetContext, ringtoneType);
                    // Add user id of parent so that custom ringtones can be read and played
                    RingtoneManager.setActualDefaultRingtoneUri(userContext, ringtoneType,
                            maybeAddUserId(ringtoneUri, parentInfo.id));
                }
            } catch (NameNotFoundException e) {
                Log.e(TAG, "Unable to create parent context", e);
            }
        }
    }
@@ -1113,4 +1178,20 @@ public class RingtoneManager {
            return mQueue.take();
        }
    }

    /**
     * Attempts to create a context for the given user.
     *
     * @return created context, or null if package does not exist
     * @hide
     */
    private static Context createPackageContextAsUser(Context context, int userId) {
        try {
            return context.createPackageContextAsUser(context.getPackageName(), 0 /* flags */,
                    UserHandle.of(userId));
        } catch (NameNotFoundException e) {
            Log.e(TAG, "Unable to create package context", e);
            return null;
        }
    }
}