diff options
Diffstat (limited to 'java/com/android/dialer/simulator/impl/SimulatorSimCallManager.java')
-rw-r--r-- | java/com/android/dialer/simulator/impl/SimulatorSimCallManager.java | 199 |
1 files changed, 199 insertions, 0 deletions
diff --git a/java/com/android/dialer/simulator/impl/SimulatorSimCallManager.java b/java/com/android/dialer/simulator/impl/SimulatorSimCallManager.java new file mode 100644 index 000000000..33eac51d1 --- /dev/null +++ b/java/com/android/dialer/simulator/impl/SimulatorSimCallManager.java @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.dialer.simulator.impl; + +import android.content.ComponentName; +import android.content.Context; +import android.net.Uri; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.telecom.ConnectionRequest; +import android.telecom.PhoneAccount; +import android.telecom.PhoneAccountHandle; +import android.telecom.TelecomManager; +import android.telephony.TelephonyManager; +import com.android.dialer.common.Assert; +import com.android.dialer.common.LogUtil; +import java.util.Arrays; +import java.util.List; +import java.util.Random; + +/** + * Utility to use the simulator connection service to add phone calls. To ensure that the added + * calls are routed through the simulator we register ourselves as a SIM call manager using + * CAPABILITY_CONNECTION_MANAGER. This ensures that all calls on the device must first go through + * our connection service. + * + * <p>For video calls this will only work if the underlying telephony phone account also supports + * video. To ensure that video always works we use a separate video account. The user must manually + * enable this account in call settings for video calls to work. + */ +public class SimulatorSimCallManager { + + private static final String SIM_CALL_MANAGER_ACCOUNT_ID = "SIMULATOR_ACCOUNT_ID"; + private static final String VIDEO_PROVIDER_ACCOUNT_ID = "SIMULATOR_VIDEO_ACCOUNT_ID"; + private static final String EXTRA_IS_SIMULATOR_CONNECTION = "is_simulator_connection"; + + static void register(@NonNull Context context) { + LogUtil.enterBlock("SimulatorSimCallManager.register"); + Assert.isNotNull(context); + TelecomManager telecomManager = context.getSystemService(TelecomManager.class); + telecomManager.registerPhoneAccount(buildSimCallManagerAccount(context)); + telecomManager.registerPhoneAccount(buildVideoProviderAccount(context)); + } + + static void unregister(@NonNull Context context) { + LogUtil.enterBlock("SimulatorSimCallManager.unregister"); + Assert.isNotNull(context); + TelecomManager telecomManager = context.getSystemService(TelecomManager.class); + telecomManager.unregisterPhoneAccount(getSimCallManagerHandle(context)); + telecomManager.unregisterPhoneAccount(getVideoProviderHandle(context)); + } + + @NonNull + public static String addNewOutgoingCall( + @NonNull Context context, @NonNull String phoneNumber, boolean isVideo) { + return addNewOutgoingCall(context, phoneNumber, isVideo, new Bundle()); + } + + @NonNull + public static String addNewOutgoingCall( + @NonNull Context context, + @NonNull String phoneNumber, + boolean isVideo, + @NonNull Bundle extras) { + LogUtil.enterBlock("SimulatorSimCallManager.addNewOutgoingCall"); + Assert.isNotNull(context); + Assert.isNotNull(extras); + Assert.isNotNull(phoneNumber); + Assert.isNotNull(extras); + + register(context); + + extras = new Bundle(extras); + extras.putBoolean(EXTRA_IS_SIMULATOR_CONNECTION, true); + String connectionTag = createUniqueConnectionTag(); + extras.putBoolean(connectionTag, true); + + Bundle outgoingCallExtras = new Bundle(); + outgoingCallExtras.putBundle(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS, extras); + outgoingCallExtras.putParcelable( + TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, + isVideo ? getVideoProviderHandle(context) : getSystemPhoneAccountHandle(context)); + + TelecomManager telecomManager = context.getSystemService(TelecomManager.class); + try { + telecomManager.placeCall( + Uri.fromParts(PhoneAccount.SCHEME_TEL, phoneNumber, null), outgoingCallExtras); + } catch (SecurityException e) { + throw Assert.createIllegalStateFailException("Unable to place call: " + e); + } + return connectionTag; + } + + @NonNull + public static String addNewIncomingCall( + @NonNull Context context, @NonNull String callerId, boolean isVideo) { + return addNewIncomingCall(context, callerId, isVideo, new Bundle()); + } + + @NonNull + public static String addNewIncomingCall( + @NonNull Context context, @NonNull String callerId, boolean isVideo, @NonNull Bundle extras) { + LogUtil.enterBlock("SimulatorSimCallManager.addNewIncomingCall"); + Assert.isNotNull(context); + Assert.isNotNull(callerId); + Assert.isNotNull(extras); + + register(context); + + extras = new Bundle(extras); + extras.putString(TelephonyManager.EXTRA_INCOMING_NUMBER, callerId); + extras.putBoolean(EXTRA_IS_SIMULATOR_CONNECTION, true); + String connectionTag = createUniqueConnectionTag(); + extras.putBoolean(connectionTag, true); + + TelecomManager telecomManager = context.getSystemService(TelecomManager.class); + telecomManager.addNewIncomingCall( + isVideo ? getVideoProviderHandle(context) : getSystemPhoneAccountHandle(context), extras); + return connectionTag; + } + + @NonNull + private static PhoneAccount buildSimCallManagerAccount(Context context) { + return new PhoneAccount.Builder(getSimCallManagerHandle(context), "Simulator SIM call manager") + .setCapabilities(PhoneAccount.CAPABILITY_CONNECTION_MANAGER) + .setShortDescription("Simulator SIM call manager") + .setSupportedUriSchemes(Arrays.asList(PhoneAccount.SCHEME_TEL)) + .build(); + } + + @NonNull + private static PhoneAccount buildVideoProviderAccount(Context context) { + return new PhoneAccount.Builder(getVideoProviderHandle(context), "Simulator video provider") + .setCapabilities( + PhoneAccount.CAPABILITY_CALL_PROVIDER + | PhoneAccount.CAPABILITY_SUPPORTS_VIDEO_CALLING + | PhoneAccount.CAPABILITY_VIDEO_CALLING) + .setShortDescription("Simulator video provider") + .setSupportedUriSchemes(Arrays.asList(PhoneAccount.SCHEME_TEL)) + .build(); + } + + @NonNull + public static PhoneAccountHandle getSimCallManagerHandle(@NonNull Context context) { + return new PhoneAccountHandle( + new ComponentName(context, SimulatorConnectionService.class), SIM_CALL_MANAGER_ACCOUNT_ID); + } + + @NonNull + static PhoneAccountHandle getVideoProviderHandle(@NonNull Context context) { + return new PhoneAccountHandle( + new ComponentName(context, SimulatorConnectionService.class), VIDEO_PROVIDER_ACCOUNT_ID); + } + + @NonNull + private static PhoneAccountHandle getSystemPhoneAccountHandle(@NonNull Context context) { + TelecomManager telecomManager = context.getSystemService(TelecomManager.class); + List<PhoneAccountHandle> handles; + try { + handles = telecomManager.getCallCapablePhoneAccounts(); + } catch (SecurityException e) { + throw Assert.createIllegalStateFailException("Unable to get phone accounts: " + e); + } + for (PhoneAccountHandle handle : handles) { + PhoneAccount account = telecomManager.getPhoneAccount(handle); + if (account.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) { + return handle; + } + } + throw Assert.createIllegalStateFailException("no SIM phone account available"); + } + + public static boolean isSimulatorConnectionRequest(@NonNull ConnectionRequest request) { + return request.getExtras() != null + && request.getExtras().getBoolean(EXTRA_IS_SIMULATOR_CONNECTION); + } + + @NonNull + private static String createUniqueConnectionTag() { + int callId = new Random().nextInt(); + return String.format("simulator_phone_call_%x", Math.abs(callId)); + } + + private SimulatorSimCallManager() {} +} |