1 /* 2 * Copyright (C) 2014 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; 18 19 import android.content.ActivityNotFoundException; 20 import android.content.Context; 21 import android.content.Intent; 22 import android.os.Looper; 23 import android.telecom.InCallAdapter; 24 import android.telecom.Phone; 25 import android.telecom.PhoneAccountHandle; 26 27 import com.google.common.base.Preconditions; 28 29 import java.util.List; 30 31 /** Wrapper around {@link InCallAdapter} that only forwards calls to the adapter when it's valid. */ 32 final class TelecomAdapter implements InCallPhoneListener { 33 private static final String ADD_CALL_MODE_KEY = "add_call_mode"; 34 35 private static TelecomAdapter sInstance; 36 private Context mContext; 37 private Phone mPhone; 38 39 static TelecomAdapter getInstance() { 40 Preconditions.checkState(Looper.getMainLooper().getThread() == Thread.currentThread()); 41 if (sInstance == null) { 42 sInstance = new TelecomAdapter(); 43 } 44 return sInstance; 45 } 46 47 private TelecomAdapter() { 48 } 49 50 void setContext(Context context) { 51 mContext = context; 52 } 53 54 @Override 55 public void setPhone(Phone phone) { 56 mPhone = phone; 57 } 58 59 @Override 60 public void clearPhone() { 61 mPhone = null; 62 } 63 64 private android.telecom.Call getTelecommCallById(String callId) { 65 final Call call = CallList.getInstance().getCallById(callId); 66 return call == null ? null : call.getTelecommCall(); 67 } 68 69 void answerCall(String callId, int videoState) { 70 if (mPhone != null) { 71 final android.telecom.Call call = getTelecommCallById(callId); 72 if (call != null) { 73 call.answer(videoState); 74 } else { 75 Log.e(this, "error answerCall, call not in call list: " + callId); 76 } 77 } else { 78 Log.e(this, "error answerCall, mPhone is null"); 79 } 80 } 81 82 void rejectCall(String callId, boolean rejectWithMessage, String message) { 83 if (mPhone != null) { 84 final android.telecom.Call call = getTelecommCallById(callId); 85 if (call != null) { 86 call.reject(rejectWithMessage, message); 87 } else { 88 Log.e(this, "error rejectCall, call not in call list: " + callId); 89 } 90 } else { 91 Log.e(this, "error rejectCall, mPhone is null"); 92 } 93 } 94 95 void disconnectCall(String callId) { 96 if (mPhone != null) { 97 getTelecommCallById(callId).disconnect(); 98 } else { 99 Log.e(this, "error disconnectCall, mPhone is null"); 100 } 101 } 102 103 void holdCall(String callId) { 104 if (mPhone != null) { 105 getTelecommCallById(callId).hold(); 106 } else { 107 Log.e(this, "error holdCall, mPhone is null"); 108 } 109 } 110 111 void unholdCall(String callId) { 112 if (mPhone != null) { 113 getTelecommCallById(callId).unhold(); 114 } else { 115 Log.e(this, "error unholdCall, mPhone is null"); 116 } 117 } 118 119 void mute(boolean shouldMute) { 120 if (mPhone != null) { 121 mPhone.setMuted(shouldMute); 122 } else { 123 Log.e(this, "error mute, mPhone is null"); 124 } 125 } 126 127 void setAudioRoute(int route) { 128 if (mPhone != null) { 129 mPhone.setAudioRoute(route); 130 } else { 131 Log.e(this, "error setAudioRoute, mPhone is null"); 132 } 133 } 134 135 void turnOnProximitySensor() { 136 if (mPhone != null) { 137 mPhone.setProximitySensorOn(); 138 } else { 139 Log.e(this, "error setProximitySensorOn, mPhone is null"); 140 } 141 } 142 143 void turnOffProximitySensor(boolean screenOnImmediately) { 144 if (mPhone != null) { 145 mPhone.setProximitySensorOff(screenOnImmediately); 146 } else { 147 Log.e(this, "error setProximitySensorOff, mPhone is null"); 148 } 149 } 150 151 void separateCall(String callId) { 152 if (mPhone != null) { 153 getTelecommCallById(callId).splitFromConference(); 154 } else { 155 Log.e(this, "error separateCall, mPhone is null."); 156 } 157 } 158 159 void merge(String callId) { 160 if (mPhone != null) { 161 android.telecom.Call call = getTelecommCallById(callId); 162 List<android.telecom.Call> conferenceable = call.getConferenceableCalls(); 163 if (!conferenceable.isEmpty()) { 164 call.conference(conferenceable.get(0)); 165 } else { 166 if (call.getDetails().can( 167 android.telecom.Call.Details.CAPABILITY_MERGE_CONFERENCE)) { 168 call.mergeConference(); 169 } 170 } 171 } else { 172 Log.e(this, "error merge, mPhone is null."); 173 } 174 } 175 176 void swap(String callId) { 177 if (mPhone != null) { 178 android.telecom.Call call = getTelecommCallById(callId); 179 if (call.getDetails().can( 180 android.telecom.Call.Details.CAPABILITY_SWAP_CONFERENCE)) { 181 call.swapConference(); 182 } 183 } else { 184 Log.e(this, "Error swap, mPhone is null."); 185 } 186 } 187 188 void addCall() { 189 if (mContext != null) { 190 Intent intent = new Intent(Intent.ACTION_DIAL); 191 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 192 193 // when we request the dialer come up, we also want to inform 194 // it that we're going through the "add call" option from the 195 // InCallScreen / PhoneUtils. 196 intent.putExtra(ADD_CALL_MODE_KEY, true); 197 try { 198 Log.d(this, "Sending the add Call intent"); 199 mContext.startActivity(intent); 200 } catch (ActivityNotFoundException e) { 201 // This is rather rare but possible. 202 // Note: this method is used even when the phone is encrypted. At that moment 203 // the system may not find any Activity which can accept this Intent. 204 Log.e(this, "Activity for adding calls isn't found.", e); 205 } 206 } 207 } 208 209 void playDtmfTone(String callId, char digit) { 210 if (mPhone != null) { 211 getTelecommCallById(callId).playDtmfTone(digit); 212 } else { 213 Log.e(this, "error playDtmfTone, mPhone is null"); 214 } 215 } 216 217 void stopDtmfTone(String callId) { 218 if (mPhone != null) { 219 getTelecommCallById(callId).stopDtmfTone(); 220 } else { 221 Log.e(this, "error stopDtmfTone, mPhone is null"); 222 } 223 } 224 225 void postDialContinue(String callId, boolean proceed) { 226 if (mPhone != null) { 227 getTelecommCallById(callId).postDialContinue(proceed); 228 } else { 229 Log.e(this, "error postDialContinue, mPhone is null"); 230 } 231 } 232 233 void phoneAccountSelected(String callId, PhoneAccountHandle accountHandle, boolean setDefault) { 234 if (mPhone != null) { 235 getTelecommCallById(callId).phoneAccountSelected(accountHandle, setDefault); 236 } else { 237 Log.e(this, "error phoneAccountSelected, mAdapter is null"); 238 } 239 240 if (accountHandle == null) { 241 Log.e(this, "error phoneAccountSelected, accountHandle is null"); 242 } 243 } 244 245 boolean canAddCall() { 246 // Default to true if we are not connected to telecom. 247 return mPhone == null ? true : mPhone.canAddCall(); 248 } 249 } 250