Skip to content

Commit

Permalink
[RingtonePicker] Get cursor to list parent sounds
Browse files Browse the repository at this point in the history
Since it is now possible for the work profile to use ringtones from the
personal profile, even custom ringtones, then it makes sense for the
RingtonePicker to list them as well.

This changes use a new RingtoneManager API to also include the personal
ringtones in the work profile RingtonePicker, also displaying a small
work badge next to the custom ringtones of the work profile.

Test: manual - install custom ringtone in work profile and see if it shows with a work badge in the picker
Bug: 30658854
Change-Id: I76e46e7d9401d54e8f096b80ea79e643ce2ab37e
  • Loading branch information
Andre Lago authored and hex539 committed Jan 6, 2017
1 parent ee988a6 commit c50825e
Show file tree
Hide file tree
Showing 3 changed files with 211 additions and 10 deletions.
48 changes: 48 additions & 0 deletions res/layout/radio_with_work_badge.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->

<com.android.providers.media.CheckedListItem xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:background="?android:attr/selectableItemBackground"
>

<CheckedTextView
android:id="@+id/checked_text_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeightSmall"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="?android:attr/textColorAlertDialogListItem"
android:gravity="center_vertical"
android:paddingStart="20dp"
android:paddingEnd="?android:attr/dialogPreferredPadding"
android:drawableStart="?android:attr/listChoiceIndicatorSingle"
android:drawablePadding="20dp"
android:ellipsize="marquee"
android:layout_toLeftOf="@+id/work_icon"
android:maxLines="3" />

<ImageView
android:id="@id/work_icon"
android:layout_width="18dp"
android:layout_height="18dp"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:scaleType="centerCrop"
android:layout_marginRight="20dp" />
</com.android.providers.media.CheckedListItem>
67 changes: 67 additions & 0 deletions src/com/android/providers/media/CheckedListItem.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* 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 com.android.providers.media;

import android.content.Context;
import android.widget.Checkable;
import android.widget.CheckedTextView;
import android.widget.RelativeLayout;
import android.util.AttributeSet;

/**
* The {@link CheckedListItem} is a layout item that represents a ringtone, and is used in
* {@link RingtonePickerActivity}. It contains the ringtone's name, and a work badge to right of the
* name if the ringtone belongs to a work profile.
*/
public class CheckedListItem extends RelativeLayout implements Checkable {

public CheckedListItem(Context context) {
super(context);
}

public CheckedListItem(Context context, AttributeSet attrs) {
super(context, attrs);
}

public CheckedListItem(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}

public CheckedListItem(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}

@Override
public void setChecked(boolean checked) {
getCheckedTextView().setChecked(checked);
}

@Override
public boolean isChecked() {
return getCheckedTextView().isChecked();
}

@Override
public void toggle() {
getCheckedTextView().toggle();
}

private CheckedTextView getCheckedTextView() {
return (CheckedTextView) findViewById(R.id.checked_text_view);
}

}
106 changes: 96 additions & 10 deletions src/com/android/providers/media/RingtonePickerActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package com.android.providers.media;

import android.content.ContentProvider;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
Expand All @@ -37,8 +38,13 @@
import android.provider.Settings;
import android.util.Log;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.CursorAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;

Expand Down Expand Up @@ -103,6 +109,9 @@ public final class RingtonePickerActivity extends AlertActivity implements
/** The Uri to play when the 'Default' item is clicked. */
private Uri mUriForDefaultItem;

/** Id of the user to which the ringtone picker should list the ringtones */
private int mPickerUserId;

/**
* A Ringtone for the default ringtone. In most cases, the RingtoneManager
* will stop the previous ringtone. However, the RingtoneManager doesn't
Expand Down Expand Up @@ -156,32 +165,33 @@ protected void onCreate(Bundle savedInstanceState) {

Intent intent = getIntent();

int pickerUserId = intent.getIntExtra(Intent.EXTRA_USER_ID, UserHandle.USER_CURRENT);

mPickerUserId = intent.getIntExtra(Intent.EXTRA_USER_ID, UserHandle.USER_CURRENT);
// Give the Activity so it can do managed queries
Context targetContext = this;
if (pickerUserId != UserHandle.USER_CURRENT) {
UserInfo parentInfo = UserManager.get(this).getProfileParent(pickerUserId);
if (mPickerUserId != UserHandle.USER_CURRENT) {
UserInfo parentInfo = UserManager.get(this).getProfileParent(mPickerUserId);
final int myUserId = UserHandle.myUserId();

// pickerUserId must be calling user or its parent
if (pickerUserId != myUserId && (parentInfo == null || myUserId != parentInfo.id)) {
// calling user must be mPickerUserId or its parent
if (mPickerUserId != myUserId && (parentInfo == null || myUserId != parentInfo.id)) {
finish();
throw new SecurityException(
"User " + pickerUserId + " is not owned by user " + myUserId);
"User " + mPickerUserId + " is not managed by user " + myUserId);
}

try {
// This allows listing ringtones of a different profile (managed by the caller)
targetContext = createPackageContextAsUser(getPackageName(), 0 /* flags */,
UserHandle.of(pickerUserId));
UserHandle.of(mPickerUserId));
} catch (NameNotFoundException e) {
Log.w(TAG, "Unable to create user context.", e);
finish();
return;
}
} else {
mPickerUserId = UserHandle.myUserId();
}
mRingtoneManager = new RingtoneManager(targetContext);
mRingtoneManager = new RingtoneManager(targetContext, /* includeParentRingtones */ true);

// Get the types of ringtones to show
mType = intent.getIntExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, -1);
Expand Down Expand Up @@ -231,7 +241,7 @@ protected void onCreate(Bundle savedInstanceState) {
.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI);

final AlertController.AlertParams p = mAlertParams;
p.mCursor = mCursor;
p.mAdapter = new WorkRingtonesAdapter(mCursor);
p.mOnClickListener = mRingtoneClickListener;
p.mLabelColumn = COLUMN_LABEL;
p.mIsSingleChoice = true;
Expand Down Expand Up @@ -264,6 +274,15 @@ public void onSaveInstanceState(Bundle outState) {
outState.putInt(SAVE_CLICKED_POS, mClickedPos);
}

@Override
public void onDestroy() {
if (mCursor != null) {
mCursor.close();
mCursor = null;
}
super.onDestroy();
}

public void onPrepareListView(ListView listView) {

if (mHasDefaultItem) {
Expand Down Expand Up @@ -550,4 +569,71 @@ public String getString(int columnIndex) {
}
}
}

private class BadgedRingtoneAdapter extends CursorAdapter {
private final boolean mIsManagedProfile;

public BadgedRingtoneAdapter(Context context, Cursor cursor, boolean isManagedProfile) {
super(context, cursor);
mIsManagedProfile = isManagedProfile;
}

@Override
public boolean areAllItemsEnabled() {
return true;
}

@Override
public boolean isEnabled(int position) {
return true;
}

@Override
public long getItemId(int position) {
if (position < 0) {
return position;
}
return super.getItemId(position);
}

@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
LayoutInflater inflater = LayoutInflater.from(context);
return inflater.inflate(R.layout.radio_with_work_badge, parent, false);
}

@Override
public void bindView(View view, Context context, Cursor cursor) {
// Set text as the title of the ringtone
((TextView) view.findViewById(R.id.checked_text_view))
.setText(cursor.getString(RingtoneManager.TITLE_COLUMN_INDEX));

boolean isWorkRingtone = false;
if (mIsManagedProfile) {
/*
* Display the work icon if the ringtone belongs to a work profile. We can tell that
* a ringtone belongs to a work profile if the picker user is a managed profile, the
* ringtone Uri is in external storage, and either the uri has no user id or has the
* id of the picker user
*/
Uri currentUri = mRingtoneManager.getRingtoneUri(cursor.getPosition());
int uriUserId = ContentProvider.getUserIdFromUri(currentUri, mPickerUserId);
Uri uriWithoutUserId = ContentProvider.getUriWithoutUserId(currentUri);

if (uriUserId == mPickerUserId && uriWithoutUserId.toString()
.startsWith(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI.toString())) {
isWorkRingtone = true;
}
}

ImageView workIcon = (ImageView) view.findViewById(R.id.work_icon);
if(isWorkRingtone) {
workIcon.setImageDrawable(getPackageManager().getUserBadgeForDensityNoBackground(
UserHandle.of(mPickerUserId), -1 /* density */));
workIcon.setVisibility(View.VISIBLE);
} else {
workIcon.setVisibility(View.GONE);
}
}
}
}

0 comments on commit c50825e

Please sign in to comment.