diff options
author | Ihab Awad <ihab@google.com> | 2014-07-11 18:13:26 -0700 |
---|---|---|
committer | Ihab Awad <ihab@google.com> | 2014-07-14 21:49:48 +0000 |
commit | 8d38cf6761ae048b1a42504f1b59e872cf43df47 (patch) | |
tree | 37c8d932737f6949abacc6b9343e0ecde14149c4 | |
parent | be720ee5b611396446bc93068ff1389bd3dc59e8 (diff) |
Implement new In-Call Service interface
Change-Id: Ic1eb6fc98e7f030885596c9c40f0ed4f0e34e28b
(cherry picked from commit c90543e6ef64b16b4c1bb240494152bc513f1e36)
14 files changed, 418 insertions, 355 deletions
diff --git a/InCallUI/src/com/android/incallui/AnswerPresenter.java b/InCallUI/src/com/android/incallui/AnswerPresenter.java index 78aa64b23..5c7188e28 100644 --- a/InCallUI/src/com/android/incallui/AnswerPresenter.java +++ b/InCallUI/src/com/android/incallui/AnswerPresenter.java @@ -75,7 +75,7 @@ public class AnswerPresenter extends Presenter<AnswerPresenter.AnswerUi> // getting updates here. Log.d(this, "onIncomingCall: " + this); if (getUi() != null) { - if (!call.getCallId().equals(mCallId)) { + if (!call.getId().equals(mCallId)) { // A new call is coming in. processIncomingCall(call); } @@ -83,14 +83,14 @@ public class AnswerPresenter extends Presenter<AnswerPresenter.AnswerUi> } private void processIncomingCall(Call call) { - mCallId = call.getCallId(); + mCallId = call.getId(); mCall = call; // Listen for call updates for the current call. CallList.getInstance().addCallUpdateListener(mCallId, this); Log.d(TAG, "Showing incoming for call id: " + mCallId + " " + this); - final List<String> textMsgs = CallList.getInstance().getTextResponses(call.getCallId()); + final List<String> textMsgs = CallList.getInstance().getTextResponses(call.getId()); getUi().showAnswerUi(true); if (call.can(CallCapabilities.RESPOND_VIA_TEXT) && textMsgs != null) { @@ -123,7 +123,7 @@ public class AnswerPresenter extends Presenter<AnswerPresenter.AnswerUi> } Log.d(this, "onAnswer " + mCallId); - TelecommAdapter.getInstance().answerCall(mCall.getCallId()); + TelecommAdapter.getInstance().answerCall(mCall.getId()); } /** @@ -132,7 +132,7 @@ public class AnswerPresenter extends Presenter<AnswerPresenter.AnswerUi> */ public void onDecline() { Log.d(this, "onDecline " + mCallId); - TelecommAdapter.getInstance().rejectCall(mCall.getCallId(), false, null); + TelecommAdapter.getInstance().rejectCall(mCall.getId(), false, null); } public void onText() { @@ -143,7 +143,7 @@ public class AnswerPresenter extends Presenter<AnswerPresenter.AnswerUi> public void rejectCallWithMessage(String message) { Log.d(this, "sendTextToDefaultActivity()..."); - TelecommAdapter.getInstance().rejectCall(mCall.getCallId(), true, message); + TelecommAdapter.getInstance().rejectCall(mCall.getId(), true, message); onDismissDialog(); } diff --git a/InCallUI/src/com/android/incallui/AudioModeProvider.java b/InCallUI/src/com/android/incallui/AudioModeProvider.java index 407aa3a0f..f3c7da623 100644 --- a/InCallUI/src/com/android/incallui/AudioModeProvider.java +++ b/InCallUI/src/com/android/incallui/AudioModeProvider.java @@ -20,23 +20,47 @@ import com.google.common.collect.Lists; import com.android.services.telephony.common.AudioMode; +import android.telecomm.CallAudioState; +import android.telecomm.Phone; + import java.util.List; /** * Proxy class for getting and setting the audio mode. */ -/* package */ class AudioModeProvider { +/* package */ class AudioModeProvider implements InCallPhoneListener { private static AudioModeProvider sAudioModeProvider = new AudioModeProvider(); private int mAudioMode = AudioMode.EARPIECE; private boolean mMuted = false; private int mSupportedModes = AudioMode.ALL_MODES; private final List<AudioModeListener> mListeners = Lists.newArrayList(); + private Phone mPhone; + + private Phone.Listener mPhoneListener = new Phone.Listener() { + @Override + public void onAudioStateChanged(Phone phone, CallAudioState audioState) { + onAudioModeChange(audioState.route, audioState.isMuted); + onSupportedAudioModeChange(audioState.supportedRouteMask); + } + }; public static AudioModeProvider getInstance() { return sAudioModeProvider; } + @Override + public void setPhone(Phone phone) { + mPhone = phone; + mPhone.addListener(mPhoneListener); + } + + @Override + public void clearPhone() { + mPhone.removeListener(mPhoneListener); + mPhone = null; + } + public void onAudioModeChange(int newMode, boolean muted) { if (mAudioMode != newMode) { mAudioMode = newMode; diff --git a/InCallUI/src/com/android/incallui/Call.java b/InCallUI/src/com/android/incallui/Call.java index c8a21e968..5dbd038fe 100644 --- a/InCallUI/src/com/android/incallui/Call.java +++ b/InCallUI/src/com/android/incallui/Call.java @@ -17,19 +17,13 @@ package com.android.incallui; import android.net.Uri; -import android.os.RemoteException; import android.telecomm.CallCapabilities; -import android.telecomm.CallPropertyPresentation; -import android.telecomm.CallServiceDescriptor; import android.telecomm.PhoneAccount; import android.telecomm.RemoteCallVideoProvider; import android.telecomm.GatewayInfo; import android.telephony.DisconnectCause; -import com.google.common.collect.ImmutableSortedSet; -import com.google.common.primitives.Ints; - -import java.util.Collections; +import java.util.ArrayList; import java.util.List; import java.util.Locale; @@ -100,58 +94,154 @@ public final class Call { } } - private String mCallId; + private static final String ID_PREFIX = Call.class.getSimpleName() + "_"; + private static int sIdCounter = 0; + + private android.telecomm.Call.Listener mTelecommCallListener = + new android.telecomm.Call.Listener() { + @Override + public void onStateChanged(android.telecomm.Call call, int newState) { + update(); + } + + @Override + public void onParentChanged(android.telecomm.Call call, + android.telecomm.Call newParent) { + update(); + } + + @Override + public void onChildrenChanged(android.telecomm.Call call, + List<android.telecomm.Call> children) { + update(); + } + + @Override + public void onDetailsChanged(android.telecomm.Call call, + android.telecomm.Call.Details details) { + update(); + } + + @Override + public void onCannedTextResponsesLoaded(android.telecomm.Call call, + List<String> cannedTextResponses) { + update(); + } + + @Override + public void onPostDial(android.telecomm.Call call, + String remainingPostDialSequence) { + update(); + } + + @Override + public void onPostDialWait(android.telecomm.Call call, + String remainingPostDialSequence) { + update(); + } + + @Override + public void onCallVideoProviderChanged(android.telecomm.Call call, + RemoteCallVideoProvider callVideoProvider) { + update(); + } + + @Override + public void onCallDestroyed(android.telecomm.Call call) { + call.removeListener(mTelecommCallListener); + } + }; + + private final android.telecomm.Call mTelecommCall; + private final String mId; private int mState = State.INVALID; - private int mDisconnectCause = DisconnectCause.NOT_VALID; - private List<String> mCannedSmsResponses = Collections.EMPTY_LIST; - private int mCapabilities; - private long mConnectTimeMillis = 0; - private Uri mHandle; - private int mNumberPresentation; - private String mCnapName; - private int mCnapNamePresentation; - private GatewayInfo mGatewayInfo; - private PhoneAccount mAccount; - private CallServiceDescriptor mCurrentCallServiceDescriptor; - private RemoteCallVideoProvider mCallVideoProvider; + private int mDisconnectCause; private String mParentCallId; - private List<String> mChildCallIds; - + private final List<String> mChildCallIds = new ArrayList<>(); private InCallVideoClient mCallVideoClient; - public Call(String callId) { - mCallId = callId; + public Call(android.telecomm.Call telecommCall) { + mTelecommCall = telecommCall; + mId = ID_PREFIX + Integer.toString(sIdCounter++); + updateFromTelecommCall(); + if (getState() == Call.State.INCOMING) { + CallList.getInstance().onIncoming(this, getCannedSmsResponses()); + } else { + CallList.getInstance().onUpdate(this); + } + mTelecommCall.addListener(mTelecommCallListener); } - public String getCallId() { - return mCallId; + public android.telecomm.Call getTelecommCall() { + return mTelecommCall; } - public String getNumber() { - if (mGatewayInfo != null) { - return mGatewayInfo.getOriginalHandle().getSchemeSpecificPart(); + private void update() { + int oldState = getState(); + updateFromTelecommCall(); + if (oldState != getState() && getState() == Call.State.DISCONNECTED) { + CallList.getInstance().onDisconnect(this); + } else { + CallList.getInstance().onUpdate(this); } - return mHandle == null ? null : mHandle.getSchemeSpecificPart(); } - public Uri getHandle() { - return mHandle; + private void updateFromTelecommCall() { + setState(translateState(mTelecommCall.getState())); + setDisconnectCause(mTelecommCall.getDetails().getDisconnectCauseCode()); + + if (mTelecommCall.getParent() != null) { + mParentCallId = CallList.getInstance().getCallByTelecommCall( + mTelecommCall.getParent()).getId(); + } + + if (mTelecommCall.getCallVideoProvider() != null) { + if (mCallVideoClient == null) { + mCallVideoClient = new InCallVideoClient(); + } + mTelecommCall.getCallVideoProvider().setCallVideoClient(mCallVideoClient); + } + + mChildCallIds.clear(); + for (int i = 0; i < mTelecommCall.getChildren().size(); i++) { + mChildCallIds.add( + CallList.getInstance().getCallByTelecommCall( + mTelecommCall.getChildren().get(i)).getId()); + } } - public void setHandle(Uri handle) { - mHandle = handle; + private static int translateState(int state) { + switch (state) { + case android.telecomm.Call.STATE_DIALING: + case android.telecomm.Call.STATE_NEW: + return Call.State.DIALING; + case android.telecomm.Call.STATE_RINGING: + return Call.State.INCOMING; + case android.telecomm.Call.STATE_ACTIVE: + return Call.State.ACTIVE; + case android.telecomm.Call.STATE_HOLDING: + return Call.State.ONHOLD; + case android.telecomm.Call.STATE_DISCONNECTED: + return Call.State.DISCONNECTED; + default: + return Call.State.INVALID; + } } - public void setNumberPresentation(int presentation) { - mNumberPresentation = presentation; + public String getId() { + return mId; } - public void setCnapName(String cnapName) { - mCnapName = cnapName; + public String getNumber() { + if (mTelecommCall.getDetails().getGatewayInfo() != null) { + return mTelecommCall.getDetails().getGatewayInfo() + .getOriginalHandle().getSchemeSpecificPart(); + } + return getHandle() == null ? null : getHandle().getSchemeSpecificPart(); } - public void setCnapNamePresentation(int presentation) { - mCnapNamePresentation = presentation; + public Uri getHandle() { + return mTelecommCall.getDetails().getHandle(); } public int getState() { @@ -167,15 +257,15 @@ public final class Call { } public int getNumberPresentation() { - return mNumberPresentation; + return getTelecommCall().getDetails().getHandlePresentation(); } public int getCnapNamePresentation() { - return mCnapNamePresentation; + return getTelecommCall().getDetails().getCallerDisplayNamePresentation(); } public String getCnapName() { - return mCnapName; + return getTelecommCall().getDetails().getCallerDisplayName(); } /** Returns call disconnect cause; values are defined in {@link DisconnectCause}. */ @@ -187,39 +277,23 @@ public final class Call { return DisconnectCause.NOT_DISCONNECTED; } - /** Sets the call disconnect cause; values are defined in {@link DisconnectCause}. */ - public void setDisconnectCause(int cause) { - mDisconnectCause = cause; - } - - /** Sets the possible text message responses. */ - public void setCannedSmsResponses(List<String> cannedSmsResponses) { - mCannedSmsResponses = cannedSmsResponses; + public void setDisconnectCause(int disconnectCause) { + mDisconnectCause = disconnectCause; } /** Returns the possible text message responses. */ public List<String> getCannedSmsResponses() { - return mCannedSmsResponses; - } - - /** Sets a bit mask of capabilities unique to this call. */ - public void setCapabilities(int capabilities) { - mCapabilities = (CallCapabilities.ALL & capabilities); + return mTelecommCall.getCannedTextResponses(); } /** Checks if the call supports the given set of capabilities supplied as a bit mask. */ public boolean can(int capabilities) { - return (capabilities == (capabilities & mCapabilities)); - } - - /** Sets the time when the call first became active. */ - public void setConnectTimeMillis(long connectTimeMillis) { - mConnectTimeMillis = connectTimeMillis; + return (capabilities == (capabilities & mTelecommCall.getDetails().getCapabilities())); } /** Gets the time when the call first became active. */ public long getConnectTimeMillis() { - return mConnectTimeMillis; + return mTelecommCall.getDetails().getConnectTimeMillis(); } public boolean isConferenceCall() { @@ -227,60 +301,21 @@ public final class Call { } public GatewayInfo getGatewayInfo() { - return mGatewayInfo; - } - - public void setGatewayInfo(GatewayInfo gatewayInfo) { - mGatewayInfo = gatewayInfo; + return mTelecommCall.getDetails().getGatewayInfo(); } public PhoneAccount getAccount() { - return mAccount; - } - - public void setAccount(PhoneAccount account) { - mAccount = account; - } - - /** The descriptor for the call service currently routing this call. */ - public CallServiceDescriptor getCurrentCallServiceDescriptor() { - return mCurrentCallServiceDescriptor; - } - - public void setCurrentCallServiceDescriptor(CallServiceDescriptor descriptor) { - mCurrentCallServiceDescriptor = descriptor; + return mTelecommCall.getDetails().getAccount(); } public RemoteCallVideoProvider getCallVideoProvider() { - return mCallVideoProvider; - } - - public void setCallVideoProvider(RemoteCallVideoProvider callVideoProvider) { - mCallVideoProvider = callVideoProvider; - - if (mCallVideoProvider != null) { - try { - if (mCallVideoClient == null) { - mCallVideoClient = new InCallVideoClient(); - } - mCallVideoProvider.setCallVideoClient(mCallVideoClient); - } catch (RemoteException ignored) { - } - } - } - - public void setChildCallIds(List<String> callIds) { - mChildCallIds = callIds; + return mTelecommCall.getCallVideoProvider(); } public List<String> getChildCallIds() { return mChildCallIds; } - public void setParentId(String callId) { - mParentCallId = callId; - } - public String getParentId() { return mParentCallId; } @@ -288,9 +323,9 @@ public final class Call { @Override public String toString() { return String.format(Locale.US, "[%s, %s, %s, children:%s, parent:%s]", - mCallId, + mId, State.toString(mState), - CallCapabilities.toString(mCapabilities), + CallCapabilities.toString(mTelecommCall.getDetails().getCapabilities()), mChildCallIds, mParentCallId); } diff --git a/InCallUI/src/com/android/incallui/CallButtonPresenter.java b/InCallUI/src/com/android/incallui/CallButtonPresenter.java index d9fee5f44..84cb8ac96 100644 --- a/InCallUI/src/com/android/incallui/CallButtonPresenter.java +++ b/InCallUI/src/com/android/incallui/CallButtonPresenter.java @@ -203,15 +203,15 @@ public class CallButtonPresenter extends Presenter<CallButtonPresenter.CallButto } if (checked) { Log.i(this, "Putting the call on hold: " + mCall); - TelecommAdapter.getInstance().holdCall(mCall.getCallId()); + TelecommAdapter.getInstance().holdCall(mCall.getId()); } else { Log.i(this, "Removing the call from hold: " + mCall); - TelecommAdapter.getInstance().unholdCall(mCall.getCallId()); + TelecommAdapter.getInstance().unholdCall(mCall.getId()); } } public void mergeClicked() { - TelecommAdapter.getInstance().merge(mCall.getCallId()); + TelecommAdapter.getInstance().merge(mCall.getId()); } public void addCallClicked() { @@ -225,7 +225,7 @@ public class CallButtonPresenter extends Presenter<CallButtonPresenter.CallButto } public void swapClicked() { - TelecommAdapter.getInstance().swap(mCall.getCallId()); + TelecommAdapter.getInstance().swap(mCall.getId()); } public void showDialpadClicked(boolean checked) { diff --git a/InCallUI/src/com/android/incallui/CallCardPresenter.java b/InCallUI/src/com/android/incallui/CallCardPresenter.java index 9993ffbc4..bc9fadfd8 100644 --- a/InCallUI/src/com/android/incallui/CallCardPresenter.java +++ b/InCallUI/src/com/android/incallui/CallCardPresenter.java @@ -21,7 +21,6 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.graphics.drawable.Drawable; import android.telecomm.CallCapabilities; -import android.telecomm.CallServiceDescriptor; import android.telecomm.PhoneAccount; import android.telephony.DisconnectCause; import android.text.TextUtils; @@ -228,7 +227,7 @@ public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi> if (mPrimary == null) { return; } - TelecommAdapter.getInstance().phoneAccountClicked(mPrimary.getCallId()); + TelecommAdapter.getInstance().phoneAccountClicked(mPrimary.getId()); } private boolean areCallsSame(Call call1, Call call2) { @@ -239,7 +238,7 @@ public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi> } // otherwise compare call Ids - return call1.getCallId().equals(call2.getCallId()); + return call1.getId().equals(call2.getId()); } private void maybeStartSearch(Call call, boolean isPrimary) { @@ -274,7 +273,7 @@ public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi> return; } if (entry.photo != null) { - if (mPrimary != null && callId.equals(mPrimary.getCallId())) { + if (mPrimary != null && callId.equals(mPrimary.getId())) { getUi().setPrimaryImage(entry.photo); } } @@ -492,7 +491,7 @@ public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi> } Log.i(this, "Swapping call to foreground: " + mSecondary); - TelecommAdapter.getInstance().unholdCall(mSecondary.getCallId()); + TelecommAdapter.getInstance().unholdCall(mSecondary.getId()); } public void endCallClicked() { @@ -501,7 +500,7 @@ public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi> } Log.i(this, "Disconnecting call: " + mPrimary); - TelecommAdapter.getInstance().disconnectCall(mPrimary.getCallId()); + TelecommAdapter.getInstance().disconnectCall(mPrimary.getId()); } public interface CallCardUi extends Ui { diff --git a/InCallUI/src/com/android/incallui/CallList.java b/InCallUI/src/com/android/incallui/CallList.java index 343a94337..f89d8aafe 100644 --- a/InCallUI/src/com/android/incallui/CallList.java +++ b/InCallUI/src/com/android/incallui/CallList.java @@ -23,6 +23,7 @@ import com.google.common.base.Preconditions; import android.os.Handler; import android.os.Message; +import android.telecomm.Phone; import android.telephony.DisconnectCause; import java.util.HashMap; @@ -34,7 +35,7 @@ import java.util.Set; * as they are received from the telephony stack. Primary listener of changes to this class is * InCallPresenter. */ -public class CallList { +public class CallList implements InCallPhoneListener { private static final int DISCONNECTED_CALL_SHORT_TIMEOUT_MS = 200; private static final int DISCONNECTED_CALL_MEDIUM_TIMEOUT_MS = 2000; @@ -44,12 +45,14 @@ public class CallList { private static CallList sInstance = new CallList(); - private final HashMap<String, Call> mCallMap = Maps.newHashMap(); + private final HashMap<String, Call> mCallById = new HashMap<>(); + private final HashMap<android.telecomm.Call, Call> mCallByTelecommCall = new HashMap<>(); private final HashMap<String, List<String>> mCallTextReponsesMap = Maps.newHashMap(); private final Set<Listener> mListeners = Sets.newHashSet(); private final HashMap<String, List<CallUpdateListener>> mCallUpdateListenerMap = Maps .newHashMap(); + private Phone mPhone; /** * Static singleton accessor method. @@ -58,12 +61,38 @@ public class CallList { return sInstance; } + private Phone.Listener mPhoneListener = new Phone.Listener() { + @Override + public void onCallAdded(Phone phone, android.telecomm.Call call) { + // TODO(ihab): The Call adds itself to various singletons within its ctor. Refactor + // so that this is done more explicitly; otherwise, the below looks like we're creating + // an object and never using it. + new Call(call); + } + @Override + public void onCallRemoved(Phone phone, android.telecomm.Call call) { + // Handled by disconnection cascade from the Call itself + } + }; + /** * Private constructor. Instance should only be acquired through getInstance(). */ private CallList() { } + @Override + public void setPhone(Phone phone) { + mPhone = phone; + mPhone.addListener(mPhoneListener); + } + + @Override + public void clearPhone() { + mPhone.removeListener(mPhoneListener); + mPhone = null; + } + /** * Called when a single call disconnects. */ @@ -100,27 +129,12 @@ public class CallList { */ public void onUpdate(Call call) { Log.d(this, "onUpdate - ", call); - onUpdateCall(call); notifyGenericListeners(); } - /** - * Called when multiple calls have changed. - */ - public void onUpdate(List<Call> callsToUpdate) { - Log.d(this, "onUpdate(...)"); - - Preconditions.checkNotNull(callsToUpdate); - for (Call call : callsToUpdate) { - onUpdateCall(call); - } - - notifyGenericListeners(); - } - public void notifyCallUpdateListeners(Call call) { - final List<CallUpdateListener> listeners = mCallUpdateListenerMap.get(call.getCallId()); + final List<CallUpdateListener> listeners = mCallUpdateListenerMap.get(call.getId()); if (listeners != null) { for (CallUpdateListener listener : listeners) { listener.onCallChanged(call); @@ -245,17 +259,12 @@ public class CallList { return result; } - public Call getCall(String callId) { - return mCallMap.get(callId); + public Call getCallById(String callId) { + return mCallById.get(callId); } - public boolean existsLiveCall() { - for (Call call : mCallMap.values()) { - if (!isCallDead(call)) { - return true; - } - } - return false; + public Call getCallByTelecommCall(android.telecomm.Call telecommCall) { + return mCallByTelecommCall.get(telecommCall); } public List<String> getTextResponses(String callId) { @@ -276,7 +285,7 @@ public class CallList { public Call getCallWithState(int state, int positionToFind) { Call retval = null; int position = 0; - for (Call call : mCallMap.values()) { + for (Call call : mCallById.values()) { if (call.getState() == state) { if (position >= positionToFind) { retval = call; @@ -297,7 +306,7 @@ public class CallList { * there can be no active calls, so this is relatively safe thing to do. */ public void clearOnDisconnect() { - for (Call call : mCallMap.values()) { + for (Call call : mCallById.values()) { final int state = call.getState(); if (state != Call.State.IDLE && state != Call.State.INVALID && @@ -350,7 +359,7 @@ public class CallList { if (call.getState() == Call.State.DISCONNECTED) { // update existing (but do not add!!) disconnected calls - if (mCallMap.containsKey(call.getCallId())) { + if (mCallById.containsKey(call.getId())) { // For disconnected calls, we want to keep them alive for a few seconds so that the // UI has a chance to display anything it needs when a call is disconnected. @@ -359,14 +368,17 @@ public class CallList { final Message msg = mHandler.obtainMessage(EVENT_DISCONNECTED_TIMEOUT, call); mHandler.sendMessageDelayed(msg, getDelayForDisconnect(call)); - mCallMap.put(call.getCallId(), call); + mCallById.put(call.getId(), call); + mCallByTelecommCall.put(call.getTelecommCall(), call); updated = true; } } else if (!isCallDead(call)) { - mCallMap.put(call.getCallId(), call); + mCallById.put(call.getId(), call); + mCallByTelecommCall.put(call.getTelecommCall(), call); updated = true; - } else if (mCallMap.containsKey(call.getCallId())) { - mCallMap.remove(call.getCallId()); + } else if (mCallById.containsKey(call.getId())) { + mCallById.remove(call.getId()); + mCallByTelecommCall.remove(call.getTelecommCall()); updated = true; } @@ -404,10 +416,10 @@ public class CallList { if (!isCallDead(call)) { if (textResponses != null) { - mCallTextReponsesMap.put(call.getCallId(), textResponses); + mCallTextReponsesMap.put(call.getId(), textResponses); } - } else if (mCallMap.containsKey(call.getCallId())) { - mCallTextReponsesMap.remove(call.getCallId()); + } else if (mCallById.containsKey(call.getId())) { + mCallTextReponsesMap.remove(call.getId()); } } diff --git a/InCallUI/src/com/android/incallui/ContactInfoCache.java b/InCallUI/src/com/android/incallui/ContactInfoCache.java index 19b026787..ba1dca706 100644 --- a/InCallUI/src/com/android/incallui/ContactInfoCache.java +++ b/InCallUI/src/com/android/incallui/ContactInfoCache.java @@ -109,7 +109,7 @@ public class ContactInfoCache implements ContactsAsyncHelper.OnImageLoadComplete Preconditions.checkState(Looper.getMainLooper().getThread() == Thread.currentThread()); Preconditions.checkNotNull(callback); - final String callId = call.getCallId(); + final String callId = call.getId(); final ContactCacheEntry cacheEntry = mInfoMap.get(callId); Set<ContactInfoCacheCallback> callBacks = mCallBacks.get(callId); @@ -149,7 +149,7 @@ public class ContactInfoCache implements ContactsAsyncHelper.OnImageLoadComplete private void findInfoQueryComplete(Call call, CallerInfo callerInfo, boolean isIncoming, boolean didLocalLookup) { - final String callId = call.getCallId(); + final String callId = call.getId(); int presentationMode = call.getNumberPresentation(); if (callerInfo.contactExists || callerInfo.isEmergencyNumber() || callerInfo.isVoiceMailNumber()) { diff --git a/InCallUI/src/com/android/incallui/DialpadPresenter.java b/InCallUI/src/com/android/incallui/DialpadPresenter.java index b3818646f..0778b1e9b 100644 --- a/InCallUI/src/com/android/incallui/DialpadPresenter.java +++ b/InCallUI/src/com/android/incallui/DialpadPresenter.java @@ -16,7 +16,6 @@ package com.android.incallui; -import android.telecomm.InCallAdapter; import android.telephony.PhoneNumberUtils; /** @@ -60,7 +59,7 @@ public class DialpadPresenter extends Presenter<DialpadPresenter.DialpadUi> // Append this key to the "digits" widget. getUi().appendDigitsToField(c); // Plays the tone through Telecomm. - TelecommAdapter.getInstance().playDtmfTone(mCall.getCallId(), c); + TelecommAdapter.getInstance().playDtmfTone(mCall.getId(), c); } else { Log.d(this, "ignoring dtmf request for '" + c + "'"); } @@ -72,7 +71,7 @@ public class DialpadPresenter extends Presenter<DialpadPresenter.DialpadUi> public void stopTone() { if (mCall != null) { Log.d(this, "stopping remote tone"); - TelecommAdapter.getInstance().stopDtmfTone(mCall.getCallId()); + TelecommAdapter.getInstance().stopDtmfTone(mCall.getId()); } } diff --git a/InCallUI/src/com/android/incallui/InCallActivity.java b/InCallUI/src/com/android/incallui/InCallActivity.java index 4e6bc5009..24e57625e 100644 --- a/InCallUI/src/com/android/incallui/InCallActivity.java +++ b/InCallUI/src/com/android/incallui/InCallActivity.java @@ -34,7 +34,6 @@ import android.view.View; import android.view.Window; import android.view.WindowManager; import android.view.accessibility.AccessibilityEvent; -import android.widget.Toast; import com.android.phone.common.animation.AnimationListenerAdapter; import com.android.incallui.Call.State; @@ -400,7 +399,7 @@ public class InCallActivity extends Activity { // wants to use the dialpad toward the exact line, so un-hold the holding line. final Call call = CallList.getInstance().getActiveOrBackgroundCall(); if (call != null && call.getState() == State.ONHOLD) { - TelecommAdapter.getInstance().unholdCall(call.getCallId()); + TelecommAdapter.getInstance().unholdCall(call.getId()); } } } diff --git a/InCallUI/src/com/android/incallui/InCallPhoneListener.java b/InCallUI/src/com/android/incallui/InCallPhoneListener.java new file mode 100644 index 000000000..c2be3e6f8 --- /dev/null +++ b/InCallUI/src/com/android/incallui/InCallPhoneListener.java @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.incallui; + +import android.telecomm.Phone; + +/** + * Interface implemented by In-Call components that maintain a reference to the Telecomm API + * {@code Phone} object. Clarifies the expectations associated with the relevant method calls. + */ +public interface InCallPhoneListener { + + /** + * Called once at {@code InCallService} startup time with a valid {@code Phone}. At + * that time, there will be no existing {@code Call}s. + * + * @param phone The {@code Phone} object. + */ + void setPhone(Phone phone); + + /** + * Called once at {@code InCallService} shutdown time. At that time, any {@code Call}s + * will have transitioned through the disconnected state and will no longer exist. + */ + void clearPhone(); +} diff --git a/InCallUI/src/com/android/incallui/InCallPresenter.java b/InCallUI/src/com/android/incallui/InCallPresenter.java index 5ef7c5a52..5c6283ea4 100644 --- a/InCallUI/src/com/android/incallui/InCallPresenter.java +++ b/InCallUI/src/com/android/incallui/InCallPresenter.java @@ -19,6 +19,7 @@ package com.android.incallui; import android.content.Context; import android.content.Intent; import android.telecomm.CallCapabilities; +import android.telecomm.Phone; import com.google.common.base.Preconditions; import com.google.common.collect.Sets; @@ -36,7 +37,7 @@ import java.util.Set; * that want to listen in on the in-call state changes. * TODO: This class has become more of a state machine at this point. Consider renaming. */ -public class InCallPresenter implements CallList.Listener { +public class InCallPresenter implements CallList.Listener, InCallPhoneListener { private static InCallPresenter sInCallPresenter; @@ -53,6 +54,32 @@ public class InCallPresenter implements CallList.Listener { private ProximitySensor mProximitySensor; private boolean mServiceConnected = false; + private final Phone.Listener mPhoneListener = new Phone.Listener() { + @Override + public void onBringToForeground(Phone phone, boolean showDialpad) { + Log.i(this, "Bringing UI to foreground."); + bringToForeground(showDialpad); + } + @Override + public void onCallAdded(Phone phone, android.telecomm.Call call) { + call.addListener(mCallListener); + } + @Override + public void onCallRemoved(Phone phone, android.telecomm.Call call) { + call.removeListener(mCallListener); + } + }; + + private final android.telecomm.Call.Listener mCallListener = + new android.telecomm.Call.Listener() { + @Override + public void onPostDialWait(android.telecomm.Call call, String remainingPostDialSequence) { + onPostDialCharWait( + CallList.getInstance().getCallByTelecommCall(call).getId(), + remainingPostDialSequence); + } + }; + /** * Is true when the activity has been previously started. Some code needs to know not just if * the activity is currently up, but if it had been previously shown in foreground for this @@ -61,6 +88,8 @@ public class InCallPresenter implements CallList.Listener { */ private boolean mIsActivityPreviouslyStarted = false; + private Phone mPhone; + public static synchronized InCallPresenter getInstance() { if (sInCallPresenter == null) { sInCallPresenter = new InCallPresenter(); @@ -68,6 +97,18 @@ public class InCallPresenter implements CallList.Listener { return sInCallPresenter; } + @Override + public void setPhone(Phone phone) { + mPhone = phone; + mPhone.addListener(mPhoneListener); + } + + @Override + public void clearPhone() { + mPhone.removeListener(mPhoneListener); + mPhone = null; + } + public InCallState getInCallState() { return mInCallState; } @@ -343,7 +384,7 @@ public class InCallPresenter implements CallList.Listener { } if (call != null) { - TelecommAdapter.getInstance().disconnectCall(call.getCallId()); + TelecommAdapter.getInstance().disconnectCall(call.getId()); } } @@ -360,7 +401,7 @@ public class InCallPresenter implements CallList.Listener { Call call = mCallList.getIncomingCall(); if (call != null) { - TelecommAdapter.getInstance().answerCall(call.getCallId()); + TelecommAdapter.getInstance().answerCall(call.getId()); showInCall(false, false/* newOutgoingCall */); } } @@ -378,7 +419,7 @@ public class InCallPresenter implements CallList.Listener { Call call = mCallList.getIncomingCall(); if (call != null) { - TelecommAdapter.getInstance().rejectCall(call.getCallId(), false, null); + TelecommAdapter.getInstance().rejectCall(call.getId(), false, null); } } @@ -463,7 +504,7 @@ public class InCallPresenter implements CallList.Listener { // (1) Attempt to answer a call if (incomingCall != null) { - TelecommAdapter.getInstance().answerCall(incomingCall.getCallId()); + TelecommAdapter.getInstance().answerCall(incomingCall.getId()); return true; } @@ -484,17 +525,17 @@ public class InCallPresenter implements CallList.Listener { // (2) Attempt actions on Generic conference calls if (activeCall.isConferenceCall() && isGeneric) { if (canMerge) { - TelecommAdapter.getInstance().merge(activeCall.getCallId()); + TelecommAdapter.getInstance().merge(activeCall.getId()); return true; } else if (canSwap) { - TelecommAdapter.getInstance().swap(activeCall.getCallId()); + TelecommAdapter.getInstance().swap(activeCall.getId()); return true; } } // (3) Swap calls if (canSwap) { - TelecommAdapter.getInstance().swap(activeCall.getCallId()); + TelecommAdapter.getInstance().swap(activeCall.getId()); return true; } } @@ -512,7 +553,7 @@ public class InCallPresenter implements CallList.Listener { // (4) unhold call if (heldCall.getState() == Call.State.ONHOLD && canHold) { - TelecommAdapter.getInstance().unholdCall(heldCall.getCallId()); + TelecommAdapter.getInstance().unholdCall(heldCall.getId()); return true; } } diff --git a/InCallUI/src/com/android/incallui/InCallServiceImpl.java b/InCallUI/src/com/android/incallui/InCallServiceImpl.java index 9fed90cb4..c69571a67 100644 --- a/InCallUI/src/com/android/incallui/InCallServiceImpl.java +++ b/InCallUI/src/com/android/incallui/InCallServiceImpl.java @@ -16,14 +16,11 @@ package com.android.incallui; -import android.os.RemoteException; -import android.telecomm.CallAudioState; -import android.telecomm.CallState; -import android.telecomm.InCallAdapter; -import android.telecomm.InCallCall; +import android.app.Service; +import android.content.Intent; +import android.os.IBinder; import android.telecomm.InCallService; - -import com.google.common.collect.ImmutableList; +import android.telecomm.Phone; /** * Used to receive updates about calls from the Telecomm component. This service is bound to @@ -31,132 +28,38 @@ import com.google.common.collect.ImmutableList; * dialing (outgoing), and active calls. When the last call is disconnected, Telecomm will unbind to * the service triggering InCallActivity (via CallList) to finish soon after. */ -public class InCallServiceImpl extends InCallService { - private static final ImmutableList<String> EMPTY_RESPONSE_TEXTS = ImmutableList.of(); - - /** {@inheritDoc} */ - @Override public void onCreate() { - Log.v(this, "onCreate"); - InCallPresenter inCallPresenter = InCallPresenter.getInstance(); - inCallPresenter.setUp( - getApplicationContext(), CallList.getInstance(), AudioModeProvider.getInstance()); - TelecommAdapter.getInstance().setContext(this); - } - - /** {@inheritDoc} */ - @Override public void onDestroy() { - Log.v(this, "onDestroy"); - // Tear down the InCall system - TelecommAdapter.getInstance().setAdapter(null); - TelecommAdapter.getInstance().setContext(null); - CallList.getInstance().clearOnDisconnect(); - InCallPresenter.getInstance().tearDown(); - } - - /** {@inheritDoc} */ - @Override protected void onAdapterAttached(InCallAdapter inCallAdapter) { - Log.v(this, "onAdapterAttached"); - TelecommAdapter.getInstance().setAdapter(inCallAdapter); - } - - /** {@inheritDoc} */ - @Override protected void addCall(InCallCall telecommCall) { - Call call = new Call(telecommCall.getId()); - updateCall(call, telecommCall); - Log.i(this, "addCall: " + call); - - if (call.getState() == Call.State.INCOMING) { - CallList.getInstance().onIncoming(call, call.getCannedSmsResponses()); - } else { - CallList.getInstance().onUpdate(call); +public class InCallServiceImpl extends Service { + + private final InCallService mInCallServiceInstance = new InCallService() { + @Override + public void onPhoneCreated(Phone phone) { + Log.v(this, "onPhoneCreated"); + CallList.getInstance().setPhone(phone); + AudioModeProvider.getInstance().setPhone(phone); + TelecommAdapter.getInstance().setPhone(phone); + InCallPresenter.getInstance().setPhone(phone); + InCallPresenter.getInstance().setUp( + getApplicationContext(), + CallList.getInstance(), + AudioModeProvider.getInstance()); + TelecommAdapter.getInstance().setContext(InCallServiceImpl.this); } - } - /** {@inheritDoc} */ - @Override protected void updateCall(InCallCall telecommCall) { - Call call = CallList.getInstance().getCall(telecommCall.getId()); - if (call == null) { - Log.v(this, "updateCall for unknown call: " + telecommCall.getId()); - return; + @Override + public void onPhoneDestroyed(Phone phone) { + Log.v(this, "onPhoneDestroyed"); + // Tear down the InCall system + CallList.getInstance().clearPhone(); + AudioModeProvider.getInstance().clearPhone(); + TelecommAdapter.getInstance().clearPhone(); + TelecommAdapter.getInstance().setContext(null); + CallList.getInstance().clearOnDisconnect(); + InCallPresenter.getInstance().tearDown(); } + }; - int oldState = call.getState(); - updateCall(call, telecommCall); - Log.i(this, "updateCall: " + telecommCall + " => " + call); - - if (oldState != call.getState() && call.getState() == Call.State.DISCONNECTED) { - CallList.getInstance().onDisconnect(call); - } else { - CallList.getInstance().onUpdate(call); - } - } - - /** {@inheritDoc} */ - @Override - protected void setPostDial(String callId, String remaining) { - // TODO(ihab): Add post-dial state to user interface - } - - /** {@inheritDoc} */ - @Override - protected void setPostDialWait(String callId, String remaining) { - InCallPresenter.getInstance().onPostDialCharWait(callId, remaining); - } - - /** {@inheritDoc} */ - @Override - protected void onAudioStateChanged(CallAudioState audioState) { - AudioModeProvider.getInstance().onAudioModeChange(audioState.route, audioState.isMuted); - AudioModeProvider.getInstance().onSupportedAudioModeChange(audioState.supportedRouteMask); - } - - /** {@inheritDoc} */ @Override - protected void bringToForeground(boolean showDialpad) { - Log.i(this, "Bringing UI to foreground."); - InCallPresenter.getInstance().bringToForeground(showDialpad); - } - - private void updateCall(Call call, InCallCall telecommCall) { - call.setHandle(telecommCall.getHandle()); - call.setNumberPresentation(telecommCall.getHandlePresentation()); - call.setCnapName(telecommCall.getCallerDisplayName()); - call.setCnapNamePresentation(telecommCall.getCallerDisplayNamePresentation()); - call.setDisconnectCause(telecommCall.getDisconnectCauseCode()); - call.setCannedSmsResponses(telecommCall.getCannedSmsResponses()); - call.setCapabilities(telecommCall.getCapabilities()); - call.setConnectTimeMillis(telecommCall.getConnectTimeMillis()); - call.setGatewayInfo(telecommCall.getGatewayInfo()); - call.setAccount(telecommCall.getAccount()); - call.setCurrentCallServiceDescriptor(telecommCall.getCurrentCallServiceDescriptor()); - call.setState(translateState(telecommCall.getState())); - call.setParentId(telecommCall.getParentCallId()); - call.setChildCallIds(telecommCall.getChildCallIds()); - - try { - call.setCallVideoProvider(telecommCall.getCallVideoProvider()); - } catch (RemoteException ignore) { - // Do nothing. - } - } - - private static int translateState(CallState state) { - switch (state) { - case DIALING: - case NEW: - return Call.State.DIALING; - case RINGING: - return Call.State.INCOMING; - case POST_DIAL: - case POST_DIAL_WAIT: - case ACTIVE: - return Call.State.ACTIVE; - case ON_HOLD: - return Call.State.ONHOLD; - case DISCONNECTED: - return Call.State.DISCONNECTED; - default: - return Call.State.INVALID; - } + public IBinder onBind(Intent intent) { + return mInCallServiceInstance.getBinder(); } } diff --git a/InCallUI/src/com/android/incallui/StatusBarNotifier.java b/InCallUI/src/com/android/incallui/StatusBarNotifier.java index 43aaa4a12..1208527a7 100644 --- a/InCallUI/src/com/android/incallui/StatusBarNotifier.java +++ b/InCallUI/src/com/android/incallui/StatusBarNotifier.java @@ -227,7 +227,7 @@ public class StatusBarNotifier implements InCallPresenter.InCallStateListener { mContactInfoCache.findInfo(call, isIncoming, new ContactInfoCacheCallback() { @Override public void onContactInfoComplete(String callId, ContactCacheEntry entry) { - Call call = CallList.getInstance().getCall(callId); + Call call = CallList.getInstance().getCallById(callId); if (call != null) { buildAndSendNotification(call, entry); } @@ -235,7 +235,7 @@ public class StatusBarNotifier implements InCallPresenter.InCallStateListener { @Override public void onImageLoadComplete(String callId, ContactCacheEntry entry) { - Call call = CallList.getInstance().getCall(callId); + Call call = CallList.getInstance().getCallById(callId); if (call != null) { buildAndSendNotification(call, entry); } @@ -251,7 +251,7 @@ public class StatusBarNotifier implements InCallPresenter.InCallStateListener { // back. However, it can happen much later. Before we continue, we need to make sure that // the call being passed in is still the one we want to show in the notification. final Call call = getCallToShow(CallList.getInstance()); - if (call == null || !call.getCallId().equals(originalCall.getCallId())) { + if (call == null || !call.getId().equals(originalCall.getId())) { return; } diff --git a/InCallUI/src/com/android/incallui/TelecommAdapter.java b/InCallUI/src/com/android/incallui/TelecommAdapter.java index d22cb1577..6d0e0a62d 100644 --- a/InCallUI/src/com/android/incallui/TelecommAdapter.java +++ b/InCallUI/src/com/android/incallui/TelecommAdapter.java @@ -21,16 +21,17 @@ import android.content.Context; import android.content.Intent; import android.os.Looper; import android.telecomm.InCallAdapter; +import android.telecomm.Phone; import com.google.common.base.Preconditions; /** Wrapper around {@link InCallAdapter} that only forwards calls to the adapter when it's valid. */ -final class TelecommAdapter { +final class TelecommAdapter implements InCallPhoneListener { private static final String ADD_CALL_MODE_KEY = "add_call_mode"; private static TelecommAdapter sInstance; private Context mContext; - private InCallAdapter mAdapter; + private Phone mPhone; static TelecommAdapter getInstance() { Preconditions.checkState(Looper.getMainLooper().getThread() == Thread.currentThread()); @@ -47,85 +48,95 @@ final class TelecommAdapter { mContext = context; } - void setAdapter(InCallAdapter adapter) { - mAdapter = adapter; + @Override + public void setPhone(Phone phone) { + mPhone = phone; + } + + @Override + public void clearPhone() { + mPhone = null; + } + + private android.telecomm.Call getTelecommCallById(String callId) { + return CallList.getInstance().getCallById(callId).getTelecommCall(); } void answerCall(String callId) { - if (mAdapter != null) { - mAdapter.answerCall(callId); + if (mPhone != null) { + getTelecommCallById(callId).answer(); } else { - Log.e(this, "error answerCall, mAdapter is null"); + Log.e(this, "error answerCall, mPhone is null"); } } void rejectCall(String callId, boolean rejectWithMessage, String message) { - if (mAdapter != null) { - mAdapter.rejectCall(callId, rejectWithMessage, message); + if (mPhone != null) { + getTelecommCallById(callId).reject(rejectWithMessage, message); } else { - Log.e(this, "error rejectCall, mAdapter is null"); + Log.e(this, "error rejectCall, mPhone is null"); } } void disconnectCall(String callId) { - if (mAdapter != null) { - mAdapter.disconnectCall(callId); + if (mPhone != null) { + getTelecommCallById(callId).disconnect(); } else { - Log.e(this, "error disconnectCall, mAdapter is null"); + Log.e(this, "error disconnectCall, mPhone is null"); } } void holdCall(String callId) { - if (mAdapter != null) { - mAdapter.holdCall(callId); + if (mPhone != null) { + getTelecommCallById(callId).hold(); } else { - Log.e(this, "error holdCall, mAdapter is null"); + Log.e(this, "error holdCall, mPhone is null"); } } void unholdCall(String callId) { - if (mAdapter != null) { - mAdapter.unholdCall(callId); + if (mPhone != null) { + getTelecommCallById(callId).unhold(); } else { - Log.e(this, "error unholdCall, mAdapter is null"); + Log.e(this, "error unholdCall, mPhone is null"); } } void mute(boolean shouldMute) { - if (mAdapter != null) { - mAdapter.mute(shouldMute); + if (mPhone != null) { + mPhone.setMuted(shouldMute); } else { - Log.e(this, "error mute, mAdapter is null"); + Log.e(this, "error mute, mPhone is null"); } } void setAudioRoute(int route) { - if (mAdapter != null) { - mAdapter.setAudioRoute(route); + if (mPhone != null) { + mPhone.setAudioRoute(route); } else { - Log.e(this, "error setAudioRoute, mAdapter is null"); + Log.e(this, "error setAudioRoute, mPhone is null"); } } void separateCall(String callId) { - if (mAdapter != null) { - mAdapter.splitFromConference(callId); + if (mPhone != null) { + getTelecommCallById(callId).splitFromConference(); } else { - Log.e(this, "error separateCall, mAdapter is null."); + Log.e(this, "error separateCall, mPhone is null."); } } void merge(String callId) { - if (mAdapter != null) { - mAdapter.conference(callId); + if (mPhone != null) { + getTelecommCallById(callId).conference(); } else { - Log.e(this, "error merge, mAdapter is null."); + Log.e(this, "error merge, mPhone is null."); } } void swap(String callId) { - if (mAdapter != null) { - mAdapter.swapWithBackgroundCall(callId); + if (mPhone != null) { + getTelecommCallById(callId).swapWithBackgroundCall(); } else { Log.e(this, "error swapWithBackgroundCall, mAdapter is null."); } @@ -153,34 +164,34 @@ final class TelecommAdapter { } void playDtmfTone(String callId, char digit) { - if (mAdapter != null) { - mAdapter.playDtmfTone(callId, digit); + if (mPhone != null) { + getTelecommCallById(callId).playDtmfTone(digit); } else { - Log.e(this, "error playDtmfTone, mAdapter is null"); + Log.e(this, "error playDtmfTone, mPhone is null"); } } void stopDtmfTone(String callId) { - if (mAdapter != null) { - mAdapter.stopDtmfTone(callId); + if (mPhone != null) { + getTelecommCallById(callId).stopDtmfTone(); } else { - Log.e(this, "error stopDtmfTone, mAdapter is null"); + Log.e(this, "error stopDtmfTone, mPhone is null"); } } void postDialContinue(String callId, boolean proceed) { - if (mAdapter != null) { - mAdapter.postDialContinue(callId, proceed); + if (mPhone != null) { + getTelecommCallById(callId).postDialContinue(proceed); } else { - Log.e(this, "error postDialContinue, mAdapter is null"); + Log.e(this, "error postDialContinue, mPhone is null"); } } void phoneAccountClicked(String callId) { - if (mAdapter != null) { - mAdapter.phoneAccountClicked(callId); + if (mPhone != null) { + getTelecommCallById(callId).phoneAccountClicked(); } else { - Log.e(this, "error phoneAccountClicked, mAdapter is null"); + Log.e(this, "error phoneAccountClicked, mPhone is null"); } } } |