diff options
author | Tyler Gunn <tgunn@google.com> | 2015-05-14 13:20:24 -0700 |
---|---|---|
committer | Tyler Gunn <tgunn@google.com> | 2015-12-06 22:04:27 -0800 |
commit | a860052619d1c3d13a33629e97a8e05509fa0e1b (patch) | |
tree | 8541c2ab65ceefbcd334093a8be6775cea8c8429 | |
parent | cb7cae60b850cad577e03e4688f05e9819c3202e (diff) |
Fix issue where secondary call info overlaps video preview.
Other issues:
- Secondary caller info should not be shown when in fullscreen mode.
Solution:
- Added onSecondaryCallerInfoVisibilityChanged to InCallEventListener (
which is documented as a place for events between fragments).
- In CallCard fragment, call notify listeners of this callback of the
state change.
- In VideoCallPresenter/Fragment, handle changes to the visibility of the
secondary caller info box to shift the preview surface up or down.
- Added hide/show animation for the secondary caller info when entering
and exiting fullscreen mode.
Bug: 20914754
Change-Id: I44ae0e94e214892776487bff4cc09be8c5640db1
5 files changed, 178 insertions, 15 deletions
diff --git a/InCallUI/src/com/android/incallui/CallCardFragment.java b/InCallUI/src/com/android/incallui/CallCardFragment.java index 3efdb7570..e7d4f4836 100644 --- a/InCallUI/src/com/android/incallui/CallCardFragment.java +++ b/InCallUI/src/com/android/incallui/CallCardFragment.java @@ -183,6 +183,11 @@ public class CallCardFragment extends BaseFragment<CallCardPresenter, CallCardPr private boolean mCallStateLabelResetPending = false; private Handler mHandler; + /** + * Determines if secondary call info is populated in the secondary call info UI. + */ + private boolean mHasSecondaryCallInfo = false; + @Override public CallCardPresenter.CallCardUi getUi() { return this; @@ -585,15 +590,16 @@ public class CallCardFragment extends BaseFragment<CallCardPresenter, CallCardPr @Override public void setSecondary(boolean show, String name, boolean nameIsNumber, String label, - String providerLabel, boolean isConference, boolean isVideoCall) { - - if (show != mSecondaryCallInfo.isShown()) { - updateFabPositionForSecondaryCallInfo(); - } + String providerLabel, boolean isConference, boolean isVideoCall, boolean isFullscreen) { if (show) { + mHasSecondaryCallInfo = true; boolean hasProvider = !TextUtils.isEmpty(providerLabel); - showAndInitializeSecondaryCallInfo(hasProvider); + initializeSecondaryCallInfo(hasProvider); + + // Do not show the secondary caller info in fullscreen mode, but ensure it is populated + // in case fullscreen mode is exited in the future. + setSecondaryInfoVisible(!isFullscreen); mSecondaryCallConferenceCallIcon.setVisibility(isConference ? View.VISIBLE : View.GONE); mSecondaryCallVideoCallIcon.setVisibility(isVideoCall ? View.VISIBLE : View.GONE); @@ -611,10 +617,94 @@ public class CallCardFragment extends BaseFragment<CallCardPresenter, CallCardPr } mSecondaryCallName.setTextDirection(nameDirection); } else { - mSecondaryCallInfo.setVisibility(View.GONE); + mHasSecondaryCallInfo = false; + setSecondaryInfoVisible(false); } } + /** + * Sets the visibility of the secondary caller info box. Note, if the {@code visible} parameter + * is passed in {@code true}, and there is no secondary caller info populated (as determined by + * {@code mHasSecondaryCallInfo}, the secondary caller info box will not be shown. + * + * @param visible {@code true} if the secondary caller info should be shown, {@code false} + * otherwise. + */ + @Override + public void setSecondaryInfoVisible(final boolean visible) { + boolean wasVisible = mSecondaryCallInfo.isShown(); + final boolean isVisible = visible && mHasSecondaryCallInfo; + Log.v(this, "setSecondaryInfoVisible: wasVisible = " + wasVisible + " isVisible = " + + isVisible); + + // If visibility didn't change, nothing to do. + if (wasVisible == isVisible) { + return; + } + + // If we are showing the secondary info, we need to show it before animating so that its + // height will be determined on layout. + if (isVisible) { + mSecondaryCallInfo.setVisibility(View.VISIBLE); + } + + // We need to translate the secondary caller info, but we need to know its position after + // the layout has occurred so use a {@code ViewTreeObserver}. + final ViewTreeObserver observer = getView().getViewTreeObserver(); + observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { + @Override + public boolean onPreDraw() { + // We don't want to continue getting called. + if (observer.isAlive()) { + observer.removeOnPreDrawListener(this); + } + + updateFabPositionForSecondaryCallInfo(); + + // Get the height of the secondary call info now, and then re-hide the view prior + // to doing the actual animation. + int secondaryHeight = mSecondaryCallInfo.getHeight(); + if (isVisible) { + mSecondaryCallInfo.setVisibility(View.GONE); + } + Log.v(this, "setSecondaryInfoVisible: secondaryHeight = " + secondaryHeight); + + // Set the position of the secondary call info card to its starting location. + mSecondaryCallInfo.setTranslationY(visible ? secondaryHeight : 0); + + // Animate the secondary card info slide up/down as it appears and disappears. + ViewPropertyAnimator secondaryInfoAnimator = mSecondaryCallInfo.animate() + .setInterpolator(AnimUtils.EASE_OUT_EASE_IN) + .setDuration(mVideoAnimationDuration) + .translationY(isVisible ? 0 : secondaryHeight) + .setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + if (!isVisible) { + mSecondaryCallInfo.setVisibility(View.GONE); + } + } + + @Override + public void onAnimationStart(Animator animation) { + if (isVisible) { + mSecondaryCallInfo.setVisibility(View.VISIBLE); + } + } + }); + secondaryInfoAnimator.start(); + + // Notify listeners of a change in the visibility of the secondary info. This is + // important when in a video call so that the video call presenter can shift the + // video preview up or down to accommodate the secondary caller info. + InCallPresenter.getInstance().notifySecondaryCallerInfoVisibilityChanged(visible, + secondaryHeight); + + return true; + } + }); + } + @Override public void setCallState( int state, @@ -1006,9 +1096,7 @@ public class CallCardFragment extends BaseFragment<CallCardPresenter, CallCardPr return new CallStateLabel(callStateLabel, isAutoDismissing); } - private void showAndInitializeSecondaryCallInfo(boolean hasProvider) { - mSecondaryCallInfo.setVisibility(View.VISIBLE); - + private void initializeSecondaryCallInfo(boolean hasProvider) { // mSecondaryCallName is initialized here (vs. onViewCreated) because it is inaccessible // until mSecondaryCallInfo is inflated in the call above. if (mSecondaryCallName == null) { diff --git a/InCallUI/src/com/android/incallui/CallCardPresenter.java b/InCallUI/src/com/android/incallui/CallCardPresenter.java index ba5823d5a..170e78501 100644 --- a/InCallUI/src/com/android/incallui/CallCardPresenter.java +++ b/InCallUI/src/com/android/incallui/CallCardPresenter.java @@ -83,6 +83,7 @@ public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi> private boolean mSpinnerShowing = false; private boolean mHasShownToast = false; private InCallContactInteractions mInCallContactInteractions; + private boolean mIsFullscreen = false; public static class ContactLookupCallback implements ContactInfoCacheCallback { private final WeakReference<CallCardPresenter> mCallCardPresenter; @@ -775,7 +776,7 @@ public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi> if (mSecondary == null) { // Clear the secondary display info. ui.setSecondary(false, null, false, null, null, false /* isConference */, - false /* isVideoCall */); + false /* isVideoCall */, mIsFullscreen); return; } @@ -787,7 +788,8 @@ public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi> null /* label */, getCallProviderLabel(mSecondary), true /* isConference */, - mSecondary.isVideoCall(mContext)); + mSecondary.isVideoCall(mContext), + mIsFullscreen); } else if (mSecondaryContactInfo != null) { Log.d(TAG, "updateSecondaryDisplayInfo() " + mSecondaryContactInfo); String name = getNameForCall(mSecondaryContactInfo); @@ -799,11 +801,12 @@ public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi> mSecondaryContactInfo.label, getCallProviderLabel(mSecondary), false /* isConference */, - mSecondary.isVideoCall(mContext)); + mSecondary.isVideoCall(mContext), + mIsFullscreen); } else { // Clear the secondary display info. ui.setSecondary(false, null, false, null, null, false /* isConference */, - false /* isVideoCall */); + false /* isVideoCall */, mIsFullscreen); } } @@ -955,11 +958,18 @@ public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi> */ @Override public void onFullscreenModeChanged(boolean isFullscreenMode) { + mIsFullscreen = isFullscreenMode; final CallCardUi ui = getUi(); if (ui == null) { return; } ui.setCallCardVisible(!isFullscreenMode); + ui.setSecondaryInfoVisible(!isFullscreenMode); + } + + @Override + public void onSecondaryCallerInfoVisibilityChanged(boolean isVisible, int height) { + // No-op - the Call Card is the origin of this event. } private boolean isPrimaryCallActive() { @@ -1061,7 +1071,9 @@ public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi> void setPrimary(String number, String name, boolean nameIsNumber, String label, Drawable photo, boolean isSipCall, boolean isContactPhotoShown); void setSecondary(boolean show, String name, boolean nameIsNumber, String label, - String providerLabel, boolean isConference, boolean isVideoCall); + String providerLabel, boolean isConference, boolean isVideoCall, + boolean isFullscreen); + void setSecondaryInfoVisible(boolean visible); void setCallState(int state, int videoState, int sessionModificationState, DisconnectCause disconnectCause, String connectionLabel, Drawable connectionIcon, String gatewayNumber, boolean isWifi, diff --git a/InCallUI/src/com/android/incallui/InCallPresenter.java b/InCallUI/src/com/android/incallui/InCallPresenter.java index 33e4e5ace..d4d95bc54 100644 --- a/InCallUI/src/com/android/incallui/InCallPresenter.java +++ b/InCallUI/src/com/android/incallui/InCallPresenter.java @@ -1175,6 +1175,21 @@ public class InCallPresenter implements CallList.Listener, } /** + * Called by the {@link CallCardPresenter} to inform of a change in visibility of the secondary + * caller info bar. + * + * @param isVisible {@code true} if the secondary caller info is visible, {@code false} + * otherwise. + * @param height the height of the secondary caller info bar. + */ + public void notifySecondaryCallerInfoVisibilityChanged(boolean isVisible, int height) { + for (InCallEventListener listener : mInCallEventListeners) { + listener.onSecondaryCallerInfoVisibilityChanged(isVisible, height); + } + } + + + /** * For some disconnected causes, we show a dialog. This calls into the activity to show * the dialog if appropriate for the call. */ @@ -1796,6 +1811,7 @@ public class InCallPresenter implements CallList.Listener, */ public interface InCallEventListener { public void onFullscreenModeChanged(boolean isFullscreenMode); + public void onSecondaryCallerInfoVisibilityChanged(boolean isVisible, int height); } public interface InCallUiListener { diff --git a/InCallUI/src/com/android/incallui/VideoCallFragment.java b/InCallUI/src/com/android/incallui/VideoCallFragment.java index ce14e48f9..eca9ab883 100644 --- a/InCallUI/src/com/android/incallui/VideoCallFragment.java +++ b/InCallUI/src/com/android/incallui/VideoCallFragment.java @@ -31,6 +31,7 @@ import android.view.ViewTreeObserver; import android.widget.FrameLayout; import android.widget.ImageView; +import com.android.phone.common.animation.AnimUtils; import com.google.common.base.Objects; /** @@ -105,6 +106,8 @@ public class VideoCallFragment extends BaseFragment<VideoCallPresenter, */ private boolean mIsLandscape; + private int mAnimationDuration; + /** * Inner-class representing a {@link TextureView} and its associated {@link SurfaceTexture} and * {@link Surface}. Used to manage the lifecycle of these objects across device orientation @@ -419,6 +422,8 @@ public class VideoCallFragment extends BaseFragment<VideoCallPresenter, @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + + mAnimationDuration = getResources().getInteger(R.integer.video_animation_duration); } /** @@ -581,6 +586,30 @@ public class VideoCallFragment extends BaseFragment<VideoCallPresenter, return mPreviewPhoto; } + /** + * Adjusts the location of the video preview view by the specified offset. + * + * @param shiftUp {@code true} if the preview should shift up, {@code false} if it should shift + * down. + * @param offset The offset. + */ + @Override + public void adjustPreviewLocation(boolean shiftUp, int offset) { + if (sPreviewSurface == null || mPreviewVideoContainer == null) { + return; + } + + // Set the position of the secondary call info card to its starting location. + mPreviewVideoContainer.setTranslationY(shiftUp ? 0 : -offset); + + // Animate the secondary card info slide up/down as it appears and disappears. + mPreviewVideoContainer.animate() + .setInterpolator(AnimUtils.EASE_OUT_EASE_IN) + .setDuration(mAnimationDuration) + .translationY(shiftUp ? -offset : 0) + .start(); + } + private void onPresenterChanged(VideoCallPresenter presenter) { Log.d(this, "onPresenterChanged: Presenter=" + presenter); if (sDisplaySurface != null) { diff --git a/InCallUI/src/com/android/incallui/VideoCallPresenter.java b/InCallUI/src/com/android/incallui/VideoCallPresenter.java index 84d9c9781..a8812a672 100644 --- a/InCallUI/src/com/android/incallui/VideoCallPresenter.java +++ b/InCallUI/src/com/android/incallui/VideoCallPresenter.java @@ -239,6 +239,7 @@ public class VideoCallPresenter extends Presenter<VideoCallPresenter.VideoCallUi InCallPresenter.getInstance().addOrientationListener(this); // To get updates of video call details changes InCallPresenter.getInstance().addDetailsListener(this); + InCallPresenter.getInstance().addInCallEventListener(this); // Register for surface and video events from {@link InCallVideoCallListener}s. InCallVideoCallCallbackNotifier.getInstance().addSurfaceChangeListener(this); @@ -266,6 +267,7 @@ public class VideoCallPresenter extends Presenter<VideoCallPresenter.VideoCallUi InCallPresenter.getInstance().removeDetailsListener(this); InCallPresenter.getInstance().removeIncomingCallListener(this); InCallPresenter.getInstance().removeOrientationListener(this); + InCallPresenter.getInstance().removeInCallEventListener(this); InCallVideoCallCallbackNotifier.getInstance().removeSurfaceChangeListener(this); InCallVideoCallCallbackNotifier.getInstance().removeVideoEventListener(this); @@ -469,6 +471,21 @@ public class VideoCallPresenter extends Presenter<VideoCallPresenter.VideoCallUi cancelAutoFullScreen(); } + /** + * Handles changes to the visibility of the secondary caller info bar. + * + * @param isVisible {@code true} if the secondary caller info is showing, {@code false} + * otherwise. + * @param height the height of the secondary caller info bar. + */ + @Override + public void onSecondaryCallerInfoVisibilityChanged(boolean isVisible, int height) { + Log.d(this, + "onSecondaryCallerInfoVisibilityChanged : isVisible = " + isVisible + " height = " + + height); + getUi().adjustPreviewLocation(isVisible /* shiftUp */, height); + } + private void checkForVideoStateChange(Call call) { final boolean isVideoCall = CallUtils.isVideoCall(call); final boolean hasVideoStateChanged = mCurrentVideoState != call.getVideoState(); @@ -1354,5 +1371,6 @@ public class VideoCallPresenter extends Presenter<VideoCallPresenter.VideoCallUi Point getPreviewSize(); void cleanupSurfaces(); ImageView getPreviewPhotoView(); + void adjustPreviewLocation(boolean shiftUp, int offset); } } |