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 }