blob: 0a2021bc21e508438f02d4283ce1b231a9756522 [file] [log] [blame]
/*
* Copyright (C) 2018 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.notification.legacy29.cts;
import static android.Manifest.permission.POST_NOTIFICATIONS;
import static android.Manifest.permission.REVOKE_POST_NOTIFICATIONS_WITHOUT_KILL;
import static android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS;
import static android.app.NotificationManager.Policy.CONVERSATION_SENDERS_ANYONE;
import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_CONVERSATIONS;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertTrue;
import static junit.framework.TestCase.assertNotNull;
import static junit.framework.TestCase.assertNull;
import android.app.Instrumentation;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.UiAutomation;
import android.content.Context;
import android.content.Intent;
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.permission.PermissionManager;
import android.permission.cts.PermissionUtils;
import android.service.notification.StatusBarNotification;
import android.util.Log;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
import com.android.compatibility.common.util.SystemUtil;
import junit.framework.Assert;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* Home for tests that need to verify behavior for apps that target old sdk versions.
*/
@RunWith(AndroidJUnit4.class)
public class NotificationManager29Test {
final String TAG = "LegacyNoManTest29";
final String NOTIFICATION_CHANNEL_ID = "LegacyNoManTest29";
private NotificationManager mNotificationManager;
private Context mContext;
@Before
public void setUp() throws Exception {
mContext = InstrumentationRegistry.getContext();
PermissionUtils.grantPermission(mContext.getPackageName(), POST_NOTIFICATIONS);
mNotificationManager = (NotificationManager) mContext.getSystemService(
Context.NOTIFICATION_SERVICE);
mNotificationManager.createNotificationChannel(new NotificationChannel(
NOTIFICATION_CHANNEL_ID, "name", NotificationManager.IMPORTANCE_DEFAULT));
}
@After
public void tearDown() throws Exception {
// Use test API to prevent PermissionManager from killing the test process when revoking
// permission.
SystemUtil.runWithShellPermissionIdentity(
() -> mContext.getSystemService(PermissionManager.class)
.revokePostNotificationPermissionWithoutKillForTest(
mContext.getPackageName(),
Process.myUserHandle().getIdentifier()),
REVOKE_POST_NOTIFICATIONS_WITHOUT_KILL,
REVOKE_RUNTIME_PERMISSIONS);
}
private void toggleNotificationPolicyAccess(String packageName,
Instrumentation instrumentation, boolean on) throws IOException {
String command = " cmd notification"
+ " " + (on ? "allow_dnd" : "disallow_dnd")
+ " " + packageName
+ " " + mContext.getUserId();
runCommand(command, instrumentation);
NotificationManager nm = mContext.getSystemService(NotificationManager.class);
Assert.assertEquals("Notification Policy Access Grant is " +
nm.isNotificationPolicyAccessGranted() + " not " + on, on,
nm.isNotificationPolicyAccessGranted());
}
private void runCommand(String command, Instrumentation instrumentation) throws IOException {
UiAutomation uiAutomation = instrumentation.getUiAutomation();
// Execute command
try (ParcelFileDescriptor fd = uiAutomation.executeShellCommand(command)) {
Assert.assertNotNull("Failed to execute shell command: " + command, fd);
// Wait for the command to finish by reading until EOF
try (InputStream in = new FileInputStream(fd.getFileDescriptor())) {
byte[] buffer = new byte[4096];
while (in.read(buffer) > 0) {}
} catch (IOException e) {
throw new IOException("Could not read stdout of command: " + command, e);
}
} finally {
uiAutomation.destroy();
}
}
private StatusBarNotification findPostedNotification(int id) {
// notification is a bit asynchronous so it may take a few ms to appear in
// getActiveNotifications()
// we will check for it for up to 500ms before giving up
StatusBarNotification n = null;
for (int tries = 5; tries--> 0;) {
final StatusBarNotification[] sbns = mNotificationManager.getActiveNotifications();
for (StatusBarNotification sbn : sbns) {
Log.d(TAG, "Found " + sbn.getKey());
if (sbn.getId() == id) {
n = sbn;
break;
}
}
if (n != null) break;
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
// pass
}
}
return n;
}
private PendingIntent getPendingIntent() {
return PendingIntent.getActivity(
mContext, 0, new Intent(mContext, this.getClass()), PendingIntent.FLAG_MUTABLE_UNAUDITED);
}
@Test
public void testPostFullScreenIntent_noPermission() {
// no permission? no full screen intent
int id = 6000;
final Notification notification =
new Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID)
.setSmallIcon(android.R.id.icon)
.setWhen(System.currentTimeMillis())
.setFullScreenIntent(getPendingIntent(), true)
.setContentText("This is #FSI notification")
.setContentIntent(getPendingIntent())
.build();
mNotificationManager.notify(id, notification);
StatusBarNotification n = findPostedNotification(id);
assertNotNull(n);
assertNull(n.getNotification().fullScreenIntent);
}
@Test
public void testApi29CannotToggleConversationsTest() throws Exception {
toggleNotificationPolicyAccess(mContext.getPackageName(),
InstrumentationRegistry.getInstrumentation(), true);
// Pre-30 cannot toggle conversations on
NotificationManager.Policy origPolicy = mNotificationManager.getNotificationPolicy();
if ((origPolicy.priorityCategories & PRIORITY_CATEGORY_CONVERSATIONS) != 0) {
return;
}
try {
mNotificationManager.setNotificationPolicy(new NotificationManager.Policy(
PRIORITY_CATEGORY_CONVERSATIONS, 0, 0, 0, CONVERSATION_SENDERS_ANYONE));
NotificationManager.Policy policy = mNotificationManager.getNotificationPolicy();
assertEquals(origPolicy.priorityConversationSenders,
policy.priorityConversationSenders);
assertTrue((policy.priorityCategories & PRIORITY_CATEGORY_CONVERSATIONS) == 0);
} finally {
mNotificationManager.setNotificationPolicy(origPolicy);
toggleNotificationPolicyAccess(mContext.getPackageName(),
InstrumentationRegistry.getInstrumentation(), false);
}
}
@Test
public void testApi29CannotToggleConversationsOffTest() throws Exception {
toggleNotificationPolicyAccess(mContext.getPackageName(),
InstrumentationRegistry.getInstrumentation(), true);
// Pre-30 cannot toggle conversations
NotificationManager.Policy origPolicy = mNotificationManager.getNotificationPolicy();
// can't test that we can't turn it off if it's not on in the first place
if ((origPolicy.priorityCategories & PRIORITY_CATEGORY_CONVERSATIONS) == 0) {
return;
}
try {
// attempt to toggle off conversations:
mNotificationManager.setNotificationPolicy(new NotificationManager.Policy(0, 0, 0));
NotificationManager.Policy policy = mNotificationManager.getNotificationPolicy();
assertTrue((policy.priorityCategories & PRIORITY_CATEGORY_CONVERSATIONS) != 0);
} finally {
mNotificationManager.setNotificationPolicy(origPolicy);
toggleNotificationPolicyAccess(mContext.getPackageName(),
InstrumentationRegistry.getInstrumentation(), false);
}
}
}