blob: 8b789f31722f97070dfeaf7af69f5d2754088b1c [file] [log] [blame]
Eric Erfanianccca3152017-02-22 16:32:36 -08001/*
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
17package com.android.incallui;
18
19import android.content.Context;
Eric Erfanian2ca43182017-08-31 06:57:16 -070020import android.os.SystemClock;
Eric Erfanian4ca9e8d2018-07-10 18:37:03 +000021import android.support.annotation.FloatRange;
Eric Erfanianccca3152017-02-22 16:32:36 -080022import android.support.annotation.NonNull;
23import android.support.v4.os.UserManagerCompat;
Eric Erfaniand5e47f62017-03-15 14:41:07 -070024import android.telecom.VideoProfile;
Eric Erfanianccca3152017-02-22 16:32:36 -080025import com.android.dialer.common.Assert;
26import com.android.dialer.common.LogUtil;
erfanian270663c2018-05-09 13:38:18 -070027import com.android.dialer.common.concurrent.DialerExecutorComponent;
Eric Erfanian2ca43182017-08-31 06:57:16 -070028import com.android.dialer.common.concurrent.ThreadUtil;
Eric Erfanian8369df02017-05-03 10:27:13 -070029import com.android.dialer.logging.DialerImpression;
30import com.android.dialer.logging.Logger;
Eric Erfanianccca3152017-02-22 16:32:36 -080031import com.android.incallui.answer.protocol.AnswerScreen;
32import com.android.incallui.answer.protocol.AnswerScreenDelegate;
33import com.android.incallui.answerproximitysensor.AnswerProximitySensor;
34import com.android.incallui.answerproximitysensor.PseudoScreenState;
Eric Erfanian90508232017-03-24 09:31:16 -070035import com.android.incallui.call.CallList;
Eric Erfanianccca3152017-02-22 16:32:36 -080036import com.android.incallui.call.DialerCall;
Eric Erfanian90508232017-03-24 09:31:16 -070037import com.android.incallui.call.DialerCallListener;
twyen8efb4952017-10-06 16:35:54 -070038import com.android.incallui.incalluilock.InCallUiLock;
erfanian270663c2018-05-09 13:38:18 -070039import com.google.common.util.concurrent.FutureCallback;
40import com.google.common.util.concurrent.Futures;
41import com.google.common.util.concurrent.ListenableFuture;
Eric Erfanianccca3152017-02-22 16:32:36 -080042
43/** Manages changes for an incoming call screen. */
44public class AnswerScreenPresenter
45 implements AnswerScreenDelegate, DialerCall.CannedTextResponsesLoadedListener {
Eric Erfanian2ca43182017-08-31 06:57:16 -070046 private static final int ACCEPT_REJECT_CALL_TIME_OUT_IN_MILLIS = 5000;
47
Eric Erfanianccca3152017-02-22 16:32:36 -080048 @NonNull private final Context context;
49 @NonNull private final AnswerScreen answerScreen;
50 @NonNull private final DialerCall call;
Eric Erfanian2ca43182017-08-31 06:57:16 -070051 private long actionPerformedTimeMillis;
Eric Erfanianccca3152017-02-22 16:32:36 -080052
Eric Erfanian2ca43182017-08-31 06:57:16 -070053 AnswerScreenPresenter(
Eric Erfanianccca3152017-02-22 16:32:36 -080054 @NonNull Context context, @NonNull AnswerScreen answerScreen, @NonNull DialerCall call) {
55 LogUtil.i("AnswerScreenPresenter.constructor", null);
56 this.context = Assert.isNotNull(context);
57 this.answerScreen = Assert.isNotNull(answerScreen);
58 this.call = Assert.isNotNull(call);
59 if (isSmsResponseAllowed(call)) {
60 answerScreen.setTextResponses(call.getCannedSmsResponses());
61 }
62 call.addCannedTextResponsesLoadedListener(this);
63
64 PseudoScreenState pseudoScreenState = InCallPresenter.getInstance().getPseudoScreenState();
65 if (AnswerProximitySensor.shouldUse(context, call)) {
66 new AnswerProximitySensor(context, call, pseudoScreenState);
67 } else {
68 pseudoScreenState.setOn(true);
69 }
70 }
71
72 @Override
Eric Erfanian2ca43182017-08-31 06:57:16 -070073 public boolean isActionTimeout() {
74 return actionPerformedTimeMillis != 0
75 && SystemClock.elapsedRealtime() - actionPerformedTimeMillis
76 >= ACCEPT_REJECT_CALL_TIME_OUT_IN_MILLIS;
77 }
78
79 @Override
twyen8efb4952017-10-06 16:35:54 -070080 public InCallUiLock acquireInCallUiLock(String tag) {
81 return InCallPresenter.getInstance().acquireInCallUiLock(tag);
82 }
83
84 @Override
Eric Erfanianccca3152017-02-22 16:32:36 -080085 public void onAnswerScreenUnready() {
86 call.removeCannedTextResponsesLoadedListener(this);
87 }
88
89 @Override
Eric Erfanianccca3152017-02-22 16:32:36 -080090 public void onRejectCallWithMessage(String message) {
91 call.reject(true /* rejectWithMessage */, message);
Eric Erfanian2ca43182017-08-31 06:57:16 -070092 addTimeoutCheck();
Eric Erfanianccca3152017-02-22 16:32:36 -080093 }
94
95 @Override
Eric Erfaniand5e47f62017-03-15 14:41:07 -070096 public void onAnswer(boolean answerVideoAsAudio) {
erfanian270663c2018-05-09 13:38:18 -070097
98 DialerCall incomingCall = CallList.getInstance().getIncomingCall();
99 InCallActivity inCallActivity =
100 (InCallActivity) answerScreen.getAnswerScreenFragment().getActivity();
101 ListenableFuture<Void> answerPrecondition;
102
103 if (incomingCall != null && inCallActivity != null) {
104 answerPrecondition = inCallActivity.getSpeakEasyCallManager().onNewIncomingCall(incomingCall);
105 } else {
106 answerPrecondition = Futures.immediateFuture(null);
107 }
108
109 Futures.addCallback(
110 answerPrecondition,
111 new FutureCallback<Void>() {
112 @Override
113 public void onSuccess(Void result) {
114 onAnswerCallback(answerVideoAsAudio);
115 }
116
117 @Override
118 public void onFailure(Throwable t) {
119 onAnswerCallback(answerVideoAsAudio);
120 // TODO(erfanian): Enumerate all error states and specify recovery strategies.
121 throw new RuntimeException("Failed to successfully complete pre call tasks.", t);
122 }
123 },
124 DialerExecutorComponent.get(context).uiExecutor());
125 addTimeoutCheck();
126 }
127
128 private void onAnswerCallback(boolean answerVideoAsAudio) {
129
Eric Erfanianccca3152017-02-22 16:32:36 -0800130 if (answerScreen.isVideoUpgradeRequest()) {
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700131 if (answerVideoAsAudio) {
Eric Erfanian8369df02017-05-03 10:27:13 -0700132 Logger.get(context)
133 .logCallImpression(
134 DialerImpression.Type.VIDEO_CALL_REQUEST_ACCEPTED_AS_AUDIO,
135 call.getUniqueCallId(),
136 call.getTimeAddedMs());
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700137 call.getVideoTech().acceptVideoRequestAsAudio();
138 } else {
Eric Erfanian8369df02017-05-03 10:27:13 -0700139 Logger.get(context)
140 .logCallImpression(
141 DialerImpression.Type.VIDEO_CALL_REQUEST_ACCEPTED,
142 call.getUniqueCallId(),
143 call.getTimeAddedMs());
twyen59209802017-09-13 10:37:01 -0700144 call.getVideoTech().acceptVideoRequest(context);
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700145 }
Eric Erfanianccca3152017-02-22 16:32:36 -0800146 } else {
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700147 if (answerVideoAsAudio) {
148 call.answer(VideoProfile.STATE_AUDIO_ONLY);
149 } else {
150 call.answer();
151 }
Eric Erfanianccca3152017-02-22 16:32:36 -0800152 }
153 }
154
155 @Override
156 public void onReject() {
157 if (answerScreen.isVideoUpgradeRequest()) {
Eric Erfanian8369df02017-05-03 10:27:13 -0700158 Logger.get(context)
159 .logCallImpression(
160 DialerImpression.Type.VIDEO_CALL_REQUEST_DECLINED,
161 call.getUniqueCallId(),
162 call.getTimeAddedMs());
Eric Erfaniand5e47f62017-03-15 14:41:07 -0700163 call.getVideoTech().declineVideoRequest();
Eric Erfanianccca3152017-02-22 16:32:36 -0800164 } else {
165 call.reject(false /* rejectWithMessage */, null);
166 }
Eric Erfanian2ca43182017-08-31 06:57:16 -0700167 addTimeoutCheck();
Eric Erfanianccca3152017-02-22 16:32:36 -0800168 }
169
170 @Override
erfaniand05d8992018-03-20 19:42:26 -0700171 public void onSpeakEasyCall() {
172 LogUtil.enterBlock("AnswerScreenPresenter.onSpeakEasyCall");
173 DialerCall incomingCall = CallList.getInstance().getIncomingCall();
174 if (incomingCall == null) {
175 LogUtil.i("AnswerScreenPresenter.onSpeakEasyCall", "incomingCall == null");
176 return;
177 }
178 incomingCall.setIsSpeakEasyCall(true);
erfaniand05d8992018-03-20 19:42:26 -0700179 }
180
181 @Override
Eric Erfanian90508232017-03-24 09:31:16 -0700182 public void onAnswerAndReleaseCall() {
Eric Erfaniand8046e52017-04-06 09:41:50 -0700183 LogUtil.enterBlock("AnswerScreenPresenter.onAnswerAndReleaseCall");
Eric Erfanian90508232017-03-24 09:31:16 -0700184 DialerCall activeCall = CallList.getInstance().getActiveCall();
185 if (activeCall == null) {
Eric Erfaniand8046e52017-04-06 09:41:50 -0700186 LogUtil.i("AnswerScreenPresenter.onAnswerAndReleaseCall", "activeCall == null");
Eric Erfanian90508232017-03-24 09:31:16 -0700187 onAnswer(false);
188 } else {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700189 activeCall.setReleasedByAnsweringSecondCall(true);
Eric Erfanian90508232017-03-24 09:31:16 -0700190 activeCall.addListener(new AnswerOnDisconnected(activeCall));
191 activeCall.disconnect();
192 }
Eric Erfanian2ca43182017-08-31 06:57:16 -0700193 addTimeoutCheck();
194 }
195
196 @Override
197 public void onAnswerAndReleaseButtonDisabled() {
198 DialerCall activeCall = CallList.getInstance().getActiveCall();
199 if (activeCall != null) {
200 activeCall.increaseSecondCallWithoutAnswerAndReleasedButtonTimes();
201 }
202 }
203
204 @Override
205 public void onAnswerAndReleaseButtonEnabled() {
206 DialerCall activeCall = CallList.getInstance().getActiveCall();
207 if (activeCall != null) {
208 activeCall.increaseAnswerAndReleaseButtonDisplayedTimes();
209 }
Eric Erfanian90508232017-03-24 09:31:16 -0700210 }
211
212 @Override
Eric Erfanianccca3152017-02-22 16:32:36 -0800213 public void onCannedTextResponsesLoaded(DialerCall call) {
214 if (isSmsResponseAllowed(call)) {
215 answerScreen.setTextResponses(call.getCannedSmsResponses());
216 }
217 }
218
Eric Erfanian4ca9e8d2018-07-10 18:37:03 +0000219 @Override
220 public void updateWindowBackgroundColor(@FloatRange(from = -1f, to = 1.0f) float progress) {
221 InCallActivity activity = (InCallActivity) answerScreen.getAnswerScreenFragment().getActivity();
222 if (activity != null) {
223 activity.updateWindowBackgroundColor(progress);
224 }
225 }
226
Eric Erfanian90508232017-03-24 09:31:16 -0700227 private class AnswerOnDisconnected implements DialerCallListener {
228
229 private final DialerCall disconnectingCall;
230
Eric Erfanian2ca43182017-08-31 06:57:16 -0700231 AnswerOnDisconnected(DialerCall disconnectingCall) {
Eric Erfanian90508232017-03-24 09:31:16 -0700232 this.disconnectingCall = disconnectingCall;
233 }
234
235 @Override
236 public void onDialerCallDisconnect() {
Eric Erfaniand8046e52017-04-06 09:41:50 -0700237 LogUtil.i(
238 "AnswerScreenPresenter.AnswerOnDisconnected", "call disconnected, answering new call");
Eric Erfanian90508232017-03-24 09:31:16 -0700239 call.answer();
240 disconnectingCall.removeListener(this);
241 }
242
243 @Override
244 public void onDialerCallUpdate() {}
245
246 @Override
247 public void onDialerCallChildNumberChange() {}
248
249 @Override
250 public void onDialerCallLastForwardedNumberChange() {}
251
252 @Override
253 public void onDialerCallUpgradeToVideo() {}
254
255 @Override
256 public void onDialerCallSessionModificationStateChange() {}
257
258 @Override
259 public void onWiFiToLteHandover() {}
260
261 @Override
262 public void onHandoverToWifiFailure() {}
Eric Erfanianc857f902017-05-15 14:05:33 -0700263
264 @Override
265 public void onInternationalCallOnWifi() {}
Eric Erfanian2ca43182017-08-31 06:57:16 -0700266
267 @Override
268 public void onEnrichedCallSessionUpdate() {}
Eric Erfanian90508232017-03-24 09:31:16 -0700269 }
270
Eric Erfanianccca3152017-02-22 16:32:36 -0800271 private boolean isSmsResponseAllowed(DialerCall call) {
272 return UserManagerCompat.isUserUnlocked(context)
273 && call.can(android.telecom.Call.Details.CAPABILITY_RESPOND_VIA_TEXT);
274 }
Eric Erfanian2ca43182017-08-31 06:57:16 -0700275
276 private void addTimeoutCheck() {
277 actionPerformedTimeMillis = SystemClock.elapsedRealtime();
278 if (answerScreen.getAnswerScreenFragment().isVisible()) {
279 ThreadUtil.postDelayedOnUiThread(
280 () -> {
281 if (!answerScreen.getAnswerScreenFragment().isVisible()) {
282 LogUtil.d(
283 "AnswerScreenPresenter.addTimeoutCheck",
284 "accept/reject call timed out, do nothing");
285 return;
286 }
287 LogUtil.i("AnswerScreenPresenter.addTimeoutCheck", "accept/reject call timed out");
288 // Force re-evaluate which fragment to show.
289 InCallPresenter.getInstance().refreshUi();
290 },
291 ACCEPT_REJECT_CALL_TIME_OUT_IN_MILLIS);
292 }
293 }
Eric Erfanianccca3152017-02-22 16:32:36 -0800294}