AnswerPresenter.java revision fa0c573d689a16401f1bf801d93b7b37d2380c5c
1/* 2 * Copyright (C) 2013 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 17package com.android.incallui; 18 19import android.content.Context; 20 21import com.android.dialer.util.TelecomUtil; 22import com.android.incallui.InCallPresenter.InCallState; 23 24import android.telecom.VideoProfile; 25 26import java.util.List; 27 28/** 29 * Presenter for the Incoming call widget. The {@link AnswerPresenter} handles the logic during 30 * incoming calls. It is also in charge of responding to incoming calls, so there needs to be 31 * an instance alive so that it can receive onIncomingCall callbacks. 32 * 33 * An instance of {@link AnswerPresenter} is created by InCallPresenter at startup, registers 34 * for callbacks via InCallPresenter, and shows/hides the {@link AnswerFragment} via IncallActivity. 35 * 36 */ 37public class AnswerPresenter extends Presenter<AnswerPresenter.AnswerUi> 38 implements CallList.CallUpdateListener, InCallPresenter.InCallUiListener, 39 InCallPresenter.IncomingCallListener, 40 CallList.Listener { 41 42 private static final String TAG = AnswerPresenter.class.getSimpleName(); 43 44 private String mCallId; 45 private Call mCall = null; 46 private boolean mHasTextMessages = false; 47 48 @Override 49 public void onUiShowing(boolean showing) { 50 if (showing) { 51 CallList.getInstance().addListener(this); 52 final CallList calls = CallList.getInstance(); 53 Call call; 54 call = calls.getIncomingCall(); 55 if (call != null) { 56 processIncomingCall(call); 57 } 58 call = calls.getVideoUpgradeRequestCall(); 59 Log.d(this, "getVideoUpgradeRequestCall call =" + call); 60 if (call != null) { 61 processVideoUpgradeRequestCall(call); 62 } 63 } else { 64 CallList.getInstance().removeListener(this); 65 // This is necessary because the activity can be destroyed while an incoming call exists. 66 // This happens when back button is pressed while incoming call is still being shown. 67 if (mCallId != null) { 68 CallList.getInstance().removeCallUpdateListener(mCallId, this); 69 } 70 } 71 } 72 73 @Override 74 public void onIncomingCall(InCallState oldState, InCallState newState, Call call) { 75 Log.d(this, "onIncomingCall: " + this); 76 Call modifyCall = CallList.getInstance().getVideoUpgradeRequestCall(); 77 if (modifyCall != null) { 78 showAnswerUi(false); 79 Log.d(this, "declining upgrade request id: "); 80 CallList.getInstance().removeCallUpdateListener(mCallId, this); 81 InCallPresenter.getInstance().declineUpgradeRequest(getUi().getContext()); 82 } 83 if (!call.getId().equals(mCallId)) { 84 // A new call is coming in. 85 processIncomingCall(call); 86 } 87 } 88 89 @Override 90 public void onIncomingCall(Call call) { 91 } 92 93 @Override 94 public void onCallListChange(CallList list) { 95 } 96 97 @Override 98 public void onDisconnect(Call call) { 99 // no-op 100 } 101 102 public void onSessionModificationStateChange(int sessionModificationState) { 103 boolean isUpgradePending = sessionModificationState == 104 Call.SessionModificationState.RECEIVED_UPGRADE_TO_VIDEO_REQUEST; 105 106 if (!isUpgradePending) { 107 // Stop listening for updates. 108 CallList.getInstance().removeCallUpdateListener(mCallId, this); 109 showAnswerUi(false); 110 } 111 } 112 113 @Override 114 public void onLastForwardedNumberChange() { 115 // no-op 116 } 117 118 private boolean isVideoUpgradePending(Call call) { 119 return call.getSessionModificationState() 120 == Call.SessionModificationState.RECEIVED_UPGRADE_TO_VIDEO_REQUEST; 121 } 122 123 @Override 124 public void onUpgradeToVideo(Call call) { 125 Log.d(this, "onUpgradeToVideo: " + this + " call=" + call); 126 if (getUi() == null) { 127 Log.d(this, "onUpgradeToVideo ui is null"); 128 return; 129 } 130 boolean isUpgradePending = isVideoUpgradePending(call); 131 InCallPresenter inCallPresenter = InCallPresenter.getInstance(); 132 if (isUpgradePending 133 && inCallPresenter.getInCallState() == InCallPresenter.InCallState.INCOMING) { 134 Log.d(this, "declining upgrade request"); 135 //If there is incoming call reject upgrade request 136 inCallPresenter.declineUpgradeRequest(getUi().getContext()); 137 } else if (isUpgradePending) { 138 Log.d(this, "process upgrade request as no MT call"); 139 processVideoUpgradeRequestCall(call); 140 } 141 } 142 143 private void processIncomingCall(Call call) { 144 mCallId = call.getId(); 145 mCall = call; 146 147 // Listen for call updates for the current call. 148 CallList.getInstance().addCallUpdateListener(mCallId, this); 149 150 Log.d(TAG, "Showing incoming for call id: " + mCallId + " " + this); 151 if (showAnswerUi(true)) { 152 final List<String> textMsgs = CallList.getInstance().getTextResponses(call.getId()); 153 configureAnswerTargetsForSms(call, textMsgs); 154 } 155 } 156 157 private boolean showAnswerUi(boolean show) { 158 final InCallActivity activity = InCallPresenter.getInstance().getActivity(); 159 if (activity != null) { 160 activity.showAnswerFragment(show); 161 if (getUi() != null) { 162 getUi().onShowAnswerUi(show); 163 } 164 return true; 165 } else { 166 return false; 167 } 168 } 169 170 private void processVideoUpgradeRequestCall(Call call) { 171 Log.d(this, " processVideoUpgradeRequestCall call=" + call); 172 mCallId = call.getId(); 173 mCall = call; 174 175 // Listen for call updates for the current call. 176 CallList.getInstance().addCallUpdateListener(mCallId, this); 177 178 final int currentVideoState = call.getVideoState(); 179 final int modifyToVideoState = call.getModifyToVideoState(); 180 181 if (currentVideoState == modifyToVideoState) { 182 Log.w(this, "processVideoUpgradeRequestCall: Video states are same. Return."); 183 return; 184 } 185 186 AnswerUi ui = getUi(); 187 188 if (ui == null) { 189 Log.e(this, "Ui is null. Can't process upgrade request"); 190 return; 191 } 192 showAnswerUi(true); 193 ui.showTargets(AnswerFragment.TARGET_SET_FOR_VIDEO_ACCEPT_REJECT_REQUEST, 194 modifyToVideoState); 195 } 196 197 private boolean isEnabled(int videoState, int mask) { 198 return (videoState & mask) == mask; 199 } 200 201 @Override 202 public void onCallChanged(Call call) { 203 Log.d(this, "onCallStateChange() " + call + " " + this); 204 if (call.getState() != Call.State.INCOMING) { 205 boolean isUpgradePending = isVideoUpgradePending(call); 206 if (!isUpgradePending) { 207 // Stop listening for updates. 208 CallList.getInstance().removeCallUpdateListener(mCallId, this); 209 } 210 211 final Call incall = CallList.getInstance().getIncomingCall(); 212 if (incall != null || isUpgradePending) { 213 showAnswerUi(true); 214 } else { 215 showAnswerUi(false); 216 } 217 218 mHasTextMessages = false; 219 } else if (!mHasTextMessages) { 220 final List<String> textMsgs = CallList.getInstance().getTextResponses(call.getId()); 221 if (textMsgs != null) { 222 configureAnswerTargetsForSms(call, textMsgs); 223 } 224 } 225 } 226 227 public void onAnswer(int videoState, Context context) { 228 if (mCallId == null) { 229 return; 230 } 231 232 if (mCall.getSessionModificationState() 233 == Call.SessionModificationState.RECEIVED_UPGRADE_TO_VIDEO_REQUEST) { 234 Log.d(this, "onAnswer (upgradeCall) mCallId=" + mCallId + " videoState=" + videoState); 235 InCallPresenter.getInstance().acceptUpgradeRequest(videoState, context); 236 } else { 237 Log.d(this, "onAnswer (answerCall) mCallId=" + mCallId + " videoState=" + videoState); 238 TelecomAdapter.getInstance().answerCall(mCall.getId(), videoState); 239 } 240 } 241 242 /** 243 * TODO: We are using reject and decline interchangeably. We should settle on 244 * reject since it seems to be more prevalent. 245 */ 246 public void onDecline(Context context) { 247 Log.d(this, "onDecline " + mCallId); 248 if (mCall.getSessionModificationState() 249 == Call.SessionModificationState.RECEIVED_UPGRADE_TO_VIDEO_REQUEST) { 250 InCallPresenter.getInstance().declineUpgradeRequest(context); 251 } else { 252 TelecomAdapter.getInstance().rejectCall(mCall.getId(), false, null); 253 } 254 } 255 256 public void onText() { 257 if (getUi() != null) { 258 TelecomUtil.silenceRinger(getUi().getContext()); 259 getUi().showMessageDialog(); 260 } 261 } 262 263 public void rejectCallWithMessage(String message) { 264 Log.d(this, "sendTextToDefaultActivity()..."); 265 TelecomAdapter.getInstance().rejectCall(mCall.getId(), true, message); 266 267 onDismissDialog(); 268 } 269 270 public void onDismissDialog() { 271 InCallPresenter.getInstance().onDismissDialog(); 272 } 273 274 private void configureAnswerTargetsForSms(Call call, List<String> textMsgs) { 275 if (getUi() == null) { 276 return; 277 } 278 mHasTextMessages = textMsgs != null; 279 boolean withSms = 280 call.can(android.telecom.Call.Details.CAPABILITY_RESPOND_VIA_TEXT) 281 && mHasTextMessages; 282 283 // Only present the user with the option to answer as a video call if the incoming call is 284 // a bi-directional video call. 285 if (CallUtils.isBidirectionalVideoCall(call)) { 286 if (withSms) { 287 getUi().showTargets(AnswerFragment.TARGET_SET_FOR_VIDEO_WITH_SMS); 288 getUi().configureMessageDialog(textMsgs); 289 } else { 290 getUi().showTargets(AnswerFragment.TARGET_SET_FOR_VIDEO_WITHOUT_SMS); 291 } 292 } else { 293 if (withSms) { 294 getUi().showTargets(AnswerFragment.TARGET_SET_FOR_AUDIO_WITH_SMS); 295 getUi().configureMessageDialog(textMsgs); 296 } else { 297 getUi().showTargets(AnswerFragment.TARGET_SET_FOR_AUDIO_WITHOUT_SMS); 298 } 299 } 300 } 301 302 interface AnswerUi extends Ui { 303 public void onShowAnswerUi(boolean shown); 304 public void showTargets(int targetSet); 305 public void showTargets(int targetSet, int videoState); 306 public void showMessageDialog(); 307 public void configureMessageDialog(List<String> textResponses); 308 public Context getContext(); 309 } 310} 311