diff options
Diffstat (limited to 'tests')
62 files changed, 1170 insertions, 94 deletions
diff --git a/tests/ActivityTests/AndroidManifest.xml b/tests/ActivityTests/AndroidManifest.xml index 33d40ad..c105491 100644 --- a/tests/ActivityTests/AndroidManifest.xml +++ b/tests/ActivityTests/AndroidManifest.xml @@ -75,5 +75,6 @@ <provider android:name="SingleUserProvider" android:authorities="com.google.android.test.activity.single_user" android:singleUser="true" android:exported="true" /> + <receiver android:name="TrackTimeReceiver" /> </application> </manifest> diff --git a/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java b/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java index 4281c68..ddcfd9e 100644 --- a/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java +++ b/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java @@ -23,6 +23,7 @@ import android.app.Activity; import android.app.ActivityManager; import android.app.ActivityOptions; import android.app.AlertDialog; +import android.app.PendingIntent; import android.content.ActivityNotFoundException; import android.content.BroadcastReceiver; import android.content.ComponentName; @@ -412,6 +413,29 @@ public class ActivityTestMain extends Activity { return true; } }); + menu.add("Track time").setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { + @Override public boolean onMenuItemClick(MenuItem item) { + Intent intent = new Intent(Intent.ACTION_SEND); + intent.setType("text/plain"); + intent.putExtra(Intent.EXTRA_TEXT, "We are sharing this with you!"); + ActivityOptions options = ActivityOptions.makeBasic(); + Intent receiveIntent = new Intent(ActivityTestMain.this, TrackTimeReceiver.class); + receiveIntent.putExtra("something", "yeah, this is us!"); + options.requestUsageTimeReport(PendingIntent.getBroadcast(ActivityTestMain.this, + 0, receiveIntent, PendingIntent.FLAG_CANCEL_CURRENT)); + startActivity(Intent.createChooser(intent, "Who do you love?"), options.toBundle()); + return true; + } + }); + menu.add("Transaction fail").setOnMenuItemClickListener( + new MenuItem.OnMenuItemClickListener() { + @Override public boolean onMenuItemClick(MenuItem item) { + Intent intent = new Intent(Intent.ACTION_MAIN); + intent.putExtra("gulp", new int[1024*1024]); + startActivity(intent); + return true; + } + }); return true; } diff --git a/tests/ActivityTests/src/com/google/android/test/activity/TrackTimeReceiver.java b/tests/ActivityTests/src/com/google/android/test/activity/TrackTimeReceiver.java new file mode 100644 index 0000000..c30d33a --- /dev/null +++ b/tests/ActivityTests/src/com/google/android/test/activity/TrackTimeReceiver.java @@ -0,0 +1,33 @@ +/* + * 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 com.google.android.test.activity; + +import android.app.ActivityOptions; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.util.Log; + +public class TrackTimeReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + Bundle data = intent.getExtras(); + data.getLong(ActivityOptions.EXTRA_USAGE_REPORT_TIME); + Log.i("ActivityTest", "Received time: " + data); + } +} diff --git a/tests/Compatibility/AndroidManifest.xml b/tests/Compatibility/AndroidManifest.xml index 8ae5bc5..7017431 100644 --- a/tests/Compatibility/AndroidManifest.xml +++ b/tests/Compatibility/AndroidManifest.xml @@ -16,6 +16,8 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.compatibilitytest" > + <uses-sdk android:minSdkVersion="21" + android:targetSdkVersion="21" /> <application > <uses-library android:name="android.test.runner" /> </application> diff --git a/tests/Compatibility/src/com/android/compatibilitytest/AppCompatibility.java b/tests/Compatibility/src/com/android/compatibilitytest/AppCompatibility.java index dd823ae..eaff6c7 100644 --- a/tests/Compatibility/src/com/android/compatibilitytest/AppCompatibility.java +++ b/tests/Compatibility/src/com/android/compatibilitytest/AppCompatibility.java @@ -17,13 +17,15 @@ package com.android.compatibilitytest; import android.app.ActivityManager; +import android.app.UiModeManager; import android.app.ActivityManager.ProcessErrorStateInfo; -import android.app.ActivityManager.RunningAppProcessInfo; +import android.app.ActivityManager.RunningTaskInfo; import android.content.Context; import android.content.Intent; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; +import android.content.res.Configuration; import android.os.Bundle; import android.test.InstrumentationTestCase; import android.util.Log; @@ -39,7 +41,7 @@ import java.util.List; */ public class AppCompatibility extends InstrumentationTestCase { - private static final String TAG = "AppCompability"; + private static final String TAG = AppCompatibility.class.getSimpleName(); private static final String PACKAGE_TO_LAUNCH = "package_to_launch"; private static final String APP_LAUNCH_TIMEOUT_MSECS = "app_launch_timeout_ms"; private static final String WORKSPACE_LAUNCH_TIMEOUT_MSECS = "workspace_launch_timeout_ms"; @@ -97,12 +99,21 @@ public class AppCompatibility extends InstrumentationTestCase { String packageName = mArgs.getString(PACKAGE_TO_LAUNCH); if (packageName != null) { Log.d(TAG, "Launching app " + packageName); - ProcessErrorStateInfo err = launchActivity(packageName); + Intent intent = getLaunchIntentForPackage(packageName); + if (intent == null) { + Log.w(TAG, String.format("Skipping %s; no launch intent", packageName)); + return; + } + ProcessErrorStateInfo err = launchActivity(packageName, intent); // Make sure there are no errors when launching the application, // otherwise raise an // exception with the first error encountered. assertNull(getStackTrace(err), err); - assertTrue("App crashed after launch.", processStillUp(packageName)); + try { + assertTrue("App crashed after launch.", processStillUp(packageName)); + } finally { + returnHome(); + } } else { Log.d(TAG, "Missing argument, use " + PACKAGE_TO_LAUNCH + " to specify the package to launch"); @@ -138,6 +149,32 @@ public class AppCompatibility extends InstrumentationTestCase { } } + private void returnHome() { + Intent homeIntent = new Intent(Intent.ACTION_MAIN); + homeIntent.addCategory(Intent.CATEGORY_HOME); + homeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + // Send the "home" intent and wait 2 seconds for us to get there + mContext.startActivity(homeIntent); + try { + Thread.sleep(mWorkspaceLaunchTimeout); + } catch (InterruptedException e) { + // ignore + } + } + + private Intent getLaunchIntentForPackage(String packageName) { + UiModeManager umm = (UiModeManager) + getInstrumentation().getContext().getSystemService(Context.UI_MODE_SERVICE); + boolean isLeanback = umm.getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION; + Intent intent = null; + if (isLeanback) { + intent = mPackageManager.getLeanbackLaunchIntentForPackage(packageName); + } else { + intent = mPackageManager.getLaunchIntentForPackage(packageName); + } + return intent; + } + /** * Launches and activity and queries for errors. * @@ -146,21 +183,9 @@ public class AppCompatibility extends InstrumentationTestCase { * @return {@link Collection} of {@link ProcessErrorStateInfo} detected * during the app launch. */ - private ProcessErrorStateInfo launchActivity(String packageName) { - // the recommended way to see if this is a tv or not. - boolean isleanback = !mPackageManager.hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN) - && !mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY); - Intent homeIntent = new Intent(Intent.ACTION_MAIN); - homeIntent.addCategory(Intent.CATEGORY_HOME); - homeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - Intent intent; - if (isleanback) { - Log.d(TAG, "Leanback and relax! " + packageName); - intent = mPackageManager.getLeanbackLaunchIntentForPackage(packageName); - } else { - intent = mPackageManager.getLaunchIntentForPackage(packageName); - } - assertNotNull("Skipping " + packageName + "; missing launch intent", intent); + private ProcessErrorStateInfo launchActivity(String packageName, Intent intent) { + Log.d(TAG, String.format("launching package \"%s\" with intent: %s", + packageName, intent.toString())); String processName = getProcessName(packageName); @@ -173,16 +198,7 @@ public class AppCompatibility extends InstrumentationTestCase { // ignore } - // Send the "home" intent and wait 2 seconds for us to get there - mContext.startActivity(homeIntent); - try { - Thread.sleep(mWorkspaceLaunchTimeout); - } catch (InterruptedException e) { - // ignore - } - - // See if there are any errors. We wait until down here to give ANRs as - // much time as + // See if there are any errors. We wait until down here to give ANRs as much time as // possible to occur. final Collection<ProcessErrorStateInfo> postErr = mActivityManager.getProcessesInErrorState(); @@ -205,22 +221,13 @@ public class AppCompatibility extends InstrumentationTestCase { * @return True if package is running, false otherwise. */ private boolean processStillUp(String packageName) { - String processName = getProcessName(packageName); - List<RunningAppProcessInfo> runningApps = mActivityManager.getRunningAppProcesses(); - for (RunningAppProcessInfo app : runningApps) { - if (app.processName.equalsIgnoreCase(processName)) { - Log.d(TAG, "Found process " + app.processName); + @SuppressWarnings("deprecation") + List<RunningTaskInfo> infos = mActivityManager.getRunningTasks(100); + for (RunningTaskInfo info : infos) { + if (info.baseActivity.getPackageName().equals(packageName)) { return true; } - for (String relatedPackage : app.pkgList) { - if (relatedPackage.equalsIgnoreCase(processName)) { - Log.d(TAG, "Found process " + app.processName); - return true; - } - } } - Log.d(TAG, "Failed to find process " + processName + " with package name " - + packageName); return false; } } diff --git a/tests/HierarchyViewerTest/.gitignore b/tests/HierarchyViewerTest/.gitignore new file mode 100644 index 0000000..75eec98 --- /dev/null +++ b/tests/HierarchyViewerTest/.gitignore @@ -0,0 +1,6 @@ +.gradle +.idea +*.iml +gradle* +build +local.properties diff --git a/tests/HierarchyViewerTest/Android.mk b/tests/HierarchyViewerTest/Android.mk new file mode 100644 index 0000000..07b90f0 --- /dev/null +++ b/tests/HierarchyViewerTest/Android.mk @@ -0,0 +1,12 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := tests + +LOCAL_SRC_FILES := $(call all-subdir-java-files) + +LOCAL_PACKAGE_NAME := HierarchyViewerTest + +LOCAL_JAVA_LIBRARIES := android.test.runner + +include $(BUILD_PACKAGE) diff --git a/tests/HierarchyViewerTest/AndroidManifest.xml b/tests/HierarchyViewerTest/AndroidManifest.xml new file mode 100644 index 0000000..65f2fd3 --- /dev/null +++ b/tests/HierarchyViewerTest/AndroidManifest.xml @@ -0,0 +1,36 @@ +<!-- + ~ 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 + --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.test.hierarchyviewer"> + + <application> + <uses-library android:name="android.test.runner" /> + + <activity + android:name=".MainActivity" + android:label="HvTest" > + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + </application> + + <instrumentation + android:name="android.test.InstrumentationTestRunner" + android:targetPackage="com.android.test.hierarchyviewer" /> +</manifest> diff --git a/tests/HierarchyViewerTest/build.gradle b/tests/HierarchyViewerTest/build.gradle new file mode 100644 index 0000000..e8cdfa2 --- /dev/null +++ b/tests/HierarchyViewerTest/build.gradle @@ -0,0 +1,31 @@ +buildscript { + repositories { + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:1.1.0+' + + } +} + +apply plugin: 'com.android.application' + +android { + compileSdkVersion 21 + buildToolsVersion "22.0.0" + + defaultConfig { + minSdkVersion 21 + targetSdkVersion 21 + versionCode 1 + versionName "1.0" + } + + sourceSets { + main { + manifest.srcFile 'AndroidManifest.xml' + java.srcDirs = ['src'] + res.srcDirs = ['res'] + } + } +} diff --git a/tests/HierarchyViewerTest/res/layout/activity_main.xml b/tests/HierarchyViewerTest/res/layout/activity_main.xml new file mode 100644 index 0000000..410a776 --- /dev/null +++ b/tests/HierarchyViewerTest/res/layout/activity_main.xml @@ -0,0 +1,12 @@ +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" + android:layout_height="match_parent"> + + <TextView + android:id="@+id/textView" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:scaleX="10" + android:text="@string/test" /> + +</RelativeLayout> diff --git a/tests/HierarchyViewerTest/res/menu/menu_main.xml b/tests/HierarchyViewerTest/res/menu/menu_main.xml new file mode 100644 index 0000000..9b78a1e --- /dev/null +++ b/tests/HierarchyViewerTest/res/menu/menu_main.xml @@ -0,0 +1,5 @@ +<menu xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" tools:context=".MainActivity"> + <item android:id="@+id/action_settings" android:title="Settings" + android:orderInCategory="100" android:showAsAction="never" /> +</menu> diff --git a/tests/HierarchyViewerTest/res/values/strings.xml b/tests/HierarchyViewerTest/res/values/strings.xml new file mode 100644 index 0000000..800ee1c --- /dev/null +++ b/tests/HierarchyViewerTest/res/values/strings.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <string name="test">Hello World</string> +</resources>
\ No newline at end of file diff --git a/tests/HierarchyViewerTest/run_tests.sh b/tests/HierarchyViewerTest/run_tests.sh new file mode 100644 index 0000000..094bb4c --- /dev/null +++ b/tests/HierarchyViewerTest/run_tests.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +# Runs the tests in this apk +adb install $OUT/data/app/HierarchyViewerTest/HierarchyViewerTest.apk +adb shell am instrument -w com.android.test.hierarchyviewer/android.test.InstrumentationTestRunner diff --git a/tests/HierarchyViewerTest/src/com/android/test/hierarchyviewer/Decoder.java b/tests/HierarchyViewerTest/src/com/android/test/hierarchyviewer/Decoder.java new file mode 100644 index 0000000..c6f1470 --- /dev/null +++ b/tests/HierarchyViewerTest/src/com/android/test/hierarchyviewer/Decoder.java @@ -0,0 +1,101 @@ +package com.android.test.hierarchyviewer; + +import java.nio.ByteBuffer; +import java.nio.charset.Charset; +import java.util.HashMap; +import java.util.Map; + +public class Decoder { + // Prefixes for simple primitives. These match the JNI definitions. + public static final byte SIG_BOOLEAN = 'Z'; + public static final byte SIG_BYTE = 'B'; + public static final byte SIG_SHORT = 'S'; + public static final byte SIG_INT = 'I'; + public static final byte SIG_LONG = 'J'; + public static final byte SIG_FLOAT = 'F'; + public static final byte SIG_DOUBLE = 'D'; + + // Prefixes for some commonly used objects + public static final byte SIG_STRING = 'R'; + + public static final byte SIG_MAP = 'M'; // a map with an short key + public static final short SIG_END_MAP = 0; + + private final ByteBuffer mBuf; + + public Decoder(byte[] buf) { + this(ByteBuffer.wrap(buf)); + } + + public Decoder(ByteBuffer buf) { + mBuf = buf; + } + + public boolean hasRemaining() { + return mBuf.hasRemaining(); + } + + public Object readObject() { + byte sig = mBuf.get(); + + switch (sig) { + case SIG_BOOLEAN: + return mBuf.get() == 0 ? Boolean.FALSE : Boolean.TRUE; + case SIG_BYTE: + return mBuf.get(); + case SIG_SHORT: + return mBuf.getShort(); + case SIG_INT: + return mBuf.getInt(); + case SIG_LONG: + return mBuf.getLong(); + case SIG_FLOAT: + return mBuf.getFloat(); + case SIG_DOUBLE: + return mBuf.getDouble(); + case SIG_STRING: + return readString(); + case SIG_MAP: + return readMap(); + default: + throw new DecoderException(sig, mBuf.position() - 1); + } + } + + private String readString() { + short len = mBuf.getShort(); + byte[] b = new byte[len]; + mBuf.get(b, 0, len); + return new String(b, Charset.forName("utf-8")); + } + + private Map<Short, Object> readMap() { + Map<Short, Object> m = new HashMap<Short, Object>(); + + while (true) { + Object o = readObject(); + if (!(o instanceof Short)) { + throw new DecoderException("Expected short key, got " + o.getClass()); + } + + Short key = (Short)o; + if (key == SIG_END_MAP) { + break; + } + + m.put(key, readObject()); + } + + return m; + } + + public static class DecoderException extends RuntimeException { + public DecoderException(byte seen, int pos) { + super(String.format("Unexpected byte %c seen at position %d", (char)seen, pos)); + } + + public DecoderException(String msg) { + super(msg); + } + } +} diff --git a/tests/HierarchyViewerTest/src/com/android/test/hierarchyviewer/MainActivity.java b/tests/HierarchyViewerTest/src/com/android/test/hierarchyviewer/MainActivity.java new file mode 100644 index 0000000..3a67273 --- /dev/null +++ b/tests/HierarchyViewerTest/src/com/android/test/hierarchyviewer/MainActivity.java @@ -0,0 +1,44 @@ +package com.android.test.hierarchyviewer; + +import android.app.Activity; +import android.os.Bundle; +import android.util.Log; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; + + +public class MainActivity extends Activity { + private static final String TAG = "Main"; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + View textView = findViewById(R.id.textView); + Log.d(TAG, "x, y = " + textView.getX() + ", " + textView.getY()); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + // Inflate the menu; this adds items to the action bar if it is present. + getMenuInflater().inflate(R.menu.menu_main, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + // Handle action bar item clicks here. The action bar will + // automatically handle clicks on the Home/Up button, so long + // as you specify a parent activity in AndroidManifest.xml. + int id = item.getItemId(); + + //noinspection SimplifiableIfStatement + if (id == R.id.action_settings) { + return true; + } + + return super.onOptionsItemSelected(item); + } +} diff --git a/tests/HierarchyViewerTest/src/com/android/test/hierarchyviewer/MainActivityTest.java b/tests/HierarchyViewerTest/src/com/android/test/hierarchyviewer/MainActivityTest.java new file mode 100644 index 0000000..ea3710d --- /dev/null +++ b/tests/HierarchyViewerTest/src/com/android/test/hierarchyviewer/MainActivityTest.java @@ -0,0 +1,81 @@ +package com.android.test.hierarchyviewer; + +import android.test.ActivityInstrumentationTestCase2; +import android.view.View; + +import java.io.ByteArrayOutputStream; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.List; +import java.util.Map; + +public class MainActivityTest extends ActivityInstrumentationTestCase2<MainActivity> { + private MainActivity mActivity; + private View mTextView; + + + public MainActivityTest() { + super(MainActivity.class); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + + mActivity = getActivity(); + mTextView = mActivity.findViewById(R.id.textView); + } + + private byte[] encode(View view) throws ClassNotFoundException, NoSuchMethodException, + IllegalAccessException, InstantiationException, InvocationTargetException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(1024 * 1024); + + Object encoder = createEncoder(baos); + invokeMethod(View.class, view, "encode", encoder); + invokeMethod(encoder.getClass(), encoder, "endStream"); + + return baos.toByteArray(); + } + + private Object invokeMethod(Class targetClass, Object target, String methodName, Object... params) + throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + Class[] paramClasses = new Class[params.length]; + for (int i = 0; i < params.length; i++) { + paramClasses[i] = params[i].getClass(); + } + Method method = targetClass.getDeclaredMethod(methodName, paramClasses); + method.setAccessible(true); + return method.invoke(target, params); + } + + private Object createEncoder(ByteArrayOutputStream baos) throws ClassNotFoundException, + NoSuchMethodException, IllegalAccessException, InvocationTargetException, + InstantiationException { + Class clazz = Class.forName("android.view.ViewHierarchyEncoder"); + Constructor constructor = clazz.getConstructor(ByteArrayOutputStream.class); + return constructor.newInstance(baos); + } + + public void testTextView() throws Exception { + byte[] data = encode(mTextView); + assertNotNull(data); + assertTrue(data.length > 0); + + ViewDumpParser parser = new ViewDumpParser(); + parser.parse(data); + + List<Map<Short, Object>> views = parser.getViews(); + Map<String, Short> propertyNameTable = parser.getIds(); + + assertEquals(1, views.size()); + assertNotNull(propertyNameTable); + + Map<Short, Object> textViewProperties = views.get(0); + assertEquals("android.widget.TextView", + textViewProperties.get(propertyNameTable.get("meta:__name__"))); + + assertEquals(mActivity.getString(R.string.test), + textViewProperties.get(propertyNameTable.get("text:text"))); + } +} diff --git a/tests/HierarchyViewerTest/src/com/android/test/hierarchyviewer/ViewDumpParser.java b/tests/HierarchyViewerTest/src/com/android/test/hierarchyviewer/ViewDumpParser.java new file mode 100644 index 0000000..0111bc6 --- /dev/null +++ b/tests/HierarchyViewerTest/src/com/android/test/hierarchyviewer/ViewDumpParser.java @@ -0,0 +1,73 @@ +package com.android.test.hierarchyviewer; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +public class ViewDumpParser { + private Map<String, Short> mIds; + private List<Map<Short,Object>> mViews; + + public void parse(byte[] data) { + Decoder d = new Decoder(ByteBuffer.wrap(data)); + + mViews = new ArrayList<>(100); + while (d.hasRemaining()) { + Object o = d.readObject(); + if (o instanceof Map) { + //noinspection unchecked + mViews.add((Map<Short, Object>) o); + } + } + + if (mViews.isEmpty()) { + return; + } + + // the last one is the property map + Map<Short,Object> idMap = mViews.remove(mViews.size() - 1); + mIds = reverse(idMap); + } + + public String getFirstView() { + if (mViews.isEmpty()) { + return null; + } + + Map<Short, Object> props = mViews.get(0); + Object name = getProperty(props, "__name__"); + Object hash = getProperty(props, "__hash__"); + + if (name instanceof String && hash instanceof Integer) { + return String.format(Locale.US, "%s@%x", name, hash); + } else { + return null; + } + } + + private Object getProperty(Map<Short, Object> props, String key) { + return props.get(mIds.get(key)); + } + + private static Map<String, Short> reverse(Map<Short, Object> m) { + Map<String, Short> r = new HashMap<String, Short>(m.size()); + + for (Map.Entry<Short, Object> e : m.entrySet()) { + r.put((String)e.getValue(), e.getKey()); + } + + return r; + } + + public List<Map<Short, Object>> getViews() { + return mViews; + } + + public Map<String, Short> getIds() { + return mIds; + } + +} diff --git a/tests/LockTaskTests/AndroidManifest.xml b/tests/LockTaskTests/AndroidManifest.xml index f88744e..e349c92 100644 --- a/tests/LockTaskTests/AndroidManifest.xml +++ b/tests/LockTaskTests/AndroidManifest.xml @@ -29,28 +29,28 @@ android:label="@string/title_activity_default" android:taskAffinity="" android:documentLaunchMode="always" - android:lockTaskMode="lockTaskModeDefault" > + android:lockTaskMode="normal" > </activity> <activity android:name="com.google.android.example.locktasktests.LockTaskNeverActivity" android:label="@string/title_activity_never" android:taskAffinity="" android:documentLaunchMode="always" - android:lockTaskMode="lockTaskModeNever" > + android:lockTaskMode="never" > </activity> <activity android:name="com.google.android.example.locktasktests.LockWhitelistedActivity" android:label="@string/title_activity_whitelist" android:taskAffinity="" android:documentLaunchMode="always" - android:lockTaskMode="lockTaskModeIfWhitelisted" > + android:lockTaskMode="if_whitelisted" > </activity> <activity android:name="com.google.android.example.locktasktests.LockAtLaunchActivity" android:label="@string/title_activity_always" android:taskAffinity="" android:documentLaunchMode="always" - android:lockTaskMode="lockTaskModeAlways" > + android:lockTaskMode="always" > </activity> </application> diff --git a/tests/LockTaskTests/res/values/strings.xml b/tests/LockTaskTests/res/values/strings.xml index 61c029f..3bcae80 100644 --- a/tests/LockTaskTests/res/values/strings.xml +++ b/tests/LockTaskTests/res/values/strings.xml @@ -7,16 +7,17 @@ <string name="title_activity_whitelist">LockWhitelistedActivity</string> <string name="title_activity_always">LockAtLaunchActivity</string> <string name="launch_default">android:lockTaskMode=\n - \"lockTaskModeDefault\"\n + \"default\"\n Pinnable from Overview.</string> <string name="launch_never">android:lockTaskMode=\n - \"lockTaskModeNever\"\n + \"never\"\n Not Lockable or Pinnable.</string> - <string name="launch_whitelist">android:lockTaskMode=\n\"lockTaskModeIfWhitelisted\"\n + <string name="launch_whitelist">android:lockTaskMode=\n + \"if_whitelisted\"\n Lockable if whitelisted, Pinnable.\n Use SampleDeviceOwner app to set whitelist.</string> <string name="launch_always">android:lockTaskMode=\n - \"lockTaskModeAlways\"\n + \"always\"\n Launches into lock mode.</string> <string name="launch_main">launch MainActivity (as activity)"</string> <string name="try_lock">Call startLockMode()</string> diff --git a/tests/LockTaskTests/src/com/google/android/example/locktasktests/MainActivity.java b/tests/LockTaskTests/src/com/google/android/example/locktasktests/MainActivity.java index c2275c8..3e4f8ee 100644 --- a/tests/LockTaskTests/src/com/google/android/example/locktasktests/MainActivity.java +++ b/tests/LockTaskTests/src/com/google/android/example/locktasktests/MainActivity.java @@ -6,26 +6,50 @@ import android.app.ActivityManager; import android.content.Context; import android.content.Intent; import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; import android.view.View; public class MainActivity extends Activity { private final static String TAG = "LockTaskTests"; + Runnable mBackgroundPolling; + boolean mRunning; + Handler mHandler; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); + mBackgroundPolling = new Runnable() { + // Poll lock task state and set background pink if locked, otherwise white. + @Override + public void run() { + if (!mRunning) { + return; + } + ActivityManager activityManager = + (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); + final int color = activityManager.getLockTaskModeState() != + ActivityManager.LOCK_TASK_MODE_NONE ? 0xFFFFC0C0 : 0xFFFFFFFF; + findViewById(R.id.root_launch).setBackgroundColor(color); + mHandler.postDelayed(this, 500); + } + }; + mHandler = new Handler(Looper.getMainLooper()); } @Override public void onResume() { super.onResume(); - ActivityManager activityManager = - (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); - final int color = activityManager.getLockTaskModeState() != - ActivityManager.LOCK_TASK_MODE_NONE ? 0xFFFFC0C0 : 0xFFFFFFFF; - findViewById(R.id.root_launch).setBackgroundColor(color); + mRunning = true; + mBackgroundPolling.run(); + } + + @Override + public void onPause() { + super.onPause(); + mRunning = false; } public void onButtonPressed(View v) { diff --git a/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbosync.rs b/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbosync.rs index 42b1cf1..0c177ef 100644 --- a/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbosync.rs +++ b/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbosync.rs @@ -116,7 +116,6 @@ static void renderAllMeshes() { rs_allocation allMeshes = rsGetAllocation(gMeshes); int size = rsAllocationGetDimX(allMeshes); gLookAt = 0.0f; - float minX, minY, minZ, maxX, maxY, maxZ; for (int i = 0; i < size; i++) { MeshInfo_t *info = (MeshInfo_t*)rsGetElementAt(allMeshes, i); rsgDrawMesh(info->mMesh); @@ -124,7 +123,6 @@ static void renderAllMeshes() { } static void drawDescription() { - uint width = rsgGetWidth(); uint height = rsgGetHeight(); int left = 0, right = 0, top = 0, bottom = 0; @@ -196,7 +194,6 @@ int root(void) { uint32_t w = rsAllocationGetDimX(gOffscreen); uint32_t h = rsAllocationGetDimY(gOffscreen); - uint32_t numElements = w*h; rsgAllocationSyncAll(gOffscreen, RS_ALLOCATION_USAGE_GRAPHICS_RENDER_TARGET); diff --git a/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbotest.rs b/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbotest.rs index 05ef3ac..13a3c85 100644 --- a/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbotest.rs +++ b/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbotest.rs @@ -115,7 +115,6 @@ static void renderAllMeshes() { rs_allocation allMeshes = rsGetAllocation(gMeshes); int size = rsAllocationGetDimX(allMeshes); gLookAt = 0.0f; - float minX, minY, minZ, maxX, maxY, maxZ; for (int i = 0; i < size; i++) { MeshInfo_t *info = (MeshInfo_t*)rsGetElementAt(allMeshes, i); rsgDrawMesh(info->mMesh); @@ -123,7 +122,6 @@ static void renderAllMeshes() { } static void drawDescription() { - uint width = rsgGetWidth(); uint height = rsgGetHeight(); int left = 0, right = 0, top = 0, bottom = 0; diff --git a/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/simplemodel.rs b/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/simplemodel.rs index de2a0a7..d3dd5b9 100644 --- a/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/simplemodel.rs +++ b/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/simplemodel.rs @@ -123,7 +123,6 @@ static void renderAllMeshes() { rs_allocation allMeshes = rsGetAllocation(gMeshes); int size = rsAllocationGetDimX(allMeshes); gLookAt = 0.0f; - float minX, minY, minZ, maxX, maxY, maxZ; for (int i = 0; i < size; i++) { MeshInfo_t *info = (MeshInfo_t*)rsGetElementAt(allMeshes, i); rsgDrawMesh(info->mMesh); @@ -131,7 +130,6 @@ static void renderAllMeshes() { } void drawDescription() { - uint width = rsgGetWidth(); uint height = rsgGetHeight(); int left = 0, right = 0, top = 0, bottom = 0; @@ -163,7 +161,7 @@ int root(void) { rsMatrixMultiply(&matrix, &gPostureMatrix); rsMatrixRotate(&matrix, gRotateX, 1.0f, 0.0f, 0.0f); rsMatrixRotate(&matrix, gRotateY, 0.0f, 1.0f, 0.0f); - + rsgProgramVertexLoadModelMatrix(&matrix); renderAllMeshes(); diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs index 27e5b11..43cf4e0 100644 --- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs +++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs @@ -85,7 +85,7 @@ static void runSubTest(int index) { TestData testData; fillSurfaceParams(&testData); - rs_allocation null_alloc; + rs_allocation null_alloc = {0}; rsForEach(gTestScripts[index].testScript, gTestScripts[index].testData, null_alloc, @@ -125,7 +125,6 @@ static bool checkInit() { static int benchMode = 0; static bool benchmarkSingleTest = false; -static int benchSubMode = 0; static int runningLoops = 0; static bool sendMsgFlag = false; @@ -209,7 +208,6 @@ static void benchmark() { drawOffscreenResult(0, 0, quadW, quadH); int left = 0, right = 0, top = 0, bottom = 0; - uint width = rsgGetWidth(); uint height = rsgGetHeight(); rsgFontColor(0.9f, 0.9f, 0.95f, 1.0f); rsgBindFont(gFontSerif); diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/text_test.rs b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/text_test.rs index 7f10019..0f50828 100644 --- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/text_test.rs +++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/text_test.rs @@ -52,7 +52,6 @@ static void displayFontSamples(int fillNum) { fonts[3] = gFontSerif; fonts[4] = gFontSans; - uint width = gRenderSurfaceW; uint height = gRenderSurfaceH; int left = 0, right = 0, top = 0, bottom = 0; rsgMeasureText(sampleText, &left, &right, &top, &bottom); diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/ui_test.rs b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/ui_test.rs index 5089092..e87db39 100644 --- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/ui_test.rs +++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/ui_test.rs @@ -143,7 +143,6 @@ static void createParticle(Particle_t *part, int idx, float scale) { float d = fabs(randomGauss()) * gGalaxyRadius * 0.5f + rsRand(64.0f); float id = d / gGalaxyRadius; float z = randomGauss() * 0.4f * (1.0f - id); - float p = -d * ELLIPSE_TWIST; if (d < gGalaxyRadius * 0.33f) { part->color.x = (uchar) (220 + id * 35); @@ -305,7 +304,6 @@ static void drawMeshInPage(float xStart, float yStart, int wResolution, int hRes int left = 0, right = 0, top = 0, bottom = 0; rsgMeasureText(gSampleTextList100[0].item, &left, &right, &top, &bottom); float textHeight = (float)(top - bottom); - float textWidth = (float)(right - left); rs_matrix4x4 matrix; rsMatrixLoadScale(&matrix, size, size, 1.0); diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/params.rsh b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/params.rsh index 575794b..00793c0 100644 --- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/params.rsh +++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/params.rsh @@ -19,7 +19,7 @@ #include "scenegraph_objects.rsh" //#define DEBUG_PARAMS -static void debugParam(SgShaderParam *p, SgShaderParamData *pData) { +static inline void debugParam(SgShaderParam *p, SgShaderParamData *pData) { rsDebug("____________ Param ____________", p); printName(pData->paramName); rsDebug("bufferOffset", p->bufferOffset); @@ -44,8 +44,7 @@ static void debugParam(SgShaderParam *p, SgShaderParamData *pData) { } } - -static void writeFloatData(float *ptr, const float4 *input, uint32_t vecSize) { +static inline void writeFloatData(float *ptr, const float4 *input, uint32_t vecSize) { #ifdef DEBUG_PARAMS rsDebug("Writing value ", *input); rsDebug("Writing vec size ", vecSize); @@ -67,7 +66,7 @@ static void writeFloatData(float *ptr, const float4 *input, uint32_t vecSize) { } } -static bool processParam(SgShaderParam *p, SgShaderParamData *pData, +static inline bool processParam(SgShaderParam *p, SgShaderParamData *pData, uint8_t *constantBuffer, const SgCamera *currentCam, SgFragmentShader *shader) { @@ -155,7 +154,7 @@ static bool processParam(SgShaderParam *p, SgShaderParamData *pData, return true; } -static void processAllParams(rs_allocation shaderConst, +static inline void processAllParams(rs_allocation shaderConst, rs_allocation allParams, const SgCamera *camera) { if (rsIsObject(shaderConst)) { @@ -177,7 +176,7 @@ static void processAllParams(rs_allocation shaderConst, } } -static void processTextureParams(SgFragmentShader *shader) { +static inline void processTextureParams(SgFragmentShader *shader) { int numParams = 0; if (rsIsObject(shader->shaderTextureParams)) { numParams = rsAllocationGetDimX(shader->shaderTextureParams); diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/render.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/render.rs index 8a73dbd..205b2cb 100644 --- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/render.rs +++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/render.rs @@ -78,7 +78,7 @@ static void draw(SgRenderable *obj) { if (rsIsObject(renderState->pr)) { rsgBindProgramRaster(renderState->pr); } else { - rs_program_raster pr; + rs_program_raster pr = {0}; rsgBindProgramRaster(pr); } diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/scenegraph_objects.rsh b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/scenegraph_objects.rsh index bdca3ab..90ae212 100644 --- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/scenegraph_objects.rsh +++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/scenegraph_objects.rsh @@ -208,7 +208,7 @@ typedef struct Texture_s { rs_allocation texture; } SgTexture; -static void printName(rs_allocation name) { +static inline void printName(rs_allocation name) { if (!rsIsObject(name)) { rsDebug("no name", 0); return; @@ -217,7 +217,7 @@ static void printName(rs_allocation name) { rsDebug((const char*)rsGetElementAt(name, 0), 0); } -static void printCameraInfo(const SgCamera *cam) { +static inline void printCameraInfo(const SgCamera *cam) { rsDebug("***** Camera information. ptr:", cam); printName(cam->name); const SgTransform *camTransform = (const SgTransform *)rsGetElementAt(cam->transformMatrix, 0); @@ -233,7 +233,7 @@ static void printCameraInfo(const SgCamera *cam) { rsDebug("View: ", &cam->view); } -static void printLightInfo(const SgLight *light) { +static inline void printLightInfo(const SgLight *light) { rsDebug("***** Light information. ptr:", light); printName(light->name); const SgTransform *lTransform = (const SgTransform *)rsGetElementAt(light->transformMatrix, 0); @@ -246,7 +246,7 @@ static void printLightInfo(const SgLight *light) { rsDebug("Type: ", light->type); } -static void getCameraRay(const SgCamera *cam, int screenX, int screenY, float3 *pnt, float3 *vec) { +static inline void getCameraRay(const SgCamera *cam, int screenX, int screenY, float3 *pnt, float3 *vec) { rsDebug("=================================", screenX); rsDebug("Point X", screenX); rsDebug("Point Y", screenY); @@ -290,7 +290,7 @@ static void getCameraRay(const SgCamera *cam, int screenX, int screenY, float3 * *pnt = cam->position.xyz; } -static bool intersect(const SgRenderable *obj, float3 pnt, float3 vec) { +static inline bool intersect(const SgRenderable *obj, float3 pnt, float3 vec) { // Solving for t^2 + Bt + C = 0 float3 originMinusCenter = pnt - obj->worldBoundingSphere.xyz; float B = dot(originMinusCenter, vec) * 2.0f; diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/transform.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/transform.rs index 941b5a8..1d0b5be 100644 --- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/transform.rs +++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/transform.rs @@ -26,6 +26,7 @@ typedef struct { } ParentData; //#define DEBUG_TRANSFORMS +/* Unused function: static void debugTransform(SgTransform *data, const ParentData *parent) { rsDebug("****** <Transform> ******", (int)data); printName(data->name); @@ -53,6 +54,7 @@ static void debugTransform(SgTransform *data, const ParentData *parent) { rsDebug("timestamp", data->timestamp); rsDebug("****** </Transform> ******", (int)data); } +*/ static void appendTransformation(int type, float4 data, rs_matrix4x4 *mat) { rs_matrix4x4 temp; @@ -119,7 +121,7 @@ void root(const rs_allocation *v_in, rs_allocation *v_out, const void *usrData) } if (rsIsObject(data->children)) { - rs_allocation nullAlloc; + rs_allocation nullAlloc = {0}; rsForEach(gTransformScript, data->children, nullAlloc, &toChild, sizeof(toChild)); } diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/test_app.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/test_app.rs index 997a1a7..d94da52 100644 --- a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/test_app.rs +++ b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/test_app.rs @@ -41,9 +41,7 @@ void init() { gRotate = 0.0f; } -static int pos = 50; static float gRotateY = 120.0f; -static float3 gLookAt = 0; static float gZoom = 50.0f; static void displayLoading() { if (rsIsObject(gRobotTex) && rsIsObject(gRobotMesh)) { diff --git a/tests/RenderScriptTests/ShadersTest/src/com/android/shaderstest/shaderstest.rs b/tests/RenderScriptTests/ShadersTest/src/com/android/shaderstest/shaderstest.rs index ae32e3a..735f6b9 100644 --- a/tests/RenderScriptTests/ShadersTest/src/com/android/shaderstest/shaderstest.rs +++ b/tests/RenderScriptTests/ShadersTest/src/com/android/shaderstest/shaderstest.rs @@ -131,7 +131,6 @@ static void renderAllMeshes() { rs_allocation allMeshes = rsGetAllocation(gMeshes); int size = rsAllocationGetDimX(allMeshes); gLookAt = 0.0f; - float minX, minY, minZ, maxX, maxY, maxZ; for (int i = 0; i < size; i++) { MeshInfo_t *info = (MeshInfo_t*)rsGetElementAt(allMeshes, i); rsgDrawMesh(info->mMesh); diff --git a/tests/VoiceInteraction/res/layout/main.xml b/tests/VoiceInteraction/res/layout/main.xml index 34a7563..092d37d 100644 --- a/tests/VoiceInteraction/res/layout/main.xml +++ b/tests/VoiceInteraction/res/layout/main.xml @@ -34,12 +34,6 @@ android:text="@string/asyncStructure" /> - <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" - android:assistBlocked="true" - android:textAppearance="?android:attr/textAppearanceMedium" - android:text="This won't be included in assist." - /> - </LinearLayout> diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AsyncStructure.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AsyncStructure.java index 73e04e5..ae8e9e4 100644 --- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AsyncStructure.java +++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AsyncStructure.java @@ -20,7 +20,7 @@ import android.annotation.Nullable; import android.content.Context; import android.util.AttributeSet; import android.view.View; -import android.view.ViewAssistStructure; +import android.view.ViewStructure; import android.widget.TextView; /** @@ -32,9 +32,9 @@ public class AsyncStructure extends TextView { } @Override - public void onProvideVirtualAssistStructure(ViewAssistStructure structure) { + public void onProvideVirtualStructure(ViewStructure structure) { structure.setChildCount(1); - final ViewAssistStructure child = structure.asyncNewChild(0); + final ViewStructure child = structure.asyncNewChild(0); final int width = getWidth(); final int height = getHeight(); (new Thread() { diff --git a/tests/notification/Android.mk b/tests/notification/Android.mk new file mode 100644 index 0000000..0669553 --- /dev/null +++ b/tests/notification/Android.mk @@ -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) + diff --git a/tests/notification/AndroidManifest.xml b/tests/notification/AndroidManifest.xml new file mode 100644 index 0000000..7cee00a --- /dev/null +++ b/tests/notification/AndroidManifest.xml @@ -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> diff --git a/tests/notification/res/drawable-nodpi/arubin_hed.jpeg b/tests/notification/res/drawable-nodpi/arubin_hed.jpeg Binary files differnew file mode 100644 index 0000000..c6d8ae9 --- /dev/null +++ b/tests/notification/res/drawable-nodpi/arubin_hed.jpeg diff --git a/tests/notification/res/drawable-nodpi/bucket.png b/tests/notification/res/drawable-nodpi/bucket.png Binary files differnew file mode 100644 index 0000000..c865649 --- /dev/null +++ b/tests/notification/res/drawable-nodpi/bucket.png diff --git a/tests/notification/res/drawable-nodpi/matias_hed.jpg b/tests/notification/res/drawable-nodpi/matias_hed.jpg Binary files differnew file mode 100644 index 0000000..8cc3081 --- /dev/null +++ b/tests/notification/res/drawable-nodpi/matias_hed.jpg diff --git a/tests/notification/res/drawable-nodpi/page_hed.jpg b/tests/notification/res/drawable-nodpi/page_hed.jpg Binary files differnew file mode 100644 index 0000000..ea950c8 --- /dev/null +++ b/tests/notification/res/drawable-nodpi/page_hed.jpg diff --git a/tests/notification/res/drawable-nodpi/romainguy_hed.jpg b/tests/notification/res/drawable-nodpi/romainguy_hed.jpg Binary files differnew file mode 100644 index 0000000..5b7643e --- /dev/null +++ b/tests/notification/res/drawable-nodpi/romainguy_hed.jpg diff --git a/tests/notification/res/drawable-nodpi/romainguy_rockaway.jpg b/tests/notification/res/drawable-nodpi/romainguy_rockaway.jpg Binary files differnew file mode 100644 index 0000000..68473ba --- /dev/null +++ b/tests/notification/res/drawable-nodpi/romainguy_rockaway.jpg diff --git a/tests/notification/res/drawable-xhdpi/add.png b/tests/notification/res/drawable-xhdpi/add.png Binary files differnew file mode 100644 index 0000000..7226b3d --- /dev/null +++ b/tests/notification/res/drawable-xhdpi/add.png diff --git a/tests/notification/res/drawable-xhdpi/ic_dial_action_call.png b/tests/notification/res/drawable-xhdpi/ic_dial_action_call.png Binary files differnew file mode 100644 index 0000000..ca20a91 --- /dev/null +++ b/tests/notification/res/drawable-xhdpi/ic_dial_action_call.png diff --git a/tests/notification/res/drawable-xhdpi/ic_end_call.png b/tests/notification/res/drawable-xhdpi/ic_end_call.png Binary files differnew file mode 100644 index 0000000..c464a6d --- /dev/null +++ b/tests/notification/res/drawable-xhdpi/ic_end_call.png diff --git a/tests/notification/res/drawable-xhdpi/ic_media_next.png b/tests/notification/res/drawable-xhdpi/ic_media_next.png Binary files differnew file mode 100644 index 0000000..4def965 --- /dev/null +++ b/tests/notification/res/drawable-xhdpi/ic_media_next.png diff --git a/tests/notification/res/drawable-xhdpi/ic_menu_upload.png b/tests/notification/res/drawable-xhdpi/ic_menu_upload.png Binary files differnew file mode 100644 index 0000000..f1438ed --- /dev/null +++ b/tests/notification/res/drawable-xhdpi/ic_menu_upload.png diff --git a/tests/notification/res/drawable-xhdpi/icon.png b/tests/notification/res/drawable-xhdpi/icon.png Binary files differnew file mode 100644 index 0000000..189e85b --- /dev/null +++ b/tests/notification/res/drawable-xhdpi/icon.png diff --git a/tests/notification/res/drawable-xhdpi/stat_notify_alarm.png b/tests/notification/res/drawable-xhdpi/stat_notify_alarm.png Binary files differnew file mode 100644 index 0000000..658d04f --- /dev/null +++ b/tests/notification/res/drawable-xhdpi/stat_notify_alarm.png diff --git a/tests/notification/res/drawable-xhdpi/stat_notify_calendar.png b/tests/notification/res/drawable-xhdpi/stat_notify_calendar.png Binary files differnew file mode 100644 index 0000000..5ae7782 --- /dev/null +++ b/tests/notification/res/drawable-xhdpi/stat_notify_calendar.png diff --git a/tests/notification/res/drawable-xhdpi/stat_notify_email.png b/tests/notification/res/drawable-xhdpi/stat_notify_email.png Binary files differnew file mode 100644 index 0000000..23c4672 --- /dev/null +++ b/tests/notification/res/drawable-xhdpi/stat_notify_email.png diff --git a/tests/notification/res/drawable-xhdpi/stat_notify_missed_call.png b/tests/notification/res/drawable-xhdpi/stat_notify_missed_call.png Binary files differnew file mode 100644 index 0000000..8719eff --- /dev/null +++ b/tests/notification/res/drawable-xhdpi/stat_notify_missed_call.png diff --git a/tests/notification/res/drawable-xhdpi/stat_notify_sms.png b/tests/notification/res/drawable-xhdpi/stat_notify_sms.png Binary files differnew file mode 100644 index 0000000..323cb3d --- /dev/null +++ b/tests/notification/res/drawable-xhdpi/stat_notify_sms.png diff --git a/tests/notification/res/drawable-xhdpi/stat_notify_snooze.png b/tests/notification/res/drawable-xhdpi/stat_notify_snooze.png Binary files differnew file mode 100644 index 0000000..26dcda35 --- /dev/null +++ b/tests/notification/res/drawable-xhdpi/stat_notify_snooze.png diff --git a/tests/notification/res/drawable-xhdpi/stat_notify_snooze_longer.png b/tests/notification/res/drawable-xhdpi/stat_notify_snooze_longer.png Binary files differnew file mode 100644 index 0000000..b8b2f8a --- /dev/null +++ b/tests/notification/res/drawable-xhdpi/stat_notify_snooze_longer.png diff --git a/tests/notification/res/drawable-xhdpi/stat_notify_talk_text.png b/tests/notification/res/drawable-xhdpi/stat_notify_talk_text.png Binary files differnew file mode 100644 index 0000000..12cae9f --- /dev/null +++ b/tests/notification/res/drawable-xhdpi/stat_notify_talk_text.png diff --git a/tests/notification/res/drawable-xhdpi/stat_sys_phone_call.png b/tests/notification/res/drawable-xhdpi/stat_sys_phone_call.png Binary files differnew file mode 100644 index 0000000..db42b7c --- /dev/null +++ b/tests/notification/res/drawable-xhdpi/stat_sys_phone_call.png diff --git a/tests/notification/res/layout/full_screen.xml b/tests/notification/res/layout/full_screen.xml new file mode 100644 index 0000000..6ff7552 --- /dev/null +++ b/tests/notification/res/layout/full_screen.xml @@ -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>
\ No newline at end of file diff --git a/tests/notification/res/layout/main.xml b/tests/notification/res/layout/main.xml new file mode 100644 index 0000000..f5a740f --- /dev/null +++ b/tests/notification/res/layout/main.xml @@ -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> diff --git a/tests/notification/res/values/dimens.xml b/tests/notification/res/values/dimens.xml new file mode 100644 index 0000000..21e7bc3 --- /dev/null +++ b/tests/notification/res/values/dimens.xml @@ -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> diff --git a/tests/notification/res/values/strings.xml b/tests/notification/res/values/strings.xml new file mode 100644 index 0000000..80bf103 --- /dev/null +++ b/tests/notification/res/values/strings.xml @@ -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> diff --git a/tests/notification/src/com/android/frameworks/tests/notification/NotificationTests.java b/tests/notification/src/com/android/frameworks/tests/notification/NotificationTests.java new file mode 100644 index 0000000..7cda977 --- /dev/null +++ b/tests/notification/src/com/android/frameworks/tests/notification/NotificationTests.java @@ -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; + } + } +} + |