1 /* 2 * Copyright (C) 2013 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.telecom.testapps; 18 19 import com.android.server.telecom.testapps.R; 20 21 import android.app.Notification; 22 import android.app.NotificationChannel; 23 import android.app.NotificationManager; 24 import android.app.PendingIntent; 25 import android.content.ComponentName; 26 import android.content.Context; 27 import android.content.Intent; 28 import android.graphics.Color; 29 import android.graphics.drawable.Icon; 30 import android.media.AudioAttributes; 31 import android.net.Uri; 32 import android.os.Bundle; 33 import android.telecom.PhoneAccount; 34 import android.telecom.PhoneAccountHandle; 35 import android.telecom.TelecomManager; 36 import android.util.Log; 37 import android.widget.Toast; 38 39 import java.util.Arrays; 40 import java.util.HashMap; 41 import java.util.List; 42 import java.util.Map; 43 44 /** 45 * Class used to create, update and cancel the notification used to display and update call state 46 * for {@link TestConnectionService}. 47 */ 48 public class CallServiceNotifier { 49 private static final CallServiceNotifier INSTANCE = new CallServiceNotifier(); 50 private static final String CHANNEL_ID = "channel1"; 51 52 public static final String CALL_PROVIDER_ID = "testapps_TestConnectionService_CALL_PROVIDER_ID"; 53 public static final String SIM_SUBSCRIPTION_ID = 54 "testapps_TestConnectionService_SIM_SUBSCRIPTION_ID"; 55 public static final String SIM_SUBSCRIPTION_ID2 = 56 "testapps_TestConnectionService_SIM_SUBSCRIPTION_ID2"; 57 public static final String CONNECTION_MANAGER_ID = 58 "testapps_TestConnectionService_CONNECTION_MANAGER_ID"; 59 60 private Map<String, PhoneAccountHandle> mPhoneAccountMap = new HashMap<>(); 61 62 /** 63 * Static notification IDs. 64 */ 65 private static final int CALL_NOTIFICATION_ID = 1; 66 private static final int PHONE_ACCOUNT_NOTIFICATION_ID = 2; 67 68 /** 69 * Whether the added call should be started as a video call. Referenced by 70 * {@link TestConnectionService} to know whether to provide a call video provider. 71 */ 72 public static boolean mStartVideoCall; 73 74 /** 75 * Singleton accessor. 76 */ getInstance()77 public static CallServiceNotifier getInstance() { 78 return INSTANCE; 79 } 80 81 /** 82 * Creates a CallService & initializes notification manager. 83 */ CallServiceNotifier()84 private CallServiceNotifier() { 85 } 86 87 /** 88 * Updates the notification in the notification pane. 89 */ updateNotification(Context context)90 public void updateNotification(Context context) { 91 log("adding the notification ------------"); 92 NotificationChannel channel = new NotificationChannel(CHANNEL_ID, "Test Channel", 93 NotificationManager.IMPORTANCE_DEFAULT); 94 getNotificationManager(context).createNotificationChannel(channel); 95 getNotificationManager(context).notify(CALL_NOTIFICATION_ID, getMainNotification(context)); 96 getNotificationManager(context).notify( 97 PHONE_ACCOUNT_NOTIFICATION_ID, getPhoneAccountNotification(context)); 98 } 99 100 /** 101 * Cancels the notification. 102 */ cancelNotifications(Context context)103 public void cancelNotifications(Context context) { 104 log("canceling notification"); 105 getNotificationManager(context).cancel(CALL_NOTIFICATION_ID); 106 getNotificationManager(context).cancel(PHONE_ACCOUNT_NOTIFICATION_ID); 107 } 108 109 /** 110 * Registers a phone account with telecom. 111 */ registerPhoneAccount(Context context)112 public void registerPhoneAccount(Context context) { 113 TelecomManager telecomManager = 114 (TelecomManager) context.getSystemService(Context.TELECOM_SERVICE); 115 116 telecomManager.clearAccounts(); 117 118 Bundle testBundle = new Bundle(); 119 testBundle.putInt("EXTRA_INT_1", 1); 120 testBundle.putInt("EXTRA_INT_100", 100); 121 testBundle.putBoolean("EXTRA_BOOL_TRUE", true); 122 testBundle.putBoolean("EXTRA_BOOL_FALSE", false); 123 testBundle.putString("EXTRA_STR1", "Hello"); 124 testBundle.putString("EXTRA_STR2", "There"); 125 126 PhoneAccountHandle handle1 = new PhoneAccountHandle( 127 new ComponentName(context, TestConnectionService.class), CALL_PROVIDER_ID); 128 mPhoneAccountMap.put(CALL_PROVIDER_ID, handle1); 129 telecomManager.registerPhoneAccount(PhoneAccount.builder( 130 handle1, 131 "TelecomTestApp Call Provider") 132 .setAddress(Uri.parse("tel:555-TEST")) 133 .setSubscriptionAddress(Uri.parse("tel:555-TEST")) 134 .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER | 135 PhoneAccount.CAPABILITY_VIDEO_CALLING | 136 PhoneAccount.CAPABILITY_RTT | 137 PhoneAccount.CAPABILITY_VIDEO_CALLING_RELIES_ON_PRESENCE) 138 .setIcon(Icon.createWithResource( 139 context.getResources(), R.drawable.stat_sys_phone_call)) 140 .setHighlightColor(Color.RED) 141 // TODO: Add icon tint (Color.RED) 142 .setShortDescription("a short description for the call provider") 143 .setSupportedUriSchemes(Arrays.asList("tel")) 144 .setExtras(testBundle) 145 .build()); 146 147 PhoneAccountHandle handle2 = new PhoneAccountHandle( 148 new ComponentName(context, TestConnectionService.class), SIM_SUBSCRIPTION_ID); 149 mPhoneAccountMap.put(SIM_SUBSCRIPTION_ID, handle2); 150 telecomManager.registerPhoneAccount(PhoneAccount.builder( 151 handle2, 152 "TelecomTestApp SIM Subscription") 153 .setAddress(Uri.parse("tel:555-TSIM")) 154 .setSubscriptionAddress(Uri.parse("tel:555-TSIM")) 155 .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER | 156 PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION | 157 PhoneAccount.CAPABILITY_VIDEO_CALLING | 158 PhoneAccount.CAPABILITY_RTT | 159 PhoneAccount.CAPABILITY_VIDEO_CALLING_RELIES_ON_PRESENCE) 160 .setIcon(Icon.createWithResource( 161 context.getResources(), R.drawable.stat_sys_phone_call)) 162 .setHighlightColor(Color.GREEN) 163 // TODO: Add icon tint (Color.GREEN) 164 .setShortDescription("a short description for the sim subscription") 165 .build()); 166 167 PhoneAccountHandle handle3 = new PhoneAccountHandle( 168 new ComponentName(context, TestConnectionService.class), SIM_SUBSCRIPTION_ID2); 169 mPhoneAccountMap.put(SIM_SUBSCRIPTION_ID2, handle3); 170 telecomManager.registerPhoneAccount(PhoneAccount.builder( 171 handle3, 172 "TelecomTestApp SIM Subscription 2") 173 .setAddress(Uri.parse("tel:555-TSI2")) 174 .setSubscriptionAddress(Uri.parse("tel:555-TSI2")) 175 .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER | 176 PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION | 177 PhoneAccount.CAPABILITY_VIDEO_CALLING | 178 PhoneAccount.CAPABILITY_RTT | 179 PhoneAccount.CAPABILITY_VIDEO_CALLING_RELIES_ON_PRESENCE) 180 .setIcon(Icon.createWithResource( 181 context.getResources(), R.drawable.stat_sys_phone_call)) 182 .setHighlightColor(Color.CYAN) 183 .setShortDescription("a short description for the sim subscription") 184 .build()); 185 186 PhoneAccountHandle handle4 = new PhoneAccountHandle( 187 new ComponentName(context, TestConnectionManager.class), CONNECTION_MANAGER_ID); 188 mPhoneAccountMap.put(CONNECTION_MANAGER_ID, handle4); 189 telecomManager.registerPhoneAccount(PhoneAccount.builder( 190 handle4, 191 "TelecomTestApp CONNECTION MANAGER") 192 .setAddress(Uri.parse("tel:555-CMGR")) 193 .setSubscriptionAddress(Uri.parse("tel:555-CMGR")) 194 .setCapabilities(PhoneAccount.CAPABILITY_CONNECTION_MANAGER) 195 .setIcon(Icon.createWithResource( 196 context.getResources(), R.drawable.stat_sys_phone_call)) 197 // TODO: Add icon tint (Color.BLUE) 198 .setShortDescription("a short description for the connection manager") 199 .build()); 200 } 201 getPhoneAccountHandle(String id)202 public PhoneAccountHandle getPhoneAccountHandle(String id) { 203 return mPhoneAccountMap.get(id); 204 } 205 206 /** 207 * Displays all phone accounts registered with telecom. 208 */ showAllPhoneAccounts(Context context)209 public void showAllPhoneAccounts(Context context) { 210 TelecomManager telecomManager = 211 (TelecomManager) context.getSystemService(Context.TELECOM_SERVICE); 212 List<PhoneAccountHandle> accounts = telecomManager.getCallCapablePhoneAccounts(); 213 214 Toast.makeText(context, accounts.toString(), Toast.LENGTH_LONG).show(); 215 } 216 217 /** 218 * Returns the system's notification manager needed to add/remove notifications. 219 */ getNotificationManager(Context context)220 private NotificationManager getNotificationManager(Context context) { 221 return (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); 222 } 223 224 /** 225 * Creates a notification object for using the telecom APIs. 226 */ getPhoneAccountNotification(Context context)227 private Notification getPhoneAccountNotification(Context context) { 228 final Notification.Builder builder = new Notification.Builder(context, CHANNEL_ID); 229 // Both notifications have buttons and only the first one with buttons will show its 230 // buttons. Since the phone accounts notification is always first, setting false ensures 231 // it can be dismissed to use the other notification. 232 builder.setOngoing(false); 233 builder.setPriority(Notification.PRIORITY_HIGH); 234 235 final PendingIntent intent = createShowAllPhoneAccountsIntent(context); 236 builder.setContentIntent(intent); 237 238 builder.setSmallIcon(android.R.drawable.stat_sys_phone_call); 239 // TODO: Consider moving this into a strings.xml 240 builder.setContentText("Test phone accounts via telecom APIs."); 241 builder.setContentTitle("Test Phone Accounts"); 242 243 addRegisterPhoneAccountAction(builder, context); 244 addShowAllPhoneAccountsAction(builder, context); 245 246 return builder.build(); 247 } 248 249 /** 250 * Creates a notification object out of the current calls state. 251 */ getMainNotification(Context context)252 private Notification getMainNotification(Context context) { 253 final Notification.Builder builder = new Notification.Builder(context, CHANNEL_ID); 254 builder.setOngoing(true); 255 builder.setPriority(Notification.PRIORITY_HIGH); 256 builder.setSmallIcon(android.R.drawable.stat_sys_phone_call); 257 builder.setContentText("Test calls via CallService API"); 258 builder.setContentTitle("Test Connection Service"); 259 260 addAddOneWayVideoCallAction(builder, context); 261 addAddTwoWayVideoCallAction(builder, context); 262 addAddCallAction(builder, context); 263 addExitAction(builder, context); 264 265 return builder.build(); 266 } 267 268 /** 269 * Creates the intent to remove the notification. 270 */ createExitIntent(Context context)271 private PendingIntent createExitIntent(Context context) { 272 final Intent intent = new Intent(CallNotificationReceiver.ACTION_CALL_SERVICE_EXIT, null, 273 context, CallNotificationReceiver.class); 274 275 return PendingIntent.getBroadcast(context, 0, intent, 0); 276 } 277 278 /** 279 * Creates the intent to register a phone account. 280 */ createRegisterPhoneAccountIntent(Context context)281 private PendingIntent createRegisterPhoneAccountIntent(Context context) { 282 final Intent intent = new Intent(CallNotificationReceiver.ACTION_REGISTER_PHONE_ACCOUNT, 283 null, context, CallNotificationReceiver.class); 284 return PendingIntent.getBroadcast(context, 0, intent, 0); 285 } 286 287 /** 288 * Creates the intent to show all phone accounts. 289 */ createShowAllPhoneAccountsIntent(Context context)290 private PendingIntent createShowAllPhoneAccountsIntent(Context context) { 291 final Intent intent = new Intent(CallNotificationReceiver.ACTION_SHOW_ALL_PHONE_ACCOUNTS, 292 null, context, CallNotificationReceiver.class); 293 return PendingIntent.getBroadcast(context, 0, intent, 0); 294 } 295 296 /** 297 * Creates the intent to start an incoming 1-way video call (receive-only) 298 */ createOneWayVideoCallIntent(Context context)299 private PendingIntent createOneWayVideoCallIntent(Context context) { 300 final Intent intent = new Intent(CallNotificationReceiver.ACTION_ONE_WAY_VIDEO_CALL, 301 null, context, CallNotificationReceiver.class); 302 return PendingIntent.getBroadcast(context, 0, intent, 0); 303 } 304 305 /** 306 * Creates the intent to start an incoming 2-way video call 307 */ createTwoWayVideoCallIntent(Context context)308 private PendingIntent createTwoWayVideoCallIntent(Context context) { 309 final Intent intent = new Intent(CallNotificationReceiver.ACTION_TWO_WAY_VIDEO_CALL, 310 null, context, CallNotificationReceiver.class); 311 return PendingIntent.getBroadcast(context, 0, intent, 0); 312 } 313 314 /** 315 * Creates the intent to start an incoming audio call 316 */ createIncomingAudioCall(Context context)317 private PendingIntent createIncomingAudioCall(Context context) { 318 final Intent intent = new Intent(CallNotificationReceiver.ACTION_AUDIO_CALL, 319 null, context, CallNotificationReceiver.class); 320 return PendingIntent.getBroadcast(context, 0, intent, 0); 321 } 322 323 /** 324 * Adds an action to the Notification Builder for adding an incoming call through Telecom. 325 * @param builder The Notification Builder. 326 */ addAddCallAction(Notification.Builder builder, Context context)327 private void addAddCallAction(Notification.Builder builder, Context context) { 328 builder.addAction(0, "Add Call", createIncomingAudioCall(context)); 329 } 330 331 /** 332 * Adds an action to the Notification Builder to add an incoming one-way video call through 333 * Telecom. 334 */ addAddOneWayVideoCallAction(Notification.Builder builder, Context context)335 private void addAddOneWayVideoCallAction(Notification.Builder builder, Context context) { 336 builder.addAction(0, "1-way Video", createOneWayVideoCallIntent(context)); 337 } 338 339 /** 340 * Adds an action to the Notification Builder to add an incoming 2-way video call through 341 * Telecom. 342 */ addAddTwoWayVideoCallAction(Notification.Builder builder, Context context)343 private void addAddTwoWayVideoCallAction(Notification.Builder builder, Context context) { 344 builder.addAction(0, "2-way Video", createTwoWayVideoCallIntent(context)); 345 } 346 347 /** 348 * Adds an action to remove the notification. 349 */ addExitAction(Notification.Builder builder, Context context)350 private void addExitAction(Notification.Builder builder, Context context) { 351 builder.addAction(0, "Exit", createExitIntent(context)); 352 } 353 354 /** 355 * Adds an action to show all registered phone accounts on a device. 356 */ addShowAllPhoneAccountsAction(Notification.Builder builder, Context context)357 private void addShowAllPhoneAccountsAction(Notification.Builder builder, Context context) { 358 builder.addAction(0, "Show Accts", createShowAllPhoneAccountsIntent(context)); 359 } 360 361 /** 362 * Adds an action to register a new phone account. 363 */ addRegisterPhoneAccountAction(Notification.Builder builder, Context context)364 private void addRegisterPhoneAccountAction(Notification.Builder builder, Context context) { 365 builder.addAction(0, "Reg.Acct.", createRegisterPhoneAccountIntent(context)); 366 } 367 shouldStartVideoCall()368 public boolean shouldStartVideoCall() { 369 return mStartVideoCall; 370 } 371 log(String msg)372 private static void log(String msg) { 373 Log.w("testcallservice", "[CallServiceNotifier] " + msg); 374 } 375 } 376