| /* |
| * Copyright (C) 2014 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package com.android.cts.robot; |
| |
| import android.app.Notification; |
| import android.app.Notification.Action; |
| import android.app.NotificationChannel; |
| import android.app.NotificationManager; |
| import android.app.PendingIntent; |
| import android.app.RemoteInput; |
| import android.content.BroadcastReceiver; |
| import android.content.ComponentName; |
| import android.content.Context; |
| import android.content.Intent; |
| import android.content.pm.ShortcutInfo; |
| import android.content.pm.ShortcutManager; |
| import android.os.SystemClock; |
| import android.util.Log; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| |
| public class NotificationBot extends BroadcastReceiver { |
| private static final String TAG = "NotificationBot"; |
| private static final String NOTIFICATION_CHANNEL_ID = TAG + "_high"; |
| private static final String EXTRA_ID = "ID"; |
| private static final String EXTRA_NOTIFICATION = "NOTIFICATION"; |
| private static final String ACTION_POST = "com.android.cts.robot.ACTION_POST"; |
| private static final String ACTION_CANCEL = "com.android.cts.robot.ACTION_CANCEL"; |
| private static final String ACTION_RESET_SETUP_NOTIFICATION = |
| "com.android.cts.robot.ACTION_RESET_SETUP_NOTIFICATION"; |
| |
| private static final String ACTION_INLINE_REPLY = |
| "com.android.cts.robot.ACTION_INLINE_REPLY"; |
| |
| private static final String EXTRA_RESET_REPLY_PACKAGE = "EXTRA_RESET_REPLY_PACKAGE"; |
| private static final String EXTRA_RESET_REPLY_ACTION = "EXTRA_RESET_REPLY_ACTION"; |
| private static final String EXTRA_NOTIFICATION_TITLE = "EXTRA_NOTIFICATION_TITLE"; |
| |
| private static final String EXTRA_RESET_REPLY_ERROR = "EXTRA_RESET_REPLY_ERROR"; |
| |
| private static final String EXTRA_RESET_REQUEST_INTENT = "EXTRA_RESET_REQUEST_INTENT"; |
| |
| private static final String SUCCESS = "**SUCCESS**"; |
| |
| @Override |
| public void onReceive(Context context, Intent intent) { |
| Log.i(TAG, "received intent: " + intent); |
| if (ACTION_POST.equals(intent.getAction())) { |
| Log.i(TAG, ACTION_POST); |
| if (!intent.hasExtra(EXTRA_NOTIFICATION) || !intent.hasExtra(EXTRA_ID)) { |
| Log.e(TAG, "received post action with missing content"); |
| return; |
| } |
| int id = intent.getIntExtra(EXTRA_ID, -1); |
| Log.i(TAG, "id: " + id); |
| Notification n = (Notification) intent.getParcelableExtra(EXTRA_NOTIFICATION); |
| Log.i(TAG, "n: " + n); |
| NotificationManager noMa = |
| (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); |
| noMa.notify(id, n); |
| |
| } else if (ACTION_CANCEL.equals(intent.getAction())) { |
| Log.i(TAG, ACTION_CANCEL); |
| int id = intent.getIntExtra(EXTRA_ID, -1); |
| Log.i(TAG, "id: " + id); |
| if (id < 0) { |
| Log.e(TAG, "received cancel action with no ID"); |
| return; |
| } |
| NotificationManager noMa = |
| (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); |
| noMa.cancel(id); |
| |
| } else if (ACTION_RESET_SETUP_NOTIFICATION.equals(intent.getAction())) { |
| testShortcutResetSetupNotification(context, intent); |
| |
| } else if (ACTION_INLINE_REPLY.equals(intent.getAction())) { |
| testShortcutResetInlineReplyReceived(context, intent); |
| |
| } else { |
| Log.i(TAG, "received unexpected action: " + intent.getAction()); |
| } |
| } |
| |
| /** |
| * Test start request from CTS verifier. Show a notification with inline reply, which will |
| * trigger {@link #testShortcutResetInlineReplyReceived}. |
| */ |
| private static void testShortcutResetSetupNotification(Context context, Intent intent) { |
| final NotificationManager nm = context.getSystemService(NotificationManager.class); |
| nm.cancelAll(); |
| |
| final ShortcutManager sm = context.getSystemService(ShortcutManager.class); |
| |
| final List<ShortcutInfo> EMPTY_LIST = new ArrayList<>(); |
| |
| long timeout = SystemClock.elapsedRealtime() + 10 * 1000; |
| |
| // First, make sure this package is throttled. |
| while (!sm.isRateLimitingActive()) { |
| sm.setDynamicShortcuts(EMPTY_LIST); |
| try { |
| Thread.sleep(0); |
| } catch (InterruptedException e) { |
| } |
| if (SystemClock.elapsedRealtime() >= timeout) { |
| sendShortcutResetReply(context, intent, |
| "ShortcutMager rate-limiting not activated."); |
| return; |
| } |
| } |
| |
| // Show a notification with inline reply. |
| final PendingIntent receiverIntent = |
| PendingIntent.getBroadcast(context, 0, |
| new Intent(ACTION_INLINE_REPLY) |
| .setComponent(new ComponentName(context, NotificationBot.class)) |
| .putExtra(EXTRA_RESET_REQUEST_INTENT, intent), |
| PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE); |
| final RemoteInput ri = new RemoteInput.Builder("result") |
| .setLabel("Type something here and press send button").build(); |
| |
| NotificationManager notificationManager = |
| context.getSystemService(NotificationManager.class); |
| notificationManager.createNotificationChannel(new NotificationChannel( |
| NOTIFICATION_CHANNEL_ID, NOTIFICATION_CHANNEL_ID, |
| NotificationManager.IMPORTANCE_HIGH)); |
| final Notification.Builder nb = new Notification.Builder(context, NOTIFICATION_CHANNEL_ID) |
| .setContentTitle(intent.getStringExtra(EXTRA_NOTIFICATION_TITLE)) |
| .setSmallIcon(android.R.drawable.ic_popup_sync) |
| .addAction(new Action.Builder(0, |
| "Type something here and press send button", receiverIntent) |
| .addRemoteInput(ri) |
| .build()); |
| notificationManager.notify(0, nb.build()); |
| } |
| |
| /** |
| * Invoked when the inline reply from {@link #testShortcutResetSetupNotification} is performed. |
| * |
| * Check the shortcut manager rate-limiting state, and post the reply to CTS verifier. |
| */ |
| private static void testShortcutResetInlineReplyReceived(Context context, Intent intent) { |
| Log.i(TAG, "Inline reply received"); |
| |
| final NotificationManager nm = context.getSystemService(NotificationManager.class); |
| nm.cancelAll(); |
| |
| // Close notification shade. |
| context.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)); |
| |
| // Check if rate-limiting has been reset. |
| final ShortcutManager sm = context.getSystemService(ShortcutManager.class); |
| |
| String error; |
| final boolean success = !sm.isRateLimitingActive(); |
| if (success) { |
| error = SUCCESS; |
| } else { |
| error = "Inline reply received, but ShortcutManager rate-limiting is still active."; |
| } |
| |
| // Send back the result. |
| sendShortcutResetReply(context, |
| intent.getParcelableExtra(EXTRA_RESET_REQUEST_INTENT), error); |
| } |
| |
| /** |
| * Reply an error message, or {@link #SUCCESS} for success, to CTS verifier for shortcut manager |
| * reset rate-limiting test. |
| |
| * @param requestIntent original intent sent from the verifier to |
| * {@link #testShortcutResetSetupNotification}. |
| * @param error error message, or {@link #SUCCESS} if success. |
| */ |
| private static void sendShortcutResetReply(Context context, Intent requestIntent, String error) { |
| final Intent replyIntent = new Intent(); |
| replyIntent.setAction(requestIntent.getStringExtra(EXTRA_RESET_REPLY_ACTION)); |
| replyIntent.putExtra(EXTRA_RESET_REPLY_ERROR, error); |
| |
| if (error != null) { |
| Log.e(TAG, error); |
| } |
| |
| context.sendBroadcast(replyIntent); |
| } |
| } |