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