Home | History | Annotate | Download | only in incallui
      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 
     38 /** Manages changes for an incoming call screen. */
     39 public class AnswerScreenPresenter
     40     implements AnswerScreenDelegate, DialerCall.CannedTextResponsesLoadedListener {
     41   private static final int ACCEPT_REJECT_CALL_TIME_OUT_IN_MILLIS = 5000;
     42 
     43   @NonNull private final Context context;
     44   @NonNull private final AnswerScreen answerScreen;
     45   @NonNull private final DialerCall call;
     46   private long actionPerformedTimeMillis;
     47 
     48   AnswerScreenPresenter(
     49       @NonNull Context context, @NonNull AnswerScreen answerScreen, @NonNull DialerCall call) {
     50     LogUtil.i("AnswerScreenPresenter.constructor", null);
     51     this.context = Assert.isNotNull(context);
     52     this.answerScreen = Assert.isNotNull(answerScreen);
     53     this.call = Assert.isNotNull(call);
     54     if (isSmsResponseAllowed(call)) {
     55       answerScreen.setTextResponses(call.getCannedSmsResponses());
     56     }
     57     call.addCannedTextResponsesLoadedListener(this);
     58 
     59     PseudoScreenState pseudoScreenState = InCallPresenter.getInstance().getPseudoScreenState();
     60     if (AnswerProximitySensor.shouldUse(context, call)) {
     61       new AnswerProximitySensor(context, call, pseudoScreenState);
     62     } else {
     63       pseudoScreenState.setOn(true);
     64     }
     65   }
     66 
     67   @Override
     68   public boolean isActionTimeout() {
     69     return actionPerformedTimeMillis != 0
     70         && SystemClock.elapsedRealtime() - actionPerformedTimeMillis
     71             >= ACCEPT_REJECT_CALL_TIME_OUT_IN_MILLIS;
     72   }
     73 
     74   @Override
     75   public void onAnswerScreenUnready() {
     76     call.removeCannedTextResponsesLoadedListener(this);
     77   }
     78 
     79   @Override
     80   public void onDismissDialog() {
     81     InCallPresenter.getInstance().onDismissDialog();
     82   }
     83 
     84   @Override
     85   public void onRejectCallWithMessage(String message) {
     86     call.reject(true /* rejectWithMessage */, message);
     87     onDismissDialog();
     88     addTimeoutCheck();
     89   }
     90 
     91   @Override
     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();
    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
    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
    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
    150   public void onAnswerAndReleaseButtonDisabled() {
    151     DialerCall activeCall = CallList.getInstance().getActiveCall();
    152     if (activeCall != null) {
    153       activeCall.increaseSecondCallWithoutAnswerAndReleasedButtonTimes();
    154     }
    155   }
    156 
    157   @Override
    158   public void onAnswerAndReleaseButtonEnabled() {
    159     DialerCall activeCall = CallList.getInstance().getActiveCall();
    160     if (activeCall != null) {
    161       activeCall.increaseAnswerAndReleaseButtonDisplayedTimes();
    162     }
    163   }
    164 
    165   @Override
    166   public void onCannedTextResponsesLoaded(DialerCall call) {
    167     if (isSmsResponseAllowed(call)) {
    168       answerScreen.setTextResponses(call.getCannedSmsResponses());
    169     }
    170   }
    171 
    172   @Override
    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 
    184     AnswerOnDisconnected(DialerCall disconnectingCall) {
    185       this.disconnectingCall = disconnectingCall;
    186     }
    187 
    188     @Override
    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
    197     public void onDialerCallUpdate() {}
    198 
    199     @Override
    200     public void onDialerCallChildNumberChange() {}
    201 
    202     @Override
    203     public void onDialerCallLastForwardedNumberChange() {}
    204 
    205     @Override
    206     public void onDialerCallUpgradeToVideo() {}
    207 
    208     @Override
    209     public void onDialerCallSessionModificationStateChange() {}
    210 
    211     @Override
    212     public void onWiFiToLteHandover() {}
    213 
    214     @Override
    215     public void onHandoverToWifiFailure() {}
    216 
    217     @Override
    218     public void onInternationalCallOnWifi() {}
    219 
    220     @Override
    221     public void onEnrichedCallSessionUpdate() {}
    222   }
    223 
    224   private boolean isSmsResponseAllowed(DialerCall call) {
    225     return UserManagerCompat.isUserUnlocked(context)
    226         && call.can(android.telecom.Call.Details.CAPABILITY_RESPOND_VIA_TEXT);
    227   }
    228 
    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