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.Intent;
27 import android.media.AudioAttributes;
28 import android.media.RingtoneManager;
29 import android.net.Uri;
30 import android.os.Bundle;
31 import android.telecom.ConnectionRequest;
32 import android.telecom.PhoneAccountHandle;
33 import android.telecom.TelecomManager;
34 import android.telecom.VideoProfile;
35 import android.util.Log;
36 import android.view.View;
37 import android.view.WindowManager;
38 import android.widget.Button;
39 import android.widget.CheckBox;
40 import android.widget.EditText;
41 import android.widget.ListView;
42 import android.widget.RadioButton;
43 import android.widget.TextView;
44 import android.widget.Toast;
45 
46 import com.android.server.telecom.testapps.R;
47 
48 import java.util.Objects;
49 
50 /**
51  * Provides a sample third-party calling app UX which implements the self managed connection service
52  * APIs.
53  */
54 public class SelfManagedCallingActivity extends Activity {
55     private static final String TAG = "SelfMgCallActivity";
56     private static final int REQUEST_ID = 1;
57     private SelfManagedCallList mCallList = SelfManagedCallList.getInstance();
58     private CheckBox mCheckIfPermittedBeforeCalling;
59     private Button mPlaceOutgoingCallButton;
60     private Button mPlaceSelfManagedOutgoingCallButton;
61     private Button mPlaceSelfManagedIncomingCallButton;
62     private Button mPlaceIncomingCallButton;
63     private Button mHandoverFrom;
64     private Button mRequestCallScreeningRole;
65     private Button mEnableCarMode;
66     private Button mDisableCarMode;
67     private RadioButton mUseAcct1Button;
68     private RadioButton mUseAcct2Button;
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         mHasFocus = findViewById(R.id.hasFocus);
169         mVideoCallCheckbox = findViewById(R.id.videoCall);
170         mHoldableCheckbox = findViewById(R.id.holdable);
171         mNumber = (EditText) findViewById(R.id.phoneNumber);
172         mListView = (ListView) findViewById(R.id.callList);
173         mCallList.setListener(mCallListListener);
174         mCallList.registerPhoneAccounts(this);
175         mListAdapter = new SelfManagedCallListAdapter(getLayoutInflater(),
176                 mCallList.getConnections());
177         mListView.setAdapter(mListAdapter);
178         Log.i(TAG, "onCreate - mCallList id " + Objects.hashCode(mCallList));
179     }
180 
getSelectedPhoneAccountHandle()181     private PhoneAccountHandle getSelectedPhoneAccountHandle() {
182         if (mUseAcct1Button.isChecked()) {
183             return mCallList.getPhoneAccountHandle(SelfManagedCallList.SELF_MANAGED_ACCOUNT_1);
184         } else if (mUseAcct2Button.isChecked()) {
185             return mCallList.getPhoneAccountHandle(SelfManagedCallList.SELF_MANAGED_ACCOUNT_2);
186         }
187         return null;
188     }
189 
placeOutgoingCall()190     private void placeOutgoingCall() {
191         TelecomManager tm = TelecomManager.from(this);
192         PhoneAccountHandle phoneAccountHandle = getSelectedPhoneAccountHandle();
193 
194         if (mCheckIfPermittedBeforeCalling.isChecked()) {
195             if (!tm.isOutgoingCallPermitted(phoneAccountHandle)) {
196                 Toast.makeText(this, R.string.outgoingCallNotPermitted , Toast.LENGTH_SHORT).show();
197                 return;
198             }
199         }
200 
201         Bundle extras = new Bundle();
202         extras.putParcelable(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE,
203                 getSelectedPhoneAccountHandle());
204         if (mVideoCallCheckbox.isChecked()) {
205             extras.putInt(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE,
206                     VideoProfile.STATE_BIDIRECTIONAL);
207         }
208         Bundle clientExtras = new Bundle();
209         clientExtras.putBoolean(SelfManagedConnectionService.EXTRA_HOLDABLE,
210                 mHoldableCheckbox.isChecked());
211         extras.putBundle(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS, clientExtras);
212         tm.placeCall(Uri.parse(mNumber.getText().toString()), extras);
213     }
214 
placeSelfManagedOutgoingCall()215     private void placeSelfManagedOutgoingCall() {
216         TelecomManager tm = TelecomManager.from(this);
217         PhoneAccountHandle phoneAccountHandle = mCallList.getPhoneAccountHandle(
218                 SelfManagedCallList.SELF_MANAGED_ACCOUNT_3);
219 
220         if (mCheckIfPermittedBeforeCalling.isChecked()) {
221             Toast.makeText(this, R.string.outgoingCallNotPermitted, Toast.LENGTH_SHORT).show();
222             return;
223         }
224 
225         Bundle extras = new Bundle();
226         extras.putParcelable(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, phoneAccountHandle);
227         if (mVideoCallCheckbox.isChecked()) {
228             extras.putInt(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE,
229                     VideoProfile.STATE_BIDIRECTIONAL);
230         }
231         tm.placeCall(Uri.parse(mNumber.getText().toString()), extras);
232     }
233 
initiateHandover()234     private void initiateHandover() {
235         TelecomManager tm = TelecomManager.from(this);
236         PhoneAccountHandle phoneAccountHandle = getSelectedPhoneAccountHandle();
237         Uri address = Uri.parse(mNumber.getText().toString());
238         tm.acceptHandover(address, VideoProfile.STATE_BIDIRECTIONAL, phoneAccountHandle);
239     }
240 
placeIncomingCall()241     private void placeIncomingCall() {
242         TelecomManager tm = TelecomManager.from(this);
243         PhoneAccountHandle phoneAccountHandle = getSelectedPhoneAccountHandle();
244 
245         if (mCheckIfPermittedBeforeCalling.isChecked()) {
246             if (!tm.isIncomingCallPermitted(phoneAccountHandle)) {
247                 Toast.makeText(this, R.string.incomingCallNotPermitted , Toast.LENGTH_SHORT).show();
248                 return;
249             }
250         }
251 
252         Bundle extras = new Bundle();
253         extras.putParcelable(TelecomManager.EXTRA_INCOMING_CALL_ADDRESS,
254                 Uri.parse(mNumber.getText().toString()));
255         extras.putBoolean(SelfManagedConnectionService.EXTRA_HOLDABLE,
256                 mHoldableCheckbox.isChecked());
257         if (mVideoCallCheckbox.isChecked()) {
258             extras.putInt(TelecomManager.EXTRA_INCOMING_VIDEO_STATE,
259                     VideoProfile.STATE_BIDIRECTIONAL);
260         }
261         tm.addNewIncomingCall(getSelectedPhoneAccountHandle(), extras);
262     }
263 
placeSelfManagedIncomingCall()264     private void placeSelfManagedIncomingCall() {
265         TelecomManager tm = TelecomManager.from(this);
266         PhoneAccountHandle phoneAccountHandle = mCallList.getPhoneAccountHandle(
267                 SelfManagedCallList.SELF_MANAGED_ACCOUNT_3);
268 
269         if (mCheckIfPermittedBeforeCalling.isChecked()) {
270             if (!tm.isIncomingCallPermitted(phoneAccountHandle)) {
271                 Toast.makeText(this, R.string.incomingCallNotPermitted , Toast.LENGTH_SHORT).show();
272                 return;
273             }
274         }
275 
276         Bundle extras = new Bundle();
277         extras.putParcelable(TelecomManager.EXTRA_INCOMING_CALL_ADDRESS,
278                 Uri.parse(mNumber.getText().toString()));
279         tm.addNewIncomingCall(phoneAccountHandle, extras);
280     }
281 
enableCarMode()282     private void enableCarMode() {
283         UiModeManager uiModeManager = getSystemService(UiModeManager.class);
284         uiModeManager.enableCarMode(0);
285         Toast.makeText(this, "Enabling car mode with priority " + DEFAULT_PRIORITY,
286                 Toast.LENGTH_LONG).show();
287     }
288 
disableCarMode()289     private void disableCarMode() {
290         UiModeManager uiModeManager = getSystemService(UiModeManager.class);
291         uiModeManager.disableCarMode(0);
292         Toast.makeText(this, "Disabling car mode", Toast.LENGTH_LONG).show();
293     }
294 
configureNotificationChannel()295     private void configureNotificationChannel() {
296         NotificationChannel channel = new NotificationChannel(
297                 SelfManagedConnection.INCOMING_CALL_CHANNEL_ID, "Incoming Calls",
298                 NotificationManager.IMPORTANCE_MAX);
299         channel.setShowBadge(false);
300         Uri ringtoneUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE);
301         channel.setSound(ringtoneUri, new AudioAttributes.Builder()
302                 .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
303                 .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
304                 .build());
305         channel.enableLights(true);
306 
307         NotificationManager mgr = getSystemService(NotificationManager.class);
308         mgr.createNotificationChannel(channel);
309     }
310 
311     @Override
onActivityResult(int requestCode, int resultCode, Intent data)312     public void onActivityResult(int requestCode, int resultCode, Intent data) {
313         if (requestCode == REQUEST_ID) {
314             if (resultCode == android.app.Activity.RESULT_OK) {
315                 Toast.makeText(this, "Call screening role granted.", Toast.LENGTH_SHORT).show();
316             } else {
317                 Toast.makeText(this, "Call screening role NOT granted.", Toast.LENGTH_SHORT).show();
318             }
319         }
320     }
321 
requestCallScreeningRole()322     private void requestCallScreeningRole() {
323         RoleManager roleManager = (RoleManager) getSystemService(ROLE_SERVICE);
324         Intent intent = roleManager.createRequestRoleIntent(RoleManager.ROLE_CALL_SCREENING);
325         startActivityForResult(intent, REQUEST_ID);
326     }
327 }