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 import android.telecom.TelecomManager;
21 
22 import java.util.List;
23 
24 /**
25  * Presenter for the Incoming call widget.
26  */
27 public class AnswerPresenter extends Presenter<AnswerPresenter.AnswerUi>
28         implements CallList.CallUpdateListener, CallList.Listener {
29 
30     private static final String TAG = AnswerPresenter.class.getSimpleName();
31 
32     private String mCallId;
33     private Call mCall = null;
34     private boolean mHasTextMessages = false;
35 
36     @Override
onUiReady(AnswerUi ui)37     public void onUiReady(AnswerUi ui) {
38         super.onUiReady(ui);
39 
40         final CallList calls = CallList.getInstance();
41         Call call;
42         call = calls.getIncomingCall();
43         if (call != null) {
44             processIncomingCall(call);
45         }
46         call = calls.getVideoUpgradeRequestCall();
47         if (call != null) {
48             processVideoUpgradeRequestCall(call);
49         }
50 
51         // Listen for incoming calls.
52         calls.addListener(this);
53     }
54 
55     @Override
onUiUnready(AnswerUi ui)56     public void onUiUnready(AnswerUi ui) {
57         super.onUiUnready(ui);
58 
59         CallList.getInstance().removeListener(this);
60 
61         // This is necessary because the activity can be destroyed while an incoming call exists.
62         // This happens when back button is pressed while incoming call is still being shown.
63         if (mCallId != null) {
64             CallList.getInstance().removeCallUpdateListener(mCallId, this);
65         }
66     }
67 
68     @Override
onCallListChange(CallList callList)69     public void onCallListChange(CallList callList) {
70         // no-op
71     }
72 
73     @Override
onDisconnect(Call call)74     public void onDisconnect(Call call) {
75         // no-op
76     }
77 
78     @Override
onIncomingCall(Call call)79     public void onIncomingCall(Call call) {
80         // TODO: Ui is being destroyed when the fragment detaches.  Need clean up step to stop
81         // getting updates here.
82         Log.d(this, "onIncomingCall: " + this);
83         if (getUi() != null) {
84             if (!call.getId().equals(mCallId)) {
85                 // A new call is coming in.
86                 processIncomingCall(call);
87             }
88         }
89     }
90 
processIncomingCall(Call call)91     private void processIncomingCall(Call call) {
92         mCallId = call.getId();
93         mCall = call;
94 
95         // Listen for call updates for the current call.
96         CallList.getInstance().addCallUpdateListener(mCallId, this);
97 
98         Log.d(TAG, "Showing incoming for call id: " + mCallId + " " + this);
99         final List<String> textMsgs = CallList.getInstance().getTextResponses(call.getId());
100         getUi().showAnswerUi(true);
101         configureAnswerTargetsForSms(call, textMsgs);
102     }
103 
processVideoUpgradeRequestCall(Call call)104     private void processVideoUpgradeRequestCall(Call call) {
105         mCallId = call.getId();
106         mCall = call;
107 
108         // Listen for call updates for the current call.
109         CallList.getInstance().addCallUpdateListener(mCallId, this);
110         getUi().showAnswerUi(true);
111 
112         getUi().showTargets(AnswerFragment.TARGET_SET_FOR_VIDEO_UPGRADE_REQUEST);
113     }
114 
115     @Override
onCallChanged(Call call)116     public void onCallChanged(Call call) {
117         Log.d(this, "onCallStateChange() " + call + " " + this);
118         if (call.getState() != Call.State.INCOMING) {
119             // Stop listening for updates.
120             CallList.getInstance().removeCallUpdateListener(mCallId, this);
121 
122             getUi().showAnswerUi(false);
123 
124             // mCallId will hold the state of the call. We don't clear the mCall variable here as
125             // it may be useful for sending text messages after phone disconnects.
126             mCallId = null;
127             mHasTextMessages = false;
128         } else if (!mHasTextMessages) {
129             final List<String> textMsgs = CallList.getInstance().getTextResponses(call.getId());
130             if (textMsgs != null) {
131                 configureAnswerTargetsForSms(call, textMsgs);
132             }
133         }
134     }
135 
onAnswer(int videoState, Context context)136     public void onAnswer(int videoState, Context context) {
137         if (mCallId == null) {
138             return;
139         }
140 
141         Log.d(this, "onAnswer " + mCallId);
142         if (mCall.getSessionModificationState()
143                 == Call.SessionModificationState.RECEIVED_UPGRADE_TO_VIDEO_REQUEST) {
144             InCallPresenter.getInstance().acceptUpgradeRequest(context);
145         } else {
146             TelecomAdapter.getInstance().answerCall(mCall.getId(), videoState);
147         }
148     }
149 
150     /**
151      * TODO: We are using reject and decline interchangeably. We should settle on
152      * reject since it seems to be more prevalent.
153      */
onDecline()154     public void onDecline() {
155         Log.d(this, "onDecline " + mCallId);
156         TelecomAdapter.getInstance().rejectCall(mCall.getId(), false, null);
157     }
158 
onText()159     public void onText() {
160         if (getUi() != null) {
161             InCallPresenter.getInstance().getTelecomManager().silenceRinger();
162             getUi().showMessageDialog();
163         }
164     }
165 
rejectCallWithMessage(String message)166     public void rejectCallWithMessage(String message) {
167         Log.d(this, "sendTextToDefaultActivity()...");
168         TelecomAdapter.getInstance().rejectCall(mCall.getId(), true, message);
169 
170         onDismissDialog();
171     }
172 
onDismissDialog()173     public void onDismissDialog() {
174         InCallPresenter.getInstance().onDismissDialog();
175     }
176 
configureAnswerTargetsForSms(Call call, List<String> textMsgs)177     private void configureAnswerTargetsForSms(Call call, List<String> textMsgs) {
178         final Context context = getUi().getContext();
179 
180         mHasTextMessages = textMsgs != null;
181         boolean withSms =
182                 call.can(android.telecom.Call.Details.CAPABILITY_RESPOND_VIA_TEXT)
183                 && mHasTextMessages;
184         if (call.isVideoCall(context)) {
185             if (withSms) {
186                 getUi().showTargets(AnswerFragment.TARGET_SET_FOR_VIDEO_WITH_SMS);
187                 getUi().configureMessageDialog(textMsgs);
188             } else {
189                 getUi().showTargets(AnswerFragment.TARGET_SET_FOR_VIDEO_WITHOUT_SMS);
190             }
191         } else {
192             if (withSms) {
193                 getUi().showTargets(AnswerFragment.TARGET_SET_FOR_AUDIO_WITH_SMS);
194                 getUi().configureMessageDialog(textMsgs);
195             } else {
196                 getUi().showTargets(AnswerFragment.TARGET_SET_FOR_AUDIO_WITHOUT_SMS);
197             }
198         }
199     }
200 
201     interface AnswerUi extends Ui {
showAnswerUi(boolean show)202         public void showAnswerUi(boolean show);
showTargets(int targetSet)203         public void showTargets(int targetSet);
showMessageDialog()204         public void showMessageDialog();
configureMessageDialog(List<String> textResponses)205         public void configureMessageDialog(List<String> textResponses);
getContext()206         public Context getContext();
207     }
208 }
209