Support for minimized controls during video call

// FREEBIE
pull/1/head
Moxie Marlinspike 7 years ago
parent 6b8336db06
commit f3e47f7b60

@ -5,7 +5,7 @@
android:versionCode="235"
android:versionName="3.29.2">
<uses-sdk tools:overrideLibrary="com.amulyakhare.textdrawable,com.astuetz.pagerslidingtabstrip,pl.tajchert.waitingdots,com.h6ah4i.android.multiselectlistpreferencecompat,android.support.v13,com.davemorrissey.labs.subscaleview"/>
<uses-sdk tools:overrideLibrary="com.amulyakhare.textdrawable,com.astuetz.pagerslidingtabstrip,pl.tajchert.waitingdots,com.h6ah4i.android.multiselectlistpreferencecompat,android.support.v13,com.davemorrissey.labs.subscaleview,com.tomergoldst.tooltips"/>
<permission android:name="org.thoughtcrime.securesms.ACCESS_SECRETS"
android:label="Access to TextSecure Secrets"

@ -89,6 +89,9 @@ dependencies {
compile ('cn.carbswang.android:NumberPickerView:1.0.9') {
exclude group: 'com.android.support', module: 'appcompat-v7'
}
compile ('com.tomergoldst.android:tooltips:1.0.6') {
exclude group: 'com.android.support', module: 'appcompat-v7'
}
testCompile 'junit:junit:4.12'
testCompile 'org.assertj:assertj-core:1.7.1'
@ -148,6 +151,7 @@ dependencyVerification {
'com.google.zxing:core:b4d82452e7a6bf6ec2698904b332431717ed8f9a850224f295aec89de80f2259',
'com.davemorrissey.labs:subsampling-scale-image-view:550c5baa07e0bb4ff0a18b705e96d34436d22619248bd8c08c08c730b1f55cfe',
'cn.carbswang.android:NumberPickerView:18b3c316d62c7c277978a8d4ed57a5b8f4e943762264960f579a8a549c756729',
'com.tomergoldst.android:tooltips:4c56697dd1ad64b8066535c61f961a6d901e7ae5d97ae27084ba40ad620349b6',
'com.android.support:support-annotations:fb941680f43afbd70ce01ec3cc837a5037f0a774701b12a9fd3090bd4727cf15',
'com.android.support:support-v4:ed4cda7c752f51d33f9bbdfff3422b425b323d356cd1bdc9786aa413c912e594',
'com.android.support:support-vector-drawable:2697503d3e8e709023ae176ba5db7f98ca0aa0b4e6290aedcb3c371904806bf7',

@ -14,17 +14,24 @@
limitations under the License.
-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/incall_screen"
android:layout_width="match_parent"
android:layout_height="match_parent">
<org.thoughtcrime.securesms.components.webrtc.PercentFrameLayout
android:id="@+id/remote_render_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:visibility="invisible"/>
<!-- "Call info" block #1, for the foreground call. -->
<RelativeLayout android:id="@+id/call_info_1"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="match_parent"
android:animateLayoutChanges="true">
<!-- Contact photo for call_info_1 -->
<FrameLayout android:id="@+id/image_container"
@ -39,6 +46,7 @@
android:background="@android:color/black"
android:scaleType="centerCrop"
android:visibility="visible"
android:clickable="true"
tools:src="@drawable/ic_contact_picture_large"
/>
@ -48,7 +56,8 @@
android:background="@color/grey_400"
android:orientation="vertical"
android:visibility="gone"
android:gravity="center">
android:gravity="center"
android:clickable="true">
<TextView android:id="@+id/untrusted_explanation"
android:layout_width="wrap_content"
@ -81,17 +90,6 @@
</LinearLayout>
<org.thoughtcrime.securesms.components.webrtc.PercentFrameLayout
android:id="@+id/remote_render_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:visibility="invisible"/>
<org.thoughtcrime.securesms.components.webrtc.PercentFrameLayout
android:id="@+id/local_render_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:visibility="invisible"/>
</FrameLayout>
@ -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. -->
<RelativeLayout android:id="@+id/call_banner_1"
<LinearLayout android:id="@+id/call_banner_1"
android:layout_alignParentTop="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="80dp"
android:paddingLeft="24dp"
android:paddingRight="24dp"
android:paddingTop="16dp"
android:paddingBottom="16dp"
android:background="@color/textsecure_primary"
>
<!-- Name (or the phone number, if we don't have a name to display). -->
<TextView android:id="@+id/name"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingRight="50sp"
android:textSize="40sp"
android:textColor="#FFFFFF"
android:singleLine="true"
android:maxLines="1"
android:ellipsize="end"
tools:text="Ali Connors"
/>
android:orientation="vertical">
<RelativeLayout android:id="@+id/expanded_info"
android:background="@color/textsecure_primary"
android:paddingLeft="24dp"
android:paddingRight="24dp"
android:paddingTop="16dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true">
<!-- Label (like "Mobile" or "Work", if present) and phone number, side by side -->
<LinearLayout android:id="@+id/labelAndNumber"
android:layout_below="@id/name"
android:layout_width="wrap_content"
<!-- Name (or the phone number, if we don't have a name to display). -->
<TextView android:id="@+id/name"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingRight="50sp"
android:orientation="horizontal"
>
<TextView android:id="@+id/label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="40sp"
android:textColor="#FFFFFF"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceSmall"
android:text="@string/redphone_call_card__signal_call"
android:layout_marginRight="10dp"
android:maxLines="1"
android:ellipsize="end"
tools:text="Ali Connors"
/>
<TextView android:id="@+id/phoneNumber"
<!-- Label (like "Mobile" or "Work", if present) and phone number, side by side -->
<LinearLayout android:id="@+id/labelAndNumber"
android:layout_below="@id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingRight="50sp"
android:orientation="horizontal"
>
<TextView android:id="@+id/label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#FFFFFF"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceSmall"
android:text="@string/redphone_call_card__signal_call"
android:layout_marginRight="10dp"
/>
<TextView android:id="@+id/phoneNumber"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="#FFFFFF"
android:singleLine="true"
tools:text="+14152222222"
/>
</LinearLayout>
<!-- Elapsed time indication for a call in progress. -->
<TextView android:id="@+id/elapsedTime"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="#FFFFFF"
android:singleLine="true"
tools:text="+14152222222"
/>
</LinearLayout>
</RelativeLayout>
<!-- Elapsed time indication for a call in progress. -->
<TextView android:id="@+id/elapsedTime"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="#FFFFFF"
android:singleLine="true"
/>
<org.thoughtcrime.securesms.components.webrtc.WebRtcCallControls
android:id="@+id/inCallControls"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/textsecure_primary"
<!-- Call type indication: a special label and/or branding
for certain kinds of calls (like "Internet call" for a SIP call.) -->
<TextView android:id="@+id/callTypeLabel"
android:layout_below="@id/labelAndNumber"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="#FFFFFF"
android:maxLines="1"
android:ellipsize="end"
android:visibility="gone"
android:text="@string/redphone_call_card__signal_call"
/>
android:paddingLeft="24dp"
android:paddingRight="24dp"
android:paddingTop="16dp"
android:paddingBottom="20dp"
android:clickable="true"/>
<!-- Social status (currently unused) -->
<TextView android:id="@+id/socialStatus"
android:layout_below="@id/callTypeLabel"
android:layout_width="wrap_content"
<TextView android:id="@+id/callStateLabel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="right"
android:paddingTop="8dp"
android:paddingBottom="8dp"
android:paddingRight="24dp"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="#FFFFFF"
android:maxLines="2"
android:ellipsize="end"
android:textAllCaps="true"
android:background="#8033b5e5"
tools:text="connected"
/>
<org.thoughtcrime.securesms.components.webrtc.WebRtcCallControls
android:id="@+id/inCallControls"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:layout_marginBottom="15dp"
android:layout_centerHorizontal="true"
android:layout_below="@id/labelAndNumber"/>
</RelativeLayout> <!-- End of call_banner for call_info #1. -->
</LinearLayout> <!-- End of call_banner for call_info #1. -->
<!-- The "call state label": In some states, this shows a special
indication like "Dialing" or "Incoming call" or "Call ended".
@ -209,41 +205,32 @@
<!-- This is visually part of the call banner, but it's not actually
part of the "call_banner_1" RelativeLayout since it needs a
different background color. -->
<TextView android:id="@+id/callStateLabel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/call_banner_1"
android:gravity="right"
android:paddingTop="8dp"
android:paddingBottom="8dp"
android:paddingRight="24dp"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="#FFFFFF"
android:textAllCaps="true"
android:background="#8033b5e5"
tools:text="connected"
/>
<android.support.design.widget.FloatingActionButton
android:id="@+id/hangup_fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="50dp"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:src="@drawable/ic_call_end_white_48dp"
android:focusable="true"
app:backgroundTint="@color/red_500"
android:visibility="visible"
android:contentDescription="End call"
tools:visibility="visible"/>
</RelativeLayout>
<org.thoughtcrime.securesms.components.webrtc.PercentFrameLayout
android:id="@+id/local_render_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:visibility="invisible"/>
<android.support.design.widget.FloatingActionButton
android:id="@+id/hangup_fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="40dp"
android:layout_gravity="bottom"
android:src="@drawable/ic_call_end_white_48dp"
android:focusable="true"
app:backgroundTint="@color/red_500"
android:visibility="visible"
android:contentDescription="End call"
tools:visibility="visible"/>
<org.thoughtcrime.securesms.components.webrtc.WebRtcIncomingCallOverlay
android:id="@+id/callControls"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</FrameLayout>
</android.support.design.widget.CoordinatorLayout>

@ -648,6 +648,8 @@
</string>
<string name="WebRtcCallScreen_new_safety_numbers_title">New safety numbers</string>
<!-- WebRtcCallControls -->
<string name="WebRtcCallControls_tap_to_enable_your_video">Tap to enable your video</string>
<!-- attachment_type_selector -->
<string name="attachment_type_selector__image">Image</string>

@ -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);

@ -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) {

@ -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);
}
}

Loading…
Cancel
Save