diff options
Diffstat (limited to 'app/src/main/java/com/wireguard/android/widget')
10 files changed, 0 insertions, 1300 deletions
diff --git a/app/src/main/java/com/wireguard/android/widget/KeyInputFilter.java b/app/src/main/java/com/wireguard/android/widget/KeyInputFilter.java deleted file mode 100644 index 79572aa3..00000000 --- a/app/src/main/java/com/wireguard/android/widget/KeyInputFilter.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright © 2017-2019 WireGuard LLC. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -package com.wireguard.android.widget; - -import androidx.annotation.Nullable; -import android.text.InputFilter; -import android.text.SpannableStringBuilder; -import android.text.Spanned; - -import com.wireguard.crypto.Key; - -/** - * InputFilter for entering WireGuard private/public keys encoded with base64. - */ - -public class KeyInputFilter implements InputFilter { - private static boolean isAllowed(final char c) { - return Character.isLetterOrDigit(c) || c == '+' || c == '/'; - } - - public static InputFilter newInstance() { - return new KeyInputFilter(); - } - - @Nullable - @Override - public CharSequence filter(final CharSequence source, - final int sStart, final int sEnd, - final Spanned dest, - final int dStart, final int dEnd) { - SpannableStringBuilder replacement = null; - int rIndex = 0; - final int dLength = dest.length(); - for (int sIndex = sStart; sIndex < sEnd; ++sIndex) { - final char c = source.charAt(sIndex); - final int dIndex = dStart + (sIndex - sStart); - // Restrict characters to the base64 character set. - // Ensure adding this character does not push the length over the limit. - if (((dIndex + 1 < Key.Format.BASE64.getLength() && isAllowed(c)) || - (dIndex + 1 == Key.Format.BASE64.getLength() && c == '=')) && - dLength + (sIndex - sStart) < Key.Format.BASE64.getLength()) { - ++rIndex; - } else { - if (replacement == null) - replacement = new SpannableStringBuilder(source, sStart, sEnd); - replacement.delete(rIndex, rIndex + 1); - } - } - return replacement; - } -} diff --git a/app/src/main/java/com/wireguard/android/widget/MultiselectableRelativeLayout.java b/app/src/main/java/com/wireguard/android/widget/MultiselectableRelativeLayout.java deleted file mode 100644 index 2fe9c924..00000000 --- a/app/src/main/java/com/wireguard/android/widget/MultiselectableRelativeLayout.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright © 2017-2019 WireGuard LLC. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -package com.wireguard.android.widget; - -import android.content.Context; -import android.util.AttributeSet; -import android.widget.RelativeLayout; - -import com.wireguard.android.R; - -public class MultiselectableRelativeLayout extends RelativeLayout { - private static final int[] STATE_MULTISELECTED = {R.attr.state_multiselected}; - private boolean multiselected; - - public MultiselectableRelativeLayout(final Context context) { - super(context); - } - - public MultiselectableRelativeLayout(final Context context, final AttributeSet attrs) { - super(context, attrs); - } - - public MultiselectableRelativeLayout(final Context context, final AttributeSet attrs, final int defStyleAttr) { - super(context, attrs, defStyleAttr); - } - - public MultiselectableRelativeLayout(final Context context, final AttributeSet attrs, final int defStyleAttr, final int defStyleRes) { - super(context, attrs, defStyleAttr, defStyleRes); - } - - @Override - protected int[] onCreateDrawableState(final int extraSpace) { - if (multiselected) { - final int[] drawableState = super.onCreateDrawableState(extraSpace + 1); - mergeDrawableStates(drawableState, STATE_MULTISELECTED); - return drawableState; - } - return super.onCreateDrawableState(extraSpace); - } - - public void setMultiSelected(final boolean on) { - if (!multiselected) { - multiselected = true; - refreshDrawableState(); - } - setActivated(on); - } - - public void setSingleSelected(final boolean on) { - if (multiselected) { - multiselected = false; - refreshDrawableState(); - } - setActivated(on); - } -} diff --git a/app/src/main/java/com/wireguard/android/widget/NameInputFilter.java b/app/src/main/java/com/wireguard/android/widget/NameInputFilter.java deleted file mode 100644 index 07759a18..00000000 --- a/app/src/main/java/com/wireguard/android/widget/NameInputFilter.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright © 2017-2019 WireGuard LLC. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -package com.wireguard.android.widget; - -import androidx.annotation.Nullable; -import android.text.InputFilter; -import android.text.SpannableStringBuilder; -import android.text.Spanned; - -import com.wireguard.android.model.Tunnel; - -/** - * InputFilter for entering WireGuard configuration names (Linux interface names). - */ - -public class NameInputFilter implements InputFilter { - private static boolean isAllowed(final char c) { - return Character.isLetterOrDigit(c) || "_=+.-".indexOf(c) >= 0; - } - - public static InputFilter newInstance() { - return new NameInputFilter(); - } - - @Nullable - @Override - public CharSequence filter(final CharSequence source, - final int sStart, final int sEnd, - final Spanned dest, - final int dStart, final int dEnd) { - SpannableStringBuilder replacement = null; - int rIndex = 0; - final int dLength = dest.length(); - for (int sIndex = sStart; sIndex < sEnd; ++sIndex) { - final char c = source.charAt(sIndex); - final int dIndex = dStart + (sIndex - sStart); - // Restrict characters to those valid in interfaces. - // Ensure adding this character does not push the length over the limit. - if ((dIndex < Tunnel.NAME_MAX_LENGTH && isAllowed(c)) && - dLength + (sIndex - sStart) < Tunnel.NAME_MAX_LENGTH) { - ++rIndex; - } else { - if (replacement == null) - replacement = new SpannableStringBuilder(source, sStart, sEnd); - replacement.delete(rIndex, rIndex + 1); - } - } - return replacement; - } -} diff --git a/app/src/main/java/com/wireguard/android/widget/SlashDrawable.java b/app/src/main/java/com/wireguard/android/widget/SlashDrawable.java deleted file mode 100644 index 9fddbe6f..00000000 --- a/app/src/main/java/com/wireguard/android/widget/SlashDrawable.java +++ /dev/null @@ -1,217 +0,0 @@ -/* - * Copyright © 2018 The Android Open Source Project - * Copyright © 2018-2019 WireGuard LLC. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -package com.wireguard.android.widget; - -import android.animation.ObjectAnimator; -import android.animation.ValueAnimator; -import android.annotation.TargetApi; -import android.content.res.ColorStateList; -import android.graphics.Canvas; -import android.graphics.ColorFilter; -import android.graphics.Matrix; -import android.graphics.Paint; -import android.graphics.Path; -import android.graphics.Path.Direction; -import android.graphics.PixelFormat; -import android.graphics.PorterDuff.Mode; -import android.graphics.Rect; -import android.graphics.RectF; -import android.graphics.Region; -import android.graphics.drawable.Drawable; -import android.os.Build; -import androidx.annotation.ColorInt; -import androidx.annotation.IntRange; -import androidx.annotation.Nullable; -import android.util.FloatProperty; - -@TargetApi(Build.VERSION_CODES.N) -public class SlashDrawable extends Drawable { - - private static final float CENTER_X = 10.65f; - private static final float CENTER_Y = 11.869239f; - private static final float CORNER_RADIUS = Build.VERSION.SDK_INT < Build.VERSION_CODES.O ? 0f : 1f; - // Draw the slash washington-monument style; rotate to no-u-turn style - private static final float DEFAULT_ROTATION = -45f; - private static final long QS_ANIM_LENGTH = 350; - private static final float SCALE = 24f; - private static final float SLASH_HEIGHT = 28f; - // These values are derived in un-rotated (vertical) orientation - private static final float SLASH_WIDTH = 1.8384776f; - // Bottom is derived during animation - private static final float LEFT = (CENTER_X - (SLASH_WIDTH / 2)) / SCALE; - private static final float RIGHT = (CENTER_X + (SLASH_WIDTH / 2)) / SCALE; - private static final float TOP = (CENTER_Y - (SLASH_HEIGHT / 2)) / SCALE; - private static final FloatProperty mSlashLengthProp = new FloatProperty<SlashDrawable>("slashLength") { - @Override - public Float get(final SlashDrawable object) { - return object.mCurrentSlashLength; - } - - @Override - public void setValue(final SlashDrawable object, final float value) { - object.mCurrentSlashLength = value; - } - }; - private final Drawable mDrawable; - private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - private final Path mPath = new Path(); - private final RectF mSlashRect = new RectF(0, 0, 0, 0); - private boolean mAnimationEnabled = true; - // Animate this value on change - private float mCurrentSlashLength; - private float mRotation; - private boolean mSlashed; - - public SlashDrawable(final Drawable d) { - mDrawable = d; - } - - @SuppressWarnings("deprecation") - @Override - public void draw(final Canvas canvas) { - canvas.save(); - final Matrix m = new Matrix(); - final int width = getBounds().width(); - final int height = getBounds().height(); - final float radiusX = scale(CORNER_RADIUS, width); - final float radiusY = scale(CORNER_RADIUS, height); - updateRect( - scale(LEFT, width), - scale(TOP, height), - scale(RIGHT, width), - scale(TOP + mCurrentSlashLength, height) - ); - - mPath.reset(); - // Draw the slash vertically - mPath.addRoundRect(mSlashRect, radiusX, radiusY, Direction.CW); - // Rotate -45 + desired rotation - m.setRotate(mRotation + DEFAULT_ROTATION, width / 2, height / 2); - mPath.transform(m); - canvas.drawPath(mPath, mPaint); - - // Rotate back to vertical - m.setRotate(-mRotation - DEFAULT_ROTATION, width / 2, height / 2); - mPath.transform(m); - - // Draw another rect right next to the first, for clipping - m.setTranslate(mSlashRect.width(), 0); - mPath.transform(m); - mPath.addRoundRect(mSlashRect, 1.0f * width, 1.0f * height, Direction.CW); - m.setRotate(mRotation + DEFAULT_ROTATION, width / 2, height / 2); - mPath.transform(m); - - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) - canvas.clipPath(mPath, Region.Op.DIFFERENCE); - else - canvas.clipOutPath(mPath); - - mDrawable.draw(canvas); - canvas.restore(); - } - - @Override - public int getIntrinsicHeight() { - return mDrawable.getIntrinsicHeight(); - } - - @Override - public int getIntrinsicWidth() { - return mDrawable.getIntrinsicWidth(); - } - - @SuppressWarnings("deprecation") - @Override - public int getOpacity() { - return PixelFormat.OPAQUE; - } - - @Override - protected void onBoundsChange(final Rect bounds) { - super.onBoundsChange(bounds); - mDrawable.setBounds(bounds); - } - - private float scale(final float frac, final int width) { - return frac * width; - } - - @Override - public void setAlpha(@IntRange(from = 0, to = 255) final int alpha) { - mDrawable.setAlpha(alpha); - mPaint.setAlpha(alpha); - } - - public void setAnimationEnabled(final boolean enabled) { - mAnimationEnabled = enabled; - } - - @Override - public void setColorFilter(@Nullable final ColorFilter colorFilter) { - mDrawable.setColorFilter(colorFilter); - mPaint.setColorFilter(colorFilter); - } - - private void setDrawableTintList(@Nullable final ColorStateList tint) { - mDrawable.setTintList(tint); - } - - public void setRotation(final float rotation) { - if (mRotation == rotation) - return; - mRotation = rotation; - invalidateSelf(); - } - - @SuppressWarnings("unchecked") - public void setSlashed(final boolean slashed) { - if (mSlashed == slashed) return; - - mSlashed = slashed; - - final float end = mSlashed ? SLASH_HEIGHT / SCALE : 0f; - final float start = mSlashed ? 0f : SLASH_HEIGHT / SCALE; - - if (mAnimationEnabled) { - final ObjectAnimator anim = ObjectAnimator.ofFloat(this, mSlashLengthProp, start, end); - anim.addUpdateListener((ValueAnimator valueAnimator) -> invalidateSelf()); - anim.setDuration(QS_ANIM_LENGTH); - anim.start(); - } else { - mCurrentSlashLength = end; - invalidateSelf(); - } - } - - @Override - public void setTint(@ColorInt final int tintColor) { - super.setTint(tintColor); - mDrawable.setTint(tintColor); - mPaint.setColor(tintColor); - } - - @Override - public void setTintList(@Nullable final ColorStateList tint) { - super.setTintList(tint); - setDrawableTintList(tint); - mPaint.setColor(tint == null ? 0 : tint.getDefaultColor()); - invalidateSelf(); - } - - @Override - public void setTintMode(final Mode tintMode) { - super.setTintMode(tintMode); - mDrawable.setTintMode(tintMode); - } - - private void updateRect(final float left, final float top, final float right, final float bottom) { - mSlashRect.left = left; - mSlashRect.top = top; - mSlashRect.right = right; - mSlashRect.bottom = bottom; - } -} diff --git a/app/src/main/java/com/wireguard/android/widget/ToggleSwitch.java b/app/src/main/java/com/wireguard/android/widget/ToggleSwitch.java deleted file mode 100644 index dcb9aceb..00000000 --- a/app/src/main/java/com/wireguard/android/widget/ToggleSwitch.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright © 2013 The Android Open Source Project - * Copyright © 2017-2019 WireGuard LLC. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -package com.wireguard.android.widget; - -import android.content.Context; -import android.os.Parcelable; -import androidx.annotation.Nullable; -import android.util.AttributeSet; -import android.widget.Switch; - -public class ToggleSwitch extends Switch { - private boolean isRestoringState; - @Nullable private OnBeforeCheckedChangeListener listener; - - public ToggleSwitch(final Context context) { - this(context, null); - } - - @SuppressWarnings({"SameParameterValue", "WeakerAccess"}) - public ToggleSwitch(final Context context, @Nullable final AttributeSet attrs) { - super(context, attrs); - } - - @Override - public void onRestoreInstanceState(final Parcelable state) { - isRestoringState = true; - super.onRestoreInstanceState(state); - isRestoringState = false; - } - - @Override - public void setChecked(final boolean checked) { - if (checked == isChecked()) - return; - if (isRestoringState || listener == null) { - super.setChecked(checked); - return; - } - setEnabled(false); - listener.onBeforeCheckedChanged(this, checked); - } - - public void setCheckedInternal(final boolean checked) { - super.setChecked(checked); - setEnabled(true); - } - - public void setOnBeforeCheckedChangeListener(final OnBeforeCheckedChangeListener listener) { - this.listener = listener; - } - - public interface OnBeforeCheckedChangeListener { - void onBeforeCheckedChanged(ToggleSwitch toggleSwitch, boolean checked); - } -} diff --git a/app/src/main/java/com/wireguard/android/widget/fab/FloatingActionButtonBehavior.java b/app/src/main/java/com/wireguard/android/widget/fab/FloatingActionButtonBehavior.java deleted file mode 100644 index 616e176e..00000000 --- a/app/src/main/java/com/wireguard/android/widget/fab/FloatingActionButtonBehavior.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright © 2017-2019 WireGuard LLC. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -package com.wireguard.android.widget.fab; - -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.animation.TimeInterpolator; -import android.animation.ValueAnimator; -import android.content.Context; -import androidx.coordinatorlayout.widget.CoordinatorLayout; -import com.google.android.material.snackbar.Snackbar; -import androidx.interpolator.view.animation.FastOutSlowInInterpolator; -import android.util.AttributeSet; -import android.view.View; - -public class FloatingActionButtonBehavior extends CoordinatorLayout.Behavior<FloatingActionsMenu> { - - private static final long ANIMATION_DURATION = 250; - private static final TimeInterpolator FAST_OUT_SLOW_IN_INTERPOLATOR = new FastOutSlowInInterpolator(); - - public FloatingActionButtonBehavior(final Context context, final AttributeSet attrs) { - super(context, attrs); - } - - private static void animateChange(final FloatingActionsMenu child, final float destination, final float fullSpan) { - final float origin = child.getBehaviorYTranslation(); - if (Math.abs(destination - origin) < fullSpan / 2) { - child.setBehaviorYTranslation(destination); - return; - } - final ValueAnimator animator = new ValueAnimator(); - animator.setFloatValues(origin, destination); - animator.setInterpolator(FAST_OUT_SLOW_IN_INTERPOLATOR); - animator.setDuration((long) (ANIMATION_DURATION * (Math.abs(destination - origin) / fullSpan))); - animator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(final Animator a) { - child.setBehaviorYTranslation(destination); - } - }); - animator.addUpdateListener(a -> child.setBehaviorYTranslation((float) a.getAnimatedValue())); - animator.start(); - } - - @Override - public boolean layoutDependsOn(final CoordinatorLayout parent, final FloatingActionsMenu child, - final View dependency) { - return dependency instanceof Snackbar.SnackbarLayout; - } - - @Override - public boolean onDependentViewChanged(final CoordinatorLayout parent, final FloatingActionsMenu child, - final View dependency) { - animateChange(child, Math.min(0, dependency.getTranslationY() - dependency.getMeasuredHeight()), dependency.getMeasuredHeight()); - return true; - } - - @Override - public void onDependentViewRemoved(final CoordinatorLayout parent, final FloatingActionsMenu child, - final View dependency) { - animateChange(child, 0, dependency.getMeasuredHeight()); - } -} diff --git a/app/src/main/java/com/wireguard/android/widget/fab/FloatingActionsMenu.java b/app/src/main/java/com/wireguard/android/widget/fab/FloatingActionsMenu.java deleted file mode 100644 index 9704081b..00000000 --- a/app/src/main/java/com/wireguard/android/widget/fab/FloatingActionsMenu.java +++ /dev/null @@ -1,629 +0,0 @@ -/* - * Copyright © 2014 Jerzy Chalupski - * Copyright © 2017-2019 WireGuard LLC. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -package com.wireguard.android.widget.fab; - -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.animation.AnimatorSet; -import android.animation.ObjectAnimator; -import android.animation.TimeInterpolator; -import android.content.Context; -import android.content.res.TypedArray; -import android.graphics.Canvas; -import android.graphics.Rect; -import android.graphics.drawable.Drawable; -import android.graphics.drawable.LayerDrawable; -import android.os.Build; -import android.os.Parcel; -import android.os.Parcelable; -import androidx.annotation.Keep; -import androidx.annotation.Nullable; -import com.google.android.material.floatingactionbutton.FloatingActionButton; -import androidx.core.content.res.ResourcesCompat; -import androidx.appcompat.widget.AppCompatTextView; -import android.util.AttributeSet; -import android.view.ContextThemeWrapper; -import android.view.TouchDelegate; -import android.view.View; -import android.view.ViewGroup; -import android.view.animation.DecelerateInterpolator; -import android.view.animation.OvershootInterpolator; -import android.widget.TextView; - -import com.wireguard.android.R; - -public class FloatingActionsMenu extends ViewGroup { - public static final int EXPAND_DOWN = 1; - public static final int EXPAND_LEFT = 2; - public static final int EXPAND_RIGHT = 3; - public static final int EXPAND_UP = 0; - public static final int LABELS_ON_LEFT_SIDE = 0; - public static final int LABELS_ON_RIGHT_SIDE = 1; - private static final TimeInterpolator ALPHA_EXPAND_INTERPOLATOR = new DecelerateInterpolator(); - private static final int ANIMATION_DURATION = 300; - private static final boolean BROKEN_LABEL_STYLE = Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1 && Build.BRAND.equals("ASUS"); - private static final float COLLAPSED_PLUS_ROTATION = 0f; - private static final TimeInterpolator COLLAPSE_INTERPOLATOR = new DecelerateInterpolator(3f); - private static final float EXPANDED_PLUS_ROTATION = 90f + 45f; - private static final TimeInterpolator EXPAND_INTERPOLATOR = new OvershootInterpolator(); - private final AnimatorSet mCollapseAnimation = new AnimatorSet().setDuration(ANIMATION_DURATION); - private final AnimatorSet mExpandAnimation = new AnimatorSet().setDuration(ANIMATION_DURATION); - private final Rect touchArea = new Rect(0, 0, 0, 0); - private float behaviorYTranslation; - @Nullable private FloatingActionButton mAddButton; - private int mButtonSpacing; - private int mButtonsCount; - private int mExpandDirection; - private boolean mExpanded; - private int mLabelsMargin; - private int mLabelsPosition; - private int mLabelsStyle; - private int mLabelsVerticalOffset; - @Nullable private OnFloatingActionsMenuUpdateListener mListener; - private int mMaxButtonHeight; - private int mMaxButtonWidth; - @Nullable private RotatingDrawable mRotatingDrawable; - @Nullable private TouchDelegateGroup mTouchDelegateGroup; - private float scrollYTranslation; - - public FloatingActionsMenu(final Context context) { - this(context, null); - } - - public FloatingActionsMenu(final Context context, @Nullable final AttributeSet attrs) { - super(context, attrs); - init(context, attrs); - } - - public FloatingActionsMenu(final Context context, @Nullable final AttributeSet attrs, final int defStyle) { - super(context, attrs, defStyle); - init(context, attrs); - } - - private static int adjustForOvershoot(final int dimension) { - return dimension * 12 / 10; - } - - public void addButton(final LabeledFloatingActionButton button) { - addView(button, mButtonsCount - 1); - mButtonsCount++; - - if (mLabelsStyle != 0) { - createLabels(); - } - } - - public void collapse() { - collapse(false); - } - - private void collapse(final boolean immediately) { - if (mExpanded) { - mExpanded = false; - mTouchDelegateGroup.setEnabled(false); - mCollapseAnimation.setDuration(immediately ? 0 : ANIMATION_DURATION); - mCollapseAnimation.start(); - mExpandAnimation.cancel(); - - if (mListener != null) { - mListener.onMenuCollapsed(); - } - } - } - - public void collapseImmediately() { - collapse(true); - } - - private void createAddButton(final Context context) { - final RotatingDrawable rotatingDrawable = new RotatingDrawable(ResourcesCompat.getDrawable(context.getResources(), R.drawable.ic_action_add_white, context.getTheme())); - mRotatingDrawable = rotatingDrawable; - - final TimeInterpolator interpolator = new OvershootInterpolator(); - - final ObjectAnimator collapseAnimator = ObjectAnimator.ofFloat(rotatingDrawable, "rotation", EXPANDED_PLUS_ROTATION, COLLAPSED_PLUS_ROTATION); - final ObjectAnimator expandAnimator = ObjectAnimator.ofFloat(rotatingDrawable, "rotation", COLLAPSED_PLUS_ROTATION, EXPANDED_PLUS_ROTATION); - - collapseAnimator.setInterpolator(interpolator); - expandAnimator.setInterpolator(interpolator); - - mExpandAnimation.play(expandAnimator); - mCollapseAnimation.play(collapseAnimator); - - mAddButton = new FloatingActionButton(context); - mAddButton.setImageDrawable(rotatingDrawable); - mAddButton.setId(R.id.fab_expand_menu_button); - mAddButton.setOnClickListener(v -> toggle()); - - addView(mAddButton, super.generateDefaultLayoutParams()); - mButtonsCount++; - } - - private void createLabels() { - final Context context = BROKEN_LABEL_STYLE ? getContext() : new ContextThemeWrapper(getContext(), mLabelsStyle); - - for (int i = 0; i < mButtonsCount; i++) { - final FloatingActionButton button = (FloatingActionButton) getChildAt(i); - - if (button instanceof LabeledFloatingActionButton) { - final String title = ((LabeledFloatingActionButton) button).getTitle(); - - final AppCompatTextView label = new AppCompatTextView(context); - if (!BROKEN_LABEL_STYLE) - label.setTextAppearance(context, mLabelsStyle); - label.setText(title); - addView(label); - - button.setTag(R.id.fab_label, label); - } - } - } - - public void expand() { - if (!mExpanded) { - mExpanded = true; - mTouchDelegateGroup.setEnabled(true); - mCollapseAnimation.cancel(); - mExpandAnimation.start(); - - if (mListener != null) { - mListener.onMenuExpanded(); - } - } - } - - private boolean expandsHorizontally() { - return mExpandDirection == EXPAND_LEFT || mExpandDirection == EXPAND_RIGHT; - } - - @Override - protected ViewGroup.LayoutParams generateDefaultLayoutParams() { - return new LayoutParams(super.generateDefaultLayoutParams()); - } - - @Override - public ViewGroup.LayoutParams generateLayoutParams(final AttributeSet attrs) { - return new LayoutParams(super.generateLayoutParams(attrs)); - } - - @Override - protected ViewGroup.LayoutParams generateLayoutParams(final ViewGroup.LayoutParams p) { - return new LayoutParams(super.generateLayoutParams(p)); - } - - public float getBehaviorYTranslation() { - return behaviorYTranslation; - } - - public float getScrollYTranslation() { - return scrollYTranslation; - } - - private void init(final Context context, @Nullable final AttributeSet attributeSet) { - mButtonSpacing = (int) (getResources().getDimension(R.dimen.fab_actions_spacing)); - mLabelsMargin = getResources().getDimensionPixelSize(R.dimen.fab_labels_margin); - mLabelsVerticalOffset = getResources().getDimensionPixelSize(R.dimen.fab_shadow_offset); - - mTouchDelegateGroup = new TouchDelegateGroup(this); - setTouchDelegate(mTouchDelegateGroup); - - final TypedArray attr = context.obtainStyledAttributes(attributeSet, R.styleable.FloatingActionsMenu, 0, 0); - mExpandDirection = attr.getInt(R.styleable.FloatingActionsMenu_fab_expandDirection, EXPAND_UP); - mLabelsStyle = attr.getResourceId(R.styleable.FloatingActionsMenu_fab_labelStyle, 0); - mLabelsPosition = attr.getInt(R.styleable.FloatingActionsMenu_fab_labelsPosition, LABELS_ON_LEFT_SIDE); - attr.recycle(); - - if (mLabelsStyle != 0 && expandsHorizontally()) { - throw new IllegalStateException("Action labels in horizontal expand orientation are not supported"); - } - - createAddButton(context); - } - - public boolean isExpanded() { - return mExpanded; - } - - @Override - protected void onFinishInflate() { - super.onFinishInflate(); - - bringChildToFront(mAddButton); - mButtonsCount = getChildCount(); - - if (mLabelsStyle != 0) { - createLabels(); - } - } - - @Override - protected void onLayout(final boolean changed, final int l, final int t, final int r, final int b) { - switch (mExpandDirection) { - case EXPAND_UP: - case EXPAND_DOWN: - final boolean expandUp = mExpandDirection == EXPAND_UP; - - if (changed) { - mTouchDelegateGroup.clearTouchDelegates(); - } - - final int addButtonY = expandUp ? b - t - mAddButton.getMeasuredHeight() : 0; - // Ensure mAddButton is centered on the line where the buttons should be - final int buttonsHorizontalCenter = (mLabelsPosition == LABELS_ON_LEFT_SIDE - ? r - l - mMaxButtonWidth / 2 - : mMaxButtonWidth / 2); - final int addButtonLeft = buttonsHorizontalCenter - mAddButton.getMeasuredWidth() / 2; - mAddButton.layout(addButtonLeft, addButtonY, addButtonLeft + mAddButton.getMeasuredWidth(), addButtonY + mAddButton.getMeasuredHeight()); - - final int labelsOffset = mMaxButtonWidth / 2 + mLabelsMargin; - final int labelsXNearButton = mLabelsPosition == LABELS_ON_LEFT_SIDE - ? buttonsHorizontalCenter - labelsOffset - : buttonsHorizontalCenter + labelsOffset; - - int nextY = expandUp ? - addButtonY - mButtonSpacing : - addButtonY + mAddButton.getMeasuredHeight() + mButtonSpacing; - - for (int i = mButtonsCount - 1; i >= 0; i--) { - final View child = getChildAt(i); - - if (child == mAddButton || child.getVisibility() == GONE) continue; - - final int childX = buttonsHorizontalCenter - child.getMeasuredWidth() / 2; - final int childY = expandUp ? nextY - child.getMeasuredHeight() : nextY; - child.layout(childX, childY, childX + child.getMeasuredWidth(), childY + child.getMeasuredHeight()); - - final float collapsedTranslation = addButtonY - childY; - final float expandedTranslation = 0f; - - child.setTranslationY(mExpanded ? expandedTranslation : collapsedTranslation); - child.setAlpha(mExpanded ? 1f : 0f); - - final LayoutParams params = (LayoutParams) child.getLayoutParams(); - params.mCollapseDir.setFloatValues(expandedTranslation, collapsedTranslation); - params.mExpandDir.setFloatValues(collapsedTranslation, expandedTranslation); - params.setAnimationsTarget(child); - - final View label = (View) child.getTag(R.id.fab_label); - if (label != null) { - final int labelXAwayFromButton = mLabelsPosition == LABELS_ON_LEFT_SIDE - ? labelsXNearButton - label.getMeasuredWidth() - : labelsXNearButton + label.getMeasuredWidth(); - - final int labelLeft = mLabelsPosition == LABELS_ON_LEFT_SIDE - ? labelXAwayFromButton - : labelsXNearButton; - - final int labelRight = mLabelsPosition == LABELS_ON_LEFT_SIDE - ? labelsXNearButton - : labelXAwayFromButton; - - final int labelTop = childY - mLabelsVerticalOffset + (child.getMeasuredHeight() - label.getMeasuredHeight()) / 2; - - label.layout(labelLeft, labelTop, labelRight, labelTop + label.getMeasuredHeight()); - - touchArea.set(Math.min(childX, labelLeft), - childY - mButtonSpacing / 2, - Math.max(childX + child.getMeasuredWidth(), labelRight), - childY + child.getMeasuredHeight() + mButtonSpacing / 2); - mTouchDelegateGroup.addTouchDelegate(new TouchDelegate(new Rect(touchArea), child)); - - label.setTranslationY(mExpanded ? expandedTranslation : collapsedTranslation); - label.setAlpha(mExpanded ? 1f : 0f); - - final LayoutParams labelParams = (LayoutParams) label.getLayoutParams(); - labelParams.mCollapseDir.setFloatValues(expandedTranslation, collapsedTranslation); - labelParams.mExpandDir.setFloatValues(collapsedTranslation, expandedTranslation); - labelParams.setAnimationsTarget(label); - } - - nextY = expandUp ? - childY - mButtonSpacing : - childY + child.getMeasuredHeight() + mButtonSpacing; - } - break; - - case EXPAND_LEFT: - case EXPAND_RIGHT: - final boolean expandLeft = mExpandDirection == EXPAND_LEFT; - - final int addButtonX = expandLeft ? r - l - mAddButton.getMeasuredWidth() : 0; - // Ensure mAddButton is centered on the line where the buttons should be - final int addButtonTop = b - t - mMaxButtonHeight + (mMaxButtonHeight - mAddButton.getMeasuredHeight()) / 2; - mAddButton.layout(addButtonX, addButtonTop, addButtonX + mAddButton.getMeasuredWidth(), addButtonTop + mAddButton.getMeasuredHeight()); - - int nextX = expandLeft ? - addButtonX - mButtonSpacing : - addButtonX + mAddButton.getMeasuredWidth() + mButtonSpacing; - - for (int i = mButtonsCount - 1; i >= 0; i--) { - final View child = getChildAt(i); - - if (child == mAddButton || child.getVisibility() == GONE) continue; - - final int childX = expandLeft ? nextX - child.getMeasuredWidth() : nextX; - final int childY = addButtonTop + (mAddButton.getMeasuredHeight() - child.getMeasuredHeight()) / 2; - child.layout(childX, childY, childX + child.getMeasuredWidth(), childY + child.getMeasuredHeight()); - - final float collapsedTranslation = addButtonX - childX; - final float expandedTranslation = 0f; - - child.setTranslationX(mExpanded ? expandedTranslation : collapsedTranslation); - child.setAlpha(mExpanded ? 1f : 0f); - - final LayoutParams params = (LayoutParams) child.getLayoutParams(); - params.mCollapseDir.setFloatValues(expandedTranslation, collapsedTranslation); - params.mExpandDir.setFloatValues(collapsedTranslation, expandedTranslation); - params.setAnimationsTarget(child); - - nextX = expandLeft ? - childX - mButtonSpacing : - childX + child.getMeasuredWidth() + mButtonSpacing; - } - - break; - } - } - - @Override - protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) { - measureChildren(widthMeasureSpec, heightMeasureSpec); - - int width = 0; - int height = 0; - - mMaxButtonWidth = 0; - mMaxButtonHeight = 0; - int maxLabelWidth = 0; - - for (int i = 0; i < mButtonsCount; i++) { - final View child = getChildAt(i); - - if (child.getVisibility() == GONE) { - continue; - } - - switch (mExpandDirection) { - case EXPAND_UP: - case EXPAND_DOWN: - mMaxButtonWidth = Math.max(mMaxButtonWidth, child.getMeasuredWidth()); - height += child.getMeasuredHeight(); - break; - case EXPAND_LEFT: - case EXPAND_RIGHT: - width += child.getMeasuredWidth(); - mMaxButtonHeight = Math.max(mMaxButtonHeight, child.getMeasuredHeight()); - break; - } - - if (!expandsHorizontally()) { - final TextView label = (TextView) child.getTag(R.id.fab_label); - if (label != null) { - maxLabelWidth = Math.max(maxLabelWidth, label.getMeasuredWidth()); - } - } - } - - if (expandsHorizontally()) { - height = mMaxButtonHeight; - } else { - width = mMaxButtonWidth + (maxLabelWidth > 0 ? maxLabelWidth + mLabelsMargin : 0); - } - - switch (mExpandDirection) { - case EXPAND_UP: - case EXPAND_DOWN: - height += mButtonSpacing * (mButtonsCount - 1); - height = adjustForOvershoot(height); - break; - case EXPAND_LEFT: - case EXPAND_RIGHT: - width += mButtonSpacing * (mButtonsCount - 1); - width = adjustForOvershoot(width); - break; - } - - setMeasuredDimension(width, height); - } - - @Override - public void onRestoreInstanceState(final Parcelable state) { - if (state instanceof SavedState) { - final SavedState savedState = (SavedState) state; - mExpanded = savedState.mExpanded; - mTouchDelegateGroup.setEnabled(mExpanded); - - if (mRotatingDrawable != null) { - mRotatingDrawable.setRotation(mExpanded ? EXPANDED_PLUS_ROTATION : COLLAPSED_PLUS_ROTATION); - } - - super.onRestoreInstanceState(savedState.getSuperState()); - } else { - super.onRestoreInstanceState(state); - } - } - - @Override - public Parcelable onSaveInstanceState() { - final Parcelable superState = super.onSaveInstanceState(); - final SavedState savedState = new SavedState(superState); - savedState.mExpanded = mExpanded; - - return savedState; - } - - public void removeButton(final LabeledFloatingActionButton button) { - removeView(button.getLabelView()); - removeView(button); - button.setTag(R.id.fab_label, null); - mButtonsCount--; - } - - public void setBehaviorYTranslation(final float behaviorYTranslation) { - this.behaviorYTranslation = behaviorYTranslation; - setTranslationY(behaviorYTranslation + scrollYTranslation); - } - - @Override - public void setEnabled(final boolean enabled) { - super.setEnabled(enabled); - - mAddButton.setEnabled(enabled); - } - - public void setOnFloatingActionsMenuUpdateListener(final OnFloatingActionsMenuUpdateListener listener) { - mListener = listener; - } - - public void setScrollYTranslation(final float scrollYTranslation) { - this.scrollYTranslation = scrollYTranslation; - setTranslationY(behaviorYTranslation + scrollYTranslation); - } - - public void toggle() { - if (mExpanded) { - collapse(); - } else { - expand(); - } - } - - public interface OnFloatingActionsMenuUpdateListener { - void onMenuCollapsed(); - - void onMenuExpanded(); - } - - private static class RotatingDrawable extends LayerDrawable { - private float mRotation; - - RotatingDrawable(final Drawable drawable) { - super(new Drawable[]{drawable}); - } - - @Override - public void draw(final Canvas canvas) { - canvas.save(); - canvas.rotate(mRotation, getBounds().centerX(), getBounds().centerY()); - super.draw(canvas); - canvas.restore(); - } - - @SuppressWarnings("UnusedDeclaration") - public float getRotation() { - return mRotation; - } - - @Keep - @SuppressWarnings("UnusedDeclaration") - public void setRotation(final float rotation) { - mRotation = rotation; - invalidateSelf(); - } - } - - public static class SavedState extends BaseSavedState { - public static final Creator<SavedState> CREATOR = new Creator<SavedState>() { - - @Override - public SavedState createFromParcel(final Parcel in) { - return new SavedState(in); - } - - @Override - public SavedState[] newArray(final int size) { - return new SavedState[size]; - } - }; - private boolean mExpanded; - - public SavedState(final Parcelable parcel) { - super(parcel); - } - - private SavedState(final Parcel in) { - super(in); - mExpanded = in.readInt() == 1; - } - - @Override - public void writeToParcel(final Parcel out, final int flags) { - super.writeToParcel(out, flags); - out.writeInt(mExpanded ? 1 : 0); - } - } - - private class LayoutParams extends ViewGroup.LayoutParams { - - private final ObjectAnimator mCollapseAlpha = new ObjectAnimator(); - private final ObjectAnimator mCollapseDir = new ObjectAnimator(); - private final ObjectAnimator mExpandAlpha = new ObjectAnimator(); - private final ObjectAnimator mExpandDir = new ObjectAnimator(); - private boolean animationsSetToPlay; - - LayoutParams(final ViewGroup.LayoutParams source) { - super(source); - - mExpandDir.setInterpolator(EXPAND_INTERPOLATOR); - mExpandAlpha.setInterpolator(ALPHA_EXPAND_INTERPOLATOR); - mCollapseDir.setInterpolator(COLLAPSE_INTERPOLATOR); - mCollapseAlpha.setInterpolator(COLLAPSE_INTERPOLATOR); - - mCollapseAlpha.setProperty(View.ALPHA); - mCollapseAlpha.setFloatValues(1f, 0f); - - mExpandAlpha.setProperty(View.ALPHA); - mExpandAlpha.setFloatValues(0f, 1f); - - switch (mExpandDirection) { - case EXPAND_UP: - case EXPAND_DOWN: - mCollapseDir.setProperty(View.TRANSLATION_Y); - mExpandDir.setProperty(View.TRANSLATION_Y); - break; - case EXPAND_LEFT: - case EXPAND_RIGHT: - mCollapseDir.setProperty(View.TRANSLATION_X); - mExpandDir.setProperty(View.TRANSLATION_X); - break; - } - } - - private void addLayerTypeListener(final Animator animator, final View view) { - animator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(final Animator animation) { - view.setLayerType(LAYER_TYPE_NONE, null); - } - - @Override - public void onAnimationStart(final Animator animation) { - view.setLayerType(LAYER_TYPE_HARDWARE, null); - } - }); - } - - public void setAnimationsTarget(final View view) { - mCollapseAlpha.setTarget(view); - mCollapseDir.setTarget(view); - mExpandAlpha.setTarget(view); - mExpandDir.setTarget(view); - - // Now that the animations have targets, set them to be played - if (!animationsSetToPlay) { - addLayerTypeListener(mExpandDir, view); - addLayerTypeListener(mCollapseDir, view); - - mCollapseAnimation.play(mCollapseAlpha); - mCollapseAnimation.play(mCollapseDir); - mExpandAnimation.play(mExpandAlpha); - mExpandAnimation.play(mExpandDir); - animationsSetToPlay = true; - } - } - } -} diff --git a/app/src/main/java/com/wireguard/android/widget/fab/FloatingActionsMenuRecyclerViewScrollListener.java b/app/src/main/java/com/wireguard/android/widget/fab/FloatingActionsMenuRecyclerViewScrollListener.java deleted file mode 100644 index e1af4484..00000000 --- a/app/src/main/java/com/wireguard/android/widget/fab/FloatingActionsMenuRecyclerViewScrollListener.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright © 2017-2019 WireGuard LLC. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -package com.wireguard.android.widget.fab; - -import androidx.recyclerview.widget.RecyclerView; - -public class FloatingActionsMenuRecyclerViewScrollListener extends RecyclerView.OnScrollListener { - private static final float SCALE_FACTOR = 1.5f; - private final FloatingActionsMenu menu; - - public FloatingActionsMenuRecyclerViewScrollListener(final FloatingActionsMenu menu) { - this.menu = menu; - } - - private static float bound(final float min, final float proposal, final float max) { - return Math.min(max, Math.max(min, proposal)); - } - - @Override - public void onScrolled(final RecyclerView recyclerView, final int dx, final int dy) { - super.onScrolled(recyclerView, dx, dy); - menu.setScrollYTranslation(bound(0, menu.getScrollYTranslation() + dy * SCALE_FACTOR, menu.getMeasuredHeight() - menu.getTranslationY())); - } -} diff --git a/app/src/main/java/com/wireguard/android/widget/fab/LabeledFloatingActionButton.java b/app/src/main/java/com/wireguard/android/widget/fab/LabeledFloatingActionButton.java deleted file mode 100644 index be94a6e5..00000000 --- a/app/src/main/java/com/wireguard/android/widget/fab/LabeledFloatingActionButton.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright © 2014 Jerzy Chalupski - * Copyright © 2017-2019 WireGuard LLC. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -package com.wireguard.android.widget.fab; - -import android.content.Context; -import android.content.res.TypedArray; -import androidx.annotation.Nullable; -import com.google.android.material.floatingactionbutton.FloatingActionButton; -import android.util.AttributeSet; -import android.widget.TextView; - -import com.wireguard.android.R; - -public class LabeledFloatingActionButton extends FloatingActionButton { - - @Nullable private final String title; - - public LabeledFloatingActionButton(final Context context) { - this(context, null); - } - - public LabeledFloatingActionButton(final Context context, @Nullable final AttributeSet attrs) { - this(context, attrs, 0); - } - - public LabeledFloatingActionButton(final Context context, @Nullable final AttributeSet attrs, final int defStyle) { - super(context, attrs, defStyle); - - final TypedArray attr = context.obtainStyledAttributes(attrs, R.styleable.LabeledFloatingActionButton, 0, 0); - title = attr.getString(R.styleable.LabeledFloatingActionButton_fab_title); - attr.recycle(); - } - - @Nullable - TextView getLabelView() { - return (TextView) getTag(R.id.fab_label); - } - - @Nullable - public String getTitle() { - return title; - } - - @Override - public void setVisibility(final int visibility) { - final TextView label = getLabelView(); - if (label != null) { - label.setVisibility(visibility); - } - - super.setVisibility(visibility); - } - -} diff --git a/app/src/main/java/com/wireguard/android/widget/fab/TouchDelegateGroup.java b/app/src/main/java/com/wireguard/android/widget/fab/TouchDelegateGroup.java deleted file mode 100644 index e16d1d3e..00000000 --- a/app/src/main/java/com/wireguard/android/widget/fab/TouchDelegateGroup.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright © 2014 Jerzy Chalupski - * Copyright © 2017-2019 WireGuard LLC. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -package com.wireguard.android.widget.fab; - -import android.graphics.Rect; -import androidx.annotation.Nullable; -import android.view.MotionEvent; -import android.view.TouchDelegate; -import android.view.View; - -import java.util.ArrayList; -import java.util.Collection; - -public class TouchDelegateGroup extends TouchDelegate { - private static final Rect USELESS_HACKY_RECT = new Rect(); - private final Collection<TouchDelegate> mTouchDelegates = new ArrayList<>(); - @Nullable private TouchDelegate mCurrentTouchDelegate; - private boolean mEnabled; - - public TouchDelegateGroup(final View uselessHackyView) { - super(USELESS_HACKY_RECT, uselessHackyView); - } - - public void addTouchDelegate(final TouchDelegate touchDelegate) { - mTouchDelegates.add(touchDelegate); - } - - public void clearTouchDelegates() { - mTouchDelegates.clear(); - mCurrentTouchDelegate = null; - } - - @Override - public boolean onTouchEvent(final MotionEvent event) { - if (!mEnabled) - return false; - - TouchDelegate delegate = null; - - switch (event.getAction()) { - case MotionEvent.ACTION_DOWN: - for (final TouchDelegate touchDelegate : mTouchDelegates) { - if (touchDelegate.onTouchEvent(event)) { - mCurrentTouchDelegate = touchDelegate; - return true; - } - } - break; - - case MotionEvent.ACTION_MOVE: - delegate = mCurrentTouchDelegate; - break; - - case MotionEvent.ACTION_CANCEL: - case MotionEvent.ACTION_UP: - delegate = mCurrentTouchDelegate; - mCurrentTouchDelegate = null; - break; - } - - return delegate != null && delegate.onTouchEvent(event); - } - - public void removeTouchDelegate(final TouchDelegate touchDelegate) { - mTouchDelegates.remove(touchDelegate); - if (mCurrentTouchDelegate == touchDelegate) { - mCurrentTouchDelegate = null; - } - } - - public void setEnabled(final boolean enabled) { - mEnabled = enabled; - } -} |