1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.wm.flicker.testapp;
18 
19 
20 import android.app.Notification;
21 import android.app.NotificationChannel;
22 import android.app.NotificationManager;
23 import android.app.PendingIntent;
24 import android.app.Person;
25 import android.content.Context;
26 import android.content.Intent;
27 import android.graphics.Point;
28 import android.graphics.drawable.Icon;
29 import android.os.SystemClock;
30 import android.service.notification.StatusBarNotification;
31 import android.view.WindowManager;
32 
33 import java.util.HashMap;
34 
35 public class BubbleHelper {
36 
37     static final String EXTRA_BUBBLE_NOTIF_ID = "EXTRA_BUBBLE_NOTIF_ID";
38     static final String CHANNEL_ID = "bubbles";
39     static final String CHANNEL_NAME = "Bubbles";
40     static final int DEFAULT_HEIGHT_DP = 300;
41 
42     private static BubbleHelper sInstance;
43 
44     private final Context mContext;
45     private NotificationManager mNotificationManager;
46     private float mDisplayHeight;
47 
48     private HashMap<Integer, BubbleInfo> mBubbleMap = new HashMap<>();
49 
50     private int mNextNotifyId = 0;
51     private int mColourIndex = 0;
52 
53     public static class BubbleInfo {
54         public int id;
55         public int height;
56         public Icon icon;
57 
BubbleInfo(int id, int height, Icon icon)58         public BubbleInfo(int id, int height, Icon icon) {
59             this.id = id;
60             this.height = height;
61             this.icon = icon;
62         }
63     }
64 
getInstance(Context context)65     public static BubbleHelper getInstance(Context context) {
66         if (sInstance == null) {
67             sInstance = new BubbleHelper(context);
68         }
69         return sInstance;
70     }
71 
BubbleHelper(Context context)72     private BubbleHelper(Context context) {
73         mContext = context;
74         mNotificationManager = context.getSystemService(NotificationManager.class);
75 
76         NotificationChannel channel = new NotificationChannel(CHANNEL_ID, CHANNEL_NAME,
77                 NotificationManager.IMPORTANCE_DEFAULT);
78         channel.setDescription("Channel that posts bubbles");
79         channel.setAllowBubbles(true);
80         mNotificationManager.createNotificationChannel(channel);
81 
82         Point p = new Point();
83         WindowManager wm = context.getSystemService(WindowManager.class);
84         wm.getDefaultDisplay().getRealSize(p);
85         mDisplayHeight = p.y;
86 
87     }
88 
getNextNotifyId()89     private int getNextNotifyId() {
90         int id = mNextNotifyId;
91         mNextNotifyId++;
92         return id;
93     }
94 
getIcon()95     private Icon getIcon() {
96         return Icon.createWithResource(mContext, R.drawable.bg);
97     }
98 
addNewBubble(boolean autoExpand, boolean suppressNotif)99     public int addNewBubble(boolean autoExpand, boolean suppressNotif) {
100         int id = getNextNotifyId();
101         BubbleInfo info = new BubbleInfo(id, DEFAULT_HEIGHT_DP, getIcon());
102         mBubbleMap.put(info.id, info);
103 
104         Notification.BubbleMetadata data = getBubbleBuilder(info)
105                 .setSuppressNotification(suppressNotif)
106                 .setAutoExpandBubble(false)
107                 .build();
108         Notification notification = getNotificationBuilder(info.id)
109                 .setBubbleMetadata(data).build();
110 
111         mNotificationManager.notify(info.id, notification);
112         return info.id;
113     }
114 
getNotificationBuilder(int id)115     private Notification.Builder getNotificationBuilder(int id) {
116         Person chatBot = new Person.Builder()
117                 .setBot(true)
118                 .setName("BubbleChat")
119                 .setImportant(true)
120                 .build();
121         String shortcutId = "BubbleChat";
122         return new Notification.Builder(mContext, CHANNEL_ID)
123                 .setChannelId(CHANNEL_ID)
124                 .setShortcutId(shortcutId)
125                 .setContentTitle("BubbleChat")
126                 .setContentIntent(PendingIntent.getActivity(mContext, 0,
127                         new Intent(mContext, LaunchBubbleActivity.class),
128                         PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE))
129                 .setStyle(new Notification.MessagingStyle(chatBot)
130                         .setConversationTitle("BubbleChat")
131                         .addMessage("BubbleChat",
132                                 SystemClock.currentThreadTimeMillis() - 300000, chatBot)
133                         .addMessage("Is it me, " + id + ", you're looking for?",
134                                 SystemClock.currentThreadTimeMillis(), chatBot)
135                 )
136                 .setSmallIcon(R.drawable.ic_bubble);
137     }
138 
getBubbleBuilder(BubbleInfo info)139     private Notification.BubbleMetadata.Builder getBubbleBuilder(BubbleInfo info) {
140         Intent target = new Intent(mContext, BubbleActivity.class);
141         target.putExtra(EXTRA_BUBBLE_NOTIF_ID, info.id);
142         PendingIntent bubbleIntent = PendingIntent.getActivity(mContext, info.id, target,
143                 PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
144 
145         return new Notification.BubbleMetadata.Builder()
146                 .setIntent(bubbleIntent)
147                 .setIcon(info.icon)
148                 .setDesiredHeight(info.height);
149     }
150 
cancel(int id)151     public void cancel(int id) {
152         mNotificationManager.cancel(id);
153     }
154 
cancelAll()155     public void cancelAll() {
156         mNotificationManager.cancelAll();
157     }
158 
cancelLast()159     public void cancelLast() {
160         StatusBarNotification[] activeNotifications = mNotificationManager.getActiveNotifications();
161         if (activeNotifications.length > 0) {
162             mNotificationManager.cancel(
163                     activeNotifications[activeNotifications.length - 1].getId());
164         }
165     }
166 
cancelFirst()167     public void cancelFirst() {
168         StatusBarNotification[] activeNotifications = mNotificationManager.getActiveNotifications();
169         if (activeNotifications.length > 0) {
170             mNotificationManager.cancel(activeNotifications[0].getId());
171         }
172     }
173 }
174