从 InstrumentationTestCase 创建通知
Creating notification from InstrumentationTestCase
我想通过单元测试来测试通知是否能够播放资产中的自定义声音。
该测试并不意味着要验证任何内容,我将其编写为一种快速演示功能的方法,而不会混淆主应用程序代码。
所以在测试项目中,我在/res/raw
里面添加了一个wav文件。我将在通知生成器中使用此 URL:
Uri path = Uri.parse("android.resource://<main app package name>/testsound.wav");
URL 应该根据我在 SO 中阅读的问题工作。让我们假设它有效。
现在因为我不想在主项目的 /res/raw
文件夹中包含测试 wav 文件,但是在测试项目一中,我不得不让我的单元测试从 InstrumentationTestCase
这样我就可以访问测试项目中的资源了
代码如下:
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());
notify
调用抛出以下异常:
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)
我已将此异常追踪到 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);
}
}
显然异常与自定义声音没有任何关系,但事实上我们正在从 InstrumentationTestCase
.
创建通知
有没有办法测试这个?我记得过去曾从 AndroidTestCase
创建通知,但如果我这样做,我将无法访问测试 wav 文件。我可以用 wav 创建一个 jar 并将 jar 放到测试项目的 lib 文件夹中,但这会隐藏文件,如果其他程序员将来需要替换它,他们可能很难找到它。
其实,我一直对这个问题有点疑惑。所以我写了一个小的 Instrumentation 测试。
为了断言,我只在API23上把测试标记为运行(getActiveNotifications
之前好像不可用),但是在旧的[=还有 29=]s。
诀窍是使用getTargetContext()
而不是getContext()
:
public final class MainActivityTest extends ActivityUnitTestCase<MainActivity> {
public MainActivityTest() {
super(MainActivity.class);
}
@TargetApi(Build.VERSION_CODES.M)
public void testSendNotification() {
final NotificationManager manager = (NotificationManager) getInstrumentation().getTargetContext().getSystemService(Context.NOTIFICATION_SERVICE);
manager.cancel(42);
assertEquals(0, manager.getActiveNotifications().length);
final NotificationCompat.Builder builder = new NotificationCompat.Builder(getInstrumentation().getTargetContext());
builder.setContentTitle("Notification test")
.setAutoCancel(true)
.setContentText("Hello, Mister Smith")
.setSmallIcon(R.drawable.ic_launcher_notification);
manager.notify(42, builder.build());
assertEquals(1, manager.getActiveNotifications().length);
}
}
它就像一个魅力:
希望对您有所帮助。
我想出了如何让 AndroidTestCase
的声音正常工作。
wav 文件已添加到测试项目的原始文件夹中,但未按预期包含在主项目中。
通知的URL是这样的:
Uri path = Uri.parse("android.resource://<test project package name>/" + R.raw.air_horn);
并且获得builder如下:
NotificationCompat.Builder builder = new NotificationCompat.Builder(getContext());
我想通过单元测试来测试通知是否能够播放资产中的自定义声音。 该测试并不意味着要验证任何内容,我将其编写为一种快速演示功能的方法,而不会混淆主应用程序代码。
所以在测试项目中,我在/res/raw
里面添加了一个wav文件。我将在通知生成器中使用此 URL:
Uri path = Uri.parse("android.resource://<main app package name>/testsound.wav");
URL 应该根据我在 SO 中阅读的问题工作。让我们假设它有效。
现在因为我不想在主项目的 /res/raw
文件夹中包含测试 wav 文件,但是在测试项目一中,我不得不让我的单元测试从 InstrumentationTestCase
这样我就可以访问测试项目中的资源了
代码如下:
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());
notify
调用抛出以下异常:
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)
我已将此异常追踪到 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);
}
}
显然异常与自定义声音没有任何关系,但事实上我们正在从 InstrumentationTestCase
.
有没有办法测试这个?我记得过去曾从 AndroidTestCase
创建通知,但如果我这样做,我将无法访问测试 wav 文件。我可以用 wav 创建一个 jar 并将 jar 放到测试项目的 lib 文件夹中,但这会隐藏文件,如果其他程序员将来需要替换它,他们可能很难找到它。
其实,我一直对这个问题有点疑惑。所以我写了一个小的 Instrumentation 测试。
为了断言,我只在API23上把测试标记为运行(getActiveNotifications
之前好像不可用),但是在旧的[=还有 29=]s。
诀窍是使用getTargetContext()
而不是getContext()
:
public final class MainActivityTest extends ActivityUnitTestCase<MainActivity> {
public MainActivityTest() {
super(MainActivity.class);
}
@TargetApi(Build.VERSION_CODES.M)
public void testSendNotification() {
final NotificationManager manager = (NotificationManager) getInstrumentation().getTargetContext().getSystemService(Context.NOTIFICATION_SERVICE);
manager.cancel(42);
assertEquals(0, manager.getActiveNotifications().length);
final NotificationCompat.Builder builder = new NotificationCompat.Builder(getInstrumentation().getTargetContext());
builder.setContentTitle("Notification test")
.setAutoCancel(true)
.setContentText("Hello, Mister Smith")
.setSmallIcon(R.drawable.ic_launcher_notification);
manager.notify(42, builder.build());
assertEquals(1, manager.getActiveNotifications().length);
}
}
它就像一个魅力:
希望对您有所帮助。
我想出了如何让 AndroidTestCase
的声音正常工作。
wav 文件已添加到测试项目的原始文件夹中,但未按预期包含在主项目中。
通知的URL是这样的:
Uri path = Uri.parse("android.resource://<test project package name>/" + R.raw.air_horn);
并且获得builder如下:
NotificationCompat.Builder builder = new NotificationCompat.Builder(getContext());