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