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.incallui.call; 18 19 import android.app.Notification; 20 import android.content.ActivityNotFoundException; 21 import android.content.Intent; 22 import android.os.Looper; 23 import android.support.annotation.MainThread; 24 import android.support.annotation.VisibleForTesting; 25 import android.telecom.InCallService; 26 import com.android.dialer.common.Assert; 27 import com.android.dialer.common.LogUtil; 28 import java.util.List; 29 30 /** Wrapper around Telecom APIs. */ 31 public class TelecomAdapter implements InCallServiceListener { 32 33 private static final String ADD_CALL_MODE_KEY = "add_call_mode"; 34 35 private static TelecomAdapter instance; 36 private InCallService inCallService; 37 38 private TelecomAdapter() {} 39 40 @MainThread 41 public static TelecomAdapter getInstance() { 42 if (!Looper.getMainLooper().isCurrentThread()) { 43 throw new IllegalStateException(); 44 } 45 if (instance == null) { 46 instance = new TelecomAdapter(); 47 } 48 return instance; 49 } 50 51 @VisibleForTesting(otherwise = VisibleForTesting.NONE) 52 public static void setInstanceForTesting(TelecomAdapter telecomAdapter) { 53 instance = telecomAdapter; 54 } 55 56 @Override 57 public void setInCallService(InCallService inCallService) { 58 this.inCallService = inCallService; 59 } 60 61 @Override 62 public void clearInCallService() { 63 inCallService = null; 64 } 65 66 private android.telecom.Call getTelecomCallById(String callId) { 67 DialerCall call = CallList.getInstance().getCallById(callId); 68 return call == null ? null : call.getTelecomCall(); 69 } 70 71 public void mute(boolean shouldMute) { 72 if (inCallService != null) { 73 inCallService.setMuted(shouldMute); 74 } else { 75 LogUtil.e("TelecomAdapter.mute", "mInCallService is null"); 76 } 77 } 78 79 public void setAudioRoute(int route) { 80 if (inCallService != null) { 81 inCallService.setAudioRoute(route); 82 } else { 83 LogUtil.e("TelecomAdapter.setAudioRoute", "mInCallService is null"); 84 } 85 } 86 87 public void merge(String callId) { 88 android.telecom.Call call = getTelecomCallById(callId); 89 if (call != null) { 90 List<android.telecom.Call> conferenceable = call.getConferenceableCalls(); 91 if (!conferenceable.isEmpty()) { 92 call.conference(conferenceable.get(0)); 93 // It's safe to clear restrict count for merge action. 94 DialerCall.clearRestrictedCount(); 95 } else { 96 if (call.getDetails().can(android.telecom.Call.Details.CAPABILITY_MERGE_CONFERENCE)) { 97 call.mergeConference(); 98 // It's safe to clear restrict count for merge action. 99 DialerCall.clearRestrictedCount(); 100 } 101 } 102 } else { 103 LogUtil.e("TelecomAdapter.merge", "call not in call list " + callId); 104 } 105 } 106 107 public void swap(String callId) { 108 android.telecom.Call call = getTelecomCallById(callId); 109 if (call != null) { 110 if (call.getDetails().can(android.telecom.Call.Details.CAPABILITY_SWAP_CONFERENCE)) { 111 call.swapConference(); 112 } 113 } else { 114 LogUtil.e("TelecomAdapter.swap", "call not in call list " + callId); 115 } 116 } 117 118 public void addCall() { 119 if (inCallService != null) { 120 Intent intent = new Intent(Intent.ACTION_DIAL); 121 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 122 123 // when we request the dialer come up, we also want to inform 124 // it that we're going through the "add call" option from the 125 // InCallScreen / PhoneUtils. 126 intent.putExtra(ADD_CALL_MODE_KEY, true); 127 try { 128 LogUtil.d("TelecomAdapter.addCall", "Sending the add DialerCall intent"); 129 inCallService.startActivity(intent); 130 } catch (ActivityNotFoundException e) { 131 // This is rather rare but possible. 132 // Note: this method is used even when the phone is encrypted. At that moment 133 // the system may not find any Activity which can accept this Intent. 134 LogUtil.e("TelecomAdapter.addCall", "Activity for adding calls isn't found.", e); 135 } 136 } 137 } 138 139 public void playDtmfTone(String callId, char digit) { 140 android.telecom.Call call = getTelecomCallById(callId); 141 if (call != null) { 142 call.playDtmfTone(digit); 143 } else { 144 LogUtil.e("TelecomAdapter.playDtmfTone", "call not in call list " + callId); 145 } 146 } 147 148 public void stopDtmfTone(String callId) { 149 android.telecom.Call call = getTelecomCallById(callId); 150 if (call != null) { 151 call.stopDtmfTone(); 152 } else { 153 LogUtil.e("TelecomAdapter.stopDtmfTone", "call not in call list " + callId); 154 } 155 } 156 157 public void postDialContinue(String callId, boolean proceed) { 158 android.telecom.Call call = getTelecomCallById(callId); 159 if (call != null) { 160 call.postDialContinue(proceed); 161 } else { 162 LogUtil.e("TelecomAdapter.postDialContinue", "call not in call list " + callId); 163 } 164 } 165 166 public boolean canAddCall() { 167 if (inCallService != null) { 168 return inCallService.canAddCall(); 169 } 170 return false; 171 } 172 173 /** 174 * Start a foreground notification. Calling it multiple times with the same id only updates the 175 * existing notification. Whoever called this function are responsible for calling {@link 176 * #stopForegroundNotification()} to remove the notification. 177 */ 178 public void startForegroundNotification(int id, Notification notification) { 179 Assert.isNotNull( 180 inCallService, "No inCallService available for starting foreground notification"); 181 inCallService.startForeground(id, notification); 182 } 183 184 /** 185 * Stop a started foreground notification. This does not stop {@code mInCallService} from running. 186 */ 187 public void stopForegroundNotification() { 188 if (inCallService != null) { 189 inCallService.stopForeground(true /*removeNotification*/); 190 } else { 191 LogUtil.e( 192 "TelecomAdapter.stopForegroundNotification", 193 "no inCallService available for stopping foreground notification"); 194 } 195 } 196 } 197