ShortcutManager CTS for throttling behavior

Turned out a content provider was still considered to be
in the foreground, so I had to use receivers...

Bug 29612099

Change-Id: Ie17b23fa6bf7ce26b3ecc797de33291396448ed6
diff --git a/tests/tests/shortcutmanager/Android.mk b/tests/tests/shortcutmanager/Android.mk
index 1f6bd27..245f0f6 100755
--- a/tests/tests/shortcutmanager/Android.mk
+++ b/tests/tests/shortcutmanager/Android.mk
@@ -31,7 +31,8 @@
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
 
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_SRC_FILES := $(call all-java-files-under, src) \
+    $(call all-java-files-under, common/src)
 
 LOCAL_PACKAGE_NAME := CtsShortcutManagerTestCases
 
diff --git a/tests/tests/shortcutmanager/AndroidTest.xml b/tests/tests/shortcutmanager/AndroidTest.xml
index 2955155..31b6b36 100644
--- a/tests/tests/shortcutmanager/AndroidTest.xml
+++ b/tests/tests/shortcutmanager/AndroidTest.xml
@@ -25,6 +25,7 @@
         <option name="test-file-name" value="CtsShortcutManagerLauncher2.apk" />
         <option name="test-file-name" value="CtsShortcutManagerLauncher3.apk" />
         <option name="test-file-name" value="CtsShortcutManagerLauncher4.apk" />
+        <option name="test-file-name" value="CtsShortcutManagerThrottlingTest.apk" />
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.content.pm.cts.shortcutmanager" />
diff --git a/tests/tests/shortcutmanager/common/src/android.content.pm.cts.shortcutmanager.common/Constants.java b/tests/tests/shortcutmanager/common/src/android.content.pm.cts.shortcutmanager.common/Constants.java
new file mode 100644
index 0000000..1fddaf9
--- /dev/null
+++ b/tests/tests/shortcutmanager/common/src/android.content.pm.cts.shortcutmanager.common/Constants.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.content.pm.cts.shortcutmanager.common;
+
+public class Constants {
+    public static final String ACTION_THROTTLING_TEST =
+            "android.content.pm.cts.shortcutmanager.ACTION_THROTTLING_TEST";
+    public static final String ACTION_THROTTLING_REPLY =
+            "android.content.pm.cts.shortcutmanager.ACTION_THROTTLING_REPLY";
+
+    public static final String EXTRA_METHOD = "method";
+    public static final String EXTRA_REPLY_ACTION = "reply_action";
+
+    public static final String TEST_SET_DYNAMIC_SHORTCUTS = "testSetDynamicShortcuts";
+    public static final String TEST_ADD_DYNAMIC_SHORTCUTS = "testAddDynamicShortcuts";
+    public static final String TEST_UPDATE_SHORTCUTS = "testUpdateShortcuts";
+}
diff --git a/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerThrottlingTest.java b/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerThrottlingTest.java
new file mode 100644
index 0000000..2f9d690
--- /dev/null
+++ b/tests/tests/shortcutmanager/src/android/content/pm/cts/shortcutmanager/ShortcutManagerThrottlingTest.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.content.pm.cts.shortcutmanager;
+
+
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.resetThrottling;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.retryUntil;
+
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.cts.shortcutmanager.common.Constants;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * The actual test is implemented in the CtsShortcutManagerThrottlingTest module.
+ * This class uses broadcast receivers to communicate with it, because if we just used an
+ * instrumentation test, the target process would never been throttled.
+ */
+@SmallTest
+public class ShortcutManagerThrottlingTest extends ShortcutManagerCtsTestsBase {
+    private void callTest(String method) {
+
+        final AtomicReference<Intent> ret = new AtomicReference<>();
+
+        // Register the reply receiver
+
+        // Use a random reply action every time.
+        final String replyAction = Constants.ACTION_THROTTLING_REPLY + sRandom.nextLong();
+        final IntentFilter filter = new IntentFilter(replyAction);
+
+        final BroadcastReceiver r = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                ret.set(intent);
+            }
+        };
+
+        getTestContext().registerReceiver(r, filter);
+
+        try {
+            // Send the request broadcast.
+
+            final Intent i = new Intent(Constants.ACTION_THROTTLING_TEST);
+            i.putExtra(Constants.EXTRA_METHOD, method);
+            i.putExtra(Constants.EXTRA_REPLY_ACTION, replyAction);
+            i.setComponent(ComponentName.unflattenFromString(
+                    "android.content.pm.cts.shortcutmanager.throttling/.ShortcutManagerThrottlingTestReceiver"
+                    ));
+            getTestContext().sendBroadcast(i);
+
+            // Wait for the response.
+            retryUntil(() -> ret.get() != null, "Didn't receiver result broadcast");
+
+            if (ret.get().getExtras().getBoolean("success")) {
+                return;
+            }
+            fail(ret.get().getExtras().getString("error"));
+        } finally {
+            getTestContext().unregisterReceiver(r);
+        }
+    }
+
+    public void testThrottling() throws InterruptedException {
+        resetThrottling(getInstrumentation());
+
+        callTest(Constants.TEST_SET_DYNAMIC_SHORTCUTS);
+
+        // --------------------------------------
+        resetThrottling(getInstrumentation());
+
+        callTest(Constants.TEST_ADD_DYNAMIC_SHORTCUTS);
+
+        // --------------------------------------
+        resetThrottling(getInstrumentation());
+
+        callTest(Constants.TEST_UPDATE_SHORTCUTS);
+    }
+}
diff --git a/tests/tests/shortcutmanager/throttling/Android.mk b/tests/tests/shortcutmanager/throttling/Android.mk
new file mode 100644
index 0000000..59d1f57
--- /dev/null
+++ b/tests/tests/shortcutmanager/throttling/Android.mk
@@ -0,0 +1,42 @@
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+# Tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts
+
+LOCAL_PACKAGE_NAME := CtsShortcutManagerThrottlingTest
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src) \
+    $(call all-java-files-under, ../common/src)
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+    android-support-test \
+    android-support-v4 \
+    mockito-target \
+    ctsdeviceutil \
+    ctstestrunner \
+    ub-uiautomator \
+    ShortcutManagerTestUtils
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/shortcutmanager/throttling/AndroidManifest.xml b/tests/tests/shortcutmanager/throttling/AndroidManifest.xml
new file mode 100644
index 0000000..2a16253
--- /dev/null
+++ b/tests/tests/shortcutmanager/throttling/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.content.pm.cts.shortcutmanager.throttling">
+
+    <application>
+        <receiver
+            android:name="ShortcutManagerThrottlingTestReceiver"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="android.content.pm.cts.shortcutmanager.ACTION_THROTTLING_TEST" />
+            </intent-filter>
+        </receiver>
+    </application>
+</manifest>
+
diff --git a/tests/tests/shortcutmanager/throttling/src/android/content/pm/cts/shortcutmanager/throttling/ShortcutManagerThrottlingTestReceiver.java b/tests/tests/shortcutmanager/throttling/src/android/content/pm/cts/shortcutmanager/throttling/ShortcutManagerThrottlingTestReceiver.java
new file mode 100644
index 0000000..e5aa3f8
--- /dev/null
+++ b/tests/tests/shortcutmanager/throttling/src/android/content/pm/cts/shortcutmanager/throttling/ShortcutManagerThrottlingTestReceiver.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.content.pm.cts.shortcutmanager.throttling;
+
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.list;
+
+import static junit.framework.Assert.assertTrue;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.fail;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ShortcutManager;
+import android.content.pm.cts.shortcutmanager.common.Constants;
+import android.os.Bundle;
+import android.util.Log;
+
+import java.util.function.BooleanSupplier;
+
+/**
+ * Throttling test case.
+ *
+ * If we run it as a regular instrumentation test, the process would always considered to be in the
+ * foreground and will never be throttled, so we use a broadcast to communicate from the
+ * main test apk.
+ */
+public class ShortcutManagerThrottlingTestReceiver extends BroadcastReceiver {
+    private ShortcutManager mManager;
+
+    public ShortcutManager getManager(Context context) {
+        if (mManager == null) {
+            mManager = context.getSystemService(ShortcutManager.class);
+        }
+        return mManager;
+    }
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        if (Constants.ACTION_THROTTLING_TEST.equals(intent.getAction())) {
+            boolean success = false;
+            String error = null;
+            try {
+                final String method = intent.getStringExtra(Constants.EXTRA_METHOD);
+                switch (method) {
+                    case Constants.TEST_SET_DYNAMIC_SHORTCUTS:
+                        testSetDynamicShortcuts(context);
+                        break;
+                    case Constants.TEST_ADD_DYNAMIC_SHORTCUTS:
+                        testAddDynamicShortcuts(context);
+                        break;
+                    case Constants.TEST_UPDATE_SHORTCUTS:
+                        testUpdateShortcuts(context);
+                        break;
+                    default:
+                        fail("Unknown test: " + method);
+                }
+
+                success = true;
+            } catch (Throwable e) {
+                error = "Test failed: " + e.getMessage() + "\n" + Log.getStackTraceString(e);
+            }
+
+            // Create the reply bundle.
+            final Bundle ret = new Bundle();
+            if (success) {
+                ret.putBoolean("success", true);
+            } else {
+                ret.putString("error", error);
+            }
+
+            // Send reply
+            final Intent reply = new Intent(intent.getStringExtra(Constants.EXTRA_REPLY_ACTION));
+            reply.putExtras(ret);
+
+            context.sendBroadcast(reply);
+        }
+    }
+
+    private void assertThrottled(Context context, BooleanSupplier apiCall) {
+        assertFalse("Throttling must be reset here", getManager(context).isRateLimitingActive());
+
+        assertTrue("First call should succeed", apiCall.getAsBoolean());
+
+        // App can make 10 API calls between the interval, but there's a chance that the throttling
+        // gets reset within this loop, so we make 20 calls.
+        boolean throttled = false;
+        for (int i = 0; i < 19; i++) {
+            if (!apiCall.getAsBoolean()) {
+                throttled = true;
+                break;
+            }
+        }
+        assertTrue("API call not throttled", throttled);
+    }
+
+    public void testSetDynamicShortcuts(Context context) {
+        assertThrottled(context, () -> getManager(context).setDynamicShortcuts(list()));
+    }
+
+    public void testAddDynamicShortcuts(Context context) {
+        assertThrottled(context, () -> getManager(context).addDynamicShortcuts(list()));
+    }
+
+    public void testUpdateShortcuts(Context context) {
+        assertThrottled(context, () -> getManager(context).updateShortcuts(list()));
+    }
+}