| /* |
| * Copyright (C) 2019 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.stubs; |
| |
| import static android.app.stubs.BubbledActivity.EXTRA_LOCUS_ID; |
| |
| import android.app.Activity; |
| import android.app.Notification; |
| import android.app.Notification.BubbleMetadata; |
| import android.app.NotificationManager; |
| import android.app.PendingIntent; |
| import android.app.Person; |
| import android.content.Context; |
| import android.content.Intent; |
| import android.content.LocusId; |
| import android.graphics.drawable.Icon; |
| import android.os.Bundle; |
| import android.os.SystemClock; |
| |
| /** |
| * Used by NotificationManagerTest for testing policy around bubbles, this activity is able to |
| * send a bubble. |
| */ |
| public class SendBubbleActivity extends Activity { |
| final String TAG = SendBubbleActivity.class.getSimpleName(); |
| |
| // Should be same as what NotificationManagerTest is using |
| private static final String NOTIFICATION_CHANNEL_ID = "NotificationManagerTest"; |
| private static final String SHARE_SHORTCUT_ID = "shareShortcut"; |
| |
| public static final String BUBBLE_ACTIVITY_OPENED = |
| "android.app.stubs.BUBBLE_ACTIVITY_OPENED"; |
| public static final int BUBBLE_NOTIF_ID = 1; |
| |
| private volatile boolean mIsStopped; |
| |
| @Override |
| public void onCreate(Bundle savedInstanceState) { |
| super.onCreate(savedInstanceState); |
| setContentView(R.layout.main); |
| |
| Intent i = new Intent(BUBBLE_ACTIVITY_OPENED); |
| sendBroadcast(i); |
| } |
| |
| public void startBubbleActivity(int id) { |
| startBubbleActivity(id, true /* addLocusId */); |
| } |
| |
| /** |
| * Starts the same activity that is in the bubble produced by this activity. |
| */ |
| public void startBubbleActivity(int id, boolean addLocusId) { |
| final Intent intent = new Intent(getApplicationContext(), BubbledActivity.class); |
| // Clear any previous instance of this activity |
| intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK); |
| if (addLocusId) { |
| intent.putExtra(EXTRA_LOCUS_ID, String.valueOf(id)); |
| } |
| startActivity(intent); |
| } |
| |
| /** |
| * Sends a notification that has bubble metadata but the rest of the notification isn't |
| * configured correctly so the system won't allow it to bubble. |
| */ |
| public void sendInvalidBubble(int notifId, boolean autoExpand) { |
| Context context = getApplicationContext(); |
| |
| PendingIntent pendingIntent = PendingIntent.getActivity(context, notifId, new Intent(), |
| PendingIntent.FLAG_MUTABLE); |
| Notification n = new Notification.Builder(context, NOTIFICATION_CHANNEL_ID) |
| .setSmallIcon(R.drawable.black) |
| .setWhen(System.currentTimeMillis()) |
| .setContentTitle("notify#" + notifId) |
| .setContentText("This is #" + notifId + "notification ") |
| .setContentIntent(pendingIntent) |
| .setBubbleMetadata(getBubbleMetadata(notifId, autoExpand, |
| false /* suppressNotification */, |
| false /* suppressBubble */, |
| false /* useShortcut */)) |
| .build(); |
| |
| NotificationManager noMan = (NotificationManager) context.getSystemService( |
| Context.NOTIFICATION_SERVICE); |
| noMan.notify(notifId, n); |
| } |
| |
| /** Sends a notification that is properly configured to bubble. */ |
| public void sendBubble(int notifId, boolean autoExpand, boolean suppressNotification) { |
| sendBubble(notifId, autoExpand, suppressNotification, false /* suppressBubble */, |
| false /* useShortcut */, true /* setLocusId */); |
| } |
| |
| /** Sends a notification that is properly configured to bubble. */ |
| public void sendBubble(int notifId, boolean autoExpand, boolean suppressNotification, |
| boolean suppressBubble) { |
| sendBubble(notifId, autoExpand, suppressNotification, suppressBubble, |
| false /* useShortcut */, true /* setLocusId */); |
| } |
| |
| /** Sends a notification that is properly configured to bubble. */ |
| public void sendBubble(int notifId, boolean autoExpand, boolean suppressNotification, |
| boolean suppressBubble, boolean useShortcut, boolean setLocusId) { |
| Context context = getApplicationContext(); |
| // Give it a person |
| Person person = new Person.Builder() |
| .setName("bubblebot" + notifId) |
| .build(); |
| // Make it messaging style |
| Notification.Builder nb = new Notification.Builder(context, NOTIFICATION_CHANNEL_ID) |
| .setSmallIcon(R.drawable.black) |
| .setContentTitle("Bubble Chat") |
| .setShortcutId(SHARE_SHORTCUT_ID) |
| .setStyle(new Notification.MessagingStyle(person) |
| .setConversationTitle("Bubble Chat") |
| .addMessage("Hello?", |
| SystemClock.currentThreadTimeMillis() - 300000, person) |
| .addMessage("Is it me you're looking for?", |
| SystemClock.currentThreadTimeMillis(), person) |
| ) |
| .setBubbleMetadata(getBubbleMetadata(notifId, |
| autoExpand, |
| suppressNotification, |
| suppressBubble, |
| useShortcut)); |
| |
| if (setLocusId) { |
| nb.setLocusId(new LocusId(String.valueOf(notifId))); |
| } |
| |
| NotificationManager noMan = (NotificationManager) context.getSystemService( |
| Context.NOTIFICATION_SERVICE); |
| noMan.notify(notifId, nb.build()); |
| } |
| |
| private BubbleMetadata getBubbleMetadata(int notifId, boolean autoExpand, |
| boolean suppressNotification, |
| boolean suppressBubble, |
| boolean useShortcut) { |
| if (useShortcut) { |
| return new Notification.BubbleMetadata.Builder(SHARE_SHORTCUT_ID) |
| .setAutoExpandBubble(autoExpand) |
| .setSuppressableBubble(suppressBubble) |
| .setSuppressNotification(suppressNotification) |
| .build(); |
| } else { |
| Context context = getApplicationContext(); |
| final Intent intent = new Intent(context, BubbledActivity.class); |
| intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); |
| intent.setAction(Intent.ACTION_MAIN); |
| final PendingIntent pendingIntent = |
| PendingIntent.getActivity(context, notifId, intent, |
| PendingIntent.FLAG_MUTABLE); |
| |
| return new Notification.BubbleMetadata.Builder(pendingIntent, |
| Icon.createWithResource(context, R.drawable.black)) |
| .setAutoExpandBubble(autoExpand) |
| .setSuppressNotification(suppressNotification) |
| .setSuppressableBubble(suppressBubble) |
| .build(); |
| } |
| } |
| |
| /** Waits for the activity to be stopped. Do not call this method on main thread. */ |
| public void waitForStopped() { |
| synchronized (this) { |
| while (!mIsStopped) { |
| try { |
| wait(5000 /* timeout */); |
| } catch (InterruptedException ignored) { |
| } |
| } |
| } |
| } |
| |
| @Override |
| protected void onStart() { |
| super.onStart(); |
| mIsStopped = false; |
| } |
| |
| @Override |
| protected void onStop() { |
| super.onStop(); |
| synchronized (this) { |
| mIsStopped = true; |
| notifyAll(); |
| } |
| } |
| } |