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.cts.verifier.telecom;
18 
19 import android.content.Context;
20 import android.net.Uri;
21 import android.os.AsyncTask;
22 import android.os.Bundle;
23 import android.telecom.Connection;
24 import android.telecom.PhoneAccount;
25 import android.telecom.TelecomManager;
26 import android.util.Log;
27 import android.view.View;
28 import android.widget.Button;
29 import android.widget.ImageView;
30 
31 import com.android.cts.verifier.PassFailButtons;
32 import com.android.cts.verifier.R;
33 
34 /**
35  * This test verifies functionality associated with the Self-Managed
36  * {@link android.telecom.ConnectionService} APIs.  It ensures that Telecom will show an incoming
37  * call UI when a new incoming self-managed call is added when there is already an ongoing managed
38  * call or when there is an ongoing self-managed call in another app.
39  */
40 public class SelfManagedIncomingCallTestActivity extends PassFailButtons.Activity {
41     private static final String TAG = "SelfManagedIncomingCall";
42     private Uri TEST_DIAL_NUMBER_1 = Uri.fromParts("tel", "6505551212", null);
43     private Uri TEST_DIAL_NUMBER_2 = Uri.fromParts("tel", "4085551212", null);
44 
45     private ImageView mStep1Status;
46     private Button mRegisterPhoneAccount;
47     private ImageView mStep2Status;
48     private Button mVerifyCall;
49     private Button mPlaceCall;
50     private ImageView mStep3Status;
51 
52     private CtsConnection.Listener mConnectionListener = new CtsConnection.Listener() {
53         @Override
54         void onShowIncomingCallUi(CtsConnection connection) {
55             // The system should have displayed the incoming call UI; this is a fail.
56             Log.w(TAG, "Step 3 fail - got unexpected onShowIncomingCallUi");
57             mStep3Status.setImageResource(R.drawable.fs_error);
58             getPassButton().setEnabled(false);
59         };
60 
61         @Override
62         void onAnswer(CtsConnection connection, int videoState) {
63             // Call was answered, so disconnect it now.
64             Log.i(TAG, "Step 3 - Incoming call answered.");
65             connection.onDisconnect();
66         };
67 
68         @Override
69         void onDisconnect(CtsConnection connection) {
70             super.onDisconnect(connection);
71 
72             cleanupConnectionServices();
73 
74             TelecomManager telecomManager =
75                     (TelecomManager) getSystemService(Context.TELECOM_SERVICE);
76             if (telecomManager == null || !telecomManager.isInManagedCall()) {
77                 // Should still be in a managed call; only one would need to be disconnected.
78                 Log.w(TAG, "Step 3 fail - not in managed call as expected.");
79                 mStep3Status.setImageResource(R.drawable.fs_error);
80                 return;
81             }
82             Log.i(TAG, "Step 3 pass - call disconnected");
83             mStep3Status.setImageResource(R.drawable.fs_good);
84             getPassButton().setEnabled(true);
85         }
86     };
87 
88     @Override
onCreate(Bundle savedInstanceState)89     protected void onCreate(Bundle savedInstanceState) {
90         super.onCreate(savedInstanceState);
91         View view = getLayoutInflater().inflate(R.layout.telecom_self_managed_answer, null);
92         setContentView(view);
93         setInfoResources(R.string.telecom_incoming_self_mgd_test,
94                 R.string.telecom_incoming_self_mgd_info, -1);
95         setPassFailButtonClickListeners();
96         getPassButton().setEnabled(false);
97 
98         mStep1Status = view.findViewById(R.id.step_1_status);
99         mRegisterPhoneAccount = view.findViewById(R.id.telecom_incoming_self_mgd_register_button);
100         mRegisterPhoneAccount.setOnClickListener(v -> {
101             PhoneAccountUtils.registerTestSelfManagedPhoneAccount(this);
102             PhoneAccount account = PhoneAccountUtils.getSelfManagedPhoneAccount(this);
103             if (account != null &&
104                     account.isEnabled() &&
105                     account.hasCapabilities(PhoneAccount.CAPABILITY_SELF_MANAGED)) {
106                 mRegisterPhoneAccount.setEnabled(false);
107                 mVerifyCall.setEnabled(true);
108                 Log.i(TAG, "Step 1 pass - account registered");
109                 mStep1Status.setImageResource(R.drawable.fs_good);
110             } else {
111                 Log.w(TAG, "Step 1 fail - account not registered");
112                 mStep1Status.setImageResource(R.drawable.fs_error);
113             }
114         });
115 
116         mStep2Status = view.findViewById(R.id.step_2_status);
117         mVerifyCall = view.findViewById(R.id.telecom_incoming_self_mgd_verify_call_button);
118         mVerifyCall.setOnClickListener(v -> {
119             TelecomManager telecomManager =
120                     (TelecomManager) getSystemService(Context.TELECOM_SERVICE);
121             if (telecomManager == null || !telecomManager.isInManagedCall()) {
122                 Log.w(TAG, "Step 2 fail - expected to be in a managed call");
123                 mStep2Status.setImageResource(R.drawable.fs_error);
124                 mPlaceCall.setEnabled(false);
125             } else {
126                 mStep2Status.setImageResource(R.drawable.fs_good);
127                 Log.i(TAG, "Step 2 pass - device in a managed call");
128                 mVerifyCall.setEnabled(false);
129                 mPlaceCall.setEnabled(true);
130             }
131         });
132 
133 
134         // telecom_incoming_self_mgd_place_call_button
135         mPlaceCall = view.findViewById(R.id.telecom_incoming_self_mgd_place_call_button);
136         mPlaceCall.setOnClickListener(v -> {
137             (new AsyncTask<Void, Void, Throwable>() {
138                 @Override
139                 protected Throwable doInBackground(Void... params) {
140                     try {
141                         Bundle extras = new Bundle();
142                         extras.putParcelable(TelecomManager.EXTRA_INCOMING_CALL_ADDRESS,
143                                 TEST_DIAL_NUMBER_1);
144                         TelecomManager telecomManager =
145                                 (TelecomManager) getSystemService(Context.TELECOM_SERVICE);
146                         if (telecomManager == null) {
147                             Log.w(TAG, "Step 2 fail - telecom manager null");
148                             mStep2Status.setImageResource(R.drawable.fs_error);
149                             return new Throwable("Could not get telecom service.");
150                         }
151                         telecomManager.addNewIncomingCall(
152                                 PhoneAccountUtils.TEST_SELF_MANAGED_PHONE_ACCOUNT_HANDLE, extras);
153 
154                         CtsConnectionService ctsConnectionService =
155                                 CtsConnectionService.waitForAndGetConnectionService();
156                         if (ctsConnectionService == null) {
157                             Log.w(TAG, "Step 2 fail - ctsConnectionService null");
158                             mStep2Status.setImageResource(R.drawable.fs_error);
159                             return new Throwable("Could not get connection service.");
160                         }
161 
162                         CtsConnection connection = ctsConnectionService.waitForAndGetConnection();
163                         if (connection == null) {
164                             Log.w(TAG, "Step 2 fail - could not get connection");
165                             mStep2Status.setImageResource(R.drawable.fs_error);
166                             return new Throwable("Could not get connection.");
167                         }
168                         connection.addListener(mConnectionListener);
169 
170                         // Wait until the connection knows its audio state changed; at this point
171                         // Telecom knows about the connection and can answer.
172                         connection.waitForAudioStateChanged();
173                         // Make it active to simulate an answer.
174                         connection.setActive();
175 
176                         // Removes the hold capability of the self-managed call, so that the follow
177                         // incoming call can trigger the incoming call UX that allow user to answer
178                         // the incoming call to disconnect the ongoing call.
179                         int capabilities = connection.getConnectionCapabilities();
180                         capabilities &= ~Connection.CAPABILITY_HOLD;
181                         connection.setConnectionCapabilities(capabilities);
182                         Log.w(TAG, "Step 2 - connection added");
183                         return null;
184                     } catch (Throwable t) {
185                         return t;
186                     }
187                 }
188 
189                 @Override
190                 protected void onPostExecute(Throwable t) {
191                     if (t == null) {
192                         mStep2Status.setImageResource(R.drawable.fs_good);
193                         mPlaceCall.setEnabled(false);
194                     } else {
195                         Log.i(TAG, "Step 2 pass - connection added");
196                         mStep2Status.setImageResource(R.drawable.fs_error);
197                     }
198                 }
199             }).execute();
200 
201 
202         });
203 
204         mStep3Status = view.findViewById(R.id.step_3_status);
205         mVerifyCall.setEnabled(false);
206         mPlaceCall.setEnabled(false);
207     }
208 
cleanupConnectionServices()209     private void cleanupConnectionServices() {
210         CtsSelfManagedConnectionService ctsSelfConnSvr =
211                 CtsSelfManagedConnectionService.getConnectionService();
212         if (ctsSelfConnSvr != null) {
213             ctsSelfConnSvr.getConnections()
214                     .stream()
215                     .forEach((c) -> {
216                         c.onDisconnect();
217                     });
218         }
219 
220         CtsConnectionService ctsConnectionService =
221                 CtsConnectionService.getConnectionService();
222         if (ctsConnectionService != null) {
223             ctsConnectionService.getConnections()
224                     .stream()
225                     .forEach((c) -> {
226                         c.onDisconnect();
227                     });
228         }
229         PhoneAccountUtils.unRegisterTestSelfManagedPhoneAccount(this);
230     }
231 }
232