Merge "Tests for Notification object construction and parceling." into mnc-dev

This commit is contained in:
Dan Sandler
2015-05-12 18:51:02 +00:00
committed by Android (Google) Code Review
28 changed files with 595 additions and 0 deletions

View File

@@ -0,0 +1,16 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
# We only want this apk build for tests.
LOCAL_MODULE_TAGS := tests
# Include all test java files.
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_JAVA_LIBRARIES := android.test.runner
LOCAL_PACKAGE_NAME := NotificationTests
LOCAL_SDK_VERSION := 21
include $(BUILD_PACKAGE)

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2008 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.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.frameworks.tests.notification"
>
<application>
<uses-library android:name="android.test.runner" />
</application>
<instrumentation
android:name="android.test.InstrumentationTestRunner"
android:targetPackage="com.android.frameworks.tests.notification"
android:label="Frameworks Notification Tests" />
</manifest>

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 405 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 211 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 485 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 823 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:layout_height="match_parent"
android:layout_width="match_parent"
android:src="@drawable/page_hed"
android:onClick="dismiss"
/>
</FrameLayout>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<LinearLayout android:id="@+id/linearLayout1" android:orientation="vertical" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_width="match_parent" android:layout_margin="35dp">
<Button android:id="@+id/button1" android:text="@string/post_button_label" android:layout_height="wrap_content" android:layout_width="match_parent" android:onClick="doPost"></Button>
<Button android:id="@+id/button2" android:text="@string/remove_button_label" android:layout_height="wrap_content" android:layout_width="match_parent" android:onClick="doRemove"></Button>
</LinearLayout>
</FrameLayout>

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
** Copyright 2012, 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.
*/
-->
<resources>
<!-- The width of the big icons in notifications. -->
<dimen name="notification_large_icon_width">64dp</dimen>
<!-- The width of the big icons in notifications. -->
<dimen name="notification_large_icon_height">64dp</dimen>
</resources>

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="hello">Hello World, NotificationShowcaseActivity!</string>
<string name="app_name">NotificationShowcase</string>
<string name="post_button_label">Post Notifications</string>
<string name="remove_button_label">Remove Notifications</string>
<string name="answered">call answered</string>
<string name="ignored">call ignored</string>
<string name="full_screen_name">Full Screen Activity</string>
</resources>

View File

@@ -0,0 +1,494 @@
/*
* Copyright (C) 2015 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;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Typeface;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Parcel;
import android.os.SystemClock;
import android.provider.ContactsContract;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.Suppress;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import android.text.style.StyleSpan;
import android.util.Log;
import android.view.View;
import android.widget.Toast;
import java.lang.reflect.Method;
import java.lang.InterruptedException;
import java.lang.NoSuchMethodError;
import java.lang.NoSuchMethodException;
import java.util.ArrayList;
import com.android.frameworks.tests.notification.R;
public class NotificationTests extends AndroidTestCase {
private static final String TAG = "NOTEST";
public static void L(String msg, Object... args) {
Log.v(TAG, (args == null || args.length == 0) ? msg : String.format(msg, args));
}
public static final String ACTION_CREATE = "create";
public static final int NOTIFICATION_ID = 31338;
public static final boolean SHOW_PHONE_CALL = false;
public static final boolean SHOW_INBOX = true;
public static final boolean SHOW_BIG_TEXT = true;
public static final boolean SHOW_BIG_PICTURE = true;
public static final boolean SHOW_MEDIA = true;
public static final boolean SHOW_STOPWATCH = false;
public static final boolean SHOW_SOCIAL = false;
public static final boolean SHOW_CALENDAR = false;
public static final boolean SHOW_PROGRESS = false;
private static Bitmap getBitmap(Context context, int resId) {
int largeIconWidth = (int) context.getResources()
.getDimension(R.dimen.notification_large_icon_width);
int largeIconHeight = (int) context.getResources()
.getDimension(R.dimen.notification_large_icon_height);
Drawable d = context.getResources().getDrawable(resId);
Bitmap b = Bitmap.createBitmap(largeIconWidth, largeIconHeight, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(b);
d.setBounds(0, 0, largeIconWidth, largeIconHeight);
d.draw(c);
return b;
}
private static PendingIntent makeEmailIntent(Context context, String who) {
final Intent intent = new Intent(android.content.Intent.ACTION_SENDTO,
Uri.parse("mailto:" + who));
return PendingIntent.getActivity(
context, 0, intent,
PendingIntent.FLAG_CANCEL_CURRENT);
}
static final String[] LINES = new String[] {
"Uh oh",
"Getting kicked out of this room",
"I'll be back in 5-10 minutes.",
"And now \u2026 I have to find my shoes. \uD83D\uDC63",
"\uD83D\uDC5F \uD83D\uDC5F",
"\uD83D\uDC60 \uD83D\uDC60",
};
static final int MAX_LINES = 5;
public static Notification makeBigTextNotification(Context context, int update, int id,
long when) {
String personUri = null;
/*
Cursor c = null;
try {
String[] projection = new String[] { ContactsContract.Contacts._ID, ContactsContract.Contacts.LOOKUP_KEY };
String selections = ContactsContract.Contacts.DISPLAY_NAME + " = 'Mike Cleron'";
final ContentResolver contentResolver = context.getContentResolver();
c = contentResolver.query(ContactsContract.Contacts.CONTENT_URI,
projection, selections, null, null);
if (c != null && c.getCount() > 0) {
c.moveToFirst();
int lookupIdx = c.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY);
int idIdx = c.getColumnIndex(ContactsContract.Contacts._ID);
String lookupKey = c.getString(lookupIdx);
long contactId = c.getLong(idIdx);
Uri lookupUri = ContactsContract.Contacts.getLookupUri(contactId, lookupKey);
personUri = lookupUri.toString();
}
} finally {
if (c != null) {
c.close();
}
}
if (TextUtils.isEmpty(personUri)) {
Log.w(TAG, "failed to find contact for Mike Cleron");
} else {
Log.w(TAG, "Mike Cleron is " + personUri);
}
*/
StringBuilder longSmsText = new StringBuilder();
int end = 2 + update;
if (end > LINES.length) {
end = LINES.length;
}
final int start = Math.max(0, end - MAX_LINES);
for (int i=start; i<end; i++) {
if (i >= LINES.length) break;
if (i > start) longSmsText.append("\n");
longSmsText.append(LINES[i]);
}
if (update > 2) {
when = System.currentTimeMillis();
}
Notification.BigTextStyle bigTextStyle = new Notification.BigTextStyle()
.bigText(longSmsText);
Notification bigText = new Notification.Builder(context)
.setContentTitle("Mike Cleron")
.setContentIntent(ToastService.getPendingIntent(context, "Clicked on bigText"))
.setContentText(longSmsText)
//.setTicker("Mike Cleron: " + longSmsText)
.setWhen(when)
.setLargeIcon(getBitmap(context, R.drawable.bucket))
.setPriority(Notification.PRIORITY_HIGH)
.setNumber(update)
.setSmallIcon(R.drawable.stat_notify_talk_text)
.setStyle(bigTextStyle)
.setDefaults(Notification.DEFAULT_SOUND)
.addPerson(personUri)
.build();
return bigText;
}
public static Notification makeUploadNotification(Context context, int progress, long when) {
Notification.Builder uploadNotification = new Notification.Builder(context)
.setContentTitle("File Upload")
.setContentText("foo.txt")
.setPriority(Notification.PRIORITY_MIN)
.setContentIntent(ToastService.getPendingIntent(context, "Clicked on Upload"))
.setWhen(when)
.setSmallIcon(R.drawable.ic_menu_upload)
.setProgress(100, Math.min(progress, 100), false);
return uploadNotification.build();
}
static SpannableStringBuilder BOLD(CharSequence str) {
final SpannableStringBuilder ssb = new SpannableStringBuilder(str);
ssb.setSpan(new StyleSpan(Typeface.BOLD), 0, ssb.length(), 0);
return ssb;
}
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) {
Log.v(TAG, "clicked a thing! intent=" + intent.toString());
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;
}
}
public static void sleepIfYouCan(int ms) {
try {
Thread.sleep(ms);
} catch (InterruptedException e) {}
}
@Override
public void setUp() throws Exception {
super.setUp();
}
public static String summarize(Notification n) {
return String.format("<notif title=\"%s\" icon=0x%08x view=%s>",
n.extras.get(Notification.EXTRA_TITLE),
n.icon,
String.valueOf(n.contentView));
}
public void testCreate() throws Exception {
ArrayList<Notification> mNotifications = new ArrayList<Notification>();
NotificationManager noMa =
(NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
L("Constructing notifications...");
if (SHOW_BIG_TEXT) {
int bigtextId = mNotifications.size();
final long time = SystemClock.currentThreadTimeMillis();
final Notification n = makeBigTextNotification(mContext, 0, bigtextId, System.currentTimeMillis());
L(" %s: create=%dms", summarize(n), SystemClock.currentThreadTimeMillis() - time);
mNotifications.add(n);
}
int uploadId = mNotifications.size();
long uploadWhen = System.currentTimeMillis();
if (SHOW_PROGRESS) {
mNotifications.add(makeUploadNotification(mContext, 0, uploadWhen));
}
if (SHOW_PHONE_CALL) {
int phoneId = mNotifications.size();
final PendingIntent fullscreenIntent
= FullScreenActivity.getPendingIntent(mContext, phoneId);
final long time = SystemClock.currentThreadTimeMillis();
Notification phoneCall = new Notification.Builder(mContext)
.setContentTitle("Incoming call")
.setContentText("Matias Duarte")
.setLargeIcon(getBitmap(mContext, R.drawable.matias_hed))
.setSmallIcon(R.drawable.stat_sys_phone_call)
.setDefaults(Notification.DEFAULT_SOUND)
.setPriority(Notification.PRIORITY_MAX)
.setContentIntent(fullscreenIntent)
.setFullScreenIntent(fullscreenIntent, true)
.addAction(R.drawable.ic_dial_action_call, "Answer",
ToastService.getPendingIntent(mContext, "Clicked on Answer"))
.addAction(R.drawable.ic_end_call, "Ignore",
ToastService.getPendingIntent(mContext, "Clicked on Ignore"))
.setOngoing(true)
.addPerson(Uri.fromParts("tel", "1 (617) 555-1212", null).toString())
.build();
L(" %s: create=%dms", phoneCall.toString(), SystemClock.currentThreadTimeMillis() - time);
mNotifications.add(phoneCall);
}
if (SHOW_STOPWATCH) {
final long time = SystemClock.currentThreadTimeMillis();
final Notification n = new Notification.Builder(mContext)
.setContentTitle("Stopwatch PRO")
.setContentText("Counting up")
.setContentIntent(ToastService.getPendingIntent(mContext, "Clicked on Stopwatch"))
.setSmallIcon(R.drawable.stat_notify_alarm)
.setUsesChronometer(true)
.build();
L(" %s: create=%dms", summarize(n), SystemClock.currentThreadTimeMillis() - time);
mNotifications.add(n);
}
if (SHOW_CALENDAR) {
final long time = SystemClock.currentThreadTimeMillis();
final Notification n = new Notification.Builder(mContext)
.setContentTitle("J Planning")
.setContentText("The Botcave")
.setWhen(System.currentTimeMillis())
.setSmallIcon(R.drawable.stat_notify_calendar)
.setContentIntent(ToastService.getPendingIntent(mContext, "Clicked on calendar event"))
.setContentInfo("7PM")
.addAction(R.drawable.stat_notify_snooze, "+10 min",
ToastService.getPendingIntent(mContext, "snoozed 10 min"))
.addAction(R.drawable.stat_notify_snooze_longer, "+1 hour",
ToastService.getPendingIntent(mContext, "snoozed 1 hr"))
.addAction(R.drawable.stat_notify_email, "Email",
ToastService.getPendingIntent(mContext,
"Congratulations, you just destroyed someone's inbox zero"))
.build();
L(" %s: create=%dms", summarize(n), SystemClock.currentThreadTimeMillis() - time);
mNotifications.add(n);
}
if (SHOW_BIG_PICTURE) {
BitmapDrawable d =
(BitmapDrawable) mContext.getResources().getDrawable(R.drawable.romainguy_rockaway);
final long time = SystemClock.currentThreadTimeMillis();
final Notification n = new Notification.Builder(mContext)
.setContentTitle("Romain Guy")
.setContentText("I was lucky to find a Canon 5D Mk III at a local Bay Area "
+ "store last week but I had not been able to try it in the field "
+ "until tonight. After a few days of rain the sky finally cleared "
+ "up. Rockaway Beach did not disappoint and I was finally able to "
+ "see what my new camera feels like when shooting landscapes.")
.setSmallIcon(android.R.drawable.stat_notify_chat)
.setContentIntent(
ToastService.getPendingIntent(mContext, "Clicked picture"))
.setLargeIcon(getBitmap(mContext, R.drawable.romainguy_hed))
.addAction(R.drawable.add, "Add to Gallery",
ToastService.getPendingIntent(mContext, "Added"))
.setStyle(new Notification.BigPictureStyle()
.bigPicture(d.getBitmap()))
.build();
L(" %s: create=%dms", summarize(n), SystemClock.currentThreadTimeMillis() - time);
mNotifications.add(n);
}
if (SHOW_INBOX) {
final long time = SystemClock.currentThreadTimeMillis();
final Notification n = new Notification.Builder(mContext)
.setContentTitle("New mail")
.setContentText("3 new messages")
.setSubText("example@gmail.com")
.setContentIntent(ToastService.getPendingIntent(mContext, "Clicked on Mail"))
.setSmallIcon(R.drawable.stat_notify_email)
.setStyle(new Notification.InboxStyle()
.setSummaryText("example@gmail.com")
.addLine(BOLD("Alice:").append(" hey there!"))
.addLine(BOLD("Bob:").append(" hi there!"))
.addLine(BOLD("Charlie:").append(" Iz IN UR EMAILZ!!"))
).build();
L(" %s: create=%dms", summarize(n), SystemClock.currentThreadTimeMillis() - time);
mNotifications.add(n);
}
if (SHOW_SOCIAL) {
final long time = SystemClock.currentThreadTimeMillis();
final Notification n = new Notification.Builder(mContext)
.setContentTitle("Social Network")
.setContentText("You were mentioned in a post")
.setContentInfo("example@gmail.com")
.setContentIntent(ToastService.getPendingIntent(mContext, "Clicked on Social"))
.setSmallIcon(android.R.drawable.stat_notify_chat)
.setPriority(Notification.PRIORITY_LOW)
.build();
L(" %s: create=%dms", summarize(n), SystemClock.currentThreadTimeMillis() - time);
mNotifications.add(n);
}
L("Posting notifications...");
for (int i=0; i<mNotifications.size(); i++) {
final int count = 4;
for (int j=0; j<count; j++) {
long time = SystemClock.currentThreadTimeMillis();
final Notification n = mNotifications.get(i);
noMa.notify(NOTIFICATION_ID + i, n);
time = SystemClock.currentThreadTimeMillis() - time;
L(" %s: notify=%dms (%d/%d)", summarize(n), time,
j + 1, count);
sleepIfYouCan(150);
}
}
sleepIfYouCan(1000);
L("Canceling notifications...");
for (int i=0; i<mNotifications.size(); i++) {
final Notification n = mNotifications.get(i);
long time = SystemClock.currentThreadTimeMillis();
noMa.cancel(NOTIFICATION_ID + i);
time = SystemClock.currentThreadTimeMillis() - time;
L(" %s: cancel=%dms", summarize(n), time);
}
sleepIfYouCan(500);
L("Parceling notifications...");
// we want to be able to use this test on older OSes that do not have getBlobAshmemSize
Method getBlobAshmemSize = null;
try {
getBlobAshmemSize = Parcel.class.getMethod("getBlobAshmemSize");
} catch (NoSuchMethodException ex) {
}
for (int i=0; i<mNotifications.size(); i++) {
Parcel p = Parcel.obtain();
{
final Notification n = mNotifications.get(i);
long time = SystemClock.currentThreadTimeMillis();
n.writeToParcel(p, 0);
time = SystemClock.currentThreadTimeMillis() - time;
L(" %s: write parcel=%dms size=%d ashmem=%s",
summarize(n), time, p.dataPosition(),
(getBlobAshmemSize != null)
? getBlobAshmemSize.invoke(p)
: "???");
p.setDataPosition(0);
}
long time = SystemClock.currentThreadTimeMillis();
final Notification n2 = Notification.CREATOR.createFromParcel(p);
time = SystemClock.currentThreadTimeMillis() - time;
L(" %s: parcel read=%dms", summarize(n2), time);
time = SystemClock.currentThreadTimeMillis();
noMa.notify(NOTIFICATION_ID + i, n2);
time = SystemClock.currentThreadTimeMillis() - time;
L(" %s: notify=%dms", summarize(n2), time);
}
sleepIfYouCan(500);
L("Canceling notifications...");
for (int i=0; i<mNotifications.size(); i++) {
long time = SystemClock.currentThreadTimeMillis();
final Notification n = mNotifications.get(i);
noMa.cancel(NOTIFICATION_ID + i);
time = SystemClock.currentThreadTimeMillis() - time;
L(" %s: cancel=%dms", summarize(n), time);
}
// if (SHOW_PROGRESS) {
// ProgressService.startProgressUpdater(this, uploadId, uploadWhen, 0);
// }
}
public static class FullScreenActivity extends Activity {
public static final String EXTRA_ID = "id";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.full_screen);
final Intent intent = getIntent();
if (intent != null && intent.hasExtra(EXTRA_ID)) {
final int id = intent.getIntExtra(EXTRA_ID, -1);
if (id >= 0) {
NotificationManager noMa =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
noMa.cancel(NOTIFICATION_ID + id);
}
}
}
public void dismiss(View v) {
finish();
}
public static PendingIntent getPendingIntent(Context context, int id) {
Intent fullScreenIntent = new Intent(context, FullScreenActivity.class);
fullScreenIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
fullScreenIntent.putExtra(EXTRA_ID, id);
PendingIntent pi = PendingIntent.getActivity(
context, 22, fullScreenIntent, PendingIntent.FLAG_UPDATE_CURRENT);
return pi;
}
}
}