Skip to content

Commit 1951db8

Browse files
jsharkeyAndroid (Google) Code Review
authored andcommitted
Merge "Multi-user ringtone playback." into jb-mr1-dev
2 parents fd3398c + 65c4a2b commit 1951db8

File tree

9 files changed

+95
-11
lines changed

9 files changed

+95
-11
lines changed

core/java/android/app/NotificationManager.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,9 @@ public void notify(String tag, int id, Notification notification)
124124
int[] idOut = new int[1];
125125
INotificationManager service = getService();
126126
String pkg = mContext.getPackageName();
127+
if (notification.sound != null) {
128+
notification.sound = notification.sound.getCanonicalUri();
129+
}
127130
if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")");
128131
try {
129132
service.enqueueNotificationWithTag(pkg, tag, id, notification, idOut,
@@ -143,6 +146,9 @@ public void notifyAsUser(String tag, int id, Notification notification, UserHand
143146
int[] idOut = new int[1];
144147
INotificationManager service = getService();
145148
String pkg = mContext.getPackageName();
149+
if (notification.sound != null) {
150+
notification.sound = notification.sound.getCanonicalUri();
151+
}
146152
if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")");
147153
try {
148154
service.enqueueNotificationWithTag(pkg, tag, id, notification, idOut,

core/java/android/net/Uri.java

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,13 @@
1616

1717
package android.net;
1818

19+
import android.os.Environment;
1920
import android.os.Parcel;
2021
import android.os.Parcelable;
22+
import android.os.Environment.UserEnvironment;
2123
import android.util.Log;
2224
import java.io.File;
25+
import java.io.IOException;
2326
import java.io.UnsupportedEncodingException;
2427
import java.net.URLEncoder;
2528
import java.nio.charset.Charsets;
@@ -2288,4 +2291,39 @@ public static Uri withAppendedPath(Uri baseUri, String pathSegment) {
22882291
builder = builder.appendEncodedPath(pathSegment);
22892292
return builder.build();
22902293
}
2294+
2295+
/**
2296+
* If this {@link Uri} is {@code file://}, then resolve and return its
2297+
* canonical path. Also fixes legacy emulated storage paths so they are
2298+
* usable across user boundaries. Should always be called from the app
2299+
* process before sending elsewhere.
2300+
*
2301+
* @hide
2302+
*/
2303+
public Uri getCanonicalUri() {
2304+
if ("file".equals(getScheme())) {
2305+
final String canonicalPath;
2306+
try {
2307+
canonicalPath = new File(getPath()).getCanonicalPath();
2308+
} catch (IOException e) {
2309+
return this;
2310+
}
2311+
2312+
if (Environment.isExternalStorageEmulated()) {
2313+
final String legacyPath = Environment.getLegacyExternalStorageDirectory()
2314+
.toString();
2315+
2316+
// Splice in user-specific path when legacy path is found
2317+
if (canonicalPath.startsWith(legacyPath)) {
2318+
return Uri.fromFile(new File(
2319+
Environment.getExternalStorageDirectory().toString(),
2320+
canonicalPath.substring(legacyPath.length() + 1)));
2321+
}
2322+
}
2323+
2324+
return Uri.fromFile(new File(canonicalPath));
2325+
} else {
2326+
return this;
2327+
}
2328+
}
22912329
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/**
2+
* Copyright (c) 2012, The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package android.os;
18+
19+
parcelable UserHandle;

core/java/android/widget/RemoteViews.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2166,6 +2166,8 @@ public void setCharSequence(int viewId, String methodName, CharSequence value) {
21662166
* @param value The value to pass to the method.
21672167
*/
21682168
public void setUri(int viewId, String methodName, Uri value) {
2169+
// Resolve any filesystem path before sending remotely
2170+
value = value.getCanonicalUri();
21692171
addAction(new ReflectionAction(viewId, methodName, ReflectionAction.URI, value));
21702172
}
21712173

media/java/android/media/IRingtonePlayer.aidl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package android.media;
1818

1919
import android.net.Uri;
20+
import android.os.UserHandle;
2021

2122
/**
2223
* @hide
@@ -28,6 +29,6 @@ interface IRingtonePlayer {
2829
boolean isPlaying(IBinder token);
2930

3031
/** Used for Notification sound playback. */
31-
void playAsync(in Uri uri, boolean looping, int streamType);
32+
void playAsync(in Uri uri, in UserHandle user, boolean looping, int streamType);
3233
void stopAsync();
3334
}

media/java/android/media/Ringtone.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,8 +225,9 @@ public void play() {
225225
mLocalPlayer.start();
226226
}
227227
} else if (mAllowRemote) {
228+
final Uri canonicalUri = mUri.getCanonicalUri();
228229
try {
229-
mRemotePlayer.play(mRemoteToken, mUri, mStreamType);
230+
mRemotePlayer.play(mRemoteToken, canonicalUri, mStreamType);
230231
} catch (RemoteException e) {
231232
Log.w(TAG, "Problem playing ringtone: " + e);
232233
}

packages/SystemUI/AndroidManifest.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
66
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
77
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
8+
<uses-permission android:name="android.permission.ACCESS_ALL_EXTERNAL_STORAGE" />
89
<uses-permission android:name="android.permission.WAKE_LOCK" />
910

1011
<uses-permission android:name="android.permission.INJECT_EVENTS" />

packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package com.android.systemui.media;
1818

1919
import android.content.Context;
20+
import android.content.pm.PackageManager.NameNotFoundException;
2021
import android.media.IAudioService;
2122
import android.media.IRingtonePlayer;
2223
import android.media.Ringtone;
@@ -26,6 +27,7 @@
2627
import android.os.Process;
2728
import android.os.RemoteException;
2829
import android.os.ServiceManager;
30+
import android.os.UserHandle;
2931
import android.util.Slog;
3032

3133
import com.android.systemui.SystemUI;
@@ -70,9 +72,10 @@ private class Client implements IBinder.DeathRecipient {
7072
private final IBinder mToken;
7173
private final Ringtone mRingtone;
7274

73-
public Client(IBinder token, Uri uri, int streamType) {
75+
public Client(IBinder token, Uri uri, UserHandle user, int streamType) {
7476
mToken = token;
75-
mRingtone = new Ringtone(mContext, false);
77+
78+
mRingtone = new Ringtone(getContextForUser(user), false);
7679
mRingtone.setStreamType(streamType);
7780
mRingtone.setUri(uri);
7881
}
@@ -90,12 +93,16 @@ public void binderDied() {
9093
private IRingtonePlayer mCallback = new IRingtonePlayer.Stub() {
9194
@Override
9295
public void play(IBinder token, Uri uri, int streamType) throws RemoteException {
93-
if (LOGD) Slog.d(TAG, "play(token=" + token + ", uri=" + uri + ")");
96+
if (LOGD) {
97+
Slog.d(TAG, "play(token=" + token + ", uri=" + uri + ", uid="
98+
+ Binder.getCallingUid() + ")");
99+
}
94100
Client client;
95101
synchronized (mClients) {
96102
client = mClients.get(token);
97103
if (client == null) {
98-
client = new Client(token, uri, streamType);
104+
final UserHandle user = Binder.getCallingUserHandle();
105+
client = new Client(token, uri, user, streamType);
99106
token.linkToDeath(client, 0);
100107
mClients.put(token, client);
101108
}
@@ -131,12 +138,13 @@ public boolean isPlaying(IBinder token) {
131138
}
132139

133140
@Override
134-
public void playAsync(Uri uri, boolean looping, int streamType) {
135-
if (LOGD) Slog.d(TAG, "playAsync(uri=" + uri + ")");
141+
public void playAsync(Uri uri, UserHandle user, boolean looping, int streamType) {
142+
if (LOGD) Slog.d(TAG, "playAsync(uri=" + uri + ", user=" + user + ")");
136143
if (Binder.getCallingUid() != Process.SYSTEM_UID) {
137144
throw new SecurityException("Async playback only available from system UID.");
138145
}
139-
mAsyncPlayer.play(mContext, uri, looping, streamType);
146+
147+
mAsyncPlayer.play(getContextForUser(user), uri, looping, streamType);
140148
}
141149

142150
@Override
@@ -149,6 +157,14 @@ public void stopAsync() {
149157
}
150158
};
151159

160+
private Context getContextForUser(UserHandle user) {
161+
try {
162+
return mContext.createPackageContextAsUser(mContext.getPackageName(), 0, user);
163+
} catch (NameNotFoundException e) {
164+
throw new RuntimeException(e);
165+
}
166+
}
167+
152168
@Override
153169
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
154170
pw.println("Clients:");

services/java/com/android/server/NotificationManagerService.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -890,6 +890,7 @@ public void enqueueNotificationInternal(String pkg, int callingUid, int callingP
890890

891891
userId = ActivityManager.handleIncomingUser(callingPid,
892892
callingUid, userId, true, true, "enqueueNotification", pkg);
893+
final UserHandle user = new UserHandle(userId);
893894

894895
// Limit the number of notifications that any given package except the android
895896
// package can enqueue. Prevents DOS attacks and deals with leaks.
@@ -991,7 +992,6 @@ public void enqueueNotificationInternal(String pkg, int callingUid, int callingP
991992
}
992993

993994
if (notification.icon != 0) {
994-
final UserHandle user = new UserHandle(userId);
995995
final StatusBarNotification n = new StatusBarNotification(
996996
pkg, id, tag, r.uid, r.initialPid, score, notification, user);
997997
if (old != null && old.statusBarKey != null) {
@@ -1063,7 +1063,7 @@ public void enqueueNotificationInternal(String pkg, int callingUid, int callingP
10631063
try {
10641064
final IRingtonePlayer player = mAudioService.getRingtonePlayer();
10651065
if (player != null) {
1066-
player.playAsync(uri, looping, audioStreamType);
1066+
player.playAsync(uri, user, looping, audioStreamType);
10671067
}
10681068
} catch (RemoteException e) {
10691069
} finally {

0 commit comments

Comments
 (0)