summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/java/android/app/NotificationManager.java6
-rw-r--r--core/java/android/net/Uri.java38
-rw-r--r--core/java/android/os/UserHandle.aidl19
-rw-r--r--core/java/android/widget/RemoteViews.java2
-rw-r--r--media/java/android/media/IRingtonePlayer.aidl3
-rw-r--r--media/java/android/media/Ringtone.java3
-rw-r--r--packages/SystemUI/AndroidManifest.xml1
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java30
-rwxr-xr-xservices/java/com/android/server/NotificationManagerService.java4
9 files changed, 95 insertions, 11 deletions
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index c095280..0acad75 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -124,6 +124,9 @@ public class NotificationManager
int[] idOut = new int[1];
INotificationManager service = getService();
String pkg = mContext.getPackageName();
+ if (notification.sound != null) {
+ notification.sound = notification.sound.getCanonicalUri();
+ }
if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")");
try {
service.enqueueNotificationWithTag(pkg, tag, id, notification, idOut,
@@ -143,6 +146,9 @@ public class NotificationManager
int[] idOut = new int[1];
INotificationManager service = getService();
String pkg = mContext.getPackageName();
+ if (notification.sound != null) {
+ notification.sound = notification.sound.getCanonicalUri();
+ }
if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")");
try {
service.enqueueNotificationWithTag(pkg, tag, id, notification, idOut,
diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java
index 3b990e3..cc6903d 100644
--- a/core/java/android/net/Uri.java
+++ b/core/java/android/net/Uri.java
@@ -16,10 +16,13 @@
package android.net;
+import android.os.Environment;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.Environment.UserEnvironment;
import android.util.Log;
import java.io.File;
+import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.Charsets;
@@ -2288,4 +2291,39 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
builder = builder.appendEncodedPath(pathSegment);
return builder.build();
}
+
+ /**
+ * If this {@link Uri} is {@code file://}, then resolve and return its
+ * canonical path. Also fixes legacy emulated storage paths so they are
+ * usable across user boundaries. Should always be called from the app
+ * process before sending elsewhere.
+ *
+ * @hide
+ */
+ public Uri getCanonicalUri() {
+ if ("file".equals(getScheme())) {
+ final String canonicalPath;
+ try {
+ canonicalPath = new File(getPath()).getCanonicalPath();
+ } catch (IOException e) {
+ return this;
+ }
+
+ if (Environment.isExternalStorageEmulated()) {
+ final String legacyPath = Environment.getLegacyExternalStorageDirectory()
+ .toString();
+
+ // Splice in user-specific path when legacy path is found
+ if (canonicalPath.startsWith(legacyPath)) {
+ return Uri.fromFile(new File(
+ Environment.getExternalStorageDirectory().toString(),
+ canonicalPath.substring(legacyPath.length() + 1)));
+ }
+ }
+
+ return Uri.fromFile(new File(canonicalPath));
+ } else {
+ return this;
+ }
+ }
}
diff --git a/core/java/android/os/UserHandle.aidl b/core/java/android/os/UserHandle.aidl
new file mode 100644
index 0000000..4892d32
--- /dev/null
+++ b/core/java/android/os/UserHandle.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2012, 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.os;
+
+parcelable UserHandle;
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 90f55bf..4b5dfb8 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -2166,6 +2166,8 @@ public class RemoteViews implements Parcelable, Filter {
* @param value The value to pass to the method.
*/
public void setUri(int viewId, String methodName, Uri value) {
+ // Resolve any filesystem path before sending remotely
+ value = value.getCanonicalUri();
addAction(new ReflectionAction(viewId, methodName, ReflectionAction.URI, value));
}
diff --git a/media/java/android/media/IRingtonePlayer.aidl b/media/java/android/media/IRingtonePlayer.aidl
index 44a0333..0872f1d 100644
--- a/media/java/android/media/IRingtonePlayer.aidl
+++ b/media/java/android/media/IRingtonePlayer.aidl
@@ -17,6 +17,7 @@
package android.media;
import android.net.Uri;
+import android.os.UserHandle;
/**
* @hide
@@ -28,6 +29,6 @@ interface IRingtonePlayer {
boolean isPlaying(IBinder token);
/** Used for Notification sound playback. */
- void playAsync(in Uri uri, boolean looping, int streamType);
+ void playAsync(in Uri uri, in UserHandle user, boolean looping, int streamType);
void stopAsync();
}
diff --git a/media/java/android/media/Ringtone.java b/media/java/android/media/Ringtone.java
index 23f7b55..f190eb9 100644
--- a/media/java/android/media/Ringtone.java
+++ b/media/java/android/media/Ringtone.java
@@ -225,8 +225,9 @@ public class Ringtone {
mLocalPlayer.start();
}
} else if (mAllowRemote) {
+ final Uri canonicalUri = mUri.getCanonicalUri();
try {
- mRemotePlayer.play(mRemoteToken, mUri, mStreamType);
+ mRemotePlayer.play(mRemoteToken, canonicalUri, mStreamType);
} catch (RemoteException e) {
Log.w(TAG, "Problem playing ringtone: " + e);
}
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 4d241ed..a7294ec 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -5,6 +5,7 @@
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.ACCESS_ALL_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.INJECT_EVENTS" />
diff --git a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
index 3502b62..0c6e59c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
+++ b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
@@ -17,6 +17,7 @@
package com.android.systemui.media;
import android.content.Context;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.media.IAudioService;
import android.media.IRingtonePlayer;
import android.media.Ringtone;
@@ -26,6 +27,7 @@ import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.UserHandle;
import android.util.Slog;
import com.android.systemui.SystemUI;
@@ -70,9 +72,10 @@ public class RingtonePlayer extends SystemUI {
private final IBinder mToken;
private final Ringtone mRingtone;
- public Client(IBinder token, Uri uri, int streamType) {
+ public Client(IBinder token, Uri uri, UserHandle user, int streamType) {
mToken = token;
- mRingtone = new Ringtone(mContext, false);
+
+ mRingtone = new Ringtone(getContextForUser(user), false);
mRingtone.setStreamType(streamType);
mRingtone.setUri(uri);
}
@@ -90,12 +93,16 @@ public class RingtonePlayer extends SystemUI {
private IRingtonePlayer mCallback = new IRingtonePlayer.Stub() {
@Override
public void play(IBinder token, Uri uri, int streamType) throws RemoteException {
- if (LOGD) Slog.d(TAG, "play(token=" + token + ", uri=" + uri + ")");
+ if (LOGD) {
+ Slog.d(TAG, "play(token=" + token + ", uri=" + uri + ", uid="
+ + Binder.getCallingUid() + ")");
+ }
Client client;
synchronized (mClients) {
client = mClients.get(token);
if (client == null) {
- client = new Client(token, uri, streamType);
+ final UserHandle user = Binder.getCallingUserHandle();
+ client = new Client(token, uri, user, streamType);
token.linkToDeath(client, 0);
mClients.put(token, client);
}
@@ -131,12 +138,13 @@ public class RingtonePlayer extends SystemUI {
}
@Override
- public void playAsync(Uri uri, boolean looping, int streamType) {
- if (LOGD) Slog.d(TAG, "playAsync(uri=" + uri + ")");
+ public void playAsync(Uri uri, UserHandle user, boolean looping, int streamType) {
+ if (LOGD) Slog.d(TAG, "playAsync(uri=" + uri + ", user=" + user + ")");
if (Binder.getCallingUid() != Process.SYSTEM_UID) {
throw new SecurityException("Async playback only available from system UID.");
}
- mAsyncPlayer.play(mContext, uri, looping, streamType);
+
+ mAsyncPlayer.play(getContextForUser(user), uri, looping, streamType);
}
@Override
@@ -149,6 +157,14 @@ public class RingtonePlayer extends SystemUI {
}
};
+ private Context getContextForUser(UserHandle user) {
+ try {
+ return mContext.createPackageContextAsUser(mContext.getPackageName(), 0, user);
+ } catch (NameNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("Clients:");
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java
index 76194ae..5d5f8d3 100755
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/java/com/android/server/NotificationManagerService.java
@@ -890,6 +890,7 @@ public class NotificationManagerService extends INotificationManager.Stub
userId = ActivityManager.handleIncomingUser(callingPid,
callingUid, userId, true, true, "enqueueNotification", pkg);
+ final UserHandle user = new UserHandle(userId);
// Limit the number of notifications that any given package except the android
// package can enqueue. Prevents DOS attacks and deals with leaks.
@@ -991,7 +992,6 @@ public class NotificationManagerService extends INotificationManager.Stub
}
if (notification.icon != 0) {
- final UserHandle user = new UserHandle(userId);
final StatusBarNotification n = new StatusBarNotification(
pkg, id, tag, r.uid, r.initialPid, score, notification, user);
if (old != null && old.statusBarKey != null) {
@@ -1063,7 +1063,7 @@ public class NotificationManagerService extends INotificationManager.Stub
try {
final IRingtonePlayer player = mAudioService.getRingtonePlayer();
if (player != null) {
- player.playAsync(uri, looping, audioStreamType);
+ player.playAsync(uri, user, looping, audioStreamType);
}
} catch (RemoteException e) {
} finally {