mirror of
https://github.com/oxen-io/session-android.git
synced 2025-02-19 19:18:27 +00:00
Replace answer/decline button and action for incoming calls
Fixes #7199
This commit is contained in:
parent
e14a97cf68
commit
86bd2351bc
BIN
res/drawable-hdpi/ic_keyboard_arrow_up_white_36dp.png
Normal file
BIN
res/drawable-hdpi/ic_keyboard_arrow_up_white_36dp.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 190 B |
BIN
res/drawable-mdpi/ic_keyboard_arrow_up_white_36dp.png
Normal file
BIN
res/drawable-mdpi/ic_keyboard_arrow_up_white_36dp.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 156 B |
BIN
res/drawable-xhdpi/ic_keyboard_arrow_up_white_36dp.png
Normal file
BIN
res/drawable-xhdpi/ic_keyboard_arrow_up_white_36dp.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 259 B |
BIN
res/drawable-xxhdpi/ic_keyboard_arrow_up_white_36dp.png
Normal file
BIN
res/drawable-xxhdpi/ic_keyboard_arrow_up_white_36dp.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 301 B |
BIN
res/drawable-xxxhdpi/ic_keyboard_arrow_up_white_36dp.png
Normal file
BIN
res/drawable-xxxhdpi/ic_keyboard_arrow_up_white_36dp.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 371 B |
79
res/layout/webrtc_answer_decline_button.xml
Normal file
79
res/layout/webrtc_answer_decline_button.xml
Normal file
@ -0,0 +1,79 @@
|
||||
<?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">
|
||||
|
||||
<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_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_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_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"/>
|
||||
|
||||
<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:text="@string/webrtc_answer_decline_button__swipe_up_to_answer"/>
|
||||
|
||||
<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:text="@string/webrtc_answer_decline_button__swipe_down_to_reject"/>
|
||||
|
||||
|
||||
</merge>
|
@ -225,10 +225,12 @@
|
||||
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"
|
||||
/>
|
||||
|
||||
<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.support.design.widget.CoordinatorLayout>
|
||||
|
@ -1,29 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<org.thoughtcrime.securesms.components.multiwaveview.MultiWaveView
|
||||
android:id="@+id/incomingCallWidget"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_marginBottom="-46dp"
|
||||
android:background="@android:color/black"
|
||||
android:visibility="gone"
|
||||
/>
|
||||
|
||||
<TextView android:id="@+id/redphone_banner"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignTop="@id/incomingCallWidget"
|
||||
android:gravity="center"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textAllCaps="true"
|
||||
android:background="@color/textsecure_primary"
|
||||
android:text="@string/redphone_call_controls__signal_call"/>
|
||||
|
||||
</RelativeLayout>
|
@ -1251,6 +1251,8 @@
|
||||
<string name="OutdatedBuildReminder_no_web_browser_installed">No web browser installed!</string>
|
||||
<string name="ContactsCursorLoader_recent_chats">Recent chats</string>
|
||||
<string name="ContactsCursorLoader_contacts">Contacts</string>
|
||||
<string name="webrtc_answer_decline_button__swipe_up_to_answer">Swipe up to answer</string>
|
||||
<string name="webrtc_answer_decline_button__swipe_down_to_reject">Swipe down to reject</string>
|
||||
|
||||
|
||||
<!-- EOF -->
|
||||
|
@ -35,9 +35,9 @@ import android.view.WindowManager;
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
import org.greenrobot.eventbus.Subscribe;
|
||||
import org.greenrobot.eventbus.ThreadMode;
|
||||
import org.thoughtcrime.securesms.components.webrtc.WebRtcAnswerDeclineButton;
|
||||
import org.thoughtcrime.securesms.components.webrtc.WebRtcCallControls;
|
||||
import org.thoughtcrime.securesms.components.webrtc.WebRtcCallScreen;
|
||||
import org.thoughtcrime.securesms.components.webrtc.WebRtcIncomingCallOverlay;
|
||||
import org.thoughtcrime.securesms.crypto.storage.TextSecureIdentityKeyStore;
|
||||
import org.thoughtcrime.securesms.events.WebRtcViewModel;
|
||||
import org.thoughtcrime.securesms.push.SignalServiceNetworkAccess;
|
||||
@ -359,14 +359,14 @@ public class WebRtcCallActivity extends Activity {
|
||||
}
|
||||
}
|
||||
|
||||
private class IncomingCallActionListener implements WebRtcIncomingCallOverlay.IncomingCallActionListener {
|
||||
private class IncomingCallActionListener implements WebRtcAnswerDeclineButton.AnswerDeclineListener {
|
||||
@Override
|
||||
public void onAcceptClick() {
|
||||
public void onAnswered() {
|
||||
WebRtcCallActivity.this.handleAnswerCall();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDenyClick() {
|
||||
public void onDeclined() {
|
||||
WebRtcCallActivity.this.handleDenyCall();
|
||||
}
|
||||
}
|
||||
|
@ -1,134 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thoughtcrime.securesms.components.multiwaveview;
|
||||
|
||||
|
||||
import android.animation.TimeInterpolator;
|
||||
import android.annotation.SuppressLint;
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
class Ease {
|
||||
private static final float DOMAIN = 1.0f;
|
||||
private static final float DURATION = 1.0f;
|
||||
private static final float START = 0.0f;
|
||||
|
||||
static class Linear {
|
||||
public static final TimeInterpolator easeNone = new TimeInterpolator() {
|
||||
public float getInterpolation(float input) {
|
||||
return input;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static class Cubic {
|
||||
public static final TimeInterpolator easeIn = new TimeInterpolator() {
|
||||
public float getInterpolation(float input) {
|
||||
return DOMAIN*(input/=DURATION)*input*input + START;
|
||||
}
|
||||
};
|
||||
public static final TimeInterpolator easeOut = new TimeInterpolator() {
|
||||
public float getInterpolation(float input) {
|
||||
return DOMAIN*((input=input/DURATION-1)*input*input + 1) + START;
|
||||
}
|
||||
};
|
||||
public static final TimeInterpolator easeInOut = new TimeInterpolator() {
|
||||
public float getInterpolation(float input) {
|
||||
return ((input/=DURATION/2) < 1.0f) ?
|
||||
(DOMAIN/2*input*input*input + START)
|
||||
: (DOMAIN/2*((input-=2)*input*input + 2) + START);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static class Quad {
|
||||
public static final TimeInterpolator easeIn = new TimeInterpolator() {
|
||||
public float getInterpolation (float input) {
|
||||
return DOMAIN*(input/=DURATION)*input + START;
|
||||
}
|
||||
};
|
||||
public static final TimeInterpolator easeOut = new TimeInterpolator() {
|
||||
public float getInterpolation(float input) {
|
||||
return -DOMAIN *(input/=DURATION)*(input-2) + START;
|
||||
}
|
||||
};
|
||||
public static final TimeInterpolator easeInOut = new TimeInterpolator() {
|
||||
public float getInterpolation(float input) {
|
||||
return ((input/=DURATION/2) < 1) ?
|
||||
(DOMAIN/2*input*input + START)
|
||||
: (-DOMAIN/2 * ((--input)*(input-2) - 1) + START);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static class Quart {
|
||||
public static final TimeInterpolator easeIn = new TimeInterpolator() {
|
||||
public float getInterpolation(float input) {
|
||||
return DOMAIN*(input/=DURATION)*input*input*input + START;
|
||||
}
|
||||
};
|
||||
public static final TimeInterpolator easeOut = new TimeInterpolator() {
|
||||
public float getInterpolation(float input) {
|
||||
return -DOMAIN * ((input=input/DURATION-1)*input*input*input - 1) + START;
|
||||
}
|
||||
};
|
||||
public static final TimeInterpolator easeInOut = new TimeInterpolator() {
|
||||
public float getInterpolation(float input) {
|
||||
return ((input/=DURATION/2) < 1) ?
|
||||
(DOMAIN/2*input*input*input*input + START)
|
||||
: (-DOMAIN/2 * ((input-=2)*input*input*input - 2) + START);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static class Quint {
|
||||
public static final TimeInterpolator easeIn = new TimeInterpolator() {
|
||||
public float getInterpolation(float input) {
|
||||
return DOMAIN*(input/=DURATION)*input*input*input*input + START;
|
||||
}
|
||||
};
|
||||
public static final TimeInterpolator easeOut = new TimeInterpolator() {
|
||||
public float getInterpolation(float input) {
|
||||
return DOMAIN*((input=input/DURATION-1)*input*input*input*input + 1) + START;
|
||||
}
|
||||
};
|
||||
public static final TimeInterpolator easeInOut = new TimeInterpolator() {
|
||||
public float getInterpolation(float input) {
|
||||
return ((input/=DURATION/2) < 1) ?
|
||||
(DOMAIN/2*input*input*input*input*input + START)
|
||||
: (DOMAIN/2*((input-=2)*input*input*input*input + 2) + START);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static class Sine {
|
||||
public static final TimeInterpolator easeIn = new TimeInterpolator() {
|
||||
public float getInterpolation(float input) {
|
||||
return -DOMAIN * (float) Math.cos(input / DURATION * (Math.PI / 2)) + DOMAIN + START;
|
||||
}
|
||||
};
|
||||
public static final TimeInterpolator easeOut = new TimeInterpolator() {
|
||||
public float getInterpolation(float input) {
|
||||
return DOMAIN * (float) Math.sin(input / DURATION * (Math.PI / 2)) + START;
|
||||
}
|
||||
};
|
||||
public static final TimeInterpolator easeInOut = new TimeInterpolator() {
|
||||
public float getInterpolation(float input) {
|
||||
return -DOMAIN/2 * ((float) Math.cos(Math.PI * input / DURATION) - 1.0f) + START;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,225 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thoughtcrime.securesms.components.multiwaveview;
|
||||
|
||||
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.ColorFilter;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.StateListDrawable;
|
||||
|
||||
public class TargetDrawable {
|
||||
private static final String TAG = "TargetDrawable";
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
public static final int[] STATE_ACTIVE =
|
||||
{ android.R.attr.state_enabled, android.R.attr.state_active };
|
||||
public static final int[] STATE_INACTIVE =
|
||||
{ android.R.attr.state_enabled, -android.R.attr.state_active };
|
||||
public static final int[] STATE_FOCUSED =
|
||||
{ android.R.attr.state_enabled, android.R.attr.state_focused };
|
||||
|
||||
private float mTranslationX = 0.0f;
|
||||
private float mTranslationY = 0.0f;
|
||||
private float mScaleX = 1.0f;
|
||||
private float mScaleY = 1.0f;
|
||||
private float mAlpha = 1.0f;
|
||||
private Drawable mDrawable;
|
||||
|
||||
/* package */ static class DrawableWithAlpha extends Drawable {
|
||||
private float mAlpha = 1.0f;
|
||||
private Drawable mRealDrawable;
|
||||
public DrawableWithAlpha(Drawable realDrawable) {
|
||||
mRealDrawable = realDrawable;
|
||||
}
|
||||
public void setAlpha(float alpha) {
|
||||
mAlpha = alpha;
|
||||
}
|
||||
public int getAlpha() {
|
||||
return (int)(mAlpha * 255);
|
||||
}
|
||||
@Override
|
||||
public void draw(Canvas canvas) {
|
||||
mRealDrawable.setAlpha((int) Math.round(mAlpha * 255f));
|
||||
mRealDrawable.draw(canvas);
|
||||
}
|
||||
@Override
|
||||
public void setAlpha(int alpha) {
|
||||
mRealDrawable.setAlpha(alpha);
|
||||
}
|
||||
@Override
|
||||
public void setColorFilter(ColorFilter cf) {
|
||||
mRealDrawable.setColorFilter(cf);
|
||||
}
|
||||
@Override
|
||||
public int getOpacity() {
|
||||
return mRealDrawable.getOpacity();
|
||||
}
|
||||
}
|
||||
|
||||
public TargetDrawable(Resources res, int resId) {
|
||||
this(res, resId == 0 ? null : res.getDrawable(resId));
|
||||
}
|
||||
|
||||
public TargetDrawable(Resources res, Drawable drawable) {
|
||||
// Mutate the drawable so we can animate shared drawable properties.
|
||||
mDrawable = drawable != null ? drawable.mutate() : null;
|
||||
resizeDrawables();
|
||||
setState(STATE_INACTIVE);
|
||||
}
|
||||
|
||||
public void setState(int [] state) {
|
||||
if (mDrawable instanceof StateListDrawable) {
|
||||
StateListDrawable d = (StateListDrawable) mDrawable;
|
||||
d.setState(state);
|
||||
}
|
||||
}
|
||||
|
||||
// public boolean hasState(int [] state) {
|
||||
// if (mDrawable instanceof StateListDrawable) {
|
||||
// StateListDrawable d = (StateListDrawable) mDrawable;
|
||||
// // TODO: this doesn't seem to work
|
||||
// return d.getStateDrawableIndex(state) != -1;
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
|
||||
/**
|
||||
* Returns true if the drawable is a StateListDrawable and is in the focused state.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isActive() {
|
||||
if (mDrawable instanceof StateListDrawable) {
|
||||
StateListDrawable d = (StateListDrawable) mDrawable;
|
||||
int[] states = d.getState();
|
||||
for (int i = 0; i < states.length; i++) {
|
||||
if (states[i] == android.R.attr.state_focused) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this target is enabled. Typically an enabled target contains a valid
|
||||
* drawable in a valid state. Currently all targets with valid drawables are valid.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isValid() {
|
||||
return mDrawable != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes drawables in a StateListDrawable all the same dimensions.
|
||||
* If not a StateListDrawable, then justs sets the bounds to the intrinsic size of the
|
||||
* drawable.
|
||||
*/
|
||||
|
||||
private void resizeDrawables() {
|
||||
if (mDrawable != null)
|
||||
mDrawable.setBounds(0, 0, mDrawable.getIntrinsicWidth(), mDrawable.getIntrinsicHeight());
|
||||
}
|
||||
// private void resizeDrawables() {
|
||||
// if (mDrawable instanceof StateListDrawable) {
|
||||
// StateListDrawable d = (StateListDrawable) mDrawable;
|
||||
// int maxWidth = 0;
|
||||
// int maxHeight = 0;
|
||||
//
|
||||
// for (int i = 0; i < d.getStateCount(); i++) {
|
||||
// Drawable childDrawable = d.getStateDrawable(i);
|
||||
// maxWidth = Math.max(maxWidth, childDrawable.getIntrinsicWidth());
|
||||
// maxHeight = Math.max(maxHeight, childDrawable.getIntrinsicHeight());
|
||||
// }
|
||||
// if (DEBUG) Log.v(TAG, "union of childDrawable rects " + d + " to: "
|
||||
// + maxWidth + "x" + maxHeight);
|
||||
// d.setBounds(0, 0, maxWidth, maxHeight);
|
||||
// for (int i = 0; i < d.getStateCount(); i++) {
|
||||
// Drawable childDrawable = d.getStateDrawable(i);
|
||||
// if (DEBUG) Log.v(TAG, "sizing drawable " + childDrawable + " to: "
|
||||
// + maxWidth + "x" + maxHeight);
|
||||
// childDrawable.setBounds(0, 0, maxWidth, maxHeight);
|
||||
// }
|
||||
// } else if (mDrawable != null) {
|
||||
// mDrawable.setBounds(0, 0,
|
||||
// mDrawable.getIntrinsicWidth(), mDrawable.getIntrinsicHeight());
|
||||
// }
|
||||
// }
|
||||
|
||||
public void setX(float x) {
|
||||
mTranslationX = x;
|
||||
}
|
||||
|
||||
public void setY(float y) {
|
||||
mTranslationY = y;
|
||||
}
|
||||
|
||||
public void setScaleX(float x) {
|
||||
mScaleX = x;
|
||||
}
|
||||
|
||||
public void setScaleY(float y) {
|
||||
mScaleY = y;
|
||||
}
|
||||
|
||||
public void setAlpha(float alpha) {
|
||||
mAlpha = alpha;
|
||||
}
|
||||
|
||||
public float getX() {
|
||||
return mTranslationX;
|
||||
}
|
||||
|
||||
public float getY() {
|
||||
return mTranslationY;
|
||||
}
|
||||
|
||||
public float getScaleX() {
|
||||
return mScaleX;
|
||||
}
|
||||
|
||||
public float getScaleY() {
|
||||
return mScaleY;
|
||||
}
|
||||
|
||||
public float getAlpha() {
|
||||
return mAlpha;
|
||||
}
|
||||
|
||||
public int getWidth() {
|
||||
return mDrawable != null ? mDrawable.getIntrinsicWidth() : 0;
|
||||
}
|
||||
|
||||
public int getHeight() {
|
||||
return mDrawable != null ? mDrawable.getIntrinsicHeight() : 0;
|
||||
}
|
||||
|
||||
public void draw(Canvas canvas) {
|
||||
if (mDrawable == null) {
|
||||
return;
|
||||
}
|
||||
canvas.save(Canvas.MATRIX_SAVE_FLAG);
|
||||
canvas.translate(mTranslationX, mTranslationY);
|
||||
canvas.scale(mScaleX, mScaleY);
|
||||
canvas.translate(-0.5f * getWidth(), -0.5f * getHeight());
|
||||
mDrawable.setAlpha((int) Math.round(mAlpha * 255f));
|
||||
mDrawable.draw(canvas);
|
||||
canvas.restore();
|
||||
}
|
||||
}
|
@ -1,180 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.thoughtcrime.securesms.components.multiwaveview;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.Animator.AnimatorListener;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.animation.PropertyValuesHolder;
|
||||
import android.animation.TimeInterpolator;
|
||||
import android.animation.ValueAnimator.AnimatorUpdateListener;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
class Tweener {
|
||||
private static final String TAG = "Tweener";
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
ObjectAnimator animator;
|
||||
private static HashMap<Object, Tweener> sTweens = new HashMap<Object, Tweener>();
|
||||
|
||||
public Tweener(ObjectAnimator anim) {
|
||||
animator = anim;
|
||||
}
|
||||
|
||||
private static void remove(Animator animator) {
|
||||
Iterator<Entry<Object, Tweener>> iter = sTweens.entrySet().iterator();
|
||||
while (iter.hasNext()) {
|
||||
Entry<Object, Tweener> entry = iter.next();
|
||||
if (entry.getValue().animator == animator) {
|
||||
if (DEBUG) Log.v(TAG, "Removing tweener " + sTweens.get(entry.getKey())
|
||||
+ " sTweens.size() = " + sTweens.size());
|
||||
iter.remove();
|
||||
break; // an animator can only be attached to one object
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
public static Tweener to(Object object, long duration, Object... vars) {
|
||||
long delay = 0;
|
||||
AnimatorUpdateListener updateListener = null;
|
||||
AnimatorListener listener = null;
|
||||
TimeInterpolator interpolator = null;
|
||||
|
||||
// Iterate through arguments and discover properties to animate
|
||||
ArrayList<PropertyValuesHolder> props = new ArrayList<PropertyValuesHolder>(vars.length/2);
|
||||
for (int i = 0; i < vars.length; i+=2) {
|
||||
if (!(vars[i] instanceof String)) {
|
||||
throw new IllegalArgumentException("Key must be a string: " + vars[i]);
|
||||
}
|
||||
String key = (String) vars[i];
|
||||
Object value = vars[i+1];
|
||||
if ("simultaneousTween".equals(key)) {
|
||||
// TODO
|
||||
} else if ("ease".equals(key)) {
|
||||
interpolator = (TimeInterpolator) value; // TODO: multiple interpolators?
|
||||
} else if ("onUpdate".equals(key) || "onUpdateListener".equals(key)) {
|
||||
updateListener = (AnimatorUpdateListener) value;
|
||||
} else if ("onCodeComplete".equals(key) || "onCompleteListener".equals(key)) {
|
||||
listener = (AnimatorListener) value;
|
||||
} else if ("delay".equals(key)) {
|
||||
delay = ((Number) value).longValue();
|
||||
} else if ("syncWith".equals(key)) {
|
||||
// TODO
|
||||
} else if (value instanceof float[]) {
|
||||
props.add(PropertyValuesHolder.ofFloat(key,
|
||||
((float[]) value)[0], ((float[]) value)[1]));
|
||||
} else if (value instanceof Number) {
|
||||
float floatValue = ((Number)value).floatValue();
|
||||
props.add(PropertyValuesHolder.ofFloat(key, floatValue));
|
||||
} else {
|
||||
throw new IllegalArgumentException(
|
||||
"Bad argument for key \"" + key + "\" with value " + value.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
// Re-use existing tween, if present
|
||||
Tweener tween = sTweens.get(object);
|
||||
ObjectAnimator anim = null;
|
||||
if (tween == null) {
|
||||
anim = ObjectAnimator.ofPropertyValuesHolder(object,
|
||||
props.toArray(new PropertyValuesHolder[props.size()]));
|
||||
tween = new Tweener(anim);
|
||||
sTweens.put(object, tween);
|
||||
if (DEBUG) Log.v(TAG, "Added new Tweener " + tween);
|
||||
} else {
|
||||
anim = sTweens.get(object).animator;
|
||||
replace(props, object); // Cancel all animators for given object
|
||||
}
|
||||
|
||||
if (interpolator != null) {
|
||||
anim.setInterpolator(interpolator);
|
||||
}
|
||||
|
||||
// Update animation with properties discovered in loop above
|
||||
anim.setStartDelay(delay);
|
||||
anim.setDuration(duration);
|
||||
if (updateListener != null) {
|
||||
anim.removeAllUpdateListeners(); // There should be only one
|
||||
anim.addUpdateListener(updateListener);
|
||||
}
|
||||
if (listener != null) {
|
||||
anim.removeAllListeners(); // There should be only one.
|
||||
anim.addListener(listener);
|
||||
}
|
||||
anim.addListener(mCleanupListener);
|
||||
anim.start();
|
||||
|
||||
return tween;
|
||||
}
|
||||
|
||||
Tweener from(Object object, long duration, Object... vars) {
|
||||
// TODO: for v of vars
|
||||
// toVars[v] = object[v]
|
||||
// object[v] = vars[v]
|
||||
return Tweener.to(object, duration, vars);
|
||||
}
|
||||
|
||||
// Listener to watch for completed animations and remove them.
|
||||
@SuppressLint("NewApi")
|
||||
private static AnimatorListener mCleanupListener = new AnimatorListenerAdapter() {
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
remove(animation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationCancel(Animator animation) {
|
||||
remove(animation);
|
||||
}
|
||||
};
|
||||
|
||||
public static void reset() {
|
||||
if (DEBUG) {
|
||||
Log.v(TAG, "Reset()");
|
||||
if (sTweens.size() > 0) {
|
||||
Log.v(TAG, "Cleaning up " + sTweens.size() + " animations");
|
||||
}
|
||||
}
|
||||
sTweens.clear();
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
private static void replace(ArrayList<PropertyValuesHolder> props, Object... args) {
|
||||
for (final Object killobject : args) {
|
||||
Tweener tween = sTweens.get(killobject);
|
||||
if (tween != null) {
|
||||
tween.animator.cancel();
|
||||
if (props != null) {
|
||||
tween.animator.setValues(
|
||||
props.toArray(new PropertyValuesHolder[props.size()]));
|
||||
} else {
|
||||
sTweens.remove(tween);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,293 @@
|
||||
package org.thoughtcrime.securesms.components.webrtc;
|
||||
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.ArgbEvaluator;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.os.Build;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.annotation.RequiresApi;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.animation.AccelerateInterpolator;
|
||||
import android.view.animation.DecelerateInterpolator;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
|
||||
public class WebRtcAnswerDeclineButton extends LinearLayout implements View.OnTouchListener {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static final String TAG = WebRtcAnswerDeclineButton.class.getSimpleName();
|
||||
|
||||
private static final int TOTAL_TIME = 1000;
|
||||
private static final int SHAKE_TIME = 200;
|
||||
|
||||
private static final int UP_TIME = (TOTAL_TIME - SHAKE_TIME) / 2;
|
||||
private static final int DOWN_TIME = (TOTAL_TIME - SHAKE_TIME) / 2;
|
||||
private static final int FADE_OUT_TIME = 300;
|
||||
private static final int FADE_IN_TIME = 100;
|
||||
private static final int SHIMMER_TOTAL = UP_TIME + SHAKE_TIME;
|
||||
|
||||
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 AnimatorSet animatorSet;
|
||||
private AnswerDeclineListener listener;
|
||||
|
||||
public WebRtcAnswerDeclineButton(Context context) {
|
||||
super(context);
|
||||
initialize();
|
||||
}
|
||||
|
||||
public WebRtcAnswerDeclineButton(Context context, @Nullable AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
initialize();
|
||||
}
|
||||
|
||||
public WebRtcAnswerDeclineButton(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
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);
|
||||
|
||||
this.swipeUpText = findViewById(R.id.swipe_up_text);
|
||||
this.fab = findViewById(R.id.answer);
|
||||
this.swipeDownText = findViewById(R.id.swipe_down_text);
|
||||
|
||||
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);
|
||||
|
||||
this.fab.setOnTouchListener(this);
|
||||
}
|
||||
|
||||
public void startRingingAnimation() {
|
||||
if (!animating) {
|
||||
animating = true;
|
||||
animateElements(0);
|
||||
}
|
||||
}
|
||||
|
||||
public void stopRingingAnimation() {
|
||||
if (animating) {
|
||||
animating = false;
|
||||
resetElements();
|
||||
}
|
||||
}
|
||||
|
||||
public void setAnswerDeclineListener(AnswerDeclineListener listener) {
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouch(View v, MotionEvent event) {
|
||||
|
||||
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);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= 21) {
|
||||
fab.getDrawable().setTint(getResources().getColor(R.color.green_600));
|
||||
fab.getBackground().setTint(Color.WHITE);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
fab.setTranslationY(difference);
|
||||
|
||||
if (percentageToThreshold == 1 && listener != null) 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);
|
||||
}
|
||||
|
||||
fab.setRotation(135 * percentageToThreshold);
|
||||
|
||||
if (percentageToThreshold == 1 && listener != null) listener.onDeclined();
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
fab.getBackground().setTint(backgroundColor);
|
||||
fab.getDrawable().setTint(foregroundColor);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void animateElements(int delay) {
|
||||
ObjectAnimator fabUp = getUpAnimation(fab);
|
||||
ObjectAnimator fabDown = getDownAnimation(fab);
|
||||
ObjectAnimator fabShake = getShakeAnimation(fab);
|
||||
|
||||
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 Animator getShimmer(View... targets) {
|
||||
AnimatorSet animatorSet = new AnimatorSet();
|
||||
int evenDuration = SHIMMER_TOTAL / targets.length;
|
||||
int interval = 75;
|
||||
|
||||
for (int i=0;i<targets.length;i++) {
|
||||
animatorSet.play(getShimmer(targets[i], evenDuration + (evenDuration - interval)))
|
||||
.after(interval * i);
|
||||
}
|
||||
|
||||
return animatorSet;
|
||||
}
|
||||
|
||||
private 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) {
|
||||
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));
|
||||
animator.setInterpolator(new AccelerateInterpolator());
|
||||
animator.setDuration(UP_TIME);
|
||||
|
||||
return animator;
|
||||
}
|
||||
|
||||
private ObjectAnimator getDownAnimation(View target) {
|
||||
ObjectAnimator animator = ObjectAnimator.ofFloat(target, "translationY", 0);
|
||||
animator.setInterpolator(new DecelerateInterpolator());
|
||||
animator.setDuration(DOWN_TIME);
|
||||
|
||||
return animator;
|
||||
}
|
||||
|
||||
private ObjectAnimator getFadeOut(View target) {
|
||||
ObjectAnimator animator = ObjectAnimator.ofFloat(target, "alpha", 1, 0);
|
||||
animator.setDuration(FADE_OUT_TIME);
|
||||
return animator;
|
||||
}
|
||||
|
||||
private ObjectAnimator getFadeIn(View target) {
|
||||
ObjectAnimator animator = ObjectAnimator.ofFloat(target, "alpha", 0, 1);
|
||||
animator.setDuration(FADE_IN_TIME);
|
||||
return animator;
|
||||
}
|
||||
|
||||
private void resetElements() {
|
||||
animating = false;
|
||||
animatorSet.cancel();
|
||||
|
||||
swipeUpText.setTranslationY(0);
|
||||
fab.setTranslationY(0);
|
||||
swipeDownText.setAlpha(1);
|
||||
}
|
||||
|
||||
public interface AnswerDeclineListener {
|
||||
void onAnswered();
|
||||
void onDeclined();
|
||||
}
|
||||
}
|
@ -58,6 +58,7 @@ import org.whispersystems.libsignal.IdentityKey;
|
||||
*/
|
||||
public class WebRtcCallScreen extends FrameLayout implements RecipientModifiedListener {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static final String TAG = WebRtcCallScreen.class.getSimpleName();
|
||||
|
||||
private ImageView photo;
|
||||
@ -77,10 +78,11 @@ public class WebRtcCallScreen extends FrameLayout implements RecipientModifiedLi
|
||||
private RelativeLayout expandedInfo;
|
||||
private ViewGroup callHeader;
|
||||
|
||||
private WebRtcAnswerDeclineButton incomingCallButton;
|
||||
|
||||
private Recipient recipient;
|
||||
private boolean minimized;
|
||||
|
||||
private WebRtcIncomingCallOverlay incomingCallOverlay;
|
||||
|
||||
public WebRtcCallScreen(Context context) {
|
||||
super(context);
|
||||
@ -100,18 +102,21 @@ public class WebRtcCallScreen extends FrameLayout implements RecipientModifiedLi
|
||||
public void setActiveCall(@NonNull Recipient personInfo, @NonNull String message, @Nullable String sas) {
|
||||
setCard(personInfo, message);
|
||||
setConnected(WebRtcCallService.localRenderer, WebRtcCallService.remoteRenderer);
|
||||
incomingCallOverlay.setActiveCall(sas);
|
||||
incomingCallButton.stopRingingAnimation();
|
||||
incomingCallButton.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
public void setActiveCall(@NonNull Recipient personInfo, @NonNull String message) {
|
||||
setCard(personInfo, message);
|
||||
incomingCallOverlay.setActiveCall();
|
||||
incomingCallButton.stopRingingAnimation();
|
||||
incomingCallButton.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
public void setIncomingCall(Recipient personInfo) {
|
||||
setCard(personInfo, getContext().getString(R.string.CallScreen_Incoming_call));
|
||||
incomingCallOverlay.setIncomingCall();
|
||||
endCallButton.setVisibility(View.INVISIBLE);
|
||||
incomingCallButton.setVisibility(View.VISIBLE);
|
||||
incomingCallButton.startRingingAnimation();
|
||||
}
|
||||
|
||||
public void setUntrustedIdentity(Recipient personInfo, IdentityKey untrustedIdentity) {
|
||||
@ -125,7 +130,8 @@ public class WebRtcCallScreen extends FrameLayout implements RecipientModifiedLi
|
||||
|
||||
setPersonInfo(personInfo);
|
||||
|
||||
this.incomingCallOverlay.setActiveCall();
|
||||
incomingCallButton.stopRingingAnimation();
|
||||
incomingCallButton.setVisibility(View.GONE);
|
||||
this.status.setText(R.string.WebRtcCallScreen_new_safety_number_title);
|
||||
this.untrustedIdentityContainer.setVisibility(View.VISIBLE);
|
||||
this.untrustedIdentityExplanation.setText(spannableString);
|
||||
@ -134,8 +140,8 @@ public class WebRtcCallScreen extends FrameLayout implements RecipientModifiedLi
|
||||
this.endCallButton.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
|
||||
public void setIncomingCallActionListener(WebRtcIncomingCallOverlay.IncomingCallActionListener listener) {
|
||||
incomingCallOverlay.setIncomingCallActionListener(listener);
|
||||
public void setIncomingCallActionListener(WebRtcAnswerDeclineButton.AnswerDeclineListener listener) {
|
||||
incomingCallButton.setAnswerDeclineListener(listener);
|
||||
}
|
||||
|
||||
public void setAudioMuteButtonListener(WebRtcCallControls.MuteButtonListener listener) {
|
||||
@ -155,12 +161,7 @@ public class WebRtcCallScreen extends FrameLayout implements RecipientModifiedLi
|
||||
}
|
||||
|
||||
public void setHangupButtonListener(final HangupButtonListener listener) {
|
||||
endCallButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
listener.onClick();
|
||||
}
|
||||
});
|
||||
endCallButton.setOnClickListener(v -> listener.onClick());
|
||||
}
|
||||
|
||||
public void setAcceptIdentityListener(OnClickListener listener) {
|
||||
@ -217,34 +218,29 @@ public class WebRtcCallScreen extends FrameLayout implements RecipientModifiedLi
|
||||
LayoutInflater inflater = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
inflater.inflate(R.layout.webrtc_call_screen, this, true);
|
||||
|
||||
this.elapsedTime = (TextView) findViewById(R.id.elapsedTime);
|
||||
this.photo = (ImageView) findViewById(R.id.photo);
|
||||
this.localRenderLayout = (PercentFrameLayout) findViewById(R.id.local_render_layout);
|
||||
this.remoteRenderLayout = (PercentFrameLayout) findViewById(R.id.remote_render_layout);
|
||||
this.phoneNumber = (TextView) findViewById(R.id.phoneNumber);
|
||||
this.name = (TextView) findViewById(R.id.name);
|
||||
this.label = (TextView) findViewById(R.id.label);
|
||||
this.status = (TextView) findViewById(R.id.callStateLabel);
|
||||
this.controls = (WebRtcCallControls) findViewById(R.id.inCallControls);
|
||||
this.endCallButton = (FloatingActionButton) findViewById(R.id.hangup_fab);
|
||||
this.incomingCallOverlay = (WebRtcIncomingCallOverlay) findViewById(R.id.callControls);
|
||||
this.elapsedTime = findViewById(R.id.elapsedTime);
|
||||
this.photo = findViewById(R.id.photo);
|
||||
this.localRenderLayout = findViewById(R.id.local_render_layout);
|
||||
this.remoteRenderLayout = findViewById(R.id.remote_render_layout);
|
||||
this.phoneNumber = findViewById(R.id.phoneNumber);
|
||||
this.name = findViewById(R.id.name);
|
||||
this.label = findViewById(R.id.label);
|
||||
this.status = findViewById(R.id.callStateLabel);
|
||||
this.controls = findViewById(R.id.inCallControls);
|
||||
this.endCallButton = findViewById(R.id.hangup_fab);
|
||||
this.incomingCallButton = findViewById(R.id.answer_decline_button);
|
||||
this.untrustedIdentityContainer = findViewById(R.id.untrusted_layout);
|
||||
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.untrustedIdentityExplanation = findViewById(R.id.untrusted_explanation);
|
||||
this.acceptIdentityButton = findViewById(R.id.accept_safety_numbers);
|
||||
this.cancelIdentityButton = findViewById(R.id.cancel_safety_numbers);
|
||||
this.expandedInfo = findViewById(R.id.expanded_info);
|
||||
this.callHeader = 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);
|
||||
}
|
||||
});
|
||||
this.remoteRenderLayout.setOnClickListener(v -> setMinimized(!minimized));
|
||||
}
|
||||
|
||||
private void setConnected(SurfaceViewRenderer localRenderer,
|
||||
@ -300,7 +296,7 @@ public class WebRtcCallScreen extends FrameLayout implements RecipientModifiedLi
|
||||
setPersonInfo(recipient);
|
||||
this.status.setText(status);
|
||||
this.untrustedIdentityContainer.setVisibility(View.GONE);
|
||||
this.endCallButton.setVisibility(View.VISIBLE);
|
||||
this.endCallButton.show();
|
||||
}
|
||||
|
||||
private void setMinimized(boolean minimized) {
|
||||
@ -315,12 +311,9 @@ public class WebRtcCallScreen extends FrameLayout implements RecipientModifiedLi
|
||||
ViewCompat.animate(callHeader).translationY(0);
|
||||
ViewCompat.animate(status).alpha(1);
|
||||
ViewCompat.animate(endCallButton).translationY(0);
|
||||
ViewCompat.animate(endCallButton).alpha(1).withEndAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// Note: This is to work around an Android bug, see #6225
|
||||
endCallButton.requestLayout();
|
||||
}
|
||||
ViewCompat.animate(endCallButton).alpha(1).withEndAction(() -> {
|
||||
// Note: This is to work around an Android bug, see #6225
|
||||
endCallButton.requestLayout();
|
||||
});
|
||||
|
||||
this.minimized = false;
|
||||
@ -336,8 +329,8 @@ public class WebRtcCallScreen extends FrameLayout implements RecipientModifiedLi
|
||||
});
|
||||
}
|
||||
|
||||
public static interface HangupButtonListener {
|
||||
public void onClick();
|
||||
public interface HangupButtonListener {
|
||||
void onClick();
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,113 +0,0 @@
|
||||
package org.thoughtcrime.securesms.components.webrtc;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.animation.Animation;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.components.multiwaveview.MultiWaveView;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
|
||||
/**
|
||||
* Displays the controls at the bottom of the in-call screen.
|
||||
*
|
||||
* @author Moxie Marlinspike
|
||||
*
|
||||
*/
|
||||
|
||||
public class WebRtcIncomingCallOverlay extends RelativeLayout {
|
||||
|
||||
private MultiWaveView incomingCallWidget;
|
||||
private TextView redphoneLabel;
|
||||
|
||||
public WebRtcIncomingCallOverlay(Context context) {
|
||||
super(context);
|
||||
initialize();
|
||||
}
|
||||
|
||||
public WebRtcIncomingCallOverlay(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
initialize();
|
||||
}
|
||||
|
||||
public WebRtcIncomingCallOverlay(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
initialize();
|
||||
}
|
||||
|
||||
public void setIncomingCall() {
|
||||
Animation animation = incomingCallWidget.getAnimation();
|
||||
|
||||
if (animation != null) {
|
||||
animation.reset();
|
||||
incomingCallWidget.clearAnimation();
|
||||
}
|
||||
|
||||
incomingCallWidget.reset(false);
|
||||
incomingCallWidget.setVisibility(View.VISIBLE);
|
||||
redphoneLabel.setVisibility(View.VISIBLE);
|
||||
|
||||
Util.runOnMainDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (incomingCallWidget.getVisibility() == View.VISIBLE) {
|
||||
incomingCallWidget.ping();
|
||||
Util.runOnMainDelayed(this, 1200);
|
||||
}
|
||||
}
|
||||
}, 500);
|
||||
}
|
||||
|
||||
public void setActiveCall() {
|
||||
incomingCallWidget.setVisibility(View.GONE);
|
||||
redphoneLabel.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
public void setActiveCall(@Nullable String sas) {
|
||||
setActiveCall();
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
incomingCallWidget.setVisibility(View.GONE);
|
||||
redphoneLabel.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
public void setIncomingCallActionListener(final IncomingCallActionListener listener) {
|
||||
incomingCallWidget.setOnTriggerListener(new MultiWaveView.OnTriggerListener() {
|
||||
@Override
|
||||
public void onTrigger(View v, int target) {
|
||||
switch (target) {
|
||||
case 0: listener.onAcceptClick(); break;
|
||||
case 2: listener.onDenyClick(); break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReleased(View v, int handle) {}
|
||||
|
||||
@Override
|
||||
public void onGrabbedStateChange(View v, int handle) {}
|
||||
|
||||
@Override
|
||||
public void onGrabbed(View v, int handle) {}
|
||||
});
|
||||
}
|
||||
|
||||
private void initialize() {
|
||||
LayoutInflater inflater = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
inflater.inflate(R.layout.webrtc_incoming_call_overlay, this, true);
|
||||
|
||||
this.incomingCallWidget = (MultiWaveView)findViewById(R.id.incomingCallWidget);
|
||||
this.redphoneLabel = (TextView)findViewById(R.id.redphone_banner);
|
||||
}
|
||||
|
||||
public static interface IncomingCallActionListener {
|
||||
public void onAcceptClick();
|
||||
public void onDenyClick();
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user