1 /*
2  * Copyright (C) 2017 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 static android.app.UiModeManager.DEFAULT_PRIORITY;
20 
21 import android.app.Activity;
22 import android.app.NotificationChannel;
23 import android.app.NotificationManager;
24 import android.app.UiModeManager;
25 import android.app.role.RoleManager;
26 import android.content.Context;
27 import android.content.Intent;
28 import android.media.AudioAttributes;
29 import android.media.RingtoneManager;
30 import android.net.Uri;
31 import android.os.Bundle;
32 import android.telecom.ConnectionRequest;
33 import android.telecom.PhoneAccountHandle;
34 import android.telecom.TelecomManager;
35 import android.telecom.VideoProfile;
36 import android.util.Log;
37 import android.view.View;
38 import android.view.WindowManager;
39 import android.widget.Button;
40 import android.widget.CheckBox;
41 import android.widget.EditText;
42 import android.widget.ListView;
43 import android.widget.RadioButton;
44 import android.widget.TextView;
45 import android.widget.Toast;
46 
47 import java.util.Objects;
48 
49 /**
50  * Provides a sample third-party calling app UX which implements the self managed connection service
51  * APIs.
52  */
53 public class SelfManagedCallingActivity extends Activity {
54     private static final String TAG = "SelfMgCallActivity";
55     private static final int REQUEST_ID = 1;
56     private SelfManagedCallList mCallList = SelfManagedCallList.getInstance();
57     private CheckBox mCheckIfPermittedBeforeCalling;
58     private Button mPlaceOutgoingCallButton;
59     private Button mPlaceSelfManagedOutgoingCallButton;
60     private Button mPlaceSelfManagedIncomingCallButton;
61     private Button mPlaceIncomingCallButton;
62     private Button mHandoverFrom;
63     private Button mRequestCallScreeningRole;
64     private Button mEnableCarMode;
65     private Button mDisableCarMode;
66     private RadioButton mUseAcct1Button;
67     private RadioButton mUseAcct2Button;
68     private RadioButton mUseAcct3Button;
69     private CheckBox mHoldableCheckbox;
70     private CheckBox mVideoCallCheckbox;
71     private EditText mNumber;
72     private ListView mListView;
73     private TextView mHasFocus;
74 
75     private SelfManagedCallListAdapter mListAdapter;
76 
77     private SelfManagedCallList.Listener mCallListListener = new SelfManagedCallList.Listener() {
78         @Override
79         public void onCreateIncomingConnectionFailed(ConnectionRequest request) {
80             Log.i(TAG, "onCreateIncomingConnectionFailed " + request);
81             Toast.makeText(SelfManagedCallingActivity.this,
82                     R.string.incomingCallNotPermittedCS , Toast.LENGTH_SHORT).show();
83         };
84 
85         @Override
86         public void onCreateOutgoingConnectionFailed(ConnectionRequest request) {
87             Log.i(TAG, "onCreateOutgoingConnectionFailed " + request);
88             Toast.makeText(SelfManagedCallingActivity.this,
89                     R.string.outgoingCallNotPermittedCS , Toast.LENGTH_SHORT).show();
90         };
91 
92         @Override
93         public void onConnectionListChanged() {
94             Log.i(TAG, "onConnectionListChanged");
95             mListAdapter.updateConnections();
96         };
97 
98         @Override
99         public void onConnectionServiceFocusLost() {
100             mHasFocus.setText("\uD83D\uDC4E No Focus \uD83D\uDC4E");
101         };
102 
103         @Override
104         public void onConnectionServiceFocusGained() {
105             mHasFocus.setText("\uD83D\uDC4D Has Focus \uD83D\uDC4D");
106         };
107     };
108 
109     @Override
onCreate(Bundle savedInstanceState)110     public void onCreate(Bundle savedInstanceState) {
111         super.onCreate(savedInstanceState);
112         int flags =
113                 WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
114                         | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
115                         | WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES;
116 
117         getWindow().addFlags(flags);
118         configureNotificationChannel();
119         setContentView(R.layout.self_managed_sample_main);
120         mCheckIfPermittedBeforeCalling = (CheckBox) findViewById(
121                 R.id.checkIfPermittedBeforeCalling);
122         mPlaceOutgoingCallButton = (Button) findViewById(R.id.placeOutgoingCallButton);
123         mPlaceOutgoingCallButton.setOnClickListener(new View.OnClickListener() {
124             @Override
125             public void onClick(View v) {
126                 placeOutgoingCall();
127             }
128         });
129         mPlaceSelfManagedOutgoingCallButton = (Button) findViewById(
130                 R.id.placeSelfManagedOutgoingCallButton);
131         mPlaceSelfManagedOutgoingCallButton.setOnClickListener(new View.OnClickListener() {
132             @Override
133             public void onClick(View v) {
134                 placeSelfManagedOutgoingCall();
135             }
136         });
137         mPlaceSelfManagedIncomingCallButton = (Button) findViewById(
138                 R.id.placeSelfManagedIncomingCallButton);
139         mPlaceSelfManagedIncomingCallButton.setOnClickListener(new View.OnClickListener() {
140             @Override
141             public void onClick(View v) { placeSelfManagedIncomingCall(); }
142         });
143         mPlaceIncomingCallButton = (Button) findViewById(R.id.placeIncomingCallButton);
144         mPlaceIncomingCallButton.setOnClickListener(new View.OnClickListener() {
145             @Override
146             public void onClick(View v) {
147                 placeIncomingCall();
148             }
149         });
150         mHandoverFrom = (Button) findViewById(R.id.handoverFrom);
151         mHandoverFrom.setOnClickListener((v -> {
152             initiateHandover();
153         }));
154         mRequestCallScreeningRole = (Button) findViewById(R.id.requestCallScreeningRole);
155         mRequestCallScreeningRole.setOnClickListener((v -> {
156             requestCallScreeningRole();
157         }));
158         mEnableCarMode = (Button) findViewById(R.id.enableCarMode);
159         mEnableCarMode.setOnClickListener((v -> {
160             enableCarMode();
161         }));
162         mDisableCarMode = (Button) findViewById(R.id.disableCarMode);
163         mDisableCarMode.setOnClickListener((v -> {
164             disableCarMode();
165         }));
166         mUseAcct1Button = findViewById(R.id.useAcct1Button);
167         mUseAcct2Button = findViewById(R.id.useAcct2Button);
168         mUseAcct3Button = findViewById(R.id.useAcct3Button);
169         mHasFocus = findViewById(R.id.hasFocus);
170         mVideoCallCheckbox = findViewById(R.id.videoCall);
171         mHoldableCheckbox = findViewById(R.id.holdable);
172         mNumber = (EditText) findViewById(R.id.phoneNumber);
173         mListView = (ListView) findViewById(R.id.callList);
174         mCallList.setListener(mCallListListener);
175         mCallList.registerPhoneAccounts(this);
176         mListAdapter = new SelfManagedCallListAdapter(getLayoutInflater(),
177                 mCallList.getConnections());
178         mListView.setAdapter(mListAdapter);
179         Log.i(TAG, "onCreate - mCallList id " + Objects.hashCode(mCallList));
180     }
181 
getSelectedPhoneAccountHandle()182     private PhoneAccountHandle getSelectedPhoneAccountHandle() {
183         if (mUseAcct1Button.isChecked()) {
184             return mCallList.getPhoneAccountHandle(SelfManagedCallList.SELF_MANAGED_ACCOUNT_1);
185         } else if (mUseAcct2Button.isChecked()) {
186             return mCallList.getPhoneAccountHandle(SelfManagedCallList.SELF_MANAGED_ACCOUNT_2);
187         } else if (mUseAcct3Button.isChecked()) {
188             return mCallList.getPhoneAccountHandle(SelfManagedCallList.SELF_MANAGED_ACCOUNT_3);
189         }
190         return null;
191     }
192 
placeOutgoingCall()193     private void placeOutgoingCall() {
194         TelecomManager tm = this.getSystemService(TelecomManager.class);
195         PhoneAccountHandle phoneAccountHandle = getSelectedPhoneAccountHandle();
196 
197         if (mCheckIfPermittedBeforeCalling.isChecked()) {
198             if (!tm.isOutgoingCallPermitted(phoneAccountHandle)) {
199                 Toast.makeText(this, R.string.outgoingCallNotPermitted , Toast.LENGTH_SHORT).show();
200                 return;
201             }
202         }
203 
204         Bundle extras = new Bundle();
205         extras.putParcelable(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE,
206                 getSelectedPhoneAccountHandle());
207         if (mVideoCallCheckbox.isChecked()) {
208             extras.putInt(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE,
209                     VideoProfile.STATE_BIDIRECTIONAL);
210         }
211         Bundle clientExtras = new Bundle();
212         clientExtras.putBoolean(SelfManagedConnectionService.EXTRA_HOLDABLE,
213                 mHoldableCheckbox.isChecked());
214         extras.putBundle(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS, clientExtras);
215         tm.placeCall(Uri.parse(mNumber.getText().toString()), extras);
216     }
217 
placeSelfManagedOutgoingCall()218     private void placeSelfManagedOutgoingCall() {
219         TelecomManager tm = this.getSystemService(TelecomManager.class);
220         PhoneAccountHandle phoneAccountHandle = getSelectedPhoneAccountHandle();
221 
222         if (mCheckIfPermittedBeforeCalling.isChecked()) {
223             Toast.makeText(this, R.string.outgoingCallNotPermitted, Toast.LENGTH_SHORT).show();
224             return;
225         }
226 
227         Bundle extras = new Bundle();
228         extras.putParcelable(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, phoneAccountHandle);
229         if (mVideoCallCheckbox.isChecked()) {
230             extras.putInt(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE,
231                     VideoProfile.STATE_BIDIRECTIONAL);
232         }
233         tm.placeCall(Uri.parse(mNumber.getText().toString()), extras);
234     }
235 
initiateHandover()236     private void initiateHandover() {
237         TelecomManager tm = this.getSystemService(TelecomManager.class);
238         PhoneAccountHandle phoneAccountHandle = getSelectedPhoneAccountHandle();
239         Uri address = Uri.parse(mNumber.getText().toString());
240         tm.acceptHandover(address, VideoProfile.STATE_BIDIRECTIONAL, phoneAccountHandle);
241     }
242 
placeIncomingCall()243     private void placeIncomingCall() {
244         TelecomManager tm = this.getSystemService(TelecomManager.class);
245         PhoneAccountHandle phoneAccountHandle = getSelectedPhoneAccountHandle();
246 
247         if (mCheckIfPermittedBeforeCalling.isChecked()) {
248             if (!tm.isIncomingCallPermitted(phoneAccountHandle)) {
249                 Toast.makeText(this, R.string.incomingCallNotPermitted , Toast.LENGTH_SHORT).show();
250                 return;
251             }
252         }
253 
254         Bundle extras = new Bundle();
255         extras.putParcelable(TelecomManager.EXTRA_INCOMING_CALL_ADDRESS,
256                 Uri.parse(mNumber.getText().toString()));
257         extras.putBoolean(SelfManagedConnectionService.EXTRA_HOLDABLE,
258                 mHoldableCheckbox.isChecked());
259         if (mVideoCallCheckbox.isChecked()) {
260             extras.putInt(TelecomManager.EXTRA_INCOMING_VIDEO_STATE,
261                     VideoProfile.STATE_BIDIRECTIONAL);
262         }
263         tm.addNewIncomingCall(getSelectedPhoneAccountHandle(), extras);
264     }
265 
placeSelfManagedIncomingCall()266     private void placeSelfManagedIncomingCall() {
267         TelecomManager tm = this.getSystemService(TelecomManager.class);
268         PhoneAccountHandle phoneAccountHandle = mCallList.getPhoneAccountHandle(
269                 SelfManagedCallList.SELF_MANAGED_ACCOUNT_1A);
270 
271         if (mCheckIfPermittedBeforeCalling.isChecked()) {
272             if (!tm.isIncomingCallPermitted(phoneAccountHandle)) {
273                 Toast.makeText(this, R.string.incomingCallNotPermitted , Toast.LENGTH_SHORT).show();
274                 return;
275             }
276         }
277 
278         Bundle extras = new Bundle();
279         extras.putParcelable(TelecomManager.EXTRA_INCOMING_CALL_ADDRESS,
280                 Uri.parse(mNumber.getText().toString()));
281         tm.addNewIncomingCall(phoneAccountHandle, extras);
282     }
283 
enableCarMode()284     private void enableCarMode() {
285         UiModeManager uiModeManager = getSystemService(UiModeManager.class);
286         uiModeManager.enableCarMode(0);
287         Toast.makeText(this, "Enabling car mode with priority " + DEFAULT_PRIORITY,
288                 Toast.LENGTH_LONG).show();
289     }
290 
disableCarMode()291     private void disableCarMode() {
292         UiModeManager uiModeManager = getSystemService(UiModeManager.class);
293         uiModeManager.disableCarMode(0);
294         Toast.makeText(this, "Disabling car mode", Toast.LENGTH_LONG).show();
295     }
296 
configureNotificationChannel()297     private void configureNotificationChannel() {
298         NotificationChannel channel = new NotificationChannel(
299                 SelfManagedConnection.INCOMING_CALL_CHANNEL_ID, "Incoming Calls",
300                 NotificationManager.IMPORTANCE_MAX);
301         channel.setShowBadge(false);
302         Uri ringtoneUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE);
303         channel.setSound(ringtoneUri, new AudioAttributes.Builder()
304                 .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
305                 .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
306                 .build());
307         channel.enableLights(true);
308 
309         NotificationManager mgr = getSystemService(NotificationManager.class);
310         mgr.createNotificationChannel(channel);
311     }
312 
313     @Override
onActivityResult(int requestCode, int resultCode, Intent data)314     public void onActivityResult(int requestCode, int resultCode, Intent data) {
315         if (requestCode == REQUEST_ID) {
316             if (resultCode == android.app.Activity.RESULT_OK) {
317                 Toast.makeText(this, "Call screening role granted.", Toast.LENGTH_SHORT).show();
318             } else {
319                 Toast.makeText(this, "Call screening role NOT granted.", Toast.LENGTH_SHORT).show();
320             }
321         }
322     }
323 
requestCallScreeningRole()324     private void requestCallScreeningRole() {
325         RoleManager roleManager = (RoleManager) getSystemService(ROLE_SERVICE);
326         Intent intent = roleManager.createRequestRoleIntent(RoleManager.ROLE_CALL_SCREENING);
327         startActivityForResult(intent, REQUEST_ID);
328     }
329 }