Accessible call answering/rejecting and content descriptions.

This commit is contained in:
Alan Evans 2019-07-29 09:36:48 -04:00
parent 17400020b7
commit e0d1987445
12 changed files with 600 additions and 473 deletions

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/webrtc_camera_front_button" android:state_checked="true" />
<item android:drawable="@drawable/webrtc_camera_rear_button" android:state_checked="false" />
</selector>

View file

@ -1,87 +1,99 @@
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:clipToPadding="false"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:parentTag="android.widget.LinearLayout"
tools:orientation="vertical">
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clipToPadding="false"
tools:background="#7f000000"
tools:orientation="vertical"
tools:parentTag="android.widget.LinearLayout">
<ImageView android:id="@+id/arrow_one"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginBottom="-15dp"
android:alpha="0"
android:src="@drawable/ic_keyboard_arrow_up_white_36dp"
android:tint="@color/gray20"
tools:alpha="1"/>
<ImageView
android:id="@+id/arrow_one"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginBottom="-15dp"
android:alpha="0"
android:importantForAccessibility="no"
android:src="@drawable/ic_keyboard_arrow_up_white_36dp"
android:tint="@color/gray20"
tools:alpha="1" />
<ImageView android:id="@+id/arrow_two"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginBottom="-15dp"
android:alpha="0"
android:src="@drawable/ic_keyboard_arrow_up_white_36dp"
android:tint="@color/gray20"
tools:alpha="1"/>
<ImageView
android:id="@+id/arrow_two"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginBottom="-15dp"
android:alpha="0"
android:importantForAccessibility="no"
android:src="@drawable/ic_keyboard_arrow_up_white_36dp"
android:tint="@color/gray20"
tools:alpha="1" />
<ImageView android:id="@+id/arrow_three"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginBottom="-15dp"
android:alpha="0"
android:src="@drawable/ic_keyboard_arrow_up_white_36dp"
android:tint="@color/gray20"
tools:alpha="1"/>
<ImageView
android:id="@+id/arrow_three"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginBottom="-15dp"
android:alpha="0"
android:importantForAccessibility="no"
android:src="@drawable/ic_keyboard_arrow_up_white_36dp"
android:tint="@color/gray20"
tools:alpha="1" />
<ImageView android:id="@+id/arrow_four"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginBottom="10dp"
android:alpha="0"
android:src="@drawable/ic_keyboard_arrow_up_white_36dp"
android:tint="@color/gray20"
tools:alpha="1"/>
<ImageView
android:id="@+id/arrow_four"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginBottom="10dp"
android:alpha="0"
android:importantForAccessibility="no"
android:src="@drawable/ic_keyboard_arrow_up_white_36dp"
android:tint="@color/gray20"
tools:alpha="1" />
<TextView android:id="@+id/swipe_up_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginBottom="19dp"
android:textColor="@color/gray20"
android:textStyle="italic"
android:shadowColor="#94000000"
android:shadowDx="2"
android:shadowDy="2"
android:shadowRadius="4"
android:text="@string/webrtc_answer_decline_button__swipe_up_to_answer"/>
<TextView
android:id="@+id/swipe_up_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginBottom="19dp"
android:shadowColor="#94000000"
android:shadowDx="2"
android:shadowDy="2"
android:shadowRadius="4"
android:text="@string/webrtc_answer_decline_button__swipe_up_to_answer"
android:textColor="@color/gray20"
android:textStyle="italic" />
<ImageView android:id="@+id/answer"
android:layout_width="56dp"
android:layout_height="56dp"
android:layout_gravity="center_horizontal"
android:padding="12dp"
android:elevation="5dp"
android:background="@drawable/circle_tintable"
android:src="@drawable/ic_phone_grey600_32dp"
android:tint="@color/green_600"/>
<TextView android:id="@+id/swipe_down_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="16dp"
android:textStyle="italic"
android:textColor="@color/gray20"
android:shadowColor="#94000000"
android:shadowDx="2"
android:shadowDy="2"
android:shadowRadius="4"
android:text="@string/webrtc_answer_decline_button__swipe_down_to_reject"/>
<ImageView
android:id="@+id/answer"
android:layout_width="56dp"
android:layout_height="56dp"
android:layout_gravity="center_horizontal"
android:background="@drawable/circle_tintable"
android:contentDescription="@string/webrtc_answer_decline_button__swipe_up_to_answer"
android:elevation="5dp"
android:padding="12dp"
android:src="@drawable/ic_phone_grey600_32dp"
android:tint="@color/green_600" />
<TextView
android:id="@+id/swipe_down_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="16dp"
android:shadowColor="#94000000"
android:shadowDx="2"
android:shadowDy="2"
android:shadowRadius="4"
android:text="@string/webrtc_answer_decline_button__swipe_down_to_reject"
android:textColor="@color/gray20"
android:textStyle="italic" />
</merge>

View file

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/merge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:background="#7f000000"
tools:orientation="vertical"
tools:parentTag="android.widget.LinearLayout">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:clipToPadding="false"
android:padding="16dp">
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/answer"
android:layout_width="56dp"
android:layout_height="56dp"
android:background="@drawable/circle_tintable"
android:contentDescription="@string/WebRtcCallControls_answer_call_description"
android:src="@drawable/ic_phone_grey600_32dp"
android:tint="@color/white"
app:backgroundTint="@color/green_600"
tools:layout_editor_absoluteX="12dp" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/reject"
android:layout_width="56dp"
android:layout_height="56dp"
android:layout_marginStart="64dp"
android:background="@drawable/circle_tintable"
android:contentDescription="@string/WebRtcCallControls_reject_call_description"
android:src="@drawable/ic_call_end_white_48dp"
app:backgroundTint="@color/red_500" />
</LinearLayout>
</merge>

View file

@ -1,12 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<org.thoughtcrime.securesms.components.webrtc.WebRtcCallScreen android:id="@+id/callScreen"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
</FrameLayout>
<org.thoughtcrime.securesms.components.webrtc.WebRtcCallScreen xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/callScreen"
android:layout_width="match_parent"
android:layout_height="match_parent" />

View file

@ -1,47 +1,63 @@
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/inCallControls"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
tools:background="@color/textsecure_primary">
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/inCallControls"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
tools:background="@color/textsecure_primary"
tools:showIn="@layout/webrtc_call_screen">
<org.thoughtcrime.securesms.components.AccessibleToggleButton
android:id="@+id/speakerButton"
style="@style/WebRtcCallCompoundButton"
android:background="@drawable/webrtc_speaker_button"
tools:checked="true"
android:layout_marginEnd="15dp"/>
<org.thoughtcrime.securesms.components.AccessibleToggleButton
android:id="@+id/speakerButton"
style="@style/WebRtcCallCompoundButton"
android:layout_marginEnd="16dp"
android:width="36dp"
android:height="36dp"
android:background="@drawable/webrtc_speaker_button"
android:contentDescription="@string/WebRtcCallControls_speaker_button_description"
tools:checked="true" />
<org.thoughtcrime.securesms.components.AccessibleToggleButton
android:id="@+id/bluetoothButton"
style="@style/WebRtcCallCompoundButton"
android:background="@drawable/webrtc_bluetooth_button"
tools:checked="true"
android:layout_marginEnd="15dp"
android:visibility="gone"/>
<org.thoughtcrime.securesms.components.AccessibleToggleButton
android:id="@+id/bluetoothButton"
style="@style/WebRtcCallCompoundButton"
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_marginEnd="16dp"
android:background="@drawable/webrtc_bluetooth_button"
android:contentDescription="@string/WebRtcCallControls_bluetooth_button_description"
android:visibility="gone"
tools:checked="true"
tools:visibility="visible" />
<org.thoughtcrime.securesms.components.AccessibleToggleButton
android:id="@+id/muteButton"
style="@style/WebRtcCallCompoundButton"
android:background="@drawable/webrtc_mute_button"
android:contentDescription="@string/redphone_call_controls__mute"
android:layout_marginEnd="15dp"
tools:checked="false"
/>
<org.thoughtcrime.securesms.components.AccessibleToggleButton
android:id="@+id/muteButton"
style="@style/WebRtcCallCompoundButton"
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_marginEnd="16dp"
android:background="@drawable/webrtc_mute_button"
android:contentDescription="@string/WebRtcCallControls_mute_button_description"
tools:checked="false" />
<org.thoughtcrime.securesms.components.AccessibleToggleButton
android:id="@+id/video_mute_button"
style="@style/WebRtcCallCompoundButton"
android:layout_marginEnd="15dp"
android:background="@drawable/webrtc_video_mute_button"/>
<org.thoughtcrime.securesms.components.AccessibleToggleButton
android:id="@+id/video_mute_button"
style="@style/WebRtcCallCompoundButton"
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_marginEnd="16dp"
android:background="@drawable/webrtc_video_mute_button"
android:contentDescription="@string/WebRtcCallControls_your_camera_button_description" />
<org.thoughtcrime.securesms.components.AccessibleToggleButton
android:id="@+id/camera_flip_button"
style="@style/WebRtcCallCompoundButton"
android:contentDescription="@string/redphone_call_controls__flip_camera_rear"
android:background="@drawable/webrtc_camera_rear_button"
android:visibility="gone"/>
<org.thoughtcrime.securesms.components.AccessibleToggleButton
android:id="@+id/camera_flip_button"
style="@style/WebRtcCallCompoundButton"
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_marginEnd="16dp"
android:background="@drawable/webrtc_camera_flip_button"
android:contentDescription="@string/WebRtcCallControls_switch_to_rear_camera_button_description"
android:visibility="gone"
tools:visibility="visible" />
</merge>

View file

@ -1,5 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2007 The Android Open Source Project
<?xml version="1.0" encoding="utf-8"?><!-- Copyright (C) 2007 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -15,74 +14,79 @@
-->
<androidx.coordinatorlayout.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">
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
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"/>
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:animateLayoutChanges="true">
<RelativeLayout
android:id="@+id/call_info_1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:animateLayoutChanges="true">
<!-- Contact photo for call_info_1 -->
<FrameLayout android:id="@+id/image_container"
android:layout_below="@+id/call_banner_1"
android:gravity="top|center_horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="@+id/image_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@+id/call_banner_1"
android:gravity="top|center_horizontal">
<ImageView android:id="@+id/photo"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:visibility="visible"
android:clickable="true"
tools:src="@drawable/ic_person_large"
/>
<ImageView
android:id="@+id/photo"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="@string/WebRtcCallControls_contact_photo_description"
android:scaleType="centerCrop"
android:visibility="visible"
tools:src="@drawable/ic_person_large" />
<LinearLayout android:id="@+id/untrusted_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/grey_400"
android:orientation="vertical"
android:visibility="gone"
android:gravity="center"
android:clickable="true">
<LinearLayout
android:id="@+id/untrusted_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/grey_400"
android:gravity="center"
android:orientation="vertical"
android:visibility="gone">
<TextView android:id="@+id/untrusted_explanation"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textSize="16sp"
android:maxWidth="270dp"
android:lineSpacingExtra="2sp"
tools:text="The safety numbers for your conversation with Masha have changed. This could either mean that someone is trying to intercept your communication, or that Masha simply re-installed Signal. You may wish to verify safety numbers for this contact."/>
<TextView
android:id="@+id/untrusted_explanation"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:lineSpacingExtra="2sp"
android:maxWidth="270dp"
android:textSize="16sp"
tools:text="The safety numbers for your conversation with Masha have changed. This could either mean that someone is trying to intercept your communication, or that Masha simply re-installed Signal. You may wish to verify safety numbers for this contact." />
<LinearLayout
android:layout_marginTop="20dp"
android:maxWidth="250dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:maxWidth="250dp">
<Button
android:id="@+id/accept_safety_numbers"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
android:layout_height="wrap_content"
android:layout_marginEnd="10dp"
android:text="@string/WebRtcCallScreen_accept" />
<Button android:id="@+id/accept_safety_numbers"
android:text="@string/WebRtcCallScreen_accept"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="10dp"/>
<Button android:id="@+id/cancel_safety_numbers"
android:text="@android:string/cancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/cancel_safety_numbers"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@android:string/cancel" />
</LinearLayout>
@ -97,103 +101,98 @@
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. -->
<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:orientation="vertical">
<RelativeLayout android:id="@+id/expanded_info"
android:background="@color/textsecure_primary"
android:paddingStart="24dp"
android:paddingEnd="24dp"
android:paddingTop="16dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true">
<LinearLayout
android:id="@+id/call_banner_1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:minHeight="80dp"
android:orientation="vertical">
<RelativeLayout
android:id="@+id/expanded_info"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/textsecure_primary"
android:paddingStart="24dp"
android:paddingTop="16dp"
android:paddingEnd="24dp">
<!-- 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_alignParentStart="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingEnd="50sp"
android:textSize="40sp"
android:textColor="#FFFFFF"
android:singleLine="true"
android:maxLines="1"
android:ellipsize="end"
tools:text="Ali Connors"
/>
<TextView
android:id="@+id/name"
style="@style/WebRtcCallScreenTextWhite.ExtraLarge"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:ellipsize="end"
android:maxLines="1"
android:singleLine="true"
android:textAlignment="viewStart"
tools:text="Ali Connors" />
<!-- 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:paddingEnd="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_marginEnd="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
android:id="@+id/labelAndNumber"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/name"
android:orientation="horizontal">
<TextView
android:id="@+id/label"
style="@style/WebRtcCallScreenTextWhite.Small"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="10dp"
android:singleLine="true"
android:text="@string/redphone_call_card__signal_call" />
<TextView
android:id="@+id/phoneNumber"
style="@style/WebRtcCallScreenTextWhite.Small"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
tools:text="+14152222222" />
</LinearLayout>
<!-- Elapsed time indication for a call in progress. -->
<TextView android:id="@+id/elapsedTime"
android:layout_alignParentEnd="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"
/>
<TextView
android:id="@+id/elapsedTime"
style="@style/WebRtcCallScreenTextWhite.Medium"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:singleLine="true" />
</RelativeLayout>
<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"
android:paddingStart="24dp"
android:paddingEnd="24dp"
android:paddingTop="16dp"
android:paddingBottom="20dp"
android:clickable="true"/>
android:id="@+id/inCallControls"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/textsecure_primary"
android:paddingStart="24dp"
android:paddingTop="16dp"
android:paddingEnd="24dp"
android:paddingBottom="20dp" />
<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:paddingEnd="24dp"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="#FFFFFF"
android:textAllCaps="true"
android:background="#8033b5e5"
tools:text="connected"
/>
<TextView
android:id="@+id/callStateLabel"
style="@style/WebRtcCallScreenTextWhite.Small"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#8033b5e5"
android:gravity="end"
android:paddingStart="24dp"
android:paddingTop="8dp"
android:paddingEnd="24dp"
android:paddingBottom="8dp"
android:textAllCaps="true"
tools:text="connected" />
</LinearLayout> <!-- End of call_banner for call_info #1. -->
@ -207,30 +206,27 @@
</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:id="@+id/local_render_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:visibility="invisible" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/hangup_fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="40dp"
android:layout_gravity="bottom|center_horizontal"
android:src="@drawable/ic_call_end_white_48dp"
android:focusable="true"
app:backgroundTint="@color/red_500"
android:visibility="visible"
android:contentDescription="@string/WebRtcCallScreen_end_call"
tools:visibility="visible"/>
android:id="@+id/hangup_fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center_horizontal"
android:layout_marginBottom="40dp"
android:contentDescription="@string/WebRtcCallScreen_end_call"
android:focusable="true"
android:src="@drawable/ic_call_end_white_48dp"
app:backgroundTint="@color/red_500" />
<org.thoughtcrime.securesms.components.webrtc.WebRtcAnswerDeclineButton
android:id="@+id/answer_decline_button"
android:layout_gravity="bottom|center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"/>
android:id="@+id/answer_decline_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center"
android:layout_marginBottom="16dp" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View file

@ -884,6 +884,17 @@
<!-- WebRtcCallControls -->
<string name="WebRtcCallControls_tap_to_enable_your_video">Tap to enable your video</string>
<!-- WebRtcCallControls Content Descriptions -->
<string name="WebRtcCallControls_contact_photo_description">Contact photo</string>
<string name="WebRtcCallControls_speaker_button_description">Speaker</string>
<string name="WebRtcCallControls_bluetooth_button_description">Bluetooth</string>
<string name="WebRtcCallControls_mute_button_description">Mute</string>
<string name="WebRtcCallControls_your_camera_button_description">Your camera</string>
<string name="WebRtcCallControls_switch_to_rear_camera_button_description">Switch to rear camera</string>
<string name="WebRtcCallControls_answer_call_description">Answer call</string>
<string name="WebRtcCallControls_reject_call_description">Reject call</string>
<!-- attachment_type_selector -->
<string name="attachment_type_selector__audio">Audio</string>
<string name="attachment_type_selector__audio_description">Audio</string>
@ -1149,8 +1160,6 @@
<!--- redphone_call_controls -->
<string name="redphone_call_card__signal_call">Signal Call</string>
<string name="redphone_call_controls__mute">Mute</string>
<string name="redphone_call_controls__flip_camera_rear">Switch Cameras</string>
<!-- registration_activity -->
<string name="registration_activity__phone_number">PHONE NUMBER</string>

View file

@ -111,7 +111,7 @@
<item name="android:shadowRadius">0.0</item>
<item name="android:lineSpacingMultiplier">1.25</item>
</style>
<style name="Registration.Label" parent="@android:style/TextAppearance">
<item name="android:textSize">12.0sp</item>
<item name="android:typeface">sans</item>
@ -126,11 +126,11 @@
<item name="android:shadowRadius">0.0</item>
<item name="android:lineSpacingMultiplier">1.25</item>
</style>
<style name="Registration.BigLabel" parent="@style/Registration.Label">
<item name="android:textSize">20sp</item>
</style>
<style name="Registration.Constant" parent="@android:style/TextAppearance">
<item name="android:typeface">sans</item>
<item name="android:textStyle">normal</item>
@ -139,7 +139,7 @@
<item name="android:shadowDx">1.0</item>
<item name="android:shadowDy">1.0</item>
<item name="android:shadowRadius">0.0</item>
<item name="android:lineSpacingMultiplier">1.25</item>
<item name="android:lineSpacingMultiplier">1.25</item>
</style>
<!-- For Holo Light Dialog Activity Styling Emulation -->
@ -235,4 +235,21 @@
<item name="colorControlActivated">@color/white</item>
</style>
<style name="WebRtcCallScreenTextWhite">
<item name="android:textColor">@color/white</item>
</style>
<style name="WebRtcCallScreenTextWhite.Small">
<item name="android:textAppearance">?android:attr/textAppearanceSmall</item>
</style>
<style name="WebRtcCallScreenTextWhite.Medium">
<item name="android:textAppearance">?android:attr/textAppearanceMedium</item>
</style>
<style name="WebRtcCallScreenTextWhite.ExtraLarge">
<item name="android:textAppearance">?android:attr/textAppearanceLarge</item>
<item name="android:textSize">40sp</item>
</style>
</resources>

View file

@ -1,6 +1,5 @@
package org.thoughtcrime.securesms.components.webrtc;
import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.ArgbEvaluator;
@ -8,25 +7,29 @@ import android.animation.ObjectAnimator;
import android.content.Context;
import android.graphics.Color;
import android.os.Build;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityManager;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.util.ServiceUtil;
import org.thoughtcrime.securesms.util.ViewUtil;
public class WebRtcAnswerDeclineButton extends LinearLayout implements View.OnTouchListener {
public final class WebRtcAnswerDeclineButton extends LinearLayout {
@SuppressWarnings("unused")
private static final String TAG = WebRtcAnswerDeclineButton.class.getSimpleName();
private static final String TAG = Log.tag(WebRtcAnswerDeclineButton.class);
private static final int TOTAL_TIME = 1000;
private static final int SHAKE_TIME = 200;
@ -40,22 +43,8 @@ public class WebRtcAnswerDeclineButton extends LinearLayout implements View.OnTo
private static final int ANSWER_THRESHOLD = 112;
private static final int DECLINE_THRESHOLD = 56;
private TextView swipeUpText;
private ImageView fab;
private TextView swipeDownText;
private ImageView arrowOne;
private ImageView arrowTwo;
private ImageView arrowThree;
private ImageView arrowFour;
private float lastY;
private boolean animating = false;
private boolean complete = false;
private AnimatorSet animatorSet;
private AnswerDeclineListener listener;
private AnswerDeclineListener listener;
@Nullable private DragToAnswer dragToAnswerListener;
public WebRtcAnswerDeclineButton(Context context) {
super(context);
@ -72,41 +61,27 @@ public class WebRtcAnswerDeclineButton extends LinearLayout implements View.OnTo
initialize();
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public WebRtcAnswerDeclineButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
initialize();
}
private void initialize() {
setOrientation(LinearLayout.VERTICAL);
setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
inflate(getContext(), R.layout.webrtc_answer_decline_button, this);
AccessibilityManager accessibilityManager = ServiceUtil.getAccessibilityManager(getContext());
boolean isExploreByTouchEnabled = accessibilityManager.isTouchExplorationEnabled();
this.swipeUpText = findViewById(R.id.swipe_up_text);
this.fab = findViewById(R.id.answer);
this.swipeDownText = findViewById(R.id.swipe_down_text);
if (isExploreByTouchEnabled) {
inflate(getContext(), R.layout.webrtc_answer_decline_button_accessible, this);
this.arrowOne = findViewById(R.id.arrow_one);
this.arrowTwo = findViewById(R.id.arrow_two);
this.arrowThree = findViewById(R.id.arrow_three);
this.arrowFour = findViewById(R.id.arrow_four);
findViewById(R.id.answer).setOnClickListener((view) -> listener.onAnswered());
findViewById(R.id.reject).setOnClickListener((view) -> listener.onDeclined());
this.fab.setOnTouchListener(this);
}
} else {
inflate(getContext(), R.layout.webrtc_answer_decline_button, this);
public void startRingingAnimation() {
if (!animating) {
animating = true;
animateElements(0);
}
}
ImageView answer = findViewById(R.id.answer);
public void stopRingingAnimation() {
if (animating) {
animating = false;
resetElements();
dragToAnswerListener = new DragToAnswer(answer, this);
answer.setOnTouchListener(dragToAnswerListener);
}
}
@ -114,132 +89,199 @@ public class WebRtcAnswerDeclineButton extends LinearLayout implements View.OnTo
this.listener = listener;
}
@Override
public boolean onTouch(View v, MotionEvent event) {
public void startRingingAnimation() {
if (dragToAnswerListener != null) {
dragToAnswerListener.startRingingAnimation();
}
}
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
resetElements();
swipeUpText.animate().alpha(0).setDuration(200).start();
swipeDownText.animate().alpha(0).setDuration(200).start();
lastY = event.getRawY();
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
swipeUpText.clearAnimation();
swipeDownText.clearAnimation();
swipeUpText.setAlpha(1);
swipeDownText.setAlpha(1);
fab.setRotation(0);
public void stopRingingAnimation() {
if (dragToAnswerListener != null) {
dragToAnswerListener.stopRingingAnimation();
}
}
if (Build.VERSION.SDK_INT >= 21) {
fab.getDrawable().setTint(getResources().getColor(R.color.green_600));
fab.getBackground().setTint(Color.WHITE);
}
private class DragToAnswer implements View.OnTouchListener {
animating = true;
animateElements(0);
break;
case MotionEvent.ACTION_MOVE:
float difference = event.getRawY() - lastY;
private final TextView swipeUpText;
private final ImageView answer;
private final TextView swipeDownText;
float differenceThreshold;
float percentageToThreshold;
int backgroundColor;
int foregroundColor;
private final ImageView arrowOne;
private final ImageView arrowTwo;
private final ImageView arrowThree;
private final ImageView arrowFour;
if (difference <= 0) {
differenceThreshold = ViewUtil.dpToPx(getContext(), ANSWER_THRESHOLD);
percentageToThreshold = Math.min(1, (difference * -1) / differenceThreshold);
backgroundColor = (int) new ArgbEvaluator().evaluate(percentageToThreshold, getResources().getColor(R.color.green_100), getResources().getColor(R.color.green_600));
private float lastY;
if (percentageToThreshold > 0.5) {
foregroundColor = Color.WHITE;
} else {
foregroundColor = getResources().getColor(R.color.green_600);
}
private boolean animating = false;
private boolean complete = false;
fab.setTranslationY(difference);
private AnimatorSet animatorSet;
if (percentageToThreshold == 1 && listener != null) {
fab.setVisibility(View.INVISIBLE);
lastY = event.getRawY();
if (!complete) {
complete = true;
listener.onAnswered();
}
}
} else {
differenceThreshold = ViewUtil.dpToPx(getContext(), DECLINE_THRESHOLD);
percentageToThreshold = Math.min(1, difference / differenceThreshold);
backgroundColor = (int) new ArgbEvaluator().evaluate(percentageToThreshold, getResources().getColor(R.color.red_100), getResources().getColor(R.color.red_600));
private DragToAnswer(@NonNull ImageView answer, WebRtcAnswerDeclineButton view) {
this.swipeUpText = view.findViewById(R.id.swipe_up_text);
this.answer = answer;
this.swipeDownText = view.findViewById(R.id.swipe_down_text);
if (percentageToThreshold > 0.5) {
foregroundColor = Color.WHITE;
} else {
foregroundColor = getResources().getColor(R.color.green_600);
}
fab.setRotation(135 * percentageToThreshold);
if (percentageToThreshold == 1 && listener != null) {
fab.setVisibility(View.INVISIBLE);
lastY = event.getRawY();
if (!complete) {
complete = true;
listener.onDeclined();
}
}
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
fab.getBackground().setTint(backgroundColor);
fab.getDrawable().setTint(foregroundColor);
}
break;
this.arrowOne = view.findViewById(R.id.arrow_one);
this.arrowTwo = view.findViewById(R.id.arrow_two);
this.arrowThree = view.findViewById(R.id.arrow_three);
this.arrowFour = view.findViewById(R.id.arrow_four);
}
return true;
}
private void startRingingAnimation() {
if (!animating) {
animating = true;
animateElements(0);
}
}
private void animateElements(int delay) {
ObjectAnimator fabUp = getUpAnimation(fab);
ObjectAnimator fabDown = getDownAnimation(fab);
ObjectAnimator fabShake = getShakeAnimation(fab);
private void stopRingingAnimation() {
if (animating) {
animating = false;
resetElements();
}
}
animatorSet = new AnimatorSet();
animatorSet.play(fabUp).with(getUpAnimation(swipeUpText));
animatorSet.play(fabShake).after(fabUp);
animatorSet.play(fabDown).with(getDownAnimation(swipeUpText)).after(fabShake);
@Override
public boolean onTouch(View v, MotionEvent event) {
animatorSet.play(getFadeOut(swipeDownText)).with(fabUp);
animatorSet.play(getFadeIn(swipeDownText)).after(fabDown);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
resetElements();
swipeUpText.animate().alpha(0).setDuration(200).start();
swipeDownText.animate().alpha(0).setDuration(200).start();
lastY = event.getRawY();
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
swipeUpText.clearAnimation();
swipeDownText.clearAnimation();
swipeUpText.setAlpha(1);
swipeDownText.setAlpha(1);
answer.setRotation(0);
animatorSet.play(getShimmer(arrowFour, arrowThree, arrowTwo, arrowOne));
if (Build.VERSION.SDK_INT >= 21) {
answer.getDrawable().setTint(getResources().getColor(R.color.green_600));
answer.getBackground().setTint(Color.WHITE);
}
animatorSet.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
animating = true;
animateElements(0);
break;
case MotionEvent.ACTION_MOVE:
float difference = event.getRawY() - lastY;
float differenceThreshold;
float percentageToThreshold;
int backgroundColor;
int foregroundColor;
if (difference <= 0) {
differenceThreshold = ViewUtil.dpToPx(getContext(), ANSWER_THRESHOLD);
percentageToThreshold = Math.min(1, (difference * -1) / differenceThreshold);
backgroundColor = (int) new ArgbEvaluator().evaluate(percentageToThreshold, getResources().getColor(R.color.green_100), getResources().getColor(R.color.green_600));
if (percentageToThreshold > 0.5) {
foregroundColor = Color.WHITE;
} else {
foregroundColor = getResources().getColor(R.color.green_600);
}
answer.setTranslationY(difference);
if (percentageToThreshold == 1 && listener != null) {
answer.setVisibility(View.INVISIBLE);
lastY = event.getRawY();
if (!complete) {
complete = true;
listener.onAnswered();
}
}
} else {
differenceThreshold = ViewUtil.dpToPx(getContext(), DECLINE_THRESHOLD);
percentageToThreshold = Math.min(1, difference / differenceThreshold);
backgroundColor = (int) new ArgbEvaluator().evaluate(percentageToThreshold, getResources().getColor(R.color.red_100), getResources().getColor(R.color.red_600));
if (percentageToThreshold > 0.5) {
foregroundColor = Color.WHITE;
} else {
foregroundColor = getResources().getColor(R.color.green_600);
}
answer.setRotation(135 * percentageToThreshold);
if (percentageToThreshold == 1 && listener != null) {
answer.setVisibility(View.INVISIBLE);
lastY = event.getRawY();
if (!complete) {
complete = true;
listener.onDeclined();
}
}
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
answer.getBackground().setTint(backgroundColor);
answer.getDrawable().setTint(foregroundColor);
}
break;
}
@Override
public void onAnimationEnd(Animator animation) {
if (animating) animateElements(1000);
}
return true;
}
@Override
public void onAnimationCancel(Animator animation) {}
@Override
public void onAnimationRepeat(Animator animation) {}
});
private void animateElements(int delay) {
ObjectAnimator fabUp = getUpAnimation(answer);
ObjectAnimator fabDown = getDownAnimation(answer);
ObjectAnimator fabShake = getShakeAnimation(answer);
animatorSet.setStartDelay(delay);
animatorSet.start();
animatorSet = new AnimatorSet();
animatorSet.play(fabUp).with(getUpAnimation(swipeUpText));
animatorSet.play(fabShake).after(fabUp);
animatorSet.play(fabDown).with(getDownAnimation(swipeUpText)).after(fabShake);
animatorSet.play(getFadeOut(swipeDownText)).with(fabUp);
animatorSet.play(getFadeIn(swipeDownText)).after(fabDown);
animatorSet.play(getShimmer(arrowFour, arrowThree, arrowTwo, arrowOne));
animatorSet.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
if (animating) animateElements(1000);
}
@Override
public void onAnimationCancel(Animator animation) {}
@Override
public void onAnimationRepeat(Animator animation) {}
});
animatorSet.setStartDelay(delay);
animatorSet.start();
}
private void resetElements() {
animating = false;
complete = false;
if (animatorSet != null) animatorSet.cancel();
swipeUpText.setTranslationY(0);
answer.setTranslationY(0);
swipeDownText.setAlpha(1);
}
}
private Animator getShimmer(View... targets) {
private static Animator getShimmer(View... targets) {
AnimatorSet animatorSet = new AnimatorSet();
int evenDuration = SHIMMER_TOTAL / targets.length;
int interval = 75;
@ -252,29 +294,29 @@ public class WebRtcAnswerDeclineButton extends LinearLayout implements View.OnTo
return animatorSet;
}
private ObjectAnimator getShimmer(View target, int duration) {
private static ObjectAnimator getShimmer(View target, int duration) {
ObjectAnimator shimmer = ObjectAnimator.ofFloat(target, "alpha", 0, 1, 0);
shimmer.setDuration(duration);
return shimmer;
}
private ObjectAnimator getShakeAnimation(View target) {
private static ObjectAnimator getShakeAnimation(View target) {
ObjectAnimator animator = ObjectAnimator.ofFloat(target, "translationX", 0, 25, -25, 25, -25,15, -15, 6, -6, 0);
animator.setDuration(SHAKE_TIME);
return animator;
}
private ObjectAnimator getUpAnimation(View target) {
ObjectAnimator animator = ObjectAnimator.ofFloat(target, "translationY", 0, -1 * ViewUtil.dpToPx(getContext(), 32));
private static ObjectAnimator getUpAnimation(View target) {
ObjectAnimator animator = ObjectAnimator.ofFloat(target, "translationY", 0, -1 * ViewUtil.dpToPx(target.getContext(), 32));
animator.setInterpolator(new AccelerateInterpolator());
animator.setDuration(UP_TIME);
return animator;
}
private ObjectAnimator getDownAnimation(View target) {
private static ObjectAnimator getDownAnimation(View target) {
ObjectAnimator animator = ObjectAnimator.ofFloat(target, "translationY", 0);
animator.setInterpolator(new DecelerateInterpolator());
animator.setDuration(DOWN_TIME);
@ -282,29 +324,18 @@ public class WebRtcAnswerDeclineButton extends LinearLayout implements View.OnTo
return animator;
}
private ObjectAnimator getFadeOut(View target) {
private static ObjectAnimator getFadeOut(View target) {
ObjectAnimator animator = ObjectAnimator.ofFloat(target, "alpha", 1, 0);
animator.setDuration(FADE_OUT_TIME);
return animator;
}
private ObjectAnimator getFadeIn(View target) {
private static ObjectAnimator getFadeIn(View target) {
ObjectAnimator animator = ObjectAnimator.ofFloat(target, "alpha", 0, 1);
animator.setDuration(FADE_IN_TIME);
return animator;
}
private void resetElements() {
animating = false;
complete = false;
if (animatorSet != null) animatorSet.cancel();
swipeUpText.setTranslationY(0);
fab.setTranslationY(0);
swipeDownText.setAlpha(1);
}
public interface AnswerDeclineListener {
void onAnswered();
void onDeclined();

View file

@ -90,7 +90,6 @@ public class WebRtcCallControls extends LinearLayout {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
listener.onToggle();
updateCameraFlipIcon(isChecked);
cameraFlipButton.setEnabled(false);
}
});
@ -151,12 +150,6 @@ public class WebRtcCallControls extends LinearLayout {
public void setCameraFlipButtonEnabled(boolean enabled) {
cameraFlipButton.setChecked(enabled, false);
updateCameraFlipIcon(cameraFlipButton.isChecked());
}
private void updateCameraFlipIcon(boolean isChecked) {
cameraFlipButton.setBackgroundResource(isChecked ? R.drawable.webrtc_camera_front_button
: R.drawable.webrtc_camera_rear_button);
}
public void setCameraFlipAvailable(boolean available) {

View file

@ -18,10 +18,6 @@
package org.thoughtcrime.securesms.components.webrtc;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import androidx.core.view.ViewCompat;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.TextUtils;
@ -36,7 +32,12 @@ import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.view.ViewCompat;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.mms.GlideApp;
@ -253,7 +254,11 @@ public class WebRtcCallScreen extends FrameLayout implements RecipientModifiedLi
this.remoteRenderLayout.setHidden(true);
this.minimized = false;
this.remoteRenderLayout.setOnClickListener(v -> setMinimized(!minimized));
this.remoteRenderLayout.setOnClickListener(v -> {
if (!this.remoteRenderLayout.isHidden()) {
setMinimized(!minimized);
}
});
}
private void setConnected(SurfaceViewRenderer localRenderer,

View file

@ -18,6 +18,7 @@ import androidx.annotation.RequiresApi;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityManager;
import android.view.inputmethod.InputMethodManager;
public class ServiceUtil {
@ -61,6 +62,10 @@ public class ServiceUtil {
return (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
}
public static AccessibilityManager getAccessibilityManager(@NonNull Context context) {
return (AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE);
}
@RequiresApi(26)
public static JobScheduler getJobScheduler(Context context) {
return (JobScheduler) context.getSystemService(JobScheduler.class);