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