diff options
Diffstat (limited to 'InCallUI/src/com/android')
6 files changed, 230 insertions, 34 deletions
diff --git a/InCallUI/src/com/android/incallui/AnswerPresenter.java b/InCallUI/src/com/android/incallui/AnswerPresenter.java index a5a88ffa5..fc75bf030 100644 --- a/InCallUI/src/com/android/incallui/AnswerPresenter.java +++ b/InCallUI/src/com/android/incallui/AnswerPresenter.java @@ -108,6 +108,11 @@ public class AnswerPresenter extends Presenter<AnswerPresenter.AnswerUi> } } + @Override + public void onLastForwardedNumberChange() { + // no-op + } + private boolean isVideoUpgradePending(Call call) { return call.getSessionModificationState() == Call.SessionModificationState.RECEIVED_UPGRADE_TO_VIDEO_REQUEST; diff --git a/InCallUI/src/com/android/incallui/Call.java b/InCallUI/src/com/android/incallui/Call.java index 807d43a13..7205b7326 100644 --- a/InCallUI/src/com/android/incallui/Call.java +++ b/InCallUI/src/com/android/incallui/Call.java @@ -18,13 +18,13 @@ package com.android.incallui; import com.android.contacts.common.CallUtil; import com.android.contacts.common.testing.NeededForTesting; -import com.android.incallui.CallList.Listener; import android.content.Context; import android.hardware.camera2.CameraCharacteristics; import android.net.Uri; import android.os.Bundle; import android.os.Trace; +import android.telecom.Connection; import android.telecom.DisconnectCause; import android.telecom.GatewayInfo; import android.telecom.InCallService.VideoCall; @@ -43,13 +43,6 @@ import java.util.Objects; */ @NeededForTesting public class Call { - /** - * Call extras key used to store a child number associated with the current call. - * Used to communicate that the connection was received via a child phone number associated with - * the {@link PhoneAccount}'s primary number. - */ - public static final String EXTRA_CHILD_ADDRESS = "android.telecom.EXTRA_CHILD_ADDRESS"; - /* Defines different states of this call */ public static class State { public static final int INVALID = 0; @@ -264,6 +257,8 @@ public class Call { private InCallVideoCallCallback mVideoCallCallback; private String mChildNumber; + private String mLastForwardedNumber; + private String mCallSubject; /** * Used only to create mock calls for testing @@ -326,10 +321,44 @@ public class Call { } Bundle callExtras = mTelecommCall.getDetails().getExtras(); - if (callExtras != null && callExtras.containsKey(EXTRA_CHILD_ADDRESS)) { - String childNumber = callExtras.getString(EXTRA_CHILD_ADDRESS); - if (!Objects.equals(childNumber, mChildNumber)) { - mChildNumber = childNumber; + if (callExtras != null) { + // Child address arrives when the call is first set up, so we do not need to notify the + // UI of this. + if (callExtras.containsKey(Connection.EXTRA_CHILD_ADDRESS)) { + String childNumber = callExtras.getString(Connection.EXTRA_CHILD_ADDRESS); + if (!Objects.equals(childNumber, mChildNumber)) { + mChildNumber = childNumber; + } + } + + // Last forwarded number comes in as an array of strings. We want to choose the last + // item in the array. The forwarding numbers arrive independently of when the call is + // originally set up, so we need to notify the the UI of the change. + if (callExtras.containsKey(Connection.EXTRA_LAST_FORWARDED_NUMBER)) { + ArrayList<String> lastForwardedNumbers = + callExtras.getStringArrayList(Connection.EXTRA_LAST_FORWARDED_NUMBER); + + if (lastForwardedNumbers != null) { + String lastForwardedNumber = null; + if (!lastForwardedNumbers.isEmpty()) { + lastForwardedNumber = lastForwardedNumbers.get( + lastForwardedNumbers.size() - 1); + } + + if (!Objects.equals(lastForwardedNumber, mLastForwardedNumber)) { + mLastForwardedNumber = lastForwardedNumber; + CallList.getInstance().onLastForwardedNumberChange(this); + } + } + } + + // Call subject is present in the extras at the start of call, so we do not need to + // notify any other listeners of this. + if (callExtras.containsKey(Connection.EXTRA_CALL_SUBJECT)) { + String callSubject = callExtras.getString(Connection.EXTRA_CALL_SUBJECT); + if (!Objects.equals(mCallSubject, callSubject)) { + mCallSubject = callSubject; + } } } } @@ -418,6 +447,20 @@ public class Call { return mChildNumber; } + /** + * @return The last forwarded number for the call, or {@code null} if none specified. + */ + public String getLastForwardedNumber() { + return mLastForwardedNumber; + } + + /** + * @return The call subject, or {@code null} if none specified. + */ + public String getCallSubject() { + return mCallSubject; + } + /** Returns call disconnect cause, defined by {@link DisconnectCause}. */ public DisconnectCause getDisconnectCause() { if (mState == State.DISCONNECTED || mState == State.IDLE) { diff --git a/InCallUI/src/com/android/incallui/CallCardFragment.java b/InCallUI/src/com/android/incallui/CallCardFragment.java index 4121390fd..5f2896040 100644 --- a/InCallUI/src/com/android/incallui/CallCardFragment.java +++ b/InCallUI/src/com/android/incallui/CallCardFragment.java @@ -117,10 +117,12 @@ public class CallCardFragment extends BaseFragment<CallCardPresenter, CallCardPr private TextView mCallStateLabel; private TextView mCallTypeLabel; private ImageView mHdAudioIcon; + private ImageView mForwardIcon; private View mCallNumberAndLabel; private ImageView mPhoto; private TextView mElapsedTime; private Drawable mPrimaryPhotoDrawable; + private TextView mCallSubject; // Container view that houses the entire primary call card, including the call buttons private View mPrimaryCallCardContainer; @@ -231,6 +233,7 @@ public class CallCardFragment extends BaseFragment<CallCardPresenter, CallCardPr mCallStateVideoCallIcon = (ImageView) view.findViewById(R.id.videoCallIcon); mCallStateLabel = (TextView) view.findViewById(R.id.callStateLabel); mHdAudioIcon = (ImageView) view.findViewById(R.id.hdAudioIcon); + mForwardIcon = (ImageView) view.findViewById(R.id.forwardIcon); mCallNumberAndLabel = view.findViewById(R.id.labelAndNumber); mCallTypeLabel = (TextView) view.findViewById(R.id.callTypeLabel); mElapsedTime = (TextView) view.findViewById(R.id.elapsedTime); @@ -281,6 +284,7 @@ public class CallCardFragment extends BaseFragment<CallCardPresenter, CallCardPr mPrimaryName.setElegantTextHeight(false); mCallStateLabel.setElegantTextHeight(false); + mCallSubject = (TextView) view.findViewById(R.id.callSubject); } @Override @@ -339,7 +343,7 @@ public class CallCardFragment extends BaseFragment<CallCardPresenter, CallCardPr float videoViewTranslation = 0f; // Translate the call card to its pre-animation state. - if (!mIsLandscape){ + if (!mIsLandscape) { mPrimaryCallCardContainer.setTranslationY(visible ? -mPrimaryCallCardContainer.getHeight() : 0); @@ -553,7 +557,12 @@ public class CallCardFragment extends BaseFragment<CallCardPresenter, CallCardPr Log.v(this, "DisconnectCause " + disconnectCause.toString()); Log.v(this, "gateway " + connectionLabel + gatewayNumber); - if (TextUtils.equals(callStateLabel.getCallStateLabel(), mCallStateLabel.getText())) { + // Check if the call subject is showing -- if it is, we want to bypass showing the call + // state. + boolean isSubjectShowing = mCallSubject.getVisibility() == View.VISIBLE; + + if (TextUtils.equals(callStateLabel.getCallStateLabel(), mCallStateLabel.getText()) && + !isSubjectShowing) { // Nothing to do if the labels are the same if (state == Call.State.ACTIVE || state == Call.State.CONFERENCED) { mCallStateLabel.clearAnimation(); @@ -562,8 +571,14 @@ public class CallCardFragment extends BaseFragment<CallCardPresenter, CallCardPr return; } - // Update the call state label and icon. - setCallStateLabel(callStateLabel); + if (isSubjectShowing) { + changeCallStateLabel(null); + callStateIcon = null; + } else { + // Update the call state label and icon. + setCallStateLabel(callStateLabel); + } + if (!TextUtils.isEmpty(callStateLabel.getCallStateLabel())) { if (state == Call.State.ACTIVE || state == Call.State.CONFERENCED) { mCallStateLabel.clearAnimation(); @@ -677,6 +692,23 @@ public class CallCardFragment extends BaseFragment<CallCardPresenter, CallCardPr mInCallMessageLabel.setVisibility(View.VISIBLE); } + /** + * Sets and shows the call subject if it is not empty. Hides the call subject otherwise. + * + * @param callSubject The call subject. + */ + @Override + public void setCallSubject(String callSubject) { + boolean showSubject = !TextUtils.isEmpty(callSubject); + + mCallSubject.setVisibility(showSubject ? View.VISIBLE : View.GONE); + if (showSubject) { + mCallSubject.setText(callSubject); + } else { + mCallSubject.setText(null); + } + } + public boolean isAnimating() { return mIsAnimating; } @@ -922,6 +954,17 @@ public class CallCardFragment extends BaseFragment<CallCardPresenter, CallCardPr } /** + * Changes the visibility of the forward icon. + * + * @param visible {@code true} if the UI should show the forward icon. + */ + @Override + public void showForwardIndicator(boolean visible) { + mForwardIcon.setVisibility(visible ? View.VISIBLE : View.GONE); + } + + + /** * Changes the visibility of the "manage conference call" button. * * @param visible Whether to set the button to be visible or not. @@ -942,6 +985,16 @@ public class CallCardFragment extends BaseFragment<CallCardPresenter, CallCardPr } /** + * Determines the current visibility of the call subject. + * + * @return {@code true} if the subject is visible. + */ + @Override + public boolean isCallSubjectVisible() { + return mCallSubject.getVisibility() == View.VISIBLE; + } + + /** * Get the overall InCallUI background colors and apply to call card. */ public void updateColors() { @@ -959,6 +1012,7 @@ public class CallCardFragment extends BaseFragment<CallCardPresenter, CallCardPr mPrimaryCallCardContainer.setBackgroundColor(themeColors.mPrimaryColor); } mCallButtonsContainer.setBackgroundColor(themeColors.mPrimaryColor); + mCallSubject.setTextColor(themeColors.mPrimaryColor); mCurrentThemeColors = themeColors; } diff --git a/InCallUI/src/com/android/incallui/CallCardPresenter.java b/InCallUI/src/com/android/incallui/CallCardPresenter.java index c39d79278..7c11b2d9f 100644 --- a/InCallUI/src/com/android/incallui/CallCardPresenter.java +++ b/InCallUI/src/com/android/incallui/CallCardPresenter.java @@ -66,7 +66,8 @@ public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi> private static final String TAG = CallCardPresenter.class.getSimpleName(); private static final long CALL_TIME_UPDATE_INTERVAL_MS = 1000; - private final EmergencyCallListener mEmergencyCallListener = ObjectFactory.newEmergencyCallListener(); + private final EmergencyCallListener mEmergencyCallListener = + ObjectFactory.newEmergencyCallListener(); private Call mPrimary; private Call mSecondary; @@ -206,6 +207,7 @@ public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi> Call.areSameNumber(mPrimary, primary)); final boolean secondaryChanged = !(Call.areSame(mSecondary, secondary) && Call.areSameNumber(mSecondary, secondary)); + final boolean shouldShowCallSubject = shouldShowCallSubject(mPrimary); mSecondary = secondary; Call previousPrimary = mPrimary; @@ -215,7 +217,8 @@ public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi> // 1. Primary call changed. // 2. The call's ability to manage conference has changed. if (mPrimary != null && (primaryChanged || - ui.isManageConferenceVisible() != shouldShowManageConference())) { + ui.isManageConferenceVisible() != shouldShowManageConference()) || + ui.isCallSubjectVisible() != shouldShowCallSubject) { // primary call has changed if (previousPrimary != null) { CallList.getInstance().removeCallUpdateListener(previousPrimary.getId(), this); @@ -320,6 +323,19 @@ public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi> updatePrimaryCallState(); } + /** + * Handles a change to the last forwarding number by refreshing the primary call info. + */ + @Override + public void onLastForwardedNumberChange() { + Log.v(this, "onLastForwardedNumberChange"); + + if (mPrimary == null) { + return; + } + updatePrimaryDisplayInfo(); + } + private String getSubscriptionNumber() { // If it's an emergency call, and they're not populating the callback number, // then try to fall back to the phone sub info (to hopefully get the SIM's @@ -348,15 +364,23 @@ public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi> mPrimary.hasProperty(Details.PROPERTY_WIFI), mPrimary.isConferenceCall()); - boolean showHdAudioIndicator = - isPrimaryCallActive() && mPrimary.hasProperty(Details.PROPERTY_HIGH_DEF_AUDIO); - getUi().showHdAudioIndicator(showHdAudioIndicator); - + maybeShowHdAudioIcon(); setCallbackNumber(); } } /** + * Show the HD icon if the call is active and has {@link Details#PROPERTY_HIGH_DEF_AUDIO}, + * except if the call has a last forwarded number (we will show that icon instead). + */ + private void maybeShowHdAudioIcon() { + boolean showHdAudioIndicator = + isPrimaryCallActive() && mPrimary.hasProperty(Details.PROPERTY_HIGH_DEF_AUDIO) && + TextUtils.isEmpty(mPrimary.getLastForwardedNumber()); + getUi().showHdAudioIndicator(showHdAudioIndicator); + } + + /** * Only show the conference call button if we can manage the conference. */ private void maybeShowManageConferenceCallButton() { @@ -584,20 +608,36 @@ public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi> String name = getNameForCall(mPrimaryContactInfo); String number; - // If a child number is present, use it instead of the 2nd line. boolean isChildNumberShown = !TextUtils.isEmpty(mPrimary.getChildNumber()); - if (isChildNumberShown) { + boolean isForwardedNumberShown = !TextUtils.isEmpty(mPrimary.getLastForwardedNumber()); + boolean isCallSubjectShown = shouldShowCallSubject(mPrimary); + + if (isCallSubjectShown) { + ui.setCallSubject(mPrimary.getCallSubject()); + } else { + ui.setCallSubject(null); + } + + if (isCallSubjectShown) { + number = null; + } else if (isChildNumberShown) { number = mContext.getString(R.string.child_number, mPrimary.getChildNumber()); + } else if (isForwardedNumberShown) { + // Use last forwarded number instead of second line, if present. + number = mPrimary.getLastForwardedNumber(); } else { number = getNumberForCall(mPrimaryContactInfo); } + ui.showForwardIndicator(isForwardedNumberShown); + maybeShowHdAudioIcon(); + boolean nameIsNumber = name != null && name.equals(mPrimaryContactInfo.number); ui.setPrimary( number, name, nameIsNumber, - isChildNumberShown ? null : mPrimaryContactInfo.label, + isChildNumberShown || isCallSubjectShown ? null : mPrimaryContactInfo.label, mPrimaryContactInfo.photo, mPrimaryContactInfo.isSipCall); } else { @@ -857,6 +897,24 @@ public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi> } } + /** + * Determines whether the call subject should be visible on the UI. For the call subject to be + * visible, the call has to be in an incoming or waiting state, and the subject must not be + * empty. + * + * @param call The call. + * @return {@code true} if the subject should be shown, {@code false} otherwise. + */ + private boolean shouldShowCallSubject(Call call) { + if (call == null) { + return false; + } + + boolean isIncomingOrWaiting = mPrimary.getState() == Call.State.INCOMING || + mPrimary.getState() == Call.State.CALL_WAITING; + return isIncomingOrWaiting && !TextUtils.isEmpty(call.getCallSubject()); + } + public interface CallCardUi extends Ui { void setVisible(boolean on); void setCallCardVisible(boolean visible); @@ -875,10 +933,13 @@ public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi> void setPrimaryLabel(String label); void setEndCallButtonEnabled(boolean enabled, boolean animate); void setCallbackNumber(String number, boolean isEmergencyCalls); + void setCallSubject(String callSubject); void setProgressSpinnerVisible(boolean visible); void showHdAudioIndicator(boolean visible); + void showForwardIndicator(boolean visible); void showManageConferenceCallButton(boolean visible); boolean isManageConferenceVisible(); + boolean isCallSubjectVisible(); void animateForNewOutgoingCall(); void sendAccessibilityAnnouncement(); } diff --git a/InCallUI/src/com/android/incallui/CallList.java b/InCallUI/src/com/android/incallui/CallList.java index c0014bdfe..fbcc1cc61 100644 --- a/InCallUI/src/com/android/incallui/CallList.java +++ b/InCallUI/src/com/android/incallui/CallList.java @@ -160,6 +160,20 @@ public class CallList { } } + /** + * Called when a single call has changed session modification state. + * + * @param call The call. + */ + public void onLastForwardedNumberChange(Call call) { + final List<CallUpdateListener> listeners = mCallUpdateListenerMap.get(call.getId()); + if (listeners != null) { + for (CallUpdateListener listener : listeners) { + listener.onLastForwardedNumberChange(); + } + } + } + public void notifyCallUpdateListeners(Call call) { final List<CallUpdateListener> listeners = mCallUpdateListenerMap.get(call.getId()); if (listeners != null) { @@ -611,5 +625,10 @@ public class CallList { * @param sessionModificationState The new session modification state. */ public void onSessionModificationStateChange(int sessionModificationState); + + /** + * Notifies of a change to the last forwarded number for a call. + */ + public void onLastForwardedNumberChange(); } } diff --git a/InCallUI/src/com/android/incallui/StatusBarNotifier.java b/InCallUI/src/com/android/incallui/StatusBarNotifier.java index 8df4520bf..e583434da 100644 --- a/InCallUI/src/com/android/incallui/StatusBarNotifier.java +++ b/InCallUI/src/com/android/incallui/StatusBarNotifier.java @@ -40,6 +40,8 @@ import com.android.incallui.InCallPresenter.InCallState; import com.google.common.base.Preconditions; +import java.util.Objects; + /** * This class adds Notifications to the status bar for the in-call experience. */ @@ -60,7 +62,7 @@ public class StatusBarNotifier implements InCallPresenter.InCallStateListener, private int mCurrentNotification = NOTIFICATION_NONE; private int mCallState = Call.State.INVALID; private int mSavedIcon = 0; - private int mSavedContent = 0; + private String mSavedContent = null; private Bitmap mSavedLargeIcon; private String mSavedContentTitle; private String mCallId = null; @@ -206,7 +208,7 @@ public class StatusBarNotifier implements InCallPresenter.InCallStateListener, // Check if data has changed; if nothing is different, don't issue another notification. final int iconResId = getIconToDisplay(call); Bitmap largeIcon = getLargeIconToDisplay(contactInfo, call); - final int contentResId = getContentString(call); + final String content = getContentString(call); final String contentTitle = getContentTitle(contactInfo, call); final int notificationType; @@ -218,7 +220,7 @@ public class StatusBarNotifier implements InCallPresenter.InCallStateListener, notificationType = NOTIFICATION_IN_CALL; } - if (!checkForChangeAndSaveData(iconResId, contentResId, largeIcon, contentTitle, state, + if (!checkForChangeAndSaveData(iconResId, content, largeIcon, contentTitle, state, notificationType)) { return; } @@ -244,7 +246,7 @@ public class StatusBarNotifier implements InCallPresenter.InCallStateListener, } // Set the content - builder.setContentText(mContext.getString(contentResId)); + builder.setContentText(content); builder.setSmallIcon(iconResId); builder.setContentTitle(contentTitle); builder.setLargeIcon(largeIcon); @@ -306,7 +308,7 @@ public class StatusBarNotifier implements InCallPresenter.InCallStateListener, * are already displaying. If the data is exactly the same, we return false so that * we do not issue a new notification for the exact same data. */ - private boolean checkForChangeAndSaveData(int icon, int content, Bitmap largeIcon, + private boolean checkForChangeAndSaveData(int icon, String content, Bitmap largeIcon, String contentTitle, int state, int notificationType) { // The two are different: @@ -317,7 +319,7 @@ public class StatusBarNotifier implements InCallPresenter.InCallStateListener, (contentTitle == null && mSavedContentTitle != null); // any change means we are definitely updating - boolean retval = (mSavedIcon != icon) || (mSavedContent != content) || + boolean retval = (mSavedIcon != icon) || !Objects.equals(mSavedContent, content) || (mCallState != state) || (mSavedLargeIcon != largeIcon) || contentTitleChanged; @@ -419,13 +421,20 @@ public class StatusBarNotifier implements InCallPresenter.InCallStateListener, /** * Returns the message to use with the notification. */ - private int getContentString(Call call) { + private String getContentString(Call call) { + boolean isIncomingOrWaiting = call.getState() == Call.State.INCOMING || + call.getState() == Call.State.CALL_WAITING; + + if (isIncomingOrWaiting && !TextUtils.isEmpty(call.getCallSubject())) { + return call.getCallSubject(); + } + int resId = R.string.notification_ongoing_call; if (call.hasProperty(Details.PROPERTY_WIFI)) { resId = R.string.notification_ongoing_call_wifi; } - if (call.getState() == Call.State.INCOMING || call.getState() == Call.State.CALL_WAITING) { + if (isIncomingOrWaiting) { if (call.hasProperty(Details.PROPERTY_WIFI)) { resId = R.string.notification_incoming_call_wifi; } else { @@ -440,7 +449,7 @@ public class StatusBarNotifier implements InCallPresenter.InCallStateListener, resId = R.string.notification_requesting_video_call; } - return resId; + return mContext.getString(resId); } /** @@ -637,4 +646,9 @@ public class StatusBarNotifier implements InCallPresenter.InCallStateListener, updateNotification(mInCallState, CallList.getInstance()); } } + + @Override + public void onLastForwardedNumberChange() { + // no-op + } } |