blob: e41bac6061141af227e178848e36294cbdb27d9a [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 Erfanianccca3152017-02-22 16:32:36 -080021import android.support.annotation.FloatRange;
22import 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);
erfanian3bb7cb62018-04-11 09:01:15 -0700179 InCallActivity inCallActivity =
180 (InCallActivity) answerScreen.getAnswerScreenFragment().getActivity();
181 inCallActivity.onPrimaryCallStateChanged();
erfaniand05d8992018-03-20 19:42:26 -0700182 }
183
184 @Override
Eric Erfanian90508232017-03-24 09:31:16 -0700185 public void onAnswerAndReleaseCall() {
Eric Erfaniand8046e52017-04-06 09:41:50 -0700186 LogUtil.enterBlock("AnswerScreenPresenter.onAnswerAndReleaseCall");
Eric Erfanian90508232017-03-24 09:31:16 -0700187 DialerCall activeCall = CallList.getInstance().getActiveCall();
188 if (activeCall == null) {
Eric Erfaniand8046e52017-04-06 09:41:50 -0700189 LogUtil.i("AnswerScreenPresenter.onAnswerAndReleaseCall", "activeCall == null");
Eric Erfanian90508232017-03-24 09:31:16 -0700190 onAnswer(false);
191 } else {
Eric Erfanian2ca43182017-08-31 06:57:16 -0700192 activeCall.setReleasedByAnsweringSecondCall(true);
Eric Erfanian90508232017-03-24 09:31:16 -0700193 activeCall.addListener(new AnswerOnDisconnected(activeCall));
194 activeCall.disconnect();
195 }
Eric Erfanian2ca43182017-08-31 06:57:16 -0700196 addTimeoutCheck();
197 }
198
199 @Override
200 public void onAnswerAndReleaseButtonDisabled() {
201 DialerCall activeCall = CallList.getInstance().getActiveCall();
202 if (activeCall != null) {
203 activeCall.increaseSecondCallWithoutAnswerAndReleasedButtonTimes();
204 }
205 }
206
207 @Override
208 public void onAnswerAndReleaseButtonEnabled() {
209 DialerCall activeCall = CallList.getInstance().getActiveCall();
210 if (activeCall != null) {
211 activeCall.increaseAnswerAndReleaseButtonDisplayedTimes();
212 }
Eric Erfanian90508232017-03-24 09:31:16 -0700213 }
214
215 @Override
Eric Erfanianccca3152017-02-22 16:32:36 -0800216 public void onCannedTextResponsesLoaded(DialerCall call) {
217 if (isSmsResponseAllowed(call)) {
218 answerScreen.setTextResponses(call.getCannedSmsResponses());
219 }
220 }
221
222 @Override
223 public void updateWindowBackgroundColor(@FloatRange(from = -1f, to = 1.0f) float progress) {
224 InCallActivity activity = (InCallActivity) answerScreen.getAnswerScreenFragment().getActivity();
225 if (activity != null) {
226 activity.updateWindowBackgroundColor(progress);
227 }
228 }
229
Eric Erfanian90508232017-03-24 09:31:16 -0700230 private class AnswerOnDisconnected implements DialerCallListener {
231
232 private final DialerCall disconnectingCall;
233
Eric Erfanian2ca43182017-08-31 06:57:16 -0700234 AnswerOnDisconnected(DialerCall disconnectingCall) {
Eric Erfanian90508232017-03-24 09:31:16 -0700235 this.disconnectingCall = disconnectingCall;
236 }
237
238 @Override
239 public void onDialerCallDisconnect() {
Eric Erfaniand8046e52017-04-06 09:41:50 -0700240 LogUtil.i(
241 "AnswerScreenPresenter.AnswerOnDisconnected", "call disconnected, answering new call");
Eric Erfanian90508232017-03-24 09:31:16 -0700242 call.answer();
243 disconnectingCall.removeListener(this);
244 }
245
246 @Override
247 public void onDialerCallUpdate() {}
248
249 @Override
250 public void onDialerCallChildNumberChange() {}
251
252 @Override
253 public void onDialerCallLastForwardedNumberChange() {}
254
255 @Override
256 public void onDialerCallUpgradeToVideo() {}
257
258 @Override
259 public void onDialerCallSessionModificationStateChange() {}
260
261 @Override
262 public void onWiFiToLteHandover() {}
263
264 @Override
265 public void onHandoverToWifiFailure() {}
Eric Erfanianc857f902017-05-15 14:05:33 -0700266
267 @Override
268 public void onInternationalCallOnWifi() {}
Eric Erfanian2ca43182017-08-31 06:57:16 -0700269
270 @Override
271 public void onEnrichedCallSessionUpdate() {}
Eric Erfanian90508232017-03-24 09:31:16 -0700272 }
273
Eric Erfanianccca3152017-02-22 16:32:36 -0800274 private boolean isSmsResponseAllowed(DialerCall call) {
275 return UserManagerCompat.isUserUnlocked(context)
276 && call.can(android.telecom.Call.Details.CAPABILITY_RESPOND_VIA_TEXT);
277 }
Eric Erfanian2ca43182017-08-31 06:57:16 -0700278
279 private void addTimeoutCheck() {
280 actionPerformedTimeMillis = SystemClock.elapsedRealtime();
281 if (answerScreen.getAnswerScreenFragment().isVisible()) {
282 ThreadUtil.postDelayedOnUiThread(
283 () -> {
284 if (!answerScreen.getAnswerScreenFragment().isVisible()) {
285 LogUtil.d(
286 "AnswerScreenPresenter.addTimeoutCheck",
287 "accept/reject call timed out, do nothing");
288 return;
289 }
290 LogUtil.i("AnswerScreenPresenter.addTimeoutCheck", "accept/reject call timed out");
291 // Force re-evaluate which fragment to show.
292 InCallPresenter.getInstance().refreshUi();
293 },
294 ACCEPT_REJECT_CALL_TIME_OUT_IN_MILLIS);
295 }
296 }
Eric Erfanianccca3152017-02-22 16:32:36 -0800297}