diff --git a/ring-android/app/src/main/java/cx/ring/fragments/CallFragment.java b/ring-android/app/src/main/java/cx/ring/fragments/CallFragment.java index 97b804bf8d2ad739e14917f7e2cf53825a8e4591..e35cf8caa1d2d35462f62288e89796de14a441c0 100644 --- a/ring-android/app/src/main/java/cx/ring/fragments/CallFragment.java +++ b/ring-android/app/src/main/java/cx/ring/fragments/CallFragment.java @@ -21,6 +21,7 @@ package cx.ring.fragments; import android.Manifest; +import android.animation.ValueAnimator; import android.annotation.SuppressLint; import android.app.Activity; import android.app.PendingIntent; @@ -32,6 +33,7 @@ import android.content.Intent; import android.content.pm.PackageManager; import android.graphics.Matrix; import android.graphics.PixelFormat; +import android.graphics.PointF; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.SurfaceTexture; @@ -48,6 +50,7 @@ import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; +import android.view.MotionEvent; import android.view.OrientationEventListener; import android.view.Surface; import android.view.SurfaceHolder; @@ -55,6 +58,7 @@ import android.view.TextureView; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; +import android.view.animation.DecelerateInterpolator; import android.view.inputmethod.InputMethodManager; import android.widget.RelativeLayout; import android.widget.Toast; @@ -145,6 +149,10 @@ public class CallFragment extends BaseSupportFragment<CallPresenter> implements private ConfParticipantAdapter confAdapter = null; private boolean mConferenceMode = false; + private PointF previewDrag = null; + private final ValueAnimator previewSnapAnimation = new ValueAnimator(); + private final int[] previewMargins = new int[4]; + @Inject DeviceRuntimeService mDeviceRuntimeService; @@ -322,6 +330,7 @@ public class CallFragment extends BaseSupportFragment<CallPresenter> implements } }; + @SuppressLint("ClickableViewAccessibility") @Override public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { setHasOptionsMenu(true); @@ -400,6 +409,89 @@ public class CallFragment extends BaseSupportFragment<CallPresenter> implements binding.previewSurface.addOnLayoutChangeListener((v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> configureTransform(mPreviewSurfaceWidth, mPreviewSurfaceHeight)); + float margin = getResources().getDimension(R.dimen.call_preview_margin); + previewSnapAnimation.setDuration(250); + previewSnapAnimation.setFloatValues(0.f, 1.f); + previewSnapAnimation.setInterpolator(new DecelerateInterpolator()); + previewSnapAnimation.addUpdateListener(animation -> { + RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) binding.previewContainer.getLayoutParams(); + float f = margin * animation.getAnimatedFraction(); + float r = 1.f - animation.getAnimatedFraction(); + params.setMargins( + (int)(previewMargins[0] * r + f), + (int)(previewMargins[1] * r + f), + (int)(previewMargins[2] * r + f), + (int)(previewMargins[3] * r + f)); + binding.previewContainer.setLayoutParams(params); + }); + + binding.previewContainer.setOnTouchListener((v, event) -> { + int action = event.getActionMasked(); + if (action == MotionEvent.ACTION_DOWN) { + previewSnapAnimation.cancel(); + previewDrag = new PointF(event.getX(), event.getY()); + v.setElevation(v.getContext().getResources().getDimension(R.dimen.call_preview_elevation_dragged)); + RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) v.getLayoutParams(); + params.removeRule(RelativeLayout.ALIGN_PARENT_RIGHT); + params.removeRule(RelativeLayout.ALIGN_PARENT_BOTTOM); + params.addRule(RelativeLayout.ALIGN_PARENT_TOP); + params.addRule(RelativeLayout.ALIGN_PARENT_LEFT); + params.setMargins((int)v.getX(), (int)v.getY(), 0, 0); + v.setLayoutParams(params); + return true; + } else if (action == MotionEvent.ACTION_MOVE) { + if (previewDrag != null) { + RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) v.getLayoutParams(); + RelativeLayout parent = (RelativeLayout) v.getParent(); + params.setMargins( + Math.min(params.leftMargin + (int) (event.getX() - previewDrag.x), parent.getWidth() - v.getWidth() - (int)margin), + Math.min(params.topMargin + (int) (event.getY() - previewDrag.y), parent.getHeight() - v.getHeight() - (int)margin), + 0, 0); + v.setLayoutParams(params); + return true; + } + return false; + } else if (action == MotionEvent.ACTION_UP) { + if (previewDrag != null) { + previewSnapAnimation.cancel(); + previewDrag = null; + v.setElevation(v.getContext().getResources().getDimension(R.dimen.call_preview_elevation)); + RelativeLayout parent = (RelativeLayout) v.getParent(); + RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) v.getLayoutParams(); + int ml = 0, mr = 0, mt = 0, mb = 0; + if (params.leftMargin + (v.getWidth() / 2) > parent.getWidth() / 2) { + params.removeRule(RelativeLayout.ALIGN_PARENT_LEFT); + params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT); + mr = (int) (parent.getWidth() - v.getWidth() - v.getX()); + } else { + params.removeRule(RelativeLayout.ALIGN_PARENT_RIGHT); + params.addRule(RelativeLayout.ALIGN_PARENT_LEFT); + ml = (int) v.getX(); + } + if (params.topMargin + (v.getHeight() / 2) > parent.getHeight() / 2) { + params.removeRule(RelativeLayout.ALIGN_PARENT_TOP); + params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM); + mb = (int) (parent.getHeight() - v.getHeight() - v.getY()); + } else { + params.removeRule(RelativeLayout.ALIGN_PARENT_BOTTOM); + params.addRule(RelativeLayout.ALIGN_PARENT_TOP); + mt = (int) v.getY(); + } + previewMargins[0] = ml; + previewMargins[1] = mt; + previewMargins[2] = mr; + previewMargins[3] = mb; + params.setMargins(ml, mt, mr, mb); + v.setLayoutParams(params); + previewSnapAnimation.start(); + return true; + } + return false; + } else { + return false; + } + }); + binding.dialpadEditText.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { diff --git a/ring-android/app/src/main/res/layout/frag_call.xml b/ring-android/app/src/main/res/layout/frag_call.xml index b8e3a9589eac284981e8e4e9e09abb213d9f6280..67890604a0a2274456403eb90ca3bd1633fa5b0a 100644 --- a/ring-android/app/src/main/res/layout/frag_call.xml +++ b/ring-android/app/src/main/res/layout/frag_call.xml @@ -51,12 +51,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. android:id="@+id/preview_container" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_alignParentEnd="true" + android:layout_alignParentRight="true" android:layout_alignParentBottom="true" - android:layout_marginStart="12dp" - android:layout_marginTop="12dp" - android:layout_marginEnd="12dp" - android:layout_marginBottom="12dp" + android:layout_marginLeft="@dimen/call_preview_margin" + android:layout_marginTop="@dimen/call_preview_margin" + android:layout_marginBottom="@dimen/call_preview_margin" + android:layout_marginRight="@dimen/call_preview_margin" android:visibility="gone" app:cardCornerRadius="16dp" app:cardPreventCornerOverlap="false" diff --git a/ring-android/app/src/main/res/values/dimens.xml b/ring-android/app/src/main/res/values/dimens.xml index 74d51101657bc9cee2522ceb26890b91cb6b302e..b48f67672988db2332a78a34d77942b5e366b717 100644 --- a/ring-android/app/src/main/res/values/dimens.xml +++ b/ring-android/app/src/main/res/values/dimens.xml @@ -69,4 +69,8 @@ along with this program; if not, write to the Free Software <dimen name="navigation_bottom_height">60dp</dimen> + <dimen name="call_preview_elevation">8dp</dimen> + <dimen name="call_preview_elevation_dragged">16dp</dimen> + <dimen name="call_preview_margin">12dp</dimen> + </resources> \ No newline at end of file