1 /* 2 * Copyright (C) 2016 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.Context; 20 import android.os.SystemClock; 21 import android.support.annotation.FloatRange; 22 import android.support.annotation.NonNull; 23 import android.support.v4.os.UserManagerCompat; 24 import android.telecom.VideoProfile; 25 import com.android.dialer.common.Assert; 26 import com.android.dialer.common.LogUtil; 27 import com.android.dialer.common.concurrent.ThreadUtil; 28 import com.android.dialer.logging.DialerImpression; 29 import com.android.dialer.logging.Logger; 30 import com.android.incallui.answer.protocol.AnswerScreen; 31 import com.android.incallui.answer.protocol.AnswerScreenDelegate; 32 import com.android.incallui.answerproximitysensor.AnswerProximitySensor; 33 import com.android.incallui.answerproximitysensor.PseudoScreenState; 34 import com.android.incallui.call.CallList; 35 import com.android.incallui.call.DialerCall; 36 import com.android.incallui.call.DialerCallListener; 37 import com.android.incallui.incalluilock.InCallUiLock; 38 39 /** Manages changes for an incoming call screen. */ 40 public class AnswerScreenPresenter 41 implements AnswerScreenDelegate, DialerCall.CannedTextResponsesLoadedListener { 42 private static final int ACCEPT_REJECT_CALL_TIME_OUT_IN_MILLIS = 5000; 43 44 @NonNull private final Context context; 45 @NonNull private final AnswerScreen answerScreen; 46 @NonNull private final DialerCall call; 47 private long actionPerformedTimeMillis; 48 AnswerScreenPresenter( @onNull Context context, @NonNull AnswerScreen answerScreen, @NonNull DialerCall call)49 AnswerScreenPresenter( 50 @NonNull Context context, @NonNull AnswerScreen answerScreen, @NonNull DialerCall call) { 51 LogUtil.i("AnswerScreenPresenter.constructor", null); 52 this.context = Assert.isNotNull(context); 53 this.answerScreen = Assert.isNotNull(answerScreen); 54 this.call = Assert.isNotNull(call); 55 if (isSmsResponseAllowed(call)) { 56 answerScreen.setTextResponses(call.getCannedSmsResponses()); 57 } 58 call.addCannedTextResponsesLoadedListener(this); 59 60 PseudoScreenState pseudoScreenState = InCallPresenter.getInstance().getPseudoScreenState(); 61 if (AnswerProximitySensor.shouldUse(context, call)) { 62 new AnswerProximitySensor(context, call, pseudoScreenState); 63 } else { 64 pseudoScreenState.setOn(true); 65 } 66 } 67 68 @Override isActionTimeout()69 public boolean isActionTimeout() { 70 return actionPerformedTimeMillis != 0 71 && SystemClock.elapsedRealtime() - actionPerformedTimeMillis 72 >= ACCEPT_REJECT_CALL_TIME_OUT_IN_MILLIS; 73 } 74 75 @Override acquireInCallUiLock(String tag)76 public InCallUiLock acquireInCallUiLock(String tag) { 77 return InCallPresenter.getInstance().acquireInCallUiLock(tag); 78 } 79 80 @Override onAnswerScreenUnready()81 public void onAnswerScreenUnready() { 82 call.removeCannedTextResponsesLoadedListener(this); 83 } 84 85 @Override onRejectCallWithMessage(String message)86 public void onRejectCallWithMessage(String message) { 87 call.reject(true /* rejectWithMessage */, message); 88 addTimeoutCheck(); 89 } 90 91 @Override onAnswer(boolean answerVideoAsAudio)92 public void onAnswer(boolean answerVideoAsAudio) { 93 if (answerScreen.isVideoUpgradeRequest()) { 94 if (answerVideoAsAudio) { 95 Logger.get(context) 96 .logCallImpression( 97 DialerImpression.Type.VIDEO_CALL_REQUEST_ACCEPTED_AS_AUDIO, 98 call.getUniqueCallId(), 99 call.getTimeAddedMs()); 100 call.getVideoTech().acceptVideoRequestAsAudio(); 101 } else { 102 Logger.get(context) 103 .logCallImpression( 104 DialerImpression.Type.VIDEO_CALL_REQUEST_ACCEPTED, 105 call.getUniqueCallId(), 106 call.getTimeAddedMs()); 107 call.getVideoTech().acceptVideoRequest(context); 108 } 109 } else { 110 if (answerVideoAsAudio) { 111 call.answer(VideoProfile.STATE_AUDIO_ONLY); 112 } else { 113 call.answer(); 114 } 115 } 116 addTimeoutCheck(); 117 } 118 119 @Override onReject()120 public void onReject() { 121 if (answerScreen.isVideoUpgradeRequest()) { 122 Logger.get(context) 123 .logCallImpression( 124 DialerImpression.Type.VIDEO_CALL_REQUEST_DECLINED, 125 call.getUniqueCallId(), 126 call.getTimeAddedMs()); 127 call.getVideoTech().declineVideoRequest(); 128 } else { 129 call.reject(false /* rejectWithMessage */, null); 130 } 131 addTimeoutCheck(); 132 } 133 134 @Override onAnswerAndReleaseCall()135 public void onAnswerAndReleaseCall() { 136 LogUtil.enterBlock("AnswerScreenPresenter.onAnswerAndReleaseCall"); 137 DialerCall activeCall = CallList.getInstance().getActiveCall(); 138 if (activeCall == null) { 139 LogUtil.i("AnswerScreenPresenter.onAnswerAndReleaseCall", "activeCall == null"); 140 onAnswer(false); 141 } else { 142 activeCall.setReleasedByAnsweringSecondCall(true); 143 activeCall.addListener(new AnswerOnDisconnected(activeCall)); 144 activeCall.disconnect(); 145 } 146 addTimeoutCheck(); 147 } 148 149 @Override onAnswerAndReleaseButtonDisabled()150 public void onAnswerAndReleaseButtonDisabled() { 151 DialerCall activeCall = CallList.getInstance().getActiveCall(); 152 if (activeCall != null) { 153 activeCall.increaseSecondCallWithoutAnswerAndReleasedButtonTimes(); 154 } 155 } 156 157 @Override onAnswerAndReleaseButtonEnabled()158 public void onAnswerAndReleaseButtonEnabled() { 159 DialerCall activeCall = CallList.getInstance().getActiveCall(); 160 if (activeCall != null) { 161 activeCall.increaseAnswerAndReleaseButtonDisplayedTimes(); 162 } 163 } 164 165 @Override onCannedTextResponsesLoaded(DialerCall call)166 public void onCannedTextResponsesLoaded(DialerCall call) { 167 if (isSmsResponseAllowed(call)) { 168 answerScreen.setTextResponses(call.getCannedSmsResponses()); 169 } 170 } 171 172 @Override updateWindowBackgroundColor(@loatRangefrom = -1f, to = 1.0f) float progress)173 public void updateWindowBackgroundColor(@FloatRange(from = -1f, to = 1.0f) float progress) { 174 InCallActivity activity = (InCallActivity) answerScreen.getAnswerScreenFragment().getActivity(); 175 if (activity != null) { 176 activity.updateWindowBackgroundColor(progress); 177 } 178 } 179 180 private class AnswerOnDisconnected implements DialerCallListener { 181 182 private final DialerCall disconnectingCall; 183 AnswerOnDisconnected(DialerCall disconnectingCall)184 AnswerOnDisconnected(DialerCall disconnectingCall) { 185 this.disconnectingCall = disconnectingCall; 186 } 187 188 @Override onDialerCallDisconnect()189 public void onDialerCallDisconnect() { 190 LogUtil.i( 191 "AnswerScreenPresenter.AnswerOnDisconnected", "call disconnected, answering new call"); 192 call.answer(); 193 disconnectingCall.removeListener(this); 194 } 195 196 @Override onDialerCallUpdate()197 public void onDialerCallUpdate() {} 198 199 @Override onDialerCallChildNumberChange()200 public void onDialerCallChildNumberChange() {} 201 202 @Override onDialerCallLastForwardedNumberChange()203 public void onDialerCallLastForwardedNumberChange() {} 204 205 @Override onDialerCallUpgradeToVideo()206 public void onDialerCallUpgradeToVideo() {} 207 208 @Override onDialerCallSessionModificationStateChange()209 public void onDialerCallSessionModificationStateChange() {} 210 211 @Override onWiFiToLteHandover()212 public void onWiFiToLteHandover() {} 213 214 @Override onHandoverToWifiFailure()215 public void onHandoverToWifiFailure() {} 216 217 @Override onInternationalCallOnWifi()218 public void onInternationalCallOnWifi() {} 219 220 @Override onEnrichedCallSessionUpdate()221 public void onEnrichedCallSessionUpdate() {} 222 } 223 isSmsResponseAllowed(DialerCall call)224 private boolean isSmsResponseAllowed(DialerCall call) { 225 return UserManagerCompat.isUserUnlocked(context) 226 && call.can(android.telecom.Call.Details.CAPABILITY_RESPOND_VIA_TEXT); 227 } 228 addTimeoutCheck()229 private void addTimeoutCheck() { 230 actionPerformedTimeMillis = SystemClock.elapsedRealtime(); 231 if (answerScreen.getAnswerScreenFragment().isVisible()) { 232 ThreadUtil.postDelayedOnUiThread( 233 () -> { 234 if (!answerScreen.getAnswerScreenFragment().isVisible()) { 235 LogUtil.d( 236 "AnswerScreenPresenter.addTimeoutCheck", 237 "accept/reject call timed out, do nothing"); 238 return; 239 } 240 LogUtil.i("AnswerScreenPresenter.addTimeoutCheck", "accept/reject call timed out"); 241 // Force re-evaluate which fragment to show. 242 InCallPresenter.getInstance().refreshUi(); 243 }, 244 ACCEPT_REJECT_CALL_TIME_OUT_IN_MILLIS); 245 } 246 } 247 } 248