blob: d4cbae725be17e8baef9608fc91d38a7aa2c571e [file] [log] [blame]
/*
* Copyright (C) 2017 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 com.android.cts.managedprofile;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.UiAutomation;
import android.app.admin.DevicePolicyManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.uiautomator.UiDevice;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.util.Collections;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@SmallTest
public class NotificationListenerTest {
static final String TAG = "ListenerTest";
static final String ACTION_NOTIFICATION_POSTED = "notification_posted";
static final String ACTION_NOTIFICATION_REMOVED = "notification_removed";
static final String ACTION_LISTENER_CONNECTED = "listener_connected";
private static final String PARAM_PROFILE_ID = "profile-id";
static final String SENDER_COMPONENT =
"com.android.cts.managedprofiletests.notificationsender/.SendNotification";
private final LocalBroadcastReceiver mReceiver = new LocalBroadcastReceiver();
private Context mContext;
private DevicePolicyManager mDpm;
private NotificationManager mNotificationManager;
private UiDevice mDevice;
private int mProfileUserId;
private String mPreviousListeners;
private boolean mChangedListeners;
@Before
public void setUp() throws Exception {
mContext = InstrumentationRegistry.getTargetContext();
mDpm = mContext.getSystemService(DevicePolicyManager.class);
mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
mProfileUserId = getParam(InstrumentationRegistry.getArguments(), PARAM_PROFILE_ID);
IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_NOTIFICATION_POSTED);
filter.addAction(ACTION_NOTIFICATION_REMOVED);
filter.addAction(ACTION_LISTENER_CONNECTED);
LocalBroadcastManager.getInstance(mContext).registerReceiver(mReceiver, filter);
}
@After
public void tearDown() throws Exception {
LocalBroadcastManager.getInstance(mContext).unregisterReceiver(mReceiver);
if (mChangedListeners) {
if (mPreviousListeners != null) {
mDevice.executeShellCommand(
"settings put secure enabled_notification_listeners "
+ mPreviousListeners);
} else {
mDevice.executeShellCommand(
"settings delete secure enabled_notification_listeners");
}
}
}
@Test
public void testSetEmptyWhitelist() throws Exception {
mDpm.setPermittedCrossProfileNotificationListeners(
BaseManagedProfileTest.ADMIN_RECEIVER_COMPONENT,
Collections.<String>emptyList());
}
@Test
public void testAddListenerToWhitelist() throws Exception {
mDpm.setPermittedCrossProfileNotificationListeners(
BaseManagedProfileTest.ADMIN_RECEIVER_COMPONENT,
Collections.singletonList(mContext.getPackageName()));
}
@Test
public void testSetNullWhitelist() throws Exception {
mDpm.setPermittedCrossProfileNotificationListeners(
BaseManagedProfileTest.ADMIN_RECEIVER_COMPONENT, null);
}
@Test
public void testCanReceiveNotifications() throws Exception {
enableNotificationListener();
sendProfileNotification();
assertTrue(mReceiver.waitForNotificationPostedReceived());
cancelProfileNotification();
assertTrue(mReceiver.waitForNotificationRemovedReceived());
mReceiver.reset();
sendPersonalNotification();
assertTrue(mReceiver.waitForNotificationPostedReceived());
cancelPersonalNotification();
assertTrue(mReceiver.waitForNotificationRemovedReceived());
}
@Test
public void testCannotReceiveProfileNotifications() throws Exception {
enableNotificationListener();
sendProfileNotification();
// Don't see notification or cancellation from work profile.
assertFalse(mReceiver.waitForNotificationPostedReceived());
cancelProfileNotification();
assertFalse(mReceiver.waitForNotificationRemovedReceived());
mReceiver.reset();
// Do see the one from the personal side.
sendPersonalNotification();
assertTrue(mReceiver.waitForNotificationPostedReceived());
cancelPersonalNotification();
assertTrue(mReceiver.waitForNotificationRemovedReceived());
}
private void cancelProfileNotification() throws IOException {
mDevice.executeShellCommand(
"am start --user " + mProfileUserId + " -a CANCEL_NOTIFICATION -n "
+ SENDER_COMPONENT);
}
private void cancelPersonalNotification() throws IOException {
mDevice.executeShellCommand(
"am start -a CANCEL_NOTIFICATION -n "
+ SENDER_COMPONENT);
}
private void sendProfileNotification() throws IOException {
mDevice.executeShellCommand(
"am start --user " + mProfileUserId + " -a POST_NOTIFICATION -n "
+ SENDER_COMPONENT);
}
private void sendPersonalNotification() throws IOException {
mDevice.executeShellCommand(
"am start -a POST_NOTIFICATION -n "
+ SENDER_COMPONENT);
}
private void enableNotificationListener() throws Exception {
String listeners = mDevice.executeShellCommand(
"settings get secure enabled_notification_listeners").trim();
if (listeners.equals("null")) {
listeners = null;
}
String testListener = new ComponentName(
mContext, CrossProfileNotificationListenerService.class).flattenToString();
if (listeners == null || !listeners.contains(testListener)) {
mPreviousListeners = listeners;
mChangedListeners = true;
String newListeners;
if (listeners != null && listeners.length() > 0) {
newListeners = listeners + ":" + testListener;
} else {
newListeners = testListener;
}
mDevice.executeShellCommand(
"settings put secure enabled_notification_listeners "
+ newListeners);
Log.i(TAG, "Enabled notification listener " + testListener);
assertTrue(mReceiver.waitForListenerConnected());
}
}
private int getParam(Bundle arguments, String key) throws Exception {
String serial = arguments.getString(key);
if (serial == null) {
throw new IllegalArgumentException("Missing argument " + key);
}
return Integer.parseInt(serial);
}
static class LocalBroadcastReceiver extends BroadcastReceiver {
private static final int TIMEOUT_SECONDS = 10;
private CountDownLatch mNotificationPostedLatch = new CountDownLatch(1);
private CountDownLatch mNotificationRemovedLatch = new CountDownLatch(1);
private CountDownLatch mListenerConnectedLatch = new CountDownLatch(1);
public void reset() {
mNotificationPostedLatch = new CountDownLatch(1);
mNotificationRemovedLatch = new CountDownLatch(1);
mListenerConnectedLatch = new CountDownLatch(1);
}
@Override
public void onReceive(Context context, Intent intent) {
Log.i(TAG, "onReceive(" + intent + ")");
if (ACTION_NOTIFICATION_POSTED.equals(intent.getAction())) {
mNotificationPostedLatch.countDown();
} else if (ACTION_NOTIFICATION_REMOVED.equals(intent.getAction())) {
mNotificationRemovedLatch.countDown();
} else if (ACTION_LISTENER_CONNECTED.equals(intent.getAction())) {
mListenerConnectedLatch.countDown();
} else {
Log.e(TAG, "Received broadcast for unknown action: " + intent.getAction());
}
}
public boolean waitForNotificationPostedReceived() throws InterruptedException {
return mNotificationPostedLatch.await(TIMEOUT_SECONDS, TimeUnit.SECONDS);
}
public boolean waitForNotificationRemovedReceived() throws InterruptedException {
return mNotificationRemovedLatch.await(TIMEOUT_SECONDS, TimeUnit.SECONDS);
}
public boolean waitForListenerConnected() throws InterruptedException {
return mListenerConnectedLatch.await(TIMEOUT_SECONDS, TimeUnit.SECONDS);
}
}
}