diff options
Diffstat (limited to 'java/com/android/incallui/call')
-rw-r--r-- | java/com/android/incallui/call/CallList.java | 48 | ||||
-rw-r--r-- | java/com/android/incallui/call/DialerCall.java | 203 | ||||
-rw-r--r-- | java/com/android/incallui/call/DialerCallListener.java | 2 | ||||
-rw-r--r-- | java/com/android/incallui/call/ExternalCallList.java | 6 | ||||
-rw-r--r-- | java/com/android/incallui/call/TelecomAdapter.java | 12 |
5 files changed, 247 insertions, 24 deletions
diff --git a/java/com/android/incallui/call/CallList.java b/java/com/android/incallui/call/CallList.java index 34f0cc0d7..d0931dd3d 100644 --- a/java/com/android/incallui/call/CallList.java +++ b/java/com/android/incallui/call/CallList.java @@ -32,6 +32,8 @@ import com.android.dialer.blocking.FilteredNumberAsyncQueryHandler; import com.android.dialer.blocking.FilteredNumbersUtil; import com.android.dialer.common.Assert; import com.android.dialer.common.LogUtil; +import com.android.dialer.enrichedcall.EnrichedCallComponent; +import com.android.dialer.enrichedcall.EnrichedCallManager; import com.android.dialer.location.GeoUtil; import com.android.dialer.logging.DialerImpression; import com.android.dialer.logging.Logger; @@ -112,11 +114,16 @@ public class CallList implements DialerCallDelegate { public void onCallAdded( final Context context, final android.telecom.Call telecomCall, LatencyReport latencyReport) { - Trace.beginSection("onCallAdded"); + Trace.beginSection("CallList.onCallAdded"); final DialerCall call = new DialerCall(context, this, telecomCall, latencyReport, true /* registerCallback */); logSecondIncomingCall(context, call); + EnrichedCallManager manager = EnrichedCallComponent.get(context).getEnrichedCallManager(); + manager.registerCapabilitiesListener(call); + manager.registerStateChangedListener(call); + + Trace.beginSection("checkSpam"); final DialerCallListenerImpl dialerCallListener = new DialerCallListenerImpl(call); call.addListener(dialerCallListener); LogUtil.d("CallList.onCallAdded", "callState=" + call.getState()); @@ -163,7 +170,9 @@ public class CallList implements DialerCallDelegate { updateUserMarkedSpamStatus(call, context, number, dialerCallListener); } + Trace.endSection(); + Trace.beginSection("checkBlock"); FilteredNumberAsyncQueryHandler filteredNumberAsyncQueryHandler = new FilteredNumberAsyncQueryHandler(context); @@ -179,6 +188,7 @@ public class CallList implements DialerCallDelegate { }, call.getNumber(), GeoUtil.getCurrentCountryIso(context)); + Trace.endSection(); if (call.getState() == DialerCall.State.INCOMING || call.getState() == DialerCall.State.CALL_WAITING) { @@ -278,6 +288,10 @@ public class CallList implements DialerCallDelegate { DialerCall call = mCallByTelecomCall.get(telecomCall); Assert.checkArgument(!call.isExternalCall()); + EnrichedCallManager manager = EnrichedCallComponent.get(context).getEnrichedCallManager(); + manager.unregisterCapabilitiesListener(call); + manager.unregisterStateChangedListener(call); + // Don't log an already logged call. logCall() might be called multiple times // for the same call due to b/24109437. if (call.getLogState() != null && !call.getLogState().isLogged) { @@ -289,6 +303,8 @@ public class CallList implements DialerCallDelegate { LogUtil.w( "CallList.onCallRemoved", "Removing call not previously disconnected " + call.getId()); } + + call.onRemovedFromCallList(); } if (!hasLiveCall()) { @@ -341,6 +357,7 @@ public class CallList implements DialerCallDelegate { /** Called when a single call has changed. */ private void onIncoming(DialerCall call) { + Trace.beginSection("CallList.onIncoming"); if (updateCallInMap(call)) { LogUtil.i("CallList.onIncoming", String.valueOf(call)); } @@ -348,6 +365,7 @@ public class CallList implements DialerCallDelegate { for (Listener listener : mListeners) { listener.onIncomingCall(call); } + Trace.endSection(); } public void addListener(@NonNull Listener listener) { @@ -518,6 +536,22 @@ public class CallList implements DialerCallDelegate { } /** + * Return if there is any active or background call which was not a parent call (never had a child + * call) + */ + public boolean hasNonParentActiveOrBackgroundCall() { + for (DialerCall call : mCallById.values()) { + if ((call.getState() == State.ACTIVE + || call.getState() == State.ONHOLD + || call.getState() == State.CONFERENCED) + && !call.wasParentCall()) { + return true; + } + } + return false; + } + + /** * This is called when the service disconnects, either expectedly or unexpectedly. For the * expected case, it's because we have no calls left. For the unexpected case, it is likely a * crash of phone and we need to clean up our calls manually. Without phone, there can be no @@ -556,7 +590,9 @@ public class CallList implements DialerCallDelegate { * * @param call The call to update. */ - private void onUpdateCall(DialerCall call) { + @VisibleForTesting + void onUpdateCall(DialerCall call) { + Trace.beginSection("CallList.onUpdateCall"); LogUtil.d("CallList.onUpdateCall", String.valueOf(call)); if (!mCallById.containsKey(call.getId()) && call.isExternalCall()) { // When a regular call becomes external, it is removed from the call list, and there may be @@ -569,6 +605,7 @@ public class CallList implements DialerCallDelegate { if (updateCallInMap(call)) { LogUtil.i("CallList.onUpdateCall", String.valueOf(call)); } + Trace.endSection(); } /** @@ -593,6 +630,7 @@ public class CallList implements DialerCallDelegate { * @return false if no call previously existed and no call was added, otherwise true. */ private boolean updateCallInMap(DialerCall call) { + Trace.beginSection("CallList.updateCallInMap"); Objects.requireNonNull(call); boolean updated = false; @@ -622,6 +660,7 @@ public class CallList implements DialerCallDelegate { updated = true; } + Trace.endSection(); return updated; } @@ -751,7 +790,7 @@ public class CallList implements DialerCallDelegate { @Override public void onDialerCallUpdate() { - Trace.beginSection("onUpdate"); + Trace.beginSection("CallList.onDialerCallUpdate"); onUpdateCall(mCall); notifyGenericListeners(); Trace.endSection(); @@ -793,6 +832,9 @@ public class CallList implements DialerCallDelegate { } @Override + public void onEnrichedCallSessionUpdate() {} + + @Override public void onDialerCallSessionModificationStateChange() { for (Listener listener : mListeners) { listener.onSessionModificationStateChange(mCall); diff --git a/java/com/android/incallui/call/DialerCall.java b/java/com/android/incallui/call/DialerCall.java index acedf41f1..1a998096a 100644 --- a/java/com/android/incallui/call/DialerCall.java +++ b/java/com/android/incallui/call/DialerCall.java @@ -41,16 +41,20 @@ import android.telecom.VideoProfile; import android.telephony.PhoneNumberUtils; import android.text.TextUtils; import com.android.contacts.common.compat.CallCompat; -import com.android.contacts.common.compat.TelephonyManagerCompat; import com.android.contacts.common.compat.telecom.TelecomManagerCompat; import com.android.dialer.callintent.CallInitiationType; import com.android.dialer.callintent.CallIntentParser; import com.android.dialer.callintent.CallSpecificAppData; import com.android.dialer.common.Assert; -import com.android.dialer.common.ConfigProviderBindings; import com.android.dialer.common.LogUtil; +import com.android.dialer.compat.telephony.TelephonyManagerCompat; +import com.android.dialer.configprovider.ConfigProviderBindings; import com.android.dialer.enrichedcall.EnrichedCallCapabilities; import com.android.dialer.enrichedcall.EnrichedCallComponent; +import com.android.dialer.enrichedcall.EnrichedCallManager; +import com.android.dialer.enrichedcall.EnrichedCallManager.CapabilitiesListener; +import com.android.dialer.enrichedcall.EnrichedCallManager.Filter; +import com.android.dialer.enrichedcall.EnrichedCallManager.StateChangedListener; import com.android.dialer.enrichedcall.Session; import com.android.dialer.lightbringer.LightbringerComponent; import com.android.dialer.logging.ContactLookupResult; @@ -77,7 +81,7 @@ import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.TimeUnit; /** Describes a single call and its state. */ -public class DialerCall implements VideoTechListener { +public class DialerCall implements VideoTechListener, StateChangedListener, CapabilitiesListener { public static final int CALL_HISTORY_STATUS_UNKNOWN = 0; public static final int CALL_HISTORY_STATUS_PRESENT = 1; @@ -143,6 +147,13 @@ public class DialerCall implements VideoTechListener { private EnrichedCallCapabilities mEnrichedCallCapabilities; private Session mEnrichedCallSession; + private int answerAndReleaseButtonDisplayedTimes = 0; + private boolean releasedByAnsweringSecondCall = false; + // Times when a second call is received but AnswerAndRelease button is not shown + // since it's not supported. + private int secondCallWithoutAnswerAndReleasedButtonTimes = 0; + private VideoTech videoTech; + public static String getNumberFromHandle(Uri handle) { return handle == null ? "" : handle.getSchemeSpecificPart(); } @@ -153,6 +164,9 @@ public class DialerCall implements VideoTechListener { */ private boolean isRemotelyHeld; + /** Indicates whether this call is currently in the process of being merged into a conference. */ + private boolean isMergeInProcess; + /** * Indicates whether the phone account associated with this call supports specifying a call * subject. @@ -181,14 +195,15 @@ public class DialerCall implements VideoTechListener { @Override public void onDetailsChanged(Call call, Call.Details details) { - LogUtil.v("TelecomCallCallback.onStateChanged", " call=" + call + " details=" + details); + LogUtil.v( + "TelecomCallCallback.onDetailsChanged", " call=" + call + " details=" + details); update(); } @Override public void onCannedTextResponsesLoaded(Call call, List<String> cannedTextResponses) { LogUtil.v( - "TelecomCallCallback.onStateChanged", + "TelecomCallCallback.onCannedTextResponsesLoaded", "call=" + call + " cannedTextResponses=" + cannedTextResponses); for (CannedTextResponsesLoadedListener listener : mCannedTextResponsesLoadedListeners) { listener.onCannedTextResponsesLoaded(DialerCall.this); @@ -198,7 +213,7 @@ public class DialerCall implements VideoTechListener { @Override public void onPostDialWait(Call call, String remainingPostDialSequence) { LogUtil.v( - "TelecomCallCallback.onStateChanged", + "TelecomCallCallback.onPostDialWait", "call=" + call + " remainingPostDialSequence=" + remainingPostDialSequence); update(); } @@ -206,20 +221,20 @@ public class DialerCall implements VideoTechListener { @Override public void onVideoCallChanged(Call call, VideoCall videoCall) { LogUtil.v( - "TelecomCallCallback.onStateChanged", "call=" + call + " videoCall=" + videoCall); + "TelecomCallCallback.onVideoCallChanged", "call=" + call + " videoCall=" + videoCall); update(); } @Override public void onCallDestroyed(Call call) { - LogUtil.v("TelecomCallCallback.onStateChanged", "call=" + call); + LogUtil.v("TelecomCallCallback.onCallDestroyed", "call=" + call); unregisterCallback(); } @Override public void onConferenceableCallsChanged(Call call, List<Call> conferenceableCalls) { LogUtil.v( - "DialerCall.onConferenceableCallsChanged", + "TelecomCallCallback.onConferenceableCallsChanged", "call %s, conferenceable calls: %d", call, conferenceableCalls.size()); @@ -229,7 +244,7 @@ public class DialerCall implements VideoTechListener { @Override public void onConnectionEvent(android.telecom.Call call, String event, Bundle extras) { LogUtil.v( - "DialerCall.onConnectionEvent", + "TelecomCallCallback.onConnectionEvent", "Call: " + call + ", Event: " + event + ", Extras: " + extras); switch (event) { // The Previous attempt to Merge two calls together has failed in Telecom. We must @@ -255,6 +270,14 @@ public class DialerCall implements VideoTechListener { case TelephonyManagerCompat.EVENT_NOTIFY_INTERNATIONAL_CALL_ON_WFC: notifyInternationalCallOnWifi(); break; + case TelephonyManagerCompat.EVENT_MERGE_START: + LogUtil.i("DialerCall.onConnectionEvent", "merge start"); + isMergeInProcess = true; + break; + case TelephonyManagerCompat.EVENT_MERGE_COMPLETE: + LogUtil.i("DialerCall.onConnectionEvent", "merge complete"); + isMergeInProcess = false; + break; default: break; } @@ -292,6 +315,8 @@ public class DialerCall implements VideoTechListener { mTimeAddedMs = System.currentTimeMillis(); parseCallSpecificAppData(); + + updateEnrichedCallSession(); } private static int translateState(int state) { @@ -404,15 +429,27 @@ public class DialerCall implements VideoTechListener { } } + public boolean wasParentCall() { + return mLogState.conferencedCalls != 0; + } + private void update() { - Trace.beginSection("Update"); + Trace.beginSection("DialerCall.update"); int oldState = getState(); + // Clear any cache here that could potentially change on update. + videoTech = null; // We want to potentially register a video call callback here. updateFromTelecomCall(); if (oldState != getState() && getState() == DialerCall.State.DISCONNECTED) { for (DialerCallListener listener : mListeners) { listener.onDialerCallDisconnect(); } + EnrichedCallComponent.get(mContext) + .getEnrichedCallManager() + .unregisterCapabilitiesListener(this); + EnrichedCallComponent.get(mContext) + .getEnrichedCallManager() + .unregisterStateChangedListener(this); } else { for (DialerCallListener listener : mListeners) { listener.onDialerCallUpdate(); @@ -422,6 +459,7 @@ public class DialerCall implements VideoTechListener { } private void updateFromTelecomCall() { + Trace.beginSection("DialerCall.updateFromTelecomCall"); LogUtil.v("DialerCall.updateFromTelecomCall", mTelecomCall.toString()); mVideoTechManager.dispatchCallStateChanged(mTelecomCall.getState()); @@ -470,6 +508,7 @@ public class DialerCall implements VideoTechListener { } } } + Trace.endSection(); } /** @@ -647,13 +686,23 @@ public class DialerCall implements VideoTechListener { } public void setState(int state) { - mState = state; - if (mState == State.INCOMING) { + if (state == State.INCOMING) { mLogState.isIncoming = true; - } else if (mState == State.DISCONNECTED) { - mLogState.duration = + } else if (state == State.DISCONNECTED) { + long newDuration = getConnectTimeMillis() == 0 ? 0 : System.currentTimeMillis() - getConnectTimeMillis(); + if (mState != state) { + mLogState.duration = newDuration; + } else { + LogUtil.i( + "DialerCall.setState", + "ignoring state transition from DISCONNECTED to DISCONNECTED." + + " Duration would have changed from %s to %s", + mLogState.duration, + newDuration); + } } + mState = state; } public int getNumberPresentation() { @@ -952,14 +1001,49 @@ public class DialerCall implements VideoTechListener { return isRemotelyHeld; } + public boolean isMergeInProcess() { + return isMergeInProcess; + } + public boolean isIncoming() { return mLogState.isIncoming; } + public boolean isAssistedDialed() { + if (getIntentExtras() != null) { + return getIntentExtras().getBoolean(TelephonyManagerCompat.IS_ASSISTED_DIALED, false); + } + return false; + } + public LatencyReport getLatencyReport() { return mLatencyReport; } + public int getAnswerAndReleaseButtonDisplayedTimes() { + return answerAndReleaseButtonDisplayedTimes; + } + + public void increaseAnswerAndReleaseButtonDisplayedTimes() { + answerAndReleaseButtonDisplayedTimes++; + } + + public boolean getReleasedByAnsweringSecondCall() { + return releasedByAnsweringSecondCall; + } + + public void setReleasedByAnsweringSecondCall(boolean releasedByAnsweringSecondCall) { + this.releasedByAnsweringSecondCall = releasedByAnsweringSecondCall; + } + + public int getSecondCallWithoutAnswerAndReleasedButtonTimes() { + return secondCallWithoutAnswerAndReleasedButtonTimes; + } + + public void increaseSecondCallWithoutAnswerAndReleasedButtonTimes() { + secondCallWithoutAnswerAndReleasedButtonTimes++; + } + @Nullable public EnrichedCallCapabilities getEnrichedCallCapabilities() { return mEnrichedCallCapabilities; @@ -1057,7 +1141,10 @@ public class DialerCall implements VideoTechListener { } public VideoTech getVideoTech() { - return mVideoTechManager.getVideoTech(); + if (videoTech == null) { + videoTech = mVideoTechManager.getVideoTech(); + } + return videoTech; } public String getCallbackNumber() { @@ -1172,6 +1259,76 @@ public class DialerCall implements VideoTechListener { TelecomAdapter.getInstance().setAudioRoute(CallAudioState.ROUTE_SPEAKER); } + @Override + public void onCapabilitiesUpdated() { + if (getNumber() == null) { + return; + } + EnrichedCallCapabilities capabilities = + EnrichedCallComponent.get(mContext).getEnrichedCallManager().getCapabilities(getNumber()); + if (capabilities != null) { + setEnrichedCallCapabilities(capabilities); + update(); + } + } + + @Override + public void onEnrichedCallStateChanged() { + updateEnrichedCallSession(); + } + + @Override + public void onImpressionLoggingNeeded(DialerImpression.Type impressionType) { + Logger.get(mContext).logCallImpression(impressionType, getUniqueCallId(), getTimeAddedMs()); + } + + private void updateEnrichedCallSession() { + if (getNumber() == null) { + return; + } + if (getEnrichedCallSession() != null) { + // State changes to existing sessions are currently handled by the UI components (which have + // their own listeners). Someday instead we could remove those and just call update() here and + // have the usual onDialerCallUpdate update the UI. + dispatchOnEnrichedCallSessionUpdate(); + return; + } + + EnrichedCallManager manager = EnrichedCallComponent.get(mContext).getEnrichedCallManager(); + + Filter filter = + isIncoming() + ? manager.createIncomingCallComposerFilter() + : manager.createOutgoingCallComposerFilter(); + + Session session = manager.getSession(getUniqueCallId(), getNumber(), filter); + if (session == null) { + return; + } + + session.setUniqueDialerCallId(getUniqueCallId()); + setEnrichedCallSession(session); + + LogUtil.i( + "DialerCall.updateEnrichedCallSession", + "setting session %d's dialer id to %s", + session.getSessionId(), + getUniqueCallId()); + + dispatchOnEnrichedCallSessionUpdate(); + } + + private void dispatchOnEnrichedCallSessionUpdate() { + for (DialerCallListener listener : mListeners) { + listener.onEnrichedCallSessionUpdate(); + } + } + + void onRemovedFromCallList() { + // Ensure we clean up when this call is removed. + mVideoTechManager.dispatchRemovedFromCallList(); + } + /** * Specifies whether a number is in the call history or not. {@link #CALL_HISTORY_STATUS_UNKNOWN} * means there is no result. @@ -1203,6 +1360,7 @@ public class DialerCall implements VideoTechListener { public static final int CONNECTING = 13; /* Waiting for Telecom broadcast to finish */ public static final int BLOCKED = 14; /* The number was found on the block list */ public static final int PULLING = 15; /* An external call being pulled to the device */ + public static final int CALL_PENDING = 16; /* A call is pending on a long process to finish */ public static boolean isConnectingOrConnected(int state) { switch (state) { @@ -1372,6 +1530,7 @@ public class DialerCall implements VideoTechListener { String phoneNumber = call.getNumber(); phoneNumber = phoneNumber != null ? phoneNumber : ""; + phoneNumber = phoneNumber.replaceAll("[^+0-9]", ""); // Insert order here determines the priority of that video tech option videoTechs = new ArrayList<>(); @@ -1390,7 +1549,10 @@ public class DialerCall implements VideoTechListener { videoTechs.add( new LightbringerTech( - LightbringerComponent.get(call.mContext).getLightbringer(), call, phoneNumber)); + LightbringerComponent.get(call.mContext).getLightbringer(), + call, + call.mTelecomCall, + phoneNumber)); } VideoTech getVideoTech() { @@ -1402,6 +1564,7 @@ public class DialerCall implements VideoTechListener { if (tech.isAvailable(context)) { // Remember the first VideoTech that becomes available and always use it savedTech = tech; + savedTech.becomePrimary(); return savedTech; } } @@ -1414,6 +1577,12 @@ public class DialerCall implements VideoTechListener { videoTech.onCallStateChanged(context, newState); } } + + void dispatchRemovedFromCallList() { + for (VideoTech videoTech : videoTechs) { + videoTech.onRemovedFromCallList(); + } + } } /** Called when canned text responses have been loaded. */ diff --git a/java/com/android/incallui/call/DialerCallListener.java b/java/com/android/incallui/call/DialerCallListener.java index ed321be05..5d24a4d4b 100644 --- a/java/com/android/incallui/call/DialerCallListener.java +++ b/java/com/android/incallui/call/DialerCallListener.java @@ -36,4 +36,6 @@ public interface DialerCallListener { void onHandoverToWifiFailure(); void onInternationalCallOnWifi(); + + void onEnrichedCallSessionUpdate(); } diff --git a/java/com/android/incallui/call/ExternalCallList.java b/java/com/android/incallui/call/ExternalCallList.java index 52a7a304b..f104dfe9f 100644 --- a/java/com/android/incallui/call/ExternalCallList.java +++ b/java/com/android/incallui/call/ExternalCallList.java @@ -22,6 +22,7 @@ import android.support.annotation.NonNull; import android.telecom.Call; import android.util.ArraySet; import com.android.contacts.common.compat.CallCompat; +import com.android.dialer.common.Assert; import com.android.dialer.common.LogUtil; import java.util.Collections; import java.util.Set; @@ -48,9 +49,8 @@ public class ExternalCallList { /** Begins tracking an external call and notifies listeners of the new call. */ public void onCallAdded(Call telecomCall) { - if (!telecomCall.getDetails().hasProperty(CallCompat.Details.PROPERTY_IS_EXTERNAL_CALL)) { - throw new IllegalArgumentException(); - } + Assert.checkArgument( + telecomCall.getDetails().hasProperty(CallCompat.Details.PROPERTY_IS_EXTERNAL_CALL)); mExternalCalls.add(telecomCall); telecomCall.registerCallback(mTelecomCallCallback, new Handler(Looper.getMainLooper())); notifyExternalCallAdded(telecomCall); diff --git a/java/com/android/incallui/call/TelecomAdapter.java b/java/com/android/incallui/call/TelecomAdapter.java index ebf4ecf4f..005278bff 100644 --- a/java/com/android/incallui/call/TelecomAdapter.java +++ b/java/com/android/incallui/call/TelecomAdapter.java @@ -20,12 +20,13 @@ import android.content.ActivityNotFoundException; import android.content.Intent; import android.os.Looper; import android.support.annotation.MainThread; +import android.support.annotation.VisibleForTesting; import android.telecom.InCallService; import com.android.dialer.common.LogUtil; import java.util.List; /** Wrapper around Telecom APIs. */ -public final class TelecomAdapter implements InCallServiceListener { +public class TelecomAdapter implements InCallServiceListener { private static final String ADD_CALL_MODE_KEY = "add_call_mode"; @@ -45,6 +46,11 @@ public final class TelecomAdapter implements InCallServiceListener { return sInstance; } + @VisibleForTesting(otherwise = VisibleForTesting.NONE) + public static void setInstanceForTesting(TelecomAdapter telecomAdapter) { + sInstance = telecomAdapter; + } + @Override public void setInCallService(InCallService inCallService) { mInCallService = inCallService; @@ -82,9 +88,13 @@ public final class TelecomAdapter implements InCallServiceListener { List<android.telecom.Call> conferenceable = call.getConferenceableCalls(); if (!conferenceable.isEmpty()) { call.conference(conferenceable.get(0)); + // It's safe to clear restrict count for merge action. + DialerCall.clearRestrictedCount(); } else { if (call.getDetails().can(android.telecom.Call.Details.CAPABILITY_MERGE_CONFERENCE)) { call.mergeConference(); + // It's safe to clear restrict count for merge action. + DialerCall.clearRestrictedCount(); } } } else { |