I want to test from a unit test whether a notification is able to play a custom sound from assets. The test is not meant to verify anything, I wrote it as a quick way of demonstrating a feature without cluttering the main app code.
So In the test project, I added a wav file inside /res/raw
. I'll be using this URL with the notification builder:
Uri path = Uri.parse("android.resource://<main app package name>/testsound.wav");
That URL should work according to the questions I've been reading in SO. Let's assume it works.
Now because I didn't want to include the test wav file in the main project's /res/raw
folder but in the test project one, I'm forced to make my unit test extend from InstrumentationTestCase
so that I can access the resources in the test project.
Here's the code:
NotificationCompat.Builder builder = new NotificationCompat.Builder(getInstrumentation().getContext());
...
builder.setSound(path, AudioManager.STREAM_NOTIFICATION);
...
NotificationManager notificationManager = (NotificationManager) getInstrumentation().getContext().getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(NOTIFICATION_ID, builder.build());
The notify
call is throwing the following exception:
java.lang.SecurityException: Calling uid 10198 gave package <main app package name> which is owned by uid 10199
at android.os.Parcel.readException(Parcel.java:1540)
at android.os.Parcel.readException(Parcel.java:1493)
at android.app.INotificationManager$Stub$Proxy.enqueueNotificationWithTag(INotificationManager.java:611)
at android.app.NotificationManager.notify(NotificationManager.java:187)
at android.app.NotificationManager.notify(NotificationManager.java:140)
...
at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1873)
I've tracked this exception down to the NotificationManagerService
class:
void checkCallerIsSystemOrSameApp(String pkg) {
int uid = Binder.getCallingUid();
if (UserHandle.getAppId(uid) == Process.SYSTEM_UID || uid == 0) {
return;
}
try {
ApplicationInfo ai = AppGlobals.getPackageManager().getApplicationInfo(
pkg, 0, UserHandle.getCallingUserId());
if (!UserHandle.isSameApp(ai.uid, uid)) {
throw new SecurityException("Calling uid " + uid + " gave package"
+ pkg + " which is owned by uid " + ai.uid);
}
} catch (RemoteException re) {
throw new SecurityException("Unknown package " + pkg + "\n" + re);
}
}
Apparently the exception doesn't have anything to do with the custom sound, but with the fact that we're creating a notification from an InstrumentationTestCase
.
Is there a way of testing this? I remember having created notifications from AndroidTestCase
in the past, but if I do that then I wont be able to access the test wav file. I could create a jar with the wav and drop the jar in the test project's lib folder, but that would be hiding the file, and other programmers might have a hard time looking for it if they need to replace it in the future.
I figured how to do get the sound to work from an AndroidTestCase
.
The wav file was added to the test project's raw folder and was not included in the main project as intended.
The URL for the notification was like this:
Uri path = Uri.parse("android.resource://<test project package name>/" + R.raw.air_horn);
And the builder was obtained as follows:
NotificationCompat.Builder builder = new NotificationCompat.Builder(getContext());