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