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