blob: a76cd1754d61b9f6852dec494d2401874811fb2d [file] [log] [blame]
/*
* Copyright (C) 2017 The Android Open Source Project
* Copyright (C) 2023 The LineageOS 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.incallui.call;
import android.app.Notification;
import android.app.Service;
import android.bluetooth.BluetoothDevice;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.content.pm.ServiceInfo;
import android.os.Looper;
import android.telecom.InCallService;
import androidx.annotation.MainThread;
import com.android.dialer.common.Assert;
import com.android.dialer.common.LogUtil;
import java.util.List;
/** Wrapper around Telecom APIs. */
public class TelecomAdapter implements InCallServiceListener {
private static final String ADD_CALL_MODE_KEY = "add_call_mode";
private static TelecomAdapter instance;
private InCallService inCallService;
private TelecomAdapter() {}
@MainThread
public static TelecomAdapter getInstance() {
if (!Looper.getMainLooper().isCurrentThread()) {
throw new IllegalStateException();
}
if (instance == null) {
instance = new TelecomAdapter();
}
return instance;
}
@Override
public void setInCallService(InCallService inCallService) {
this.inCallService = inCallService;
}
@Override
public void clearInCallService() {
inCallService = null;
}
private android.telecom.Call getTelecomCallById(String callId) {
DialerCall call = CallList.getInstance().getCallById(callId);
return call == null ? null : call.getTelecomCall();
}
public void mute(boolean shouldMute) {
if (inCallService != null) {
inCallService.setMuted(shouldMute);
} else {
LogUtil.e("TelecomAdapter.mute", "mInCallService is null");
}
}
public void setAudioRoute(int route) {
if (inCallService != null) {
inCallService.setAudioRoute(route);
} else {
LogUtil.e("TelecomAdapter.setAudioRoute", "mInCallService is null");
}
}
public void merge(String callId) {
android.telecom.Call call = getTelecomCallById(callId);
if (call != null) {
List<android.telecom.Call> conferenceable = call.getConferenceableCalls();
if (!conferenceable.isEmpty()) {
call.conference(conferenceable.get(0));
// It's safe to clear restrict count for merge action.
DialerCall.clearRestrictedCount();
} else {
if (call.getDetails().can(android.telecom.Call.Details.CAPABILITY_MERGE_CONFERENCE)) {
call.mergeConference();
// It's safe to clear restrict count for merge action.
DialerCall.clearRestrictedCount();
}
}
} else {
LogUtil.e("TelecomAdapter.merge", "call not in call list " + callId);
}
}
public void swap(String callId) {
android.telecom.Call call = getTelecomCallById(callId);
if (call != null) {
if (call.getDetails().can(android.telecom.Call.Details.CAPABILITY_SWAP_CONFERENCE)) {
call.swapConference();
}
} else {
LogUtil.e("TelecomAdapter.swap", "call not in call list " + callId);
}
}
public void addCall() {
if (inCallService != null) {
Intent intent = new Intent(Intent.ACTION_DIAL);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// when we request the dialer come up, we also want to inform
// it that we're going through the "add call" option from the
// InCallScreen / PhoneUtils.
intent.putExtra(ADD_CALL_MODE_KEY, true);
try {
LogUtil.d("TelecomAdapter.addCall", "Sending the add DialerCall intent");
inCallService.startActivity(intent);
} catch (ActivityNotFoundException e) {
// This is rather rare but possible.
// Note: this method is used even when the phone is encrypted. At that moment
// the system may not find any Activity which can accept this Intent.
LogUtil.e("TelecomAdapter.addCall", "Activity for adding calls isn't found.", e);
}
}
}
public void playDtmfTone(String callId, char digit) {
android.telecom.Call call = getTelecomCallById(callId);
if (call != null) {
call.playDtmfTone(digit);
} else {
LogUtil.e("TelecomAdapter.playDtmfTone", "call not in call list " + callId);
}
}
public void stopDtmfTone(String callId) {
android.telecom.Call call = getTelecomCallById(callId);
if (call != null) {
call.stopDtmfTone();
} else {
LogUtil.e("TelecomAdapter.stopDtmfTone", "call not in call list " + callId);
}
}
public void postDialContinue(String callId, boolean proceed) {
android.telecom.Call call = getTelecomCallById(callId);
if (call != null) {
call.postDialContinue(proceed);
} else {
LogUtil.e("TelecomAdapter.postDialContinue", "call not in call list " + callId);
}
}
public boolean canAddCall() {
if (inCallService != null) {
return inCallService.canAddCall();
}
return false;
}
/**
* Start a foreground notification. Calling it multiple times with the same id only updates the
* existing notification. Whoever called this function are responsible for calling {@link
* #stopForegroundNotification()} to remove the notification.
*/
public void startForegroundNotification(int id, Notification notification) {
Assert.isNotNull(
inCallService, "No inCallService available for starting foreground notification");
inCallService.startForeground(id, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_PHONE_CALL);
}
/**
* Stop a started foreground notification. This does not stop {@code mInCallService} from running.
*/
public void stopForegroundNotification() {
if (inCallService != null) {
inCallService.stopForeground(Service.STOP_FOREGROUND_REMOVE);
} else {
LogUtil.e(
"TelecomAdapter.stopForegroundNotification",
"no inCallService available for stopping foreground notification");
}
}
public void requestBluetoothAudio(BluetoothDevice bluetoothDevice) {
if (inCallService != null) {
inCallService.requestBluetoothAudio(bluetoothDevice);
} else {
LogUtil.e("TelecomAdapter.requestBluetoothAudio", "inCallService is null");
}
}
}