[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
This commit is contained in:
46
media/java/android/media/ExternalRingtonesCursorWrapper.java
Normal file
46
media/java/android/media/ExternalRingtonesCursorWrapper.java
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -403,14 +434,38 @@ public class RingtoneManager {
|
||||
if (mCursor != null && mCursor.requery()) {
|
||||
return mCursor;
|
||||
}
|
||||
|
||||
final Cursor internalCursor = getInternalRingtones();
|
||||
final Cursor mediaCursor = getMediaRingtones();
|
||||
|
||||
return mCursor = new SortCursor(new Cursor[] { internalCursor, mediaCursor },
|
||||
|
||||
ArrayList<Cursor> ringtoneCursors = new ArrayList<Cursor>();
|
||||
ringtoneCursors.add(getInternalRingtones());
|
||||
ringtoneCursors.add(getMediaRingtones());
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user