blob: 05f17c2eec0cd292eaee77ed2dbb3a2b2d9157de [file] [log] [blame]
/*
* Copyright (C) 2022 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.app.usage.cts;
import static android.Manifest.permission.ACCESS_BROADCAST_RESPONSE_STATS;
import static android.app.usage.cts.UsageStatsTest.TEST_APP_CLASS;
import static android.app.usage.cts.UsageStatsTest.TEST_APP_CLASS_BROADCAST_RECEIVER;
import static android.app.usage.cts.UsageStatsTest.TEST_APP_CLASS_SERVICE;
import static android.app.usage.cts.UsageStatsTest.TEST_APP_PKG;
import static android.content.Intent.EXTRA_REMOTE_CALLBACK;
import static android.provider.DeviceConfig.NAMESPACE_APP_STANDBY;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.app.BroadcastOptions;
import android.app.Notification;
import android.app.PendingIntent;
import android.app.UiAutomation;
import android.app.usage.BroadcastResponseStats;
import android.app.usage.UsageStatsManager;
import android.app.usage.cts.UsageStatsTest.TestServiceConnection;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Icon;
import android.media.session.MediaSession;
import android.os.Bundle;
import android.os.RemoteCallback;
import android.os.SystemClock;
import android.platform.test.annotations.AppModeFull;
import android.support.test.uiautomator.UiDevice;
import android.util.ArrayMap;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.MediumTest;
import com.android.compatibility.common.util.AppOpsUtils;
import com.android.compatibility.common.util.DeviceConfigStateHelper;
import com.android.compatibility.common.util.PollingCheck;
import com.android.compatibility.common.util.SystemUtil;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@RunWith(UsageStatsTestRunner.class)
public class BroadcastResponseStatsTest {
private static final String TEST_APP3_PKG = "android.app.usage.cts.test3";
private static final String TEST_APP4_PKG = "android.app.usage.cts.test4";
private static final long TEST_RESPONSE_STATS_ID_1 = 11;
private static final long TEST_RESPONSE_STATS_ID_2 = 22;
private static final String TEST_NOTIFICATION_CHANNEL_ID = "test-channel-id";
private static final String TEST_NOTIFICATION_CHANNEL_NAME = "test-channel-name";
private static final String TEST_NOTIFICATION_CHANNEL_DESC = "test-channel-description";
private static final int TEST_NOTIFICATION_ID_1 = 10;
private static final int TEST_NOTIFICATION_ID_2 = 20;
private static final String TEST_NOTIFICATION_TITLE_FMT = "Test title; id=%s";
private static final String TEST_NOTIFICATION_TEXT_1 = "Test content 1";
private static final String TEST_NOTIFICATION_TEXT_2 = "Test content 2";
private static final int DEFAULT_TIMEOUT_MS = 10_000;
// For tests that are verifying a certain event doesn't occur, wait for some time
// to ensure the event doesn't really occur. Otherwise, we cannot be sure if the event didn't
// occur or the verification was done too early before the event occurred.
private static final int WAIT_TIME_FOR_NEGATIVE_TESTS_MS = 500;
// TODO: Define these constants in UsageStatsManager as @TestApis to avoid hardcoding here.
private static final String KEY_BROADCAST_RESPONSE_WINDOW_DURATION_MS =
"broadcast_response_window_timeout_ms";
private static final String KEY_BROADCAST_RESPONSE_FG_THRESHOLD_STATE =
"broadcast_response_fg_threshold_state";
private static final String KEY_BROADCAST_SESSIONS_DURATION_MS =
"broadcast_sessions_duration_ms";
private static final String KEY_BROADCAST_SESSIONS_WITH_RESPONSE_DURATION_MS =
"broadcast_sessions_with_response_duration_ms";
private static final String KEY_NOTE_RESPONSE_EVENT_FOR_ALL_BROADCAST_SESSIONS =
"note_response_event_for_all_broadcast_sessions";
private static Context sContext;
private static String sTargetPackage;
private UsageStatsManager mUsageStatsManager;
private UiDevice mUiDevice;
private UiAutomation mUiAutomation;
private static int sInitialAppOpMode;
@BeforeClass
public static void setUpClass() throws Exception {
sContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
sTargetPackage = sContext.getPackageName();
sInitialAppOpMode = AppOpsUtils.getOpMode(sTargetPackage,
AppOpsManager.OPSTR_GET_USAGE_STATS);
AppOpsUtils.setOpMode(sTargetPackage, AppOpsManager.OPSTR_GET_USAGE_STATS,
AppOpsManager.MODE_IGNORED);
}
@AfterClass
public static void tearDownClass() throws Exception {
AppOpsUtils.setOpMode(sTargetPackage, AppOpsManager.OPSTR_GET_USAGE_STATS,
sInitialAppOpMode);
}
@Before
public void setUp() throws Exception {
mUsageStatsManager = sContext.getSystemService(UsageStatsManager.class);
mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
mUiAutomation = InstrumentationRegistry.getInstrumentation()
.getUiAutomation();
mUiAutomation.grantRuntimePermission(sTargetPackage, ACCESS_BROADCAST_RESPONSE_STATS);
}
@After
public void tearDown() throws Exception {
mUiDevice.pressHome();
// Clear broadcast response stats
mUsageStatsManager.clearBroadcastEvents();
mUsageStatsManager.clearBroadcastResponseStats(null /* packageName */, 0 /* id */);
mUiAutomation.revokeRuntimePermission(sTargetPackage, ACCESS_BROADCAST_RESPONSE_STATS);
}
@AppModeFull(reason = "No broadcast message response stats in instant apps")
@Test
public void testBroadcastOptions_noPermission() throws Exception {
final BroadcastOptions options = BroadcastOptions.makeBasic();
options.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_1);
final Intent intent = new Intent().setComponent(new ComponentName(
TEST_APP_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
sendBroadcastAndWaitForReceipt(intent, options.toBundle());
mUiAutomation.revokeRuntimePermission(sTargetPackage, ACCESS_BROADCAST_RESPONSE_STATS);
try {
assertThrows(SecurityException.class, () -> {
sendBroadcastAndWaitForReceipt(intent, options.toBundle());
});
} finally {
mUiAutomation.grantRuntimePermission(sTargetPackage, ACCESS_BROADCAST_RESPONSE_STATS);
}
}
@AppModeFull(reason = "No broadcast message response stats in instant apps")
@Test
public void testQueryBroadcastResponseStats_noPermission() throws Exception {
mUsageStatsManager.queryBroadcastResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1);
mUiAutomation.revokeRuntimePermission(sTargetPackage, ACCESS_BROADCAST_RESPONSE_STATS);
try {
assertThrows(SecurityException.class, () -> {
mUsageStatsManager.queryBroadcastResponseStats(TEST_APP_PKG,
TEST_RESPONSE_STATS_ID_1);
});
} finally {
mUiAutomation.grantRuntimePermission(sTargetPackage, ACCESS_BROADCAST_RESPONSE_STATS);
}
}
@AppModeFull(reason = "No broadcast message response stats in instant apps")
@Test
public void testClearBroadcastResponseStats_noPermission() throws Exception {
mUsageStatsManager.clearBroadcastResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1);
mUiAutomation.revokeRuntimePermission(sTargetPackage, ACCESS_BROADCAST_RESPONSE_STATS);
try {
assertThrows(SecurityException.class, () -> {
mUsageStatsManager.clearBroadcastResponseStats(TEST_APP_PKG,
TEST_RESPONSE_STATS_ID_1);
});
} finally {
mUiAutomation.grantRuntimePermission(sTargetPackage, ACCESS_BROADCAST_RESPONSE_STATS);
}
}
@AppModeFull(reason = "No broadcast message response stats in instant apps")
@Test
public void testBroadcastResponseStats_broadcastDispatchedCount() throws Exception {
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
final TestServiceConnection connection = bindToTestServiceAndGetConnection();
try {
ITestReceiver testReceiver = connection.getITestReceiver();
testReceiver.cancelAll();
// Send a normal broadcast.
final Intent intent = new Intent().setComponent(new ComponentName(
TEST_APP_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
sendBroadcastAndWaitForReceipt(intent, null);
// Trigger a notification from test app and verify none of the counts get
// incremented.
testReceiver.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
TEST_NOTIFICATION_CHANNEL_NAME,
TEST_NOTIFICATION_CHANNEL_DESC);
testReceiver.postNotification(TEST_NOTIFICATION_ID_1,
buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
TEST_NOTIFICATION_TEXT_1));
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
// Send a broadcast with a request to record response.
final BroadcastOptions options = BroadcastOptions.makeBasic();
options.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_1);
sendBroadcastAndWaitForReceipt(intent, options.toBundle());
// Trigger a notification from test app and verify notification-posted count gets
// incremented.
testReceiver.postNotification(TEST_NOTIFICATION_ID_1,
buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
TEST_NOTIFICATION_TEXT_2));
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
1 /* broadcastCount */,
0 /* notificationPostedCount */,
1 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
testReceiver.cancelAll();
} finally {
connection.unbind();
}
}
@AppModeFull(reason = "No broadcast message response stats in instant apps")
@Test
public void testBroadcastResponseStats_notificationPostedCount() throws Exception {
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
final TestServiceConnection connection = bindToTestServiceAndGetConnection();
try {
ITestReceiver testReceiver = connection.getITestReceiver();
testReceiver.cancelAll();
// Send a normal broadcast and verify none of the counts get incremented.
final Intent intent = new Intent().setComponent(new ComponentName(
TEST_APP_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
sendBroadcastAndWaitForReceipt(intent, null);
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
// Send a broadcast with a request to record response and verify broadcast-sent
// count gets incremented.
final BroadcastOptions options = BroadcastOptions.makeBasic();
options.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_1);
sendBroadcastAndWaitForReceipt(intent, options.toBundle());
// Trigger a notification from test app and verify notification-posted count gets
// incremented.
testReceiver.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
TEST_NOTIFICATION_CHANNEL_NAME,
TEST_NOTIFICATION_CHANNEL_DESC);
testReceiver.postNotification(TEST_NOTIFICATION_ID_1,
buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
TEST_NOTIFICATION_TEXT_1));
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
1 /* broadcastCount */,
1 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
mUsageStatsManager.clearBroadcastResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1);
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
testReceiver.cancelAll();
} finally {
connection.unbind();
}
}
@AppModeFull(reason = "No broadcast message response stats in instant apps")
@Test
public void testBroadcastResponseStats_notificationUpdatedCount() throws Exception {
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
final TestServiceConnection connection = bindToTestServiceAndGetConnection();
try {
ITestReceiver testReceiver = connection.getITestReceiver();
testReceiver.cancelAll();
// Post a notification (before sending any broadcast) and verify none of the counts
// get incremented.
testReceiver.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
TEST_NOTIFICATION_CHANNEL_NAME,
TEST_NOTIFICATION_CHANNEL_DESC);
testReceiver.postNotification(TEST_NOTIFICATION_ID_1,
buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
TEST_NOTIFICATION_TEXT_1));
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
// Send a broadcast with a request to record response and verify broadcast-sent
// count gets incremented.
final Intent intent = new Intent().setComponent(new ComponentName(
TEST_APP_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
final BroadcastOptions options = BroadcastOptions.makeBasic();
options.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_1);
sendBroadcastAndWaitForReceipt(intent, options.toBundle());
// Update a previously posted notification (change content text) and verify
// notification-updated count gets incremented.
testReceiver.postNotification(TEST_NOTIFICATION_ID_1,
buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
TEST_NOTIFICATION_TEXT_2));
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
1 /* broadcastCount */,
0 /* notificationPostedCount */,
1 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
mUsageStatsManager.clearBroadcastResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1);
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
testReceiver.cancelAll();
} finally {
connection.unbind();
}
}
@AppModeFull(reason = "No broadcast message response stats in instant apps")
@Test
public void testBroadcastResponseStats_notificationCancelledCount() throws Exception {
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
final TestServiceConnection connection = bindToTestServiceAndGetConnection();
try {
ITestReceiver testReceiver = connection.getITestReceiver();
testReceiver.cancelAll();
// Post a notification (before sending any broadcast) and verify none of the counts
// get incremented.
testReceiver.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
TEST_NOTIFICATION_CHANNEL_NAME,
TEST_NOTIFICATION_CHANNEL_DESC);
testReceiver.postNotification(TEST_NOTIFICATION_ID_1,
buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
TEST_NOTIFICATION_TEXT_1));
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
// Send a broadcast with a request to record response and verify broadcast-sent
// count gets incremented.
final Intent intent = new Intent().setComponent(new ComponentName(
TEST_APP_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
sendBroadcastAndWaitForReceipt(intent, null);
final BroadcastOptions options = BroadcastOptions.makeBasic();
options.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_1);
sendBroadcastAndWaitForReceipt(intent, options.toBundle());
// Cancel a previously posted notification (change content text) and verify
// notification-cancelled count gets incremented.
testReceiver.cancelNotification(TEST_NOTIFICATION_ID_1);
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
1 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
1 /* notificationCancelledCount */);
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
mUsageStatsManager.clearBroadcastResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1);
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
testReceiver.cancelAll();
} finally {
connection.unbind();
}
}
@AppModeFull(reason = "No broadcast message response stats in instant apps")
@Test
public void testBroadcastResponseStats_multipleEvents() throws Exception {
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
final TestServiceConnection connection = bindToTestServiceAndGetConnection();
try {
ITestReceiver testReceiver = connection.getITestReceiver();
testReceiver.cancelAll();
// Send a normal broadcast and verify none of the counts get incremented.
final Intent intent = new Intent().setComponent(new ComponentName(
TEST_APP_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
sendBroadcastAndWaitForReceipt(intent, null);
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
// Send a broadcast with a request to record response and verify broadcast-sent
// count gets incremented.
final BroadcastOptions options = BroadcastOptions.makeBasic();
options.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_1);
sendBroadcastAndWaitForReceipt(intent, options.toBundle());
// Trigger a notification from test app and verify notification-posted count gets
// incremented.
testReceiver.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
TEST_NOTIFICATION_CHANNEL_NAME,
TEST_NOTIFICATION_CHANNEL_DESC);
testReceiver.postNotification(TEST_NOTIFICATION_ID_1,
buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
TEST_NOTIFICATION_TEXT_1));
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
1 /* broadcastCount */,
1 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
// Send another broadcast and trigger another notification.
sendBroadcastAndWaitForReceipt(intent, options.toBundle());
testReceiver.postNotification(TEST_NOTIFICATION_ID_2,
buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_2,
TEST_NOTIFICATION_TEXT_2));
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
2 /* broadcastCount */,
2 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
// Send another broadcast with a different ID and update a previously posted
// notification.
options.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_2);
sendBroadcastAndWaitForReceipt(intent, options.toBundle());
testReceiver.postNotification(TEST_NOTIFICATION_ID_1,
buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
TEST_NOTIFICATION_TEXT_2));
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
2 /* broadcastCount */,
2 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
1 /* broadcastCount */,
0 /* notificationPostedCount */,
1 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
// Update/cancel a previously posted notifications and verify there is
// no change in counts.
testReceiver.postNotification(TEST_NOTIFICATION_ID_1,
buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
TEST_NOTIFICATION_TEXT_1));
testReceiver.cancelNotification(TEST_NOTIFICATION_ID_2);
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
2 /* broadcastCount */,
2 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
1 /* broadcastCount */,
0 /* notificationPostedCount */,
1 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
mUsageStatsManager.clearBroadcastResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1);
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
1 /* broadcastCount */,
0 /* notificationPostedCount */,
1 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
mUsageStatsManager.clearBroadcastResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2);
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
testReceiver.cancelAll();
} finally {
connection.unbind();
}
}
@AppModeFull(reason = "No broadcast message response stats in instant apps")
@Test
public void testBroadcastResponseStats_clearCounts() throws Exception {
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
final TestServiceConnection connection = bindToTestServiceAndGetConnection();
try {
ITestReceiver testReceiver = connection.getITestReceiver();
testReceiver.cancelAll();
// Send a broadcast with a request to record response and verify broadcast-sent
// count gets incremented.
final Intent intent = new Intent().setComponent(new ComponentName(
TEST_APP_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
final BroadcastOptions options = BroadcastOptions.makeBasic();
options.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_1);
sendBroadcastAndWaitForReceipt(intent, options.toBundle());
// Trigger a notification from test app and verify notification-posted count gets
// incremented.
testReceiver.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
TEST_NOTIFICATION_CHANNEL_NAME,
TEST_NOTIFICATION_CHANNEL_DESC);
testReceiver.postNotification(TEST_NOTIFICATION_ID_1,
buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
TEST_NOTIFICATION_TEXT_1));
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
1 /* broadcastCount */,
1 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
mUsageStatsManager.clearBroadcastResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1);
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
// Send the broadcast again after clearing counts and verify counts get incremented
// as expected.
sendBroadcastAndWaitForReceipt(intent, options.toBundle());
testReceiver.postNotification(TEST_NOTIFICATION_ID_1,
buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
TEST_NOTIFICATION_TEXT_2));
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
1 /* broadcastCount */,
0 /* notificationPostedCount */,
1 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
sendBroadcastAndWaitForReceipt(intent, options.toBundle());
testReceiver.cancelNotification(TEST_NOTIFICATION_ID_1);
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
2 /* broadcastCount */,
0 /* notificationPostedCount */,
1 /* notificationUpdatedCount */,
1 /* notificationCancelledCount */);
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
testReceiver.cancelAll();
} finally {
connection.unbind();
}
}
@AppModeFull(reason = "No broadcast message response stats in instant apps")
@MediumTest
@Test
public void testBroadcastResponseStats_changeResponseWindowDuration() throws Exception {
final long broadcastResponseWindowDurationMs = TimeUnit.MINUTES.toMillis(2);
try (DeviceConfigStateHelper deviceConfigStateHelper =
new DeviceConfigStateHelper(NAMESPACE_APP_STANDBY)) {
updateFlagWithDelay(deviceConfigStateHelper,
KEY_BROADCAST_RESPONSE_WINDOW_DURATION_MS,
String.valueOf(broadcastResponseWindowDurationMs));
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
final TestServiceConnection connection = bindToTestServiceAndGetConnection();
try {
ITestReceiver testReceiver = connection.getITestReceiver();
testReceiver.cancelAll();
// Send a broadcast with a request to record response and verify broadcast-sent
// count gets incremented.
final Intent intent = new Intent().setComponent(new ComponentName(
TEST_APP_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
final BroadcastOptions options = BroadcastOptions.makeBasic();
options.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_1);
sendBroadcastAndWaitForReceipt(intent, options.toBundle());
// Trigger a notification from test app and verify notification-posted count gets
// incremented.
testReceiver.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
TEST_NOTIFICATION_CHANNEL_NAME,
TEST_NOTIFICATION_CHANNEL_DESC);
testReceiver.postNotification(TEST_NOTIFICATION_ID_1,
buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
TEST_NOTIFICATION_TEXT_1));
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
1 /* broadcastCount */,
1 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
testReceiver.cancelNotification(TEST_NOTIFICATION_ID_1);
mUsageStatsManager.clearBroadcastResponseStats(TEST_APP_PKG,
TEST_RESPONSE_STATS_ID_1);
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
sendBroadcastAndWaitForReceipt(intent, options.toBundle());
SystemClock.sleep(broadcastResponseWindowDurationMs);
// Trigger a notification from test app but verify counts do not get
// incremented as the notification is posted after the window durations is expired.
testReceiver.postNotification(TEST_NOTIFICATION_ID_1,
buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
TEST_NOTIFICATION_TEXT_1));
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
1 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
testReceiver.cancelAll();
} finally {
connection.unbind();
}
}
}
@AppModeFull(reason = "No broadcast message response stats in instant apps")
@Test
public void testBroadcastResponseStats_appNotInForeground() throws Exception {
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
try (DeviceConfigStateHelper deviceConfigStateHelper =
new DeviceConfigStateHelper(NAMESPACE_APP_STANDBY)) {
final TestServiceConnection connection = bindToTestServiceAndGetConnection();
try {
updateFlagWithDelay(deviceConfigStateHelper,
KEY_BROADCAST_RESPONSE_FG_THRESHOLD_STATE,
String.valueOf(ActivityManager.PROCESS_STATE_TOP));
ITestReceiver testReceiver = connection.getITestReceiver();
testReceiver.cancelAll();
// Send a broadcast with a request to record response.
final Intent intent = new Intent().setComponent(new ComponentName(
TEST_APP_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
final BroadcastOptions options = BroadcastOptions.makeBasic();
options.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_1);
sendBroadcastAndWaitForReceipt(intent, options.toBundle());
// Trigger a notification from test app and verify notification-posted count gets
// incremented.
testReceiver.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
TEST_NOTIFICATION_CHANNEL_NAME,
TEST_NOTIFICATION_CHANNEL_DESC);
testReceiver.postNotification(TEST_NOTIFICATION_ID_1,
buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
TEST_NOTIFICATION_TEXT_1));
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
1 /* broadcastCount */,
1 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
// Bring the test app to the foreground, send the broadcast again and verify that
// counts do not change.
launchTestActivityAndWaitToBeResumed(TEST_APP_PKG, TEST_APP_CLASS);
sendBroadcastAndWaitForReceipt(intent, options.toBundle());
testReceiver.postNotification(TEST_NOTIFICATION_ID_1,
buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
TEST_NOTIFICATION_TEXT_2));
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
1 /* broadcastCount */,
1 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
// Change the threshold to something lower than TOP, send the broadcast again
// and verify that counts get incremented.
updateFlagWithDelay(deviceConfigStateHelper,
KEY_BROADCAST_RESPONSE_FG_THRESHOLD_STATE,
String.valueOf(ActivityManager.PROCESS_STATE_PERSISTENT));
sendBroadcastAndWaitForReceipt(intent, options.toBundle());
testReceiver.cancelNotification(TEST_NOTIFICATION_ID_1);
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
2 /* broadcastCount */,
1 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
1 /* notificationCancelledCount */);
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
mUiDevice.pressHome();
// Change the threshold to a process state higher than RECEIVER, send the
// broadcast again and verify that counts do not change.
updateFlagWithDelay(deviceConfigStateHelper,
KEY_BROADCAST_RESPONSE_FG_THRESHOLD_STATE,
String.valueOf(ActivityManager.PROCESS_STATE_HOME));
sendBroadcastAndWaitForReceipt(intent, options.toBundle());
testReceiver.postNotification(TEST_NOTIFICATION_ID_1,
buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
TEST_NOTIFICATION_TEXT_1));
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
2 /* broadcastCount */,
1 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
1 /* notificationCancelledCount */);
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
testReceiver.cancelAll();
} finally {
connection.unbind();
}
}
}
@AppModeFull(reason = "No broadcast message response stats in instant apps")
@Test
public void testBroadcastResponseStats_multiplePackages() throws Exception {
final ArrayMap<String, BroadcastResponseStats> expectedStats = new ArrayMap<>();
// Initially all the counts should be empty
assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStats);
final TestServiceConnection connection1 = bindToTestServiceAndGetConnection(TEST_APP_PKG);
final TestServiceConnection connection3 = bindToTestServiceAndGetConnection(TEST_APP3_PKG);
final TestServiceConnection connection4 = bindToTestServiceAndGetConnection(TEST_APP4_PKG);
try {
ITestReceiver testReceiver1 = connection1.getITestReceiver();
ITestReceiver testReceiver3 = connection3.getITestReceiver();
ITestReceiver testReceiver4 = connection4.getITestReceiver();
testReceiver1.cancelAll();
testReceiver3.cancelAll();
testReceiver4.cancelAll();
final Intent intent = new Intent().setComponent(new ComponentName(
TEST_APP_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
final Intent intent3 = new Intent().setComponent(new ComponentName(
TEST_APP3_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
final Intent intent4 = new Intent().setComponent(new ComponentName(
TEST_APP4_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
// Send a broadcast to test-pkg1 with a request to record response and verify
// broadcast-sent count gets incremented.
final BroadcastOptions options = BroadcastOptions.makeBasic();
options.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_1);
sendBroadcastAndWaitForReceipt(intent, options.toBundle());
expectedStats.put(TEST_APP_PKG, new BroadcastResponseStats(TEST_APP_PKG,
TEST_RESPONSE_STATS_ID_1));
expectedStats.get(TEST_APP_PKG).incrementBroadcastsDispatchedCount(1);
// Send a broadcast to test-pkg3 with a request to record response and verify
// broadcast-sent count gets incremented.
sendBroadcastAndWaitForReceipt(intent3, options.toBundle());
expectedStats.put(TEST_APP3_PKG, new BroadcastResponseStats(TEST_APP3_PKG,
TEST_RESPONSE_STATS_ID_1));
expectedStats.get(TEST_APP3_PKG).incrementBroadcastsDispatchedCount(1);
// Trigger a notification from test-pkg1 and verify notification-posted count gets
// incremented.
testReceiver1.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
TEST_NOTIFICATION_CHANNEL_NAME,
TEST_NOTIFICATION_CHANNEL_DESC);
testReceiver1.postNotification(TEST_NOTIFICATION_ID_1,
buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
TEST_NOTIFICATION_TEXT_1));
expectedStats.get(TEST_APP_PKG).incrementNotificationsPostedCount(1);
// Trigger a notification from test-pkg3 and verify notification-posted count gets
// incremented.
testReceiver3.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
TEST_NOTIFICATION_CHANNEL_NAME,
TEST_NOTIFICATION_CHANNEL_DESC);
testReceiver3.postNotification(TEST_NOTIFICATION_ID_1,
buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
TEST_NOTIFICATION_TEXT_1));
expectedStats.get(TEST_APP3_PKG).incrementNotificationsPostedCount(1);
assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStats);
// Send a broadcast to test-pkg1 with a request to record response and verify
// broadcast-sent count gets incremented.
sendBroadcastAndWaitForReceipt(intent, options.toBundle());
testReceiver1.postNotification(TEST_NOTIFICATION_ID_1,
buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
TEST_NOTIFICATION_TEXT_2));
expectedStats.get(TEST_APP_PKG).incrementBroadcastsDispatchedCount(1);
expectedStats.get(TEST_APP_PKG).incrementNotificationsUpdatedCount(1);
assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStats);
// Trigger a notification from test-pkg3 and verify stats remain the same
testReceiver4.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
TEST_NOTIFICATION_CHANNEL_NAME,
TEST_NOTIFICATION_CHANNEL_DESC);
testReceiver4.postNotification(TEST_NOTIFICATION_ID_1,
buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
TEST_NOTIFICATION_TEXT_1));
assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStats);
// Send a broadcast to test-pkg4 with a request to record response and verify
// broadcast-send count gets incremented.
sendBroadcastAndWaitForReceipt(intent4, options.toBundle());
testReceiver4.cancelNotification(TEST_NOTIFICATION_ID_1);
expectedStats.put(TEST_APP4_PKG, new BroadcastResponseStats(TEST_APP4_PKG,
TEST_RESPONSE_STATS_ID_1));
expectedStats.get(TEST_APP4_PKG).incrementBroadcastsDispatchedCount(1);
expectedStats.get(TEST_APP4_PKG).incrementNotificationsCancelledCount(1);
assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStats);
mUsageStatsManager.clearBroadcastResponseStats(null, TEST_RESPONSE_STATS_ID_1);
expectedStats.clear();
assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStats);
testReceiver1.cancelAll();
testReceiver3.cancelAll();
testReceiver4.cancelAll();
} finally {
connection1.unbind();
connection3.unbind();
connection4.unbind();
}
}
@AppModeFull(reason = "No broadcast message response stats in instant apps")
@Test
public void testBroadcastResponseStats_multiplePackages_multipleIds() throws Exception {
final ArrayMap<String, BroadcastResponseStats> expectedStatsForId1 = new ArrayMap<>();
final ArrayMap<String, BroadcastResponseStats> expectedStatsForId2 = new ArrayMap<>();
// Initially all the counts should be empty
assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStatsForId1);
assertResponseStats(TEST_RESPONSE_STATS_ID_2, expectedStatsForId2);
final TestServiceConnection connection1 = bindToTestServiceAndGetConnection(TEST_APP_PKG);
final TestServiceConnection connection3 = bindToTestServiceAndGetConnection(TEST_APP3_PKG);
final TestServiceConnection connection4 = bindToTestServiceAndGetConnection(TEST_APP4_PKG);
try {
ITestReceiver testReceiver1 = connection1.getITestReceiver();
ITestReceiver testReceiver3 = connection3.getITestReceiver();
ITestReceiver testReceiver4 = connection4.getITestReceiver();
testReceiver1.cancelAll();
testReceiver3.cancelAll();
testReceiver4.cancelAll();
final Intent intent = new Intent().setComponent(new ComponentName(
TEST_APP_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
final Intent intent3 = new Intent().setComponent(new ComponentName(
TEST_APP3_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
final Intent intent4 = new Intent().setComponent(new ComponentName(
TEST_APP4_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
final BroadcastOptions options1 = BroadcastOptions.makeBasic();
options1.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_1);
final BroadcastOptions options2 = BroadcastOptions.makeBasic();
options2.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_2);
// Send a broadcast to test-pkg1 with a request to record response and verify
// broadcast-sent count gets incremented.
sendBroadcastAndWaitForReceipt(intent, options1.toBundle());
sendBroadcastAndWaitForReceipt(intent3, options2.toBundle());
// Trigger a notification from test-pkg1 and verify notification-posted count gets
// incremented.
testReceiver1.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
TEST_NOTIFICATION_CHANNEL_NAME,
TEST_NOTIFICATION_CHANNEL_DESC);
testReceiver1.postNotification(TEST_NOTIFICATION_ID_1,
buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
TEST_NOTIFICATION_TEXT_1));
expectedStatsForId1.put(TEST_APP_PKG, new BroadcastResponseStats(TEST_APP_PKG,
TEST_RESPONSE_STATS_ID_1));
expectedStatsForId1.get(TEST_APP_PKG).incrementBroadcastsDispatchedCount(1);
expectedStatsForId1.get(TEST_APP_PKG).incrementNotificationsPostedCount(1);
assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStatsForId1);
assertResponseStats(TEST_RESPONSE_STATS_ID_2, expectedStatsForId2);
mUsageStatsManager.clearBroadcastEvents();
// Trigger a notification from test-pkg4 and verify notification-posted count gets
// incremented.
testReceiver4.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
TEST_NOTIFICATION_CHANNEL_NAME,
TEST_NOTIFICATION_CHANNEL_DESC);
testReceiver4.postNotification(TEST_NOTIFICATION_ID_1,
buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
TEST_NOTIFICATION_TEXT_1));
sendBroadcastAndWaitForReceipt(intent4, options2.toBundle());
expectedStatsForId2.put(TEST_APP4_PKG, new BroadcastResponseStats(TEST_APP4_PKG,
TEST_RESPONSE_STATS_ID_2));
expectedStatsForId2.get(TEST_APP4_PKG).incrementBroadcastsDispatchedCount(1);
testReceiver3.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
TEST_NOTIFICATION_CHANNEL_NAME,
TEST_NOTIFICATION_CHANNEL_DESC);
testReceiver3.postNotification(TEST_NOTIFICATION_ID_1,
buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
TEST_NOTIFICATION_TEXT_1));
testReceiver4.cancelNotification(TEST_NOTIFICATION_ID_1);
expectedStatsForId2.get(TEST_APP4_PKG).incrementNotificationsCancelledCount(1);
assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStatsForId1);
assertResponseStats(TEST_RESPONSE_STATS_ID_2, expectedStatsForId2);
mUsageStatsManager.clearBroadcastResponseStats(null, TEST_RESPONSE_STATS_ID_1);
expectedStatsForId1.clear();
assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStatsForId1);
assertResponseStats(TEST_RESPONSE_STATS_ID_2, expectedStatsForId2);
testReceiver1.cancelAll();
testReceiver3.cancelAll();
testReceiver4.cancelAll();
} finally {
connection1.unbind();
connection3.unbind();
connection4.unbind();
}
}
@AppModeFull(reason = "No broadcast message response stats in instant apps")
@Test
public void testBroadcastResponseStats_clearCounts_multiplePackages() throws Exception {
final ArrayMap<String, BroadcastResponseStats> expectedStatsForId1 = new ArrayMap<>();
final ArrayMap<String, BroadcastResponseStats> expectedStatsForId2 = new ArrayMap<>();
// Initially all the counts should be empty
assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStatsForId1);
assertResponseStats(TEST_RESPONSE_STATS_ID_2, expectedStatsForId2);
final TestServiceConnection connection1 = bindToTestServiceAndGetConnection(TEST_APP_PKG);
final TestServiceConnection connection3 = bindToTestServiceAndGetConnection(TEST_APP3_PKG);
try {
ITestReceiver testReceiver1 = connection1.getITestReceiver();
ITestReceiver testReceiver3 = connection3.getITestReceiver();
testReceiver1.cancelAll();
testReceiver3.cancelAll();
final Intent intent = new Intent().setComponent(new ComponentName(
TEST_APP_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
final Intent intent3 = new Intent().setComponent(new ComponentName(
TEST_APP3_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
final BroadcastOptions options1 = BroadcastOptions.makeBasic();
options1.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_1);
final BroadcastOptions options2 = BroadcastOptions.makeBasic();
options2.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_2);
testReceiver1.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
TEST_NOTIFICATION_CHANNEL_NAME,
TEST_NOTIFICATION_CHANNEL_DESC);
testReceiver3.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
TEST_NOTIFICATION_CHANNEL_NAME,
TEST_NOTIFICATION_CHANNEL_DESC);
// Send a broadcast to test-pkg1 with a request to record response and verify
// broadcast-sent count gets incremented.
sendBroadcastAndWaitForReceipt(intent, options1.toBundle());
sendBroadcastAndWaitForReceipt(intent3, options1.toBundle());
testReceiver1.postNotification(TEST_NOTIFICATION_ID_1,
buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
TEST_NOTIFICATION_TEXT_1));
testReceiver3.postNotification(TEST_NOTIFICATION_ID_1,
buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
TEST_NOTIFICATION_TEXT_1));
expectedStatsForId1.put(TEST_APP_PKG, new BroadcastResponseStats(TEST_APP_PKG,
TEST_RESPONSE_STATS_ID_1));
expectedStatsForId1.put(TEST_APP3_PKG, new BroadcastResponseStats(TEST_APP3_PKG,
TEST_RESPONSE_STATS_ID_1));
expectedStatsForId1.get(TEST_APP_PKG).incrementBroadcastsDispatchedCount(1);
expectedStatsForId1.get(TEST_APP_PKG).incrementNotificationsPostedCount(1);
expectedStatsForId1.get(TEST_APP3_PKG).incrementBroadcastsDispatchedCount(1);
expectedStatsForId1.get(TEST_APP3_PKG).incrementNotificationsPostedCount(1);
assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStatsForId1);
assertResponseStats(TEST_RESPONSE_STATS_ID_2, expectedStatsForId2);
sendBroadcastAndWaitForReceipt(intent, options1.toBundle());
sendBroadcastAndWaitForReceipt(intent3, options2.toBundle());
testReceiver1.postNotification(TEST_NOTIFICATION_ID_1,
buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
TEST_NOTIFICATION_TEXT_2));
testReceiver3.cancelNotification(TEST_NOTIFICATION_ID_1);
expectedStatsForId1.get(TEST_APP_PKG).incrementBroadcastsDispatchedCount(1);
expectedStatsForId1.get(TEST_APP_PKG).incrementNotificationsUpdatedCount(1);
expectedStatsForId2.put(TEST_APP3_PKG, new BroadcastResponseStats(TEST_APP3_PKG,
TEST_RESPONSE_STATS_ID_2));
expectedStatsForId2.get(TEST_APP3_PKG).incrementBroadcastsDispatchedCount(1);
expectedStatsForId2.get(TEST_APP3_PKG).incrementNotificationsCancelledCount(1);
assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStatsForId1);
assertResponseStats(TEST_RESPONSE_STATS_ID_2, expectedStatsForId2);
mUsageStatsManager.clearBroadcastResponseStats(null /* packageName */,
TEST_RESPONSE_STATS_ID_1);
expectedStatsForId1.clear();
assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStatsForId1);
assertResponseStats(TEST_RESPONSE_STATS_ID_2, expectedStatsForId2);
mUsageStatsManager.clearBroadcastResponseStats(null /* packageName */,
TEST_RESPONSE_STATS_ID_2);
expectedStatsForId2.clear();
assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStatsForId1);
assertResponseStats(TEST_RESPONSE_STATS_ID_2, expectedStatsForId2);
testReceiver1.cancelAll();
testReceiver3.cancelAll();
} finally {
connection1.unbind();
connection3.unbind();
}
}
@AppModeFull(reason = "No broadcast message response stats in instant apps")
@Test
public void testBroadcastResponseStats_clearCounts_multipleIds() throws Exception {
final ArrayMap<String, BroadcastResponseStats> expectedStatsForId1 = new ArrayMap<>();
final ArrayMap<String, BroadcastResponseStats> expectedStatsForId2 = new ArrayMap<>();
// Initially all the counts should be empty
assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStatsForId1);
assertResponseStats(TEST_RESPONSE_STATS_ID_2, expectedStatsForId2);
final TestServiceConnection connection1 = bindToTestServiceAndGetConnection(TEST_APP_PKG);
final TestServiceConnection connection3 = bindToTestServiceAndGetConnection(TEST_APP3_PKG);
try {
ITestReceiver testReceiver1 = connection1.getITestReceiver();
ITestReceiver testReceiver3 = connection3.getITestReceiver();
testReceiver1.cancelAll();
testReceiver3.cancelAll();
final Intent intent = new Intent().setComponent(new ComponentName(
TEST_APP_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
final Intent intent3 = new Intent().setComponent(new ComponentName(
TEST_APP3_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
final BroadcastOptions options1 = BroadcastOptions.makeBasic();
options1.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_1);
final BroadcastOptions options2 = BroadcastOptions.makeBasic();
options2.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_2);
testReceiver1.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
TEST_NOTIFICATION_CHANNEL_NAME,
TEST_NOTIFICATION_CHANNEL_DESC);
testReceiver3.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
TEST_NOTIFICATION_CHANNEL_NAME,
TEST_NOTIFICATION_CHANNEL_DESC);
// Send a broadcast to test-pkg1 with a request to record response and verify
// broadcast-sent count gets incremented.
sendBroadcastAndWaitForReceipt(intent, options1.toBundle());
sendBroadcastAndWaitForReceipt(intent3, options1.toBundle());
testReceiver1.postNotification(TEST_NOTIFICATION_ID_1,
buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
TEST_NOTIFICATION_TEXT_1));
testReceiver3.postNotification(TEST_NOTIFICATION_ID_1,
buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
TEST_NOTIFICATION_TEXT_1));
expectedStatsForId1.put(TEST_APP_PKG, new BroadcastResponseStats(TEST_APP_PKG,
TEST_RESPONSE_STATS_ID_1));
expectedStatsForId1.put(TEST_APP3_PKG, new BroadcastResponseStats(TEST_APP3_PKG,
TEST_RESPONSE_STATS_ID_1));
expectedStatsForId1.get(TEST_APP_PKG).incrementBroadcastsDispatchedCount(1);
expectedStatsForId1.get(TEST_APP_PKG).incrementNotificationsPostedCount(1);
expectedStatsForId1.get(TEST_APP3_PKG).incrementBroadcastsDispatchedCount(1);
expectedStatsForId1.get(TEST_APP3_PKG).incrementNotificationsPostedCount(1);
assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStatsForId1);
assertResponseStats(TEST_RESPONSE_STATS_ID_2, expectedStatsForId2);
sendBroadcastAndWaitForReceipt(intent, options1.toBundle());
sendBroadcastAndWaitForReceipt(intent3, options2.toBundle());
testReceiver1.postNotification(TEST_NOTIFICATION_ID_1,
buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
TEST_NOTIFICATION_TEXT_2));
testReceiver3.cancelNotification(TEST_NOTIFICATION_ID_1);
expectedStatsForId1.get(TEST_APP_PKG).incrementBroadcastsDispatchedCount(1);
expectedStatsForId1.get(TEST_APP_PKG).incrementNotificationsUpdatedCount(1);
expectedStatsForId2.put(TEST_APP3_PKG, new BroadcastResponseStats(TEST_APP3_PKG,
TEST_RESPONSE_STATS_ID_2));
expectedStatsForId2.get(TEST_APP3_PKG).incrementBroadcastsDispatchedCount(1);
expectedStatsForId2.get(TEST_APP3_PKG).incrementNotificationsCancelledCount(1);
assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStatsForId1);
assertResponseStats(TEST_RESPONSE_STATS_ID_2, expectedStatsForId2);
mUsageStatsManager.clearBroadcastResponseStats(TEST_APP_PKG, 0 /* id */);
expectedStatsForId1.remove(TEST_APP_PKG);
expectedStatsForId2.remove(TEST_APP_PKG);
assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStatsForId1);
assertResponseStats(TEST_RESPONSE_STATS_ID_2, expectedStatsForId2);
mUsageStatsManager.clearBroadcastResponseStats(TEST_APP3_PKG, 0 /* id */);
expectedStatsForId1.remove(TEST_APP3_PKG);
expectedStatsForId2.remove(TEST_APP3_PKG);
assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStatsForId1);
assertResponseStats(TEST_RESPONSE_STATS_ID_2, expectedStatsForId2);
testReceiver1.cancelAll();
testReceiver3.cancelAll();
} finally {
connection1.unbind();
connection3.unbind();
}
}
@AppModeFull(reason = "No broadcast message response stats in instant apps")
@Test
public void testBroadcastResponseStats_clearAllCounts() throws Exception {
final ArrayMap<String, BroadcastResponseStats> expectedStatsForId1 = new ArrayMap<>();
final ArrayMap<String, BroadcastResponseStats> expectedStatsForId2 = new ArrayMap<>();
// Initially all the counts should be empty
assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStatsForId1);
assertResponseStats(TEST_RESPONSE_STATS_ID_2, expectedStatsForId2);
final TestServiceConnection connection1 = bindToTestServiceAndGetConnection(TEST_APP_PKG);
final TestServiceConnection connection3 = bindToTestServiceAndGetConnection(TEST_APP3_PKG);
try {
ITestReceiver testReceiver1 = connection1.getITestReceiver();
ITestReceiver testReceiver3 = connection3.getITestReceiver();
testReceiver1.cancelAll();
testReceiver3.cancelAll();
final Intent intent = new Intent().setComponent(new ComponentName(
TEST_APP_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
final Intent intent3 = new Intent().setComponent(new ComponentName(
TEST_APP3_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
final BroadcastOptions options1 = BroadcastOptions.makeBasic();
options1.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_1);
final BroadcastOptions options2 = BroadcastOptions.makeBasic();
options2.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_2);
testReceiver1.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
TEST_NOTIFICATION_CHANNEL_NAME,
TEST_NOTIFICATION_CHANNEL_DESC);
testReceiver3.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
TEST_NOTIFICATION_CHANNEL_NAME,
TEST_NOTIFICATION_CHANNEL_DESC);
// Send a broadcast to test-pkg1 with a request to record response and verify
// broadcast-sent count gets incremented.
sendBroadcastAndWaitForReceipt(intent, options1.toBundle());
sendBroadcastAndWaitForReceipt(intent3, options1.toBundle());
testReceiver1.postNotification(TEST_NOTIFICATION_ID_1,
buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
TEST_NOTIFICATION_TEXT_1));
testReceiver3.postNotification(TEST_NOTIFICATION_ID_1,
buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
TEST_NOTIFICATION_TEXT_1));
expectedStatsForId1.put(TEST_APP_PKG, new BroadcastResponseStats(TEST_APP_PKG,
TEST_RESPONSE_STATS_ID_1));
expectedStatsForId1.put(TEST_APP3_PKG, new BroadcastResponseStats(TEST_APP3_PKG,
TEST_RESPONSE_STATS_ID_1));
expectedStatsForId1.get(TEST_APP_PKG).incrementBroadcastsDispatchedCount(1);
expectedStatsForId1.get(TEST_APP_PKG).incrementNotificationsPostedCount(1);
expectedStatsForId1.get(TEST_APP3_PKG).incrementBroadcastsDispatchedCount(1);
expectedStatsForId1.get(TEST_APP3_PKG).incrementNotificationsPostedCount(1);
assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStatsForId1);
assertResponseStats(TEST_RESPONSE_STATS_ID_2, expectedStatsForId2);
sendBroadcastAndWaitForReceipt(intent, options1.toBundle());
sendBroadcastAndWaitForReceipt(intent3, options2.toBundle());
testReceiver1.postNotification(TEST_NOTIFICATION_ID_1,
buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
TEST_NOTIFICATION_TEXT_2));
testReceiver3.cancelNotification(TEST_NOTIFICATION_ID_1);
expectedStatsForId1.get(TEST_APP_PKG).incrementBroadcastsDispatchedCount(1);
expectedStatsForId1.get(TEST_APP_PKG).incrementNotificationsUpdatedCount(1);
expectedStatsForId2.put(TEST_APP3_PKG, new BroadcastResponseStats(TEST_APP3_PKG,
TEST_RESPONSE_STATS_ID_2));
expectedStatsForId2.get(TEST_APP3_PKG).incrementBroadcastsDispatchedCount(1);
expectedStatsForId2.get(TEST_APP3_PKG).incrementNotificationsCancelledCount(1);
assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStatsForId1);
assertResponseStats(TEST_RESPONSE_STATS_ID_2, expectedStatsForId2);
mUsageStatsManager.clearBroadcastResponseStats(null /* packageName */, 0 /* id */);
expectedStatsForId1.clear();
expectedStatsForId2.clear();
assertResponseStats(TEST_RESPONSE_STATS_ID_1, expectedStatsForId1);
assertResponseStats(TEST_RESPONSE_STATS_ID_2, expectedStatsForId2);
testReceiver1.cancelAll();
testReceiver3.cancelAll();
} finally {
connection1.unbind();
connection3.unbind();
}
}
@AppModeFull(reason = "No broadcast message response stats in instant apps")
@Test
public void testBroadcastResponseStats_mediaNotification() throws Exception {
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
final TestServiceConnection connection = bindToTestServiceAndGetConnection();
try {
ITestReceiver testReceiver = connection.getITestReceiver();
testReceiver.cancelAll();
// Send a broadcast with a request to record response and verify broadcast-sent
// count gets incremented.
final BroadcastOptions options = BroadcastOptions.makeBasic();
options.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_1);
final Intent intent = new Intent().setComponent(new ComponentName(
TEST_APP_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
sendBroadcastAndWaitForReceipt(intent, options.toBundle());
testReceiver.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
TEST_NOTIFICATION_CHANNEL_NAME,
TEST_NOTIFICATION_CHANNEL_DESC);
testReceiver.postNotification(TEST_NOTIFICATION_ID_1,
buildMediaNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
TEST_NOTIFICATION_TEXT_1));
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
1 /* broadcastCount */,
1 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
testReceiver.cancelAll();
} finally {
connection.unbind();
}
}
@AppModeFull(reason = "No broadcast message response stats in instant apps")
@MediumTest
@Test
public void testBroadcastResponseStats_broadcastSession() throws Exception {
final long broadcastSessionDurationMs = TimeUnit.MINUTES.toMillis(1);
final long broadcastResponseWindowDurationMs = TimeUnit.MINUTES.toMillis(1);
try (DeviceConfigStateHelper deviceConfigStateHelper =
new DeviceConfigStateHelper(NAMESPACE_APP_STANDBY)) {
updateFlagWithDelay(deviceConfigStateHelper,
KEY_BROADCAST_SESSIONS_DURATION_MS,
String.valueOf(broadcastSessionDurationMs));
updateFlagWithDelay(deviceConfigStateHelper,
KEY_BROADCAST_RESPONSE_WINDOW_DURATION_MS,
String.valueOf(broadcastResponseWindowDurationMs));
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
final TestServiceConnection connection = bindToTestServiceAndGetConnection();
try {
ITestReceiver testReceiver = connection.getITestReceiver();
testReceiver.cancelAll();
// Send a broadcast with a request to record response and verify broadcast-sent
// count gets incremented.
final Intent intent = new Intent().setComponent(new ComponentName(
TEST_APP_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
final BroadcastOptions options = BroadcastOptions.makeBasic();
options.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_1);
sendBroadcastAndWaitForReceipt(intent, options.toBundle());
// Send the broadcast again multiple times
sendBroadcastAndWaitForReceipt(intent, options.toBundle());
sendBroadcastAndWaitForReceipt(intent, options.toBundle());
// Now wait for a while and send the broadcast again.
SystemClock.sleep(broadcastSessionDurationMs);
sendBroadcastAndWaitForReceipt(intent, options.toBundle());
// Now wait until the broadcast response duration is elapsed and send the
// broadcast again.
SystemClock.sleep(broadcastResponseWindowDurationMs);
sendBroadcastAndWaitForReceipt(intent, options.toBundle());
// Verify that total broadcasts are considered as only 2 even though they
// are dispatched multiple times.
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
2 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
} finally {
connection.unbind();
}
}
}
@AppModeFull(reason = "No broadcast message response stats in instant apps")
@MediumTest
@Test
public void testBroadcastResponseStats_broadcastSession_withLateNotification()
throws Exception {
final long broadcastSessionDurationMs = TimeUnit.MINUTES.toMillis(1);
final long broadcastResponseWindowDurationMs = TimeUnit.MINUTES.toMillis(1);
try (DeviceConfigStateHelper deviceConfigStateHelper =
new DeviceConfigStateHelper(NAMESPACE_APP_STANDBY)) {
updateFlagWithDelay(deviceConfigStateHelper,
KEY_BROADCAST_SESSIONS_DURATION_MS,
String.valueOf(broadcastSessionDurationMs));
updateFlagWithDelay(deviceConfigStateHelper,
KEY_BROADCAST_RESPONSE_WINDOW_DURATION_MS,
String.valueOf(broadcastResponseWindowDurationMs));
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
final TestServiceConnection connection = bindToTestServiceAndGetConnection();
try {
ITestReceiver testReceiver = connection.getITestReceiver();
testReceiver.cancelAll();
// Send a broadcast with a request to record response and verify broadcast-sent
// count gets incremented.
final Intent intent = new Intent().setComponent(new ComponentName(
TEST_APP_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
final BroadcastOptions options = BroadcastOptions.makeBasic();
options.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_1);
sendBroadcastAndWaitForReceipt(intent, options.toBundle());
// Send the broadcast again multiple times
sendBroadcastAndWaitForReceipt(intent, options.toBundle());
sendBroadcastAndWaitForReceipt(intent, options.toBundle());
// Now wait for a while and send the broadcast again.
SystemClock.sleep(broadcastSessionDurationMs);
sendBroadcastAndWaitForReceipt(intent, options.toBundle());
// Now wait until the broadcast response duration is elapsed and post a
// notification.
SystemClock.sleep(broadcastResponseWindowDurationMs);
testReceiver.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
TEST_NOTIFICATION_CHANNEL_NAME,
TEST_NOTIFICATION_CHANNEL_DESC);
testReceiver.postNotification(TEST_NOTIFICATION_ID_1,
buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
TEST_NOTIFICATION_TEXT_1));
// Verify that total broadcasts are considered as only 2 even though they
// are dispatched multiple times and the posted notification doesn't get counted.
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
2 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
} finally {
connection.unbind();
}
}
}
@AppModeFull(reason = "No broadcast message response stats in instant apps")
@MediumTest
@Test
public void testBroadcastResponseStats_broadcastSessionWithResponse() throws Exception {
final long broadcastSessionWithResponseDurationMs = TimeUnit.MINUTES.toMillis(1);
final long broadcastResponseWindowDurationMs = TimeUnit.MINUTES.toMillis(4);
try (DeviceConfigStateHelper deviceConfigStateHelper =
new DeviceConfigStateHelper(NAMESPACE_APP_STANDBY)) {
updateFlagWithDelay(deviceConfigStateHelper,
KEY_BROADCAST_SESSIONS_WITH_RESPONSE_DURATION_MS,
String.valueOf(broadcastSessionWithResponseDurationMs));
updateFlagWithDelay(deviceConfigStateHelper,
KEY_BROADCAST_RESPONSE_WINDOW_DURATION_MS,
String.valueOf(broadcastResponseWindowDurationMs));
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
final TestServiceConnection connection = bindToTestServiceAndGetConnection();
try {
ITestReceiver testReceiver = connection.getITestReceiver();
testReceiver.cancelAll();
// Send a broadcast with a request to record response and verify broadcast-sent
// count gets incremented.
final Intent intent = new Intent().setComponent(new ComponentName(
TEST_APP_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
final BroadcastOptions options = BroadcastOptions.makeBasic();
options.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_1);
sendBroadcastAndWaitForReceipt(intent, options.toBundle());
// Send the broadcast again multiple times
sendBroadcastAndWaitForReceipt(intent, options.toBundle());
sendBroadcastAndWaitForReceipt(intent, options.toBundle());
// Now wait for a while and send the broadcast again.
SystemClock.sleep(broadcastSessionWithResponseDurationMs);
sendBroadcastAndWaitForReceipt(intent, options.toBundle());
// Repeat the previous step - wait for a while and send the broadcast again.
SystemClock.sleep(broadcastSessionWithResponseDurationMs);
sendBroadcastAndWaitForReceipt(intent, options.toBundle());
// Trigger a notification from test app and verify notification-posted count gets
// incremented.
testReceiver.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
TEST_NOTIFICATION_CHANNEL_NAME,
TEST_NOTIFICATION_CHANNEL_DESC);
testReceiver.postNotification(TEST_NOTIFICATION_ID_1,
buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
TEST_NOTIFICATION_TEXT_1));
// Verify that total broadcasts are considered as only 2 even though they
// are dispatched multiple times.
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
3 /* broadcastCount */,
3 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
} finally {
connection.unbind();
}
}
}
@AppModeFull(reason = "No broadcast message response stats in instant apps")
@MediumTest
@Test
public void testBroadcastResponseStats_broadcastSessionWithResponse_recordOnlyOne()
throws Exception {
final long broadcastSessionDurationMs = TimeUnit.SECONDS.toMillis(30);
final long broadcastSessionWithResponseDurationMs = broadcastSessionDurationMs;
final long broadcastResponseWindowDurationMs = TimeUnit.MINUTES.toMillis(2);
try (DeviceConfigStateHelper deviceConfigStateHelper =
new DeviceConfigStateHelper(NAMESPACE_APP_STANDBY)) {
updateFlagWithDelay(deviceConfigStateHelper,
KEY_BROADCAST_SESSIONS_DURATION_MS,
String.valueOf(broadcastSessionDurationMs));
updateFlagWithDelay(deviceConfigStateHelper,
KEY_BROADCAST_SESSIONS_WITH_RESPONSE_DURATION_MS,
String.valueOf(broadcastSessionWithResponseDurationMs));
updateFlagWithDelay(deviceConfigStateHelper,
KEY_BROADCAST_RESPONSE_WINDOW_DURATION_MS,
String.valueOf(broadcastResponseWindowDurationMs));
updateFlagWithDelay(deviceConfigStateHelper,
KEY_NOTE_RESPONSE_EVENT_FOR_ALL_BROADCAST_SESSIONS,
String.valueOf(false));
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
final TestServiceConnection connection = bindToTestServiceAndGetConnection();
try {
ITestReceiver testReceiver = connection.getITestReceiver();
testReceiver.cancelAll();
// Send a broadcast with a request to record response and verify broadcast-sent
// count gets incremented.
final Intent intent = new Intent().setComponent(new ComponentName(
TEST_APP_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
final BroadcastOptions options = BroadcastOptions.makeBasic();
options.recordResponseEventWhileInBackground(TEST_RESPONSE_STATS_ID_1);
sendBroadcastAndWaitForReceipt(intent, options.toBundle());
// Send the broadcast again multiple times
sendBroadcastAndWaitForReceipt(intent, options.toBundle());
sendBroadcastAndWaitForReceipt(intent, options.toBundle());
// Now wait for a while and send the broadcast again.
SystemClock.sleep(broadcastSessionWithResponseDurationMs);
sendBroadcastAndWaitForReceipt(intent, options.toBundle());
// Repeat the previous step - wait for a while and send the broadcast again.
SystemClock.sleep(broadcastSessionWithResponseDurationMs);
sendBroadcastAndWaitForReceipt(intent, options.toBundle());
// Trigger a notification from test app and verify notification-posted count gets
// incremented.
testReceiver.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
TEST_NOTIFICATION_CHANNEL_NAME,
TEST_NOTIFICATION_CHANNEL_DESC);
testReceiver.postNotification(TEST_NOTIFICATION_ID_1,
buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
TEST_NOTIFICATION_TEXT_1));
// Verify that total broadcasts are considered as only 2 even though they
// are dispatched multiple times.
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
1 /* broadcastCount */,
1 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
// Wait until the broadcast response window duration is elapsed and verify that
// previously sent broadcasts are recorded correctly.
SystemClock.sleep(broadcastResponseWindowDurationMs);
testReceiver.cancelNotification(TEST_NOTIFICATION_ID_1);
// Verify that total broadcasts are considered as only 2 even though they
// are dispatched multiple times.
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_1,
3 /* broadcastCount */,
1 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
assertResponseStats(TEST_APP_PKG, TEST_RESPONSE_STATS_ID_2,
0 /* broadcastCount */,
0 /* notificationPostedCount */,
0 /* notificationUpdatedCount */,
0 /* notificationCancelledCount */);
} finally {
connection.unbind();
}
}
}
private void updateFlagWithDelay(DeviceConfigStateHelper deviceConfigStateHelper,
String key, String value) {
deviceConfigStateHelper.set(key, value);
SystemUtil.runWithShellPermissionIdentity(() -> {
final String actualValue = PollingCheck.waitFor(DEFAULT_TIMEOUT_MS,
() -> mUsageStatsManager.getAppStandbyConstant(key),
result -> value.equals(result));
assertEquals("Error changing the value of " + key, value, actualValue);
});
}
private Notification buildNotification(String channelId, int notificationId,
String notificationText) {
return new Notification.Builder(sContext, channelId)
.setSmallIcon(android.R.drawable.ic_info)
.setContentTitle(String.format(TEST_NOTIFICATION_TITLE_FMT, notificationId))
.setContentText(notificationText)
.build();
}
private Notification buildMediaNotification(String channelId, int notificationId,
String notificationText) {
final PendingIntent pendingIntent = PendingIntent.getActivity(sContext,
0 /* requestCode */, new Intent(sContext, this.getClass()),
PendingIntent.FLAG_IMMUTABLE);
final MediaSession session = new MediaSession(sContext, "test_media");
return new Notification.Builder(sContext, channelId)
.setSmallIcon(android.R.drawable.ic_menu_day)
.setContentTitle(String.format(TEST_NOTIFICATION_TITLE_FMT, notificationId))
.setContentText(notificationText)
.addAction(new Notification.Action.Builder(
Icon.createWithResource(sContext, android.R.drawable.ic_media_previous),
"previous", pendingIntent).build())
.addAction(new Notification.Action.Builder(
Icon.createWithResource(sContext, android.R.drawable.ic_media_play),
"play", pendingIntent).build())
.addAction(new Notification.Action.Builder(
Icon.createWithResource(sContext, android.R.drawable.ic_media_next),
"next", pendingIntent).build())
.setStyle(new Notification.MediaStyle()
.setShowActionsInCompactView(0, 1, 2)
.setMediaSession(session.getSessionToken()))
.build();
}
private void sendBroadcastAndWaitForReceipt(Intent intent, Bundle options)
throws Exception {
final CountDownLatch latch = new CountDownLatch(1);
intent.putExtra(EXTRA_REMOTE_CALLBACK, new RemoteCallback(result -> latch.countDown()));
sContext.sendBroadcast(intent, null /* receiverPermission */, options);
if (!latch.await(DEFAULT_TIMEOUT_MS, TimeUnit.SECONDS)) {
fail("Timed out waiting for the test app to receive the broadcast");
}
}
private void assertResponseStats(String packageName, long id, int... expectedCounts) {
final BroadcastResponseStats expectedStats = new BroadcastResponseStats(packageName, id);
expectedStats.incrementBroadcastsDispatchedCount(expectedCounts[0]);
expectedStats.incrementNotificationsPostedCount(expectedCounts[1]);
expectedStats.incrementNotificationsUpdatedCount(expectedCounts[2]);
expectedStats.incrementNotificationsCancelledCount(expectedCounts[3]);
assertResponseStats(packageName, id, expectedStats);
}
private void assertResponseStats(String packageName, long id,
BroadcastResponseStats expectedStats) {
List<BroadcastResponseStats> actualStats = mUsageStatsManager
.queryBroadcastResponseStats(packageName, id);
if (compareStats(expectedStats, actualStats)) {
SystemClock.sleep(WAIT_TIME_FOR_NEGATIVE_TESTS_MS);
}
actualStats = PollingCheck.waitFor(DEFAULT_TIMEOUT_MS,
() -> mUsageStatsManager.queryBroadcastResponseStats(packageName, id),
result -> compareStats(expectedStats, result));
actualStats.sort(Comparator.comparing(BroadcastResponseStats::getPackageName));
final String errorMsg = String.format("\nEXPECTED(%d)=%s\nACTUAL(%d)=%s\n",
1, expectedStats,
actualStats.size(), Arrays.toString(actualStats.toArray()));
assertTrue(errorMsg, compareStats(expectedStats, actualStats));
}
private void assertResponseStats(long id,
ArrayMap<String, BroadcastResponseStats> expectedStats) {
// TODO: Call into the above assertResponseStats() method instead of duplicating
// the logic.
List<BroadcastResponseStats> actualStats = mUsageStatsManager
.queryBroadcastResponseStats(null /* packageName */, id);
if (compareStats(expectedStats, actualStats)) {
SystemClock.sleep(WAIT_TIME_FOR_NEGATIVE_TESTS_MS);
}
actualStats = PollingCheck.waitFor(DEFAULT_TIMEOUT_MS,
() -> mUsageStatsManager.queryBroadcastResponseStats(null /* packageName */, id),
result -> compareStats(expectedStats, result));
actualStats.sort(Comparator.comparing(BroadcastResponseStats::getPackageName));
final String errorMsg = String.format("\nEXPECTED(%d)=%s\nACTUAL(%d)=%s\n",
expectedStats.size(), expectedStats,
actualStats.size(), Arrays.toString(actualStats.toArray()));
assertTrue(errorMsg, compareStats(expectedStats, actualStats));
}
private boolean compareStats(ArrayMap<String, BroadcastResponseStats> expectedStats,
List<BroadcastResponseStats> actualStats) {
if (expectedStats.size() != actualStats.size()) {
return false;
}
for (int i = 0; i < actualStats.size(); ++i) {
final BroadcastResponseStats actualPackageStats = actualStats.get(i);
final String packageName = actualPackageStats.getPackageName();
if (!actualPackageStats.equals(expectedStats.get(packageName))) {
return false;
}
}
return true;
}
private boolean compareStats(BroadcastResponseStats expectedStats,
List<BroadcastResponseStats> actualStats) {
if (actualStats.size() > 1) {
return false;
}
final BroadcastResponseStats stats = (actualStats == null || actualStats.isEmpty())
? new BroadcastResponseStats(expectedStats.getPackageName(), expectedStats.getId())
: actualStats.get(0);
return expectedStats.equals(stats);
}
private TestServiceConnection bindToTestServiceAndGetConnection(String packageName) {
final TestServiceConnection
connection = new TestServiceConnection(sContext);
final Intent intent = new Intent().setComponent(
new ComponentName(packageName, TEST_APP_CLASS_SERVICE));
sContext.bindService(intent, connection, Context.BIND_AUTO_CREATE);
return connection;
}
private TestServiceConnection bindToTestServiceAndGetConnection() throws Exception {
return bindToTestServiceAndGetConnection(TEST_APP_PKG);
}
private void launchTestActivityAndWaitToBeResumed(String pkgName, String className)
throws Exception {
// Make sure the screen is awake and unlocked. Otherwise, the app activity won't be resumed.
wakeUpAndDismissKeyguard();
final Intent intent = createTestActivityIntent(pkgName, className);
final CountDownLatch latch = new CountDownLatch(1);
intent.putExtra(EXTRA_REMOTE_CALLBACK, new RemoteCallback(result -> latch.countDown()));
sContext.startActivity(intent);
if (!latch.await(DEFAULT_TIMEOUT_MS, TimeUnit.SECONDS)) {
fail("Timed out waiting for the test app activity to be resumed");
}
}
private void wakeUpAndDismissKeyguard() throws Exception {
mUiDevice.wakeUp();
SystemUtil.runShellCommand("wm dismiss-keyguard");
}
private Intent createTestActivityIntent(String pkgName, String className) {
final Intent intent = new Intent();
intent.setClassName(pkgName, className);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
return intent;
}
}