From 3860ae4cd6e37e6e5438c81631b6857643691d9b Mon Sep 17 00:00:00 2001 From: Christine Chen Date: Tue, 6 Aug 2013 16:03:54 -0700 Subject: Adds support for text messages Change-Id: Ibdb279a7dff0db710bcc1d6a313b486f6816ea65 --- .../src/com/android/incallui/AnswerFragment.java | 97 ++++++++++++++++++++++ .../src/com/android/incallui/AnswerPresenter.java | 27 +++++- .../com/android/incallui/CallCommandClient.java | 4 +- .../com/android/incallui/CallHandlerService.java | 16 ++++ InCallUI/src/com/android/incallui/CallList.java | 36 ++++++++ 5 files changed, 175 insertions(+), 5 deletions(-) (limited to 'InCallUI') diff --git a/InCallUI/src/com/android/incallui/AnswerFragment.java b/InCallUI/src/com/android/incallui/AnswerFragment.java index a20fdb9ab..196a66bb0 100644 --- a/InCallUI/src/com/android/incallui/AnswerFragment.java +++ b/InCallUI/src/com/android/incallui/AnswerFragment.java @@ -16,10 +16,19 @@ package com.android.incallui; +import com.google.common.base.Preconditions; + +import android.app.AlertDialog; +import android.app.Dialog; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.ListView; + +import java.util.ArrayList; /** * @@ -27,6 +36,18 @@ import android.view.ViewGroup; public class AnswerFragment extends BaseFragment implements GlowPadWrapper.AnswerListener, AnswerPresenter.AnswerUi { + /** + * The popup showing the list of canned responses. + * + * This is an AlertDialog containing a ListView showing the possible + * choices. This may be null if the InCallScreen hasn't ever called + * showRespondViaSmsPopup() yet, or if the popup was visible once but + * then got dismissed. + */ + private Dialog mCannedResponsePopup = null; + + private ArrayAdapter mTextResponsesAdapter = null; + public AnswerFragment() { } @@ -52,6 +73,55 @@ public class AnswerFragment extends BaseFragment implements getView().setVisibility(show ? View.VISIBLE : View.GONE); } + @Override + public void showTextButton(boolean show) { + // TODO(klp) Hide the text button when the call does not support reject by text. + } + + @Override + public boolean isMessageDialogueShowing() { + return mCannedResponsePopup != null && mCannedResponsePopup.isShowing(); + } + + @Override + public void showMessageDialogue() { + final ListView lv = new ListView(getActivity()); + + Preconditions.checkNotNull(mTextResponsesAdapter); + lv.setAdapter(mTextResponsesAdapter); + lv.setOnItemClickListener(new RespondViaSmsItemClickListener()); + + final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()) + .setCancelable(true) + .setView(lv); + mCannedResponsePopup = builder.create(); + mCannedResponsePopup.show(); + } + + /** + * Dismiss currently visible popups. + * + * This is safe to call even if the popup is already dismissed, and + * even if you never called showRespondViaSmsPopup() in the first + * place. + */ + @Override + public void dismissPopup() { + if (mCannedResponsePopup != null) { + mCannedResponsePopup.dismiss(); // safe even if already dismissed + mCannedResponsePopup = null; + } + } + + @Override + public void configureMessageDialogue(ArrayList textResponses) { + textResponses.add(getResources().getString(R.string.respond_via_sms_custom_message)); + mTextResponsesAdapter = new ArrayAdapter(getActivity(), + android.R.layout.simple_list_item_1, + android.R.id.text1, + textResponses); + } + @Override public void onAnswer() { getPresenter().onAnswer(); @@ -66,4 +136,31 @@ public class AnswerFragment extends BaseFragment implements public void onText() { getPresenter().onText(); } + + /** + * OnItemClickListener for the "Respond via SMS" popup. + */ + public class RespondViaSmsItemClickListener implements AdapterView.OnItemClickListener { + /** + * Handles the user selecting an item from the popup. + */ + @Override + public void onItemClick(AdapterView parent, // The ListView + View view, // The TextView that was clicked + int position, + long id) { + Logger.d(this, "RespondViaSmsItemClickListener.onItemClick(" + position + ")..."); + final String message = (String) parent.getItemAtPosition(position); + Logger.v(this, "- message: '" + message + "'"); + + // The "Custom" choice is a special case. + // (For now, it's guaranteed to be the last item.) + if (position == (parent.getCount() - 1)) { + // Take the user to the standard SMS compose UI. + getPresenter().rejectCallWithMessage(null); + } else { + getPresenter().rejectCallWithMessage(message); + } + } + } } diff --git a/InCallUI/src/com/android/incallui/AnswerPresenter.java b/InCallUI/src/com/android/incallui/AnswerPresenter.java index 123fe9ce9..c3a7c13ad 100644 --- a/InCallUI/src/com/android/incallui/AnswerPresenter.java +++ b/InCallUI/src/com/android/incallui/AnswerPresenter.java @@ -22,6 +22,8 @@ import com.android.incallui.InCallPresenter.InCallState; import com.android.incallui.InCallPresenter.InCallStateListener; import com.android.services.telephony.common.Call; +import java.util.ArrayList; + /** * Presenter for the Incoming call widget. */ @@ -29,6 +31,7 @@ public class AnswerPresenter extends Presenter implements InCallStateListener { private Call mCall; + private ArrayList mTextResponses; @Override public void onUiReady(AnswerUi ui) { @@ -40,7 +43,13 @@ public class AnswerPresenter extends Presenter if (state == InCallState.INCOMING) { getUi().showAnswerUi(true); mCall = callList.getIncomingCall(); - + mTextResponses = callList.getTextResponses(mCall); + if (mTextResponses != null) { + getUi().showTextButton(true); + getUi().configureMessageDialogue(mTextResponses); + } else { + getUi().showTextButton(false); + } Logger.d(this, "Showing incoming with: " + mCall); } else { getUi().showAnswerUi(false); @@ -59,13 +68,25 @@ public class AnswerPresenter extends Presenter Preconditions.checkNotNull(mCall); Logger.d(this, "onDecline " + mCall.getCallId()); - CallCommandClient.getInstance().rejectCall(mCall.getCallId()); + CallCommandClient.getInstance().rejectCall(mCall.getCallId(), false, null); } public void onText() { + getUi().showMessageDialogue(); + } + + public void rejectCallWithMessage(String message) { + Logger.d(this, "sendTextToDefaultActivity()..."); + CallCommandClient.getInstance().rejectCall(mCall.getCallId(), true, message); + getUi().dismissPopup(); } interface AnswerUi extends Ui { public void showAnswerUi(boolean show); + public void showTextButton(boolean show); + public boolean isMessageDialogueShowing(); + public void showMessageDialogue(); + public void dismissPopup(); + public void configureMessageDialogue(ArrayList textResponses); } -} +} \ No newline at end of file diff --git a/InCallUI/src/com/android/incallui/CallCommandClient.java b/InCallUI/src/com/android/incallui/CallCommandClient.java index 381d8d383..80a9e9e10 100644 --- a/InCallUI/src/com/android/incallui/CallCommandClient.java +++ b/InCallUI/src/com/android/incallui/CallCommandClient.java @@ -56,9 +56,9 @@ public class CallCommandClient { } } - public void rejectCall(int callId) { + public void rejectCall(int callId, boolean rejectWithMessage, String message) { try { - mCommandService.rejectCall(callId); + mCommandService.rejectCall(callId, rejectWithMessage, message); } catch (RemoteException e) { Logger.e(this, "Error rejecting call.", e); } diff --git a/InCallUI/src/com/android/incallui/CallHandlerService.java b/InCallUI/src/com/android/incallui/CallHandlerService.java index 9046dd808..173f6a345 100644 --- a/InCallUI/src/com/android/incallui/CallHandlerService.java +++ b/InCallUI/src/com/android/incallui/CallHandlerService.java @@ -26,7 +26,10 @@ import com.android.services.telephony.common.Call; import com.android.services.telephony.common.ICallCommandService; import com.android.services.telephony.common.ICallHandlerService; +import java.util.AbstractMap; +import java.util.ArrayList; import java.util.List; +import java.util.Map; /** * Service used to listen for call state changes. @@ -35,6 +38,7 @@ public class CallHandlerService extends Service { private static final int ON_UPDATE_CALL = 1; private static final int ON_UPDATE_MULTI_CALL = 2; + private static final int ON_UPDATE_CALL_WITH_TEXT_RESPONSES = 3; private CallList mCallList; private Handler mMainHandler; @@ -71,6 +75,15 @@ public class CallHandlerService extends Service { mMainHandler.sendMessage(mMainHandler.obtainMessage(ON_UPDATE_CALL, 0, 0, call)); } + @Override + public void onIncoming(Call call, List textResponses) { + // TODO(klp): Add text responses to the call object. + Map.Entry > incomingCall = new AbstractMap.SimpleEntry >(call, textResponses); + mMainHandler.sendMessage(mMainHandler.obtainMessage(ON_UPDATE_CALL_WITH_TEXT_RESPONSES, + 0, 0, incomingCall)); + } + @Override public void onUpdate(List calls, boolean fullUpdate) { // TODO(klp): Add use of fullUpdate to message @@ -109,6 +122,9 @@ public class CallHandlerService extends Service { case ON_UPDATE_MULTI_CALL: mCallList.onUpdate((List) msg.obj); break; + case ON_UPDATE_CALL_WITH_TEXT_RESPONSES: + mCallList.onUpdate((AbstractMap.SimpleEntry >) msg.obj); + break; default: break; } diff --git a/InCallUI/src/com/android/incallui/CallList.java b/InCallUI/src/com/android/incallui/CallList.java index c16c53df0..3a90a7e52 100644 --- a/InCallUI/src/com/android/incallui/CallList.java +++ b/InCallUI/src/com/android/incallui/CallList.java @@ -25,6 +25,8 @@ import com.google.common.collect.ImmutableMap; import com.android.services.telephony.common.Call; +import java.util.AbstractMap; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -49,6 +51,8 @@ public class CallList { private static CallList sInstance; private final HashMap mCallMap = Maps.newHashMap(); + private final HashMap> mCallTextReponsesMap = + Maps.newHashMap(); private final Set mListeners = Sets.newArraySet(); /** @@ -74,6 +78,19 @@ public class CallList { Logger.d(this, "onUpdate - " + safeCallString(call)); updateCallInMap(call); + + notifyListenersOfChange(); + } + + /** + * Called when a single call has changed. + */ + public void onUpdate(AbstractMap.SimpleEntry > incomingCall) { + Logger.d(this, "onUpdate - " + safeCallString(incomingCall.getKey())); + + updateCallInMap(incomingCall.getKey()); + updateCallTextMap(incomingCall.getKey(), incomingCall.getValue()); + notifyListenersOfChange(); } @@ -88,6 +105,7 @@ public class CallList { Logger.d(this, "\t" + safeCallString(call)); updateCallInMap(call); + updateCallTextMap(call, null); } notifyListenersOfChange(); @@ -158,6 +176,10 @@ public class CallList { return false; } + public ArrayList getTextResponses(Call call) { + return mCallTextReponsesMap.get(call.getCallId()); + } + /** * Returns first call found in the call map with the specified state. */ @@ -210,6 +232,20 @@ public class CallList { } } + private void updateCallTextMap(Call call, List textResponses) { + Preconditions.checkNotNull(call); + + final Integer id = new Integer(call.getCallId()); + + if (!isCallDead(call)) { + if (textResponses != null) { + mCallTextReponsesMap.put(id, (ArrayList) textResponses); + } + } else if (mCallMap.containsKey(id)) { + mCallTextReponsesMap.remove(id); + } + } + private boolean isCallDead(Call call) { final int state = call.getState(); return Call.State.IDLE == state || Call.State.INVALID == state; -- cgit v1.2.3