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