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 }