From f3e47f7b608a6beb77b6732d676b47c56184248c Mon Sep 17 00:00:00 2001 From: Moxie Marlinspike Date: Sat, 11 Feb 2017 11:05:53 -0800 Subject: [PATCH] Support for minimized controls during video call // FREEBIE --- AndroidManifest.xml | 2 +- build.gradle | 4 + res/layout/webrtc_call_screen.xml | 229 +++++++++--------- res/values/strings.xml | 2 + .../components/webrtc/WebRtcCallControls.java | 27 +++ .../components/webrtc/WebRtcCallScreen.java | 48 +++- .../thoughtcrime/securesms/util/ViewUtil.java | 5 + 7 files changed, 194 insertions(+), 123 deletions(-) diff --git a/AndroidManifest.xml b/AndroidManifest.xml index b8eb01cea5..fbc3edec88 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -5,7 +5,7 @@ android:versionCode="235" android:versionName="3.29.2"> - + - + + + android:layout_height="match_parent" + android:animateLayoutChanges="true"> @@ -48,7 +56,8 @@ android:background="@color/grey_400" android:orientation="vertical" android:visibility="gone" - android:gravity="center"> + android:gravity="center" + android:clickable="true"> - - - @@ -100,108 +98,106 @@ including the contact name, phone number, call time counter, and other status info. This info is shown as a "banner" overlaid across the top of contact photo. --> - - - - + android:orientation="vertical"> + + - - + - - + + + + + + + + - + - - + - + android:paddingLeft="24dp" + android:paddingRight="24dp" + android:paddingTop="16dp" + android:paddingBottom="20dp" + android:clickable="true"/> - - - - - - + - - - + + + + - + diff --git a/res/values/strings.xml b/res/values/strings.xml index 38cc3abf61..22664f52b1 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -648,6 +648,8 @@ New safety numbers + + Tap to enable your video Image diff --git a/src/org/thoughtcrime/securesms/components/webrtc/WebRtcCallControls.java b/src/org/thoughtcrime/securesms/components/webrtc/WebRtcCallControls.java index 3cc1efccf1..4ac2b25b8c 100644 --- a/src/org/thoughtcrime/securesms/components/webrtc/WebRtcCallControls.java +++ b/src/org/thoughtcrime/securesms/components/webrtc/WebRtcCallControls.java @@ -5,13 +5,18 @@ import android.annotation.TargetApi; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.graphics.Color; import android.media.AudioManager; import android.os.Build; import android.util.AttributeSet; import android.view.LayoutInflater; +import android.view.ViewGroup; import android.widget.CompoundButton; import android.widget.LinearLayout; +import com.tomergoldst.tooltips.ToolTip; +import com.tomergoldst.tooltips.ToolTipsManager; + import org.thoughtcrime.redphone.util.AudioUtils; import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.util.ViewUtil; @@ -107,6 +112,28 @@ public class WebRtcCallControls extends LinearLayout { return videoMuteButton.isChecked(); } + public void setVideoEnabled(boolean enabled) { + videoMuteButton.setChecked(enabled); + } + + public void displayVideoTooltip(ViewGroup viewGroup) { + if (Build.VERSION.SDK_INT > 15) { + final ToolTipsManager toolTipsManager = new ToolTipsManager(); + + ToolTip toolTip = new ToolTip.Builder(getContext(), videoMuteButton, viewGroup, + getContext().getString(R.string.WebRtcCallControls_tap_to_enable_your_video), + ToolTip.POSITION_BELOW).build(); + toolTipsManager.show(toolTip); + + videoMuteButton.postDelayed(new Runnable() { + @Override + public void run() { + toolTipsManager.findAndDismiss(videoMuteButton); + } + }, 4000); + } + } + public void reset() { updateAudioButton(); audioMuteButton.setChecked(false); diff --git a/src/org/thoughtcrime/securesms/components/webrtc/WebRtcCallScreen.java b/src/org/thoughtcrime/securesms/components/webrtc/WebRtcCallScreen.java index 13f692cf1e..1ed0be4082 100644 --- a/src/org/thoughtcrime/securesms/components/webrtc/WebRtcCallScreen.java +++ b/src/org/thoughtcrime/securesms/components/webrtc/WebRtcCallScreen.java @@ -24,6 +24,7 @@ import android.provider.ContactsContract; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.design.widget.FloatingActionButton; +import android.support.v4.view.ViewCompat; import android.text.SpannableString; import android.text.Spanned; import android.text.method.LinkMovementMethod; @@ -36,6 +37,7 @@ import android.view.WindowManager; import android.widget.Button; import android.widget.FrameLayout; import android.widget.ImageView; +import android.widget.RelativeLayout; import android.widget.TextView; import org.thoughtcrime.securesms.R; @@ -44,6 +46,7 @@ import org.thoughtcrime.securesms.contacts.avatars.ContactPhotoFactory; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.service.WebRtcCallService; import org.thoughtcrime.securesms.util.VerifySpan; +import org.thoughtcrime.securesms.util.ViewUtil; import org.webrtc.SurfaceViewRenderer; import org.whispersystems.libsignal.IdentityKey; @@ -72,8 +75,11 @@ public class WebRtcCallScreen extends FrameLayout implements Recipient.Recipient private TextView status; private FloatingActionButton endCallButton; private WebRtcCallControls controls; + private RelativeLayout expandedInfo; + private ViewGroup callHeader; private Recipient recipient; + private boolean minimized; private WebRtcIncomingCallOverlay incomingCallOverlay; @@ -106,6 +112,7 @@ public class WebRtcCallScreen extends FrameLayout implements Recipient.Recipient public void setIncomingCall(Recipient personInfo) { setCard(personInfo, getContext().getString(R.string.CallScreen_Incoming_call)); incomingCallOverlay.setIncomingCall(); + endCallButton.setVisibility(View.INVISIBLE); } public void setUntrustedIdentity(Recipient personInfo, IdentityKey untrustedIdentity) { @@ -131,8 +138,10 @@ public class WebRtcCallScreen extends FrameLayout implements Recipient.Recipient public void reset() { setPersonInfo(Recipient.getUnknownRecipient()); + setMinimized(false); this.status.setText(""); this.recipient = null; + this.controls.reset(); this.untrustedIdentityExplanation.setText(""); this.untrustedIdentityContainer.setVisibility(View.GONE); @@ -185,9 +194,11 @@ public class WebRtcCallScreen extends FrameLayout implements Recipient.Recipient public void setLocalVideoEnabled(boolean enabled) { if (enabled && this.localRenderLayout.isHidden()) { + this.controls.setVideoEnabled(true); this.localRenderLayout.setHidden(false); this.localRenderLayout.requestLayout(); } else if (!enabled && !this.localRenderLayout.isHidden()){ + this.controls.setVideoEnabled(false); this.localRenderLayout.setHidden(true); this.localRenderLayout.requestLayout(); } @@ -195,9 +206,16 @@ public class WebRtcCallScreen extends FrameLayout implements Recipient.Recipient public void setRemoteVideoEnabled(boolean enabled) { if (enabled && this.remoteRenderLayout.isHidden()) { + this.photo.setVisibility(View.INVISIBLE); + setMinimized(true); + this.remoteRenderLayout.setHidden(false); this.remoteRenderLayout.requestLayout(); + + if (localRenderLayout.isHidden()) this.controls.displayVideoTooltip(callHeader); } else if (!enabled && !this.remoteRenderLayout.isHidden()){ + setMinimized(false); + this.photo.setVisibility(View.VISIBLE); this.remoteRenderLayout.setHidden(true); this.remoteRenderLayout.requestLayout(); } @@ -226,9 +244,19 @@ public class WebRtcCallScreen extends FrameLayout implements Recipient.Recipient this.untrustedIdentityExplanation = (TextView) findViewById(R.id.untrusted_explanation); this.acceptIdentityButton = (Button)findViewById(R.id.accept_safety_numbers); this.cancelIdentityButton = (Button)findViewById(R.id.cancel_safety_numbers); + this.expandedInfo = (RelativeLayout)findViewById(R.id.expanded_info); + this.callHeader = (ViewGroup)findViewById(R.id.call_info_1); this.localRenderLayout.setHidden(true); this.remoteRenderLayout.setHidden(true); + this.minimized = false; + + this.remoteRenderLayout.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + setMinimized(!minimized); + } + }); } private void setConnected(SurfaceViewRenderer localRenderer, @@ -243,7 +271,7 @@ public class WebRtcCallScreen extends FrameLayout implements Recipient.Recipient ((ViewGroup)remoteRenderer.getParent()).removeView(remoteRenderer); } - localRenderLayout.setPosition(7, 7, 25, 25); + localRenderLayout.setPosition(7, 70, 25, 25); localRenderLayout.setSquare(true); remoteRenderLayout.setPosition(0, 0, 100, 100); @@ -295,6 +323,24 @@ public class WebRtcCallScreen extends FrameLayout implements Recipient.Recipient this.endCallButton.setVisibility(View.VISIBLE); } + private void setMinimized(boolean minimized) { + if (minimized) { + ViewCompat.animate(callHeader).translationY(-1 * expandedInfo.getHeight()); + ViewCompat.animate(status).alpha(0); + ViewCompat.animate(endCallButton).translationY(endCallButton.getHeight() + ViewUtil.dpToPx(getContext(), 40)); + ViewCompat.animate(endCallButton).alpha(0); + + this.minimized = true; + } else { + ViewCompat.animate(callHeader).translationY(0); + ViewCompat.animate(status).alpha(1); + ViewCompat.animate(endCallButton).translationY(0); + ViewCompat.animate(endCallButton).alpha(1); + + this.minimized = false; + } + } + @Override public void onModified(Recipient recipient) { if (recipient == this.recipient) { diff --git a/src/org/thoughtcrime/securesms/util/ViewUtil.java b/src/org/thoughtcrime/securesms/util/ViewUtil.java index 947a902660..6a561422dd 100644 --- a/src/org/thoughtcrime/securesms/util/ViewUtil.java +++ b/src/org/thoughtcrime/securesms/util/ViewUtil.java @@ -30,6 +30,7 @@ import android.support.v4.view.ViewCompat; import android.support.v4.view.animation.FastOutSlowInInterpolator; import android.text.TextUtils; import android.text.TextUtils.TruncateAt; +import android.util.DisplayMetrics; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; @@ -206,4 +207,8 @@ public class ViewUtil { view.setScaleX(-1.0f); } } + + public static int dpToPx(Context context, int dp) { + return (int)((dp * context.getResources().getDisplayMetrics().density) + 0.5); + } }