blob: a2678de2d47a885d3cf03091044e5309da131d3c [file] [log] [blame]
/*
* Copyright (C) 2016 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.androidbvt;
import android.app.IntentService;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.RemoteInput;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.platform.test.annotations.HermeticTest;
import android.service.notification.StatusBarNotification;
import android.support.test.InstrumentationRegistry;
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.Direction;
import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.UiObject2;
import android.support.test.uiautomator.Until;
import android.view.KeyEvent;
import android.view.inputmethod.InputMethodManager;
import android.test.suitebuilder.annotation.LargeTest;
import android.test.suitebuilder.annotation.MediumTest;
import android.util.Log;
import android.view.inputmethod.InputMethodManager;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import junit.framework.TestCase;
@HermeticTest
public class SysUINotificationShadeTests extends TestCase {
private static final String LOG_TAG = SysUINotificationShadeTests.class.getSimpleName();
private static final int SHORT_TIMEOUT = 200;
private static final int LONG_TIMEOUT = 2000;
private static final int GROUP_NOTIFICATION_ID = 1;
private static final int CHILD_NOTIFICATION_ID = 100;
private static final int SECOND_CHILD_NOTIFICATION_ID = 101;
private static final int NOTIFICATION_ID_2 = 2;
private static final String KEY_QUICK_REPLY_TEXT = "quick_reply";
private static final String INLINE_REPLY_TITLE = "INLINE REPLY TITLE";
private static final String RECEIVER_PKG_NAME = "com.android.systemui";
private static final String BUNDLE_GROUP_KEY = "group key ";
private UiDevice mDevice = null;
private Context mContext;
private NotificationManager mNotificationManager;
private ContentResolver mResolver;
private AndroidBvtHelper mABvtHelper = null;
private enum QuickSettingTiles {
WIFI("Wi-Fi"), SIM("SIM"), DND("Do not disturb"), BATTERY("Battery"),
FLASHLIGHT("Flashlight"), SCREEN("screen"), BLUETOOTH("Bluetooth"),
AIRPLANE("Airplane mode");
private final String name;
private QuickSettingTiles(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
};
@Override
public void setUp() throws Exception {
super.setUp();
mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
mContext = InstrumentationRegistry.getTargetContext();
mResolver = mContext.getContentResolver();
mABvtHelper = AndroidBvtHelper.getInstance(mDevice, mContext,
InstrumentationRegistry.getInstrumentation().getUiAutomation());
mDevice.setOrientationNatural();
mNotificationManager = (NotificationManager) mContext
.getSystemService(Context.NOTIFICATION_SERVICE);
mDevice.pressHome();
mNotificationManager.cancelAll();
}
@Override
public void tearDown() throws Exception {
mNotificationManager.cancelAll();
mDevice.pressHome();
mDevice.unfreezeRotation();
mDevice.waitForIdle();
super.tearDown();
}
/**
* Following test will create notifications, and verify notification can be expanded and
* redacted
*/
@LargeTest
public void testNotifications() throws Exception {
// test receive notification and expand/redact notification
verifyReceiveAndExpandRedactNotification();
// test inline notification and dismiss notification
verifyInlineAndDimissNotification();
}
/**
* Following test will open Quick Setting shade, and verify icons in the shade
*/
@MediumTest
public void testQuickSettings() throws Exception {
mDevice.openQuickSettings();
Thread.sleep(LONG_TIMEOUT * 2);
// Verify quick settings are displayed on the phone screen.
for (QuickSettingTiles tile : QuickSettingTiles.values()) {
if (!(mABvtHelper.isTablet() && tile.getName().equals("SIM"))) {
UiObject2 quickSettingTile = mDevice.wait(
Until.findObject(By.descContains(tile.getName())),
SHORT_TIMEOUT);
assertNotNull(String.format("%s did not load correctly", tile.getName()),
quickSettingTile);
}
}
// Verify tapping on Settings icon in Quick settings launches Settings.
mDevice.wait(Until.findObject(By.descContains("Open settings.")), LONG_TIMEOUT)
.click();
UiObject2 settingHeading = mDevice.wait(Until.findObject(By.text("Settings")),
LONG_TIMEOUT);
assertNotNull("Setting menu has not loaded correctly", settingHeading);
}
private void verifyReceiveAndExpandRedactNotification() throws Exception {
List<Integer> lists = new ArrayList<Integer>(Arrays.asList(GROUP_NOTIFICATION_ID,
CHILD_NOTIFICATION_ID, SECOND_CHILD_NOTIFICATION_ID));
sendBundlingNotifications(lists, BUNDLE_GROUP_KEY);
Thread.sleep(LONG_TIMEOUT);
swipeDown();
UiObject2 obj = mDevice.wait(
Until.findObject(By.textContains(lists.get(1).toString())),
LONG_TIMEOUT);
int currentY = obj.getVisibleCenter().y;
mDevice.wait(Until.findObject(By.res("android:id/expand_button")), LONG_TIMEOUT * 2)
.click();
obj = mDevice.wait(Until.findObject(By.textContains(lists.get(0).toString())),
LONG_TIMEOUT);
assertFalse("The notifications has not been bundled",
obj.getVisibleCenter().y == currentY);
mDevice.wait(Until.findObject(By.res("android:id/expand_button")), LONG_TIMEOUT).click();
obj = mDevice.wait(Until.findObject(By.textContains(lists.get(1).toString())),
LONG_TIMEOUT);
assertTrue("The notifications can not be redacted",
obj.getVisibleCenter().y == currentY);
mNotificationManager.cancelAll();
}
private void verifyInlineAndDimissNotification() throws Exception {
sendNotificationsWithInLineReply(NOTIFICATION_ID_2, INLINE_REPLY_TITLE);
Thread.sleep(LONG_TIMEOUT);
mDevice.openNotification();
mDevice.wait(Until.findObject(By.text("REPLY")), LONG_TIMEOUT).click();
UiObject2 replyBox = mDevice.wait(
Until.findObject(By.res(RECEIVER_PKG_NAME, "remote_input_send")),
LONG_TIMEOUT);
InputMethodManager imm = (InputMethodManager) mContext
.getSystemService(Context.INPUT_METHOD_SERVICE);
if (!imm.isAcceptingText()) {
assertNotNull("Keyboard for inline reply has not loaded correctly", replyBox);
}
// make the IME down
mDevice.pressKeyCode(KeyEvent.KEYCODE_BACK);
UiObject2 obj = mDevice.wait(Until.findObject(By.text(INLINE_REPLY_TITLE)),
LONG_TIMEOUT);
obj.swipe(Direction.LEFT, 1.0f);
Thread.sleep(LONG_TIMEOUT);
if (checkNotificationExistence(NOTIFICATION_ID_2)) {
fail(String.format("Notification %s has not been dismissed", NOTIFICATION_ID_2));
}
}
/**
* send out a group of notifications
* @param lists notification list for a group of notifications which includes two child
* notifications and one summary notification
* @param groupKey the group key of group notification
*/
private void sendBundlingNotifications(List<Integer> lists, String groupKey) throws Exception {
Notification childNotification = new Notification.Builder(mContext)
.setContentTitle(lists.get(1).toString())
.setSmallIcon(R.drawable.stat_notify_email)
.setContentText("test1")
.setWhen(System.currentTimeMillis())
.setGroup(groupKey)
.build();
mNotificationManager.notify(lists.get(1),
childNotification);
childNotification = new Notification.Builder(mContext)
.setContentTitle(lists.get(2).toString())
.setContentText("test2")
.setSmallIcon(R.drawable.stat_notify_email)
.setWhen(System.currentTimeMillis())
.setGroup(groupKey)
.build();
mNotificationManager.notify(lists.get(2),
childNotification);
Notification notification = new Notification.Builder(mContext)
.setContentTitle(lists.get(0).toString())
.setSubText(groupKey)
.setSmallIcon(R.drawable.stat_notify_email)
.setGroup(groupKey)
.setGroupSummary(true)
.build();
mNotificationManager.notify(lists.get(0),
notification);
}
/**
* send out a notification with inline reply
*
* @param notificationId An identifier for this notification
* @param title notification title
*/
private void sendNotificationsWithInLineReply(int notificationId, String title) {
Notification.Action action = new Notification.Action.Builder(
R.drawable.stat_notify_email, "Reply", ToastService.getPendingIntent(mContext,
title))
.addRemoteInput(new RemoteInput.Builder(KEY_QUICK_REPLY_TEXT)
.setLabel("Quick reply").build())
.build();
Notification.Builder n = new Notification.Builder(mContext)
.setContentTitle(Integer.toString(notificationId))
.setContentText(title)
.setWhen(System.currentTimeMillis())
.setSmallIcon(R.drawable.stat_notify_email)
.addAction(action)
.setPriority(Notification.PRIORITY_HIGH)
.setDefaults(Notification.DEFAULT_VIBRATE);
mNotificationManager.notify(notificationId, n.build());
}
private boolean checkNotificationExistence(int id) throws Exception {
boolean isFound = false;
for (int tries = 3; tries-- > 0;) {
isFound = false;
StatusBarNotification[] sbns = mNotificationManager.getActiveNotifications();
for (StatusBarNotification sbn : sbns) {
if (sbn.getId() == id) {
isFound = true;
break;
}
}
if (isFound) {
break;
}
Thread.sleep(SHORT_TIMEOUT);
}
Log.i(LOG_TAG, "checkNotificationExistence..." + isFound);
return isFound;
}
private void swipeDown() throws Exception {
mDevice.swipe(mDevice.getDisplayWidth() / 2, 0, mDevice.getDisplayWidth() / 2,
mDevice.getDisplayHeight() / 2 + 50, 20);
Thread.sleep(SHORT_TIMEOUT);
}
public static class ToastService extends IntentService {
private static final String TAG = "ToastService";
private static final String ACTION_TOAST = "toast";
private Handler handler;
public ToastService() {
super(TAG);
}
public ToastService(String name) {
super(name);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
handler = new Handler();
return super.onStartCommand(intent, flags, startId);
}
@Override
protected void onHandleIntent(Intent intent) {
if (intent.hasExtra("text")) {
final String text = intent.getStringExtra("text");
handler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(ToastService.this, text, Toast.LENGTH_LONG).show();
Log.v(TAG, "toast " + text);
}
});
}
}
public static PendingIntent getPendingIntent(Context context, String text) {
Intent toastIntent = new Intent(context, ToastService.class);
toastIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
toastIntent.setAction(ACTION_TOAST + ":" + text); // one per toast message
toastIntent.putExtra("text", text);
PendingIntent pi = PendingIntent.getService(
context, 58, toastIntent, PendingIntent.FLAG_UPDATE_CURRENT);
return pi;
}
}
}