From 2a3f85008b14bbd28f01afc669460a1931016184 Mon Sep 17 00:00:00 2001 From: Greyson Parrelli Date: Thu, 11 Feb 2021 10:41:40 -0500 Subject: [PATCH] Do not use View.getLayoutDirection(). This value doesn't populate until after the first layout pass. Instead, it appears to be safer to just read it from the Configuration. --- .../ContactSelectionListFragment.java | 3 +- .../components/ConversationItemFooter.java | 4 +- .../securesms/components/InputPanel.java | 5 +-- .../InsetAwareConstraintLayout.java | 13 ++++++- .../components/MicrophoneRecorderView.java | 5 ++- .../webrtc/PictureInPictureGestureHelper.java | 5 ++- .../conversation/ConversationFragment.java | 4 +- .../ConversationReactionOverlay.java | 8 ++-- .../ui/managegroup/ManageGroupFragment.java | 5 ++- ...ientSettingsCoordinatorLayoutBehavior.java | 3 +- .../ManageRecipientFragment.java | 3 +- .../thoughtcrime/securesms/util/ViewUtil.java | 37 ++++++++++++++----- .../ChatWallpaperAlignmentDecoration.java | 8 ++-- 13 files changed, 68 insertions(+), 35 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/ContactSelectionListFragment.java b/app/src/main/java/org/thoughtcrime/securesms/ContactSelectionListFragment.java index 41bf769d6e..8e394aef6f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/ContactSelectionListFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/ContactSelectionListFragment.java @@ -76,6 +76,7 @@ import org.thoughtcrime.securesms.recipients.RecipientId; import org.thoughtcrime.securesms.util.StickyHeaderDecoration; import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.thoughtcrime.securesms.util.UsernameUtil; +import org.thoughtcrime.securesms.util.ViewUtil; import org.thoughtcrime.securesms.util.adapter.FixedViewsAdapter; import org.thoughtcrime.securesms.util.adapter.RecyclerViewConcatenateAdapterStickyHeader; import org.thoughtcrime.securesms.util.concurrent.SimpleTask; @@ -672,7 +673,7 @@ public final class ContactSelectionListFragment extends LoggingFragment } private void smoothScrollChipsToEnd() { - int x = chipGroupScrollContainer.getLayoutDirection() == View.LAYOUT_DIRECTION_LTR ? chipGroup.getWidth() : 0; + int x = ViewUtil.isLtr(chipGroupScrollContainer) ? chipGroup.getWidth() : 0; chipGroupScrollContainer.smoothScrollTo(x, 0); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/ConversationItemFooter.java b/app/src/main/java/org/thoughtcrime/securesms/components/ConversationItemFooter.java index 3aeff4fad6..d5256b4f88 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/ConversationItemFooter.java +++ b/app/src/main/java/org/thoughtcrime/securesms/components/ConversationItemFooter.java @@ -275,8 +275,8 @@ public class ConversationItemFooter extends LinearLayout { addView(audioDuration, 0); int padStart = ViewUtil.dpToPx(60); - int padLeft = getLayoutDirection() == LAYOUT_DIRECTION_LTR ? padStart : 0; - int padRight = getLayoutDirection() == LAYOUT_DIRECTION_RTL ? padStart : 0; + int padLeft = ViewUtil.isLtr(this) ? padStart : 0; + int padRight = ViewUtil.isRtl(this) ? padStart : 0; audioDuration.setPadding(padLeft, 0, padRight, 0); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/InputPanel.java b/app/src/main/java/org/thoughtcrime/securesms/components/InputPanel.java index 08cbfcbbd0..b937a98beb 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/InputPanel.java +++ b/app/src/main/java/org/thoughtcrime/securesms/components/InputPanel.java @@ -335,11 +335,10 @@ public class InputPanel extends LinearLayout public void onRecordMoved(float offsetX, float absoluteX) { slideToCancel.moveTo(offsetX); - int direction = ViewCompat.getLayoutDirection(this); float position = absoluteX / recordingContainer.getWidth(); - if (direction == ViewCompat.LAYOUT_DIRECTION_LTR && position <= 0.5 || - direction == ViewCompat.LAYOUT_DIRECTION_RTL && position >= 0.6) + if (ViewUtil.isLtr(this) && position <= 0.5 || + ViewUtil.isRtl(this) && position >= 0.6) { this.microphoneRecorderView.cancelAction(); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/InsetAwareConstraintLayout.java b/app/src/main/java/org/thoughtcrime/securesms/components/InsetAwareConstraintLayout.java index 34f6e3fd63..7153e86928 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/InsetAwareConstraintLayout.java +++ b/app/src/main/java/org/thoughtcrime/securesms/components/InsetAwareConstraintLayout.java @@ -10,6 +10,7 @@ import androidx.constraintlayout.widget.ConstraintLayout; import androidx.constraintlayout.widget.Guideline; import org.thoughtcrime.securesms.R; +import org.thoughtcrime.securesms.util.ViewUtil; public class InsetAwareConstraintLayout extends ConstraintLayout { @@ -45,11 +46,19 @@ public class InsetAwareConstraintLayout extends ConstraintLayout { } if (parentStartGuideline != null) { - parentStartGuideline.setGuidelineBegin(insets.left); + if (ViewUtil.isLtr(this)) { + parentStartGuideline.setGuidelineBegin(insets.left); + } else { + parentStartGuideline.setGuidelineBegin(insets.right); + } } if (parentEndGuideline != null) { - parentEndGuideline.setGuidelineEnd(insets.right); + if (ViewUtil.isLtr(this)) { + parentEndGuideline.setGuidelineEnd(insets.right); + } else { + parentEndGuideline.setGuidelineEnd(insets.left); + } } return true; diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/MicrophoneRecorderView.java b/app/src/main/java/org/thoughtcrime/securesms/components/MicrophoneRecorderView.java index 9906b8136c..320304bb56 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/MicrophoneRecorderView.java +++ b/app/src/main/java/org/thoughtcrime/securesms/components/MicrophoneRecorderView.java @@ -23,6 +23,7 @@ import androidx.core.view.ViewCompat; import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.permissions.Permissions; +import org.thoughtcrime.securesms.util.ViewUtil; public final class MicrophoneRecorderView extends FrameLayout implements View.OnTouchListener { @@ -224,8 +225,8 @@ public final class MicrophoneRecorderView extends FrameLayout implements View.On } private float getXOffset(float x) { - return ViewCompat.getLayoutDirection(recordButtonFab) == ViewCompat.LAYOUT_DIRECTION_LTR ? - -Math.max(0, this.startPositionX - x) : Math.max(0, x - this.startPositionX); + return ViewUtil.isLtr(recordButtonFab) ? -Math.max(0, this.startPositionX - x) + : Math.max(0, x - this.startPositionX); } private float getYOffset(float y) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/PictureInPictureGestureHelper.java b/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/PictureInPictureGestureHelper.java index 0a8391220b..d5dc2f7c21 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/PictureInPictureGestureHelper.java +++ b/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/PictureInPictureGestureHelper.java @@ -17,6 +17,7 @@ import androidx.core.view.GestureDetectorCompat; import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.animation.AnimationCompleteListener; +import org.thoughtcrime.securesms.util.ViewUtil; import org.thoughtcrime.securesms.util.views.TouchInterceptingFrameLayout; import java.util.Arrays; @@ -259,8 +260,8 @@ public class PictureInPictureGestureHelper extends GestureDetector.SimpleOnGestu private Point findNearestCornerPosition(Point projection) { if (isLockedToBottomEnd) { - return parent.getLayoutDirection() == View.LAYOUT_DIRECTION_LTR ? calculateBottomRightCoordinates(parent) - : calculateBottomLeftCoordinates(parent); + return ViewUtil.isLtr(parent) ? calculateBottomRightCoordinates(parent) + : calculateBottomLeftCoordinates(parent); } Point maxPoint = null; diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationFragment.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationFragment.java index 41df43130c..805e096eb5 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationFragment.java @@ -1084,8 +1084,8 @@ public class ConversationFragment extends LoggingFragment { private void maybeShowSwipeToReplyTooltip() { if (!TextSecurePreferences.hasSeenSwipeToReplyTooltip(requireContext())) { - int text = getResources().getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_LTR ? R.string.ConversationFragment_you_can_swipe_to_the_right_reply - : R.string.ConversationFragment_you_can_swipe_to_the_left_reply; + int text = ViewUtil.isLtr(requireContext()) ? R.string.ConversationFragment_you_can_swipe_to_the_right_reply + : R.string.ConversationFragment_you_can_swipe_to_the_left_reply; TooltipPopup.forTarget(requireActivity().findViewById(R.id.menu_context_reply)) .setText(text) .setTextColor(getResources().getColor(R.color.core_white)) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationReactionOverlay.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationReactionOverlay.java index 1ab1d546db..66c6154eb7 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationReactionOverlay.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationReactionOverlay.java @@ -176,10 +176,10 @@ public final class ConversationReactionOverlay extends RelativeLayout { final float halfWidth = scrubberWidth / 2f + scrubberHorizontalMargin; final float screenWidth = getResources().getDisplayMetrics().widthPixels; - final float downX = getLayoutDirection() == LAYOUT_DIRECTION_LTR ? lastSeenDownPoint.x : screenWidth - lastSeenDownPoint.x; + final float downX = ViewUtil.isLtr(this) ? lastSeenDownPoint.x : screenWidth - lastSeenDownPoint.x; final float scrubberTranslationX = Util.clamp(downX - halfWidth, scrubberHorizontalMargin, - screenWidth + scrubberHorizontalMargin - halfWidth * 2) * (getLayoutDirection() == LAYOUT_DIRECTION_LTR ? 1 : -1); + screenWidth + scrubberHorizontalMargin - halfWidth * 2) * (ViewUtil.isLtr(this) ? 1 : -1); backgroundView.setTranslationX(scrubberTranslationX); backgroundView.setTranslationY(scrubberTranslationY); @@ -275,7 +275,7 @@ public final class ConversationReactionOverlay extends RelativeLayout { } private int getStart(@NonNull Rect rect) { - if (getLayoutDirection() == LAYOUT_DIRECTION_LTR) { + if (ViewUtil.isLtr(this)) { return rect.left; } else { return rect.right; @@ -283,7 +283,7 @@ public final class ConversationReactionOverlay extends RelativeLayout { } private int getEnd(@NonNull Rect rect) { - if (getLayoutDirection() == LAYOUT_DIRECTION_LTR) { + if (ViewUtil.isLtr(this)) { return rect.right; } else { return rect.left; diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/ui/managegroup/ManageGroupFragment.java b/app/src/main/java/org/thoughtcrime/securesms/groups/ui/managegroup/ManageGroupFragment.java index 6892c8d54e..7631539f3c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/groups/ui/managegroup/ManageGroupFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/groups/ui/managegroup/ManageGroupFragment.java @@ -60,6 +60,7 @@ import org.thoughtcrime.securesms.util.AsynchronousCallback; import org.thoughtcrime.securesms.util.DateUtils; import org.thoughtcrime.securesms.util.FeatureFlags; import org.thoughtcrime.securesms.util.LifecycleCursorWrapper; +import org.thoughtcrime.securesms.util.ViewUtil; import org.thoughtcrime.securesms.util.views.LearnMoreTextView; import org.thoughtcrime.securesms.util.views.SimpleProgressDialog; import org.thoughtcrime.securesms.wallpaper.ChatWallpaperActivity; @@ -261,8 +262,8 @@ public class ManageGroupFragment extends LoggingFragment { threadPhotoRailView.setListener(mediaRecord -> startActivityForResult(MediaPreviewActivity.intentFromMediaRecord(context, mediaRecord, - ViewCompat.getLayoutDirection(threadPhotoRailView) == ViewCompat.LAYOUT_DIRECTION_LTR), - RETURN_FROM_MEDIA)); + ViewUtil.isLtr(threadPhotoRailView)), + RETURN_FROM_MEDIA)); groupLinkCard.setVisibility(vs.getGroupRecipient().requireGroupId().isV2() ? View.VISIBLE : View.GONE); }); diff --git a/app/src/main/java/org/thoughtcrime/securesms/recipients/ui/RecipientSettingsCoordinatorLayoutBehavior.java b/app/src/main/java/org/thoughtcrime/securesms/recipients/ui/RecipientSettingsCoordinatorLayoutBehavior.java index d766e1a78b..cf3c6d1e9a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/recipients/ui/RecipientSettingsCoordinatorLayoutBehavior.java +++ b/app/src/main/java/org/thoughtcrime/securesms/recipients/ui/RecipientSettingsCoordinatorLayoutBehavior.java @@ -16,6 +16,7 @@ import androidx.coordinatorlayout.widget.CoordinatorLayout; import com.google.android.material.appbar.AppBarLayout; import org.thoughtcrime.securesms.R; +import org.thoughtcrime.securesms.util.ViewUtil; import java.lang.ref.WeakReference; @@ -92,7 +93,7 @@ public final class RecipientSettingsCoordinatorLayoutBehavior extends Coordinato } private static int getStart(@NonNull CoordinatorLayout parent, @NonNull Rect rect) { - return parent.getLayoutDirection() == View.LAYOUT_DIRECTION_LTR ? rect.left : rect.right; + return ViewUtil.isLtr(parent) ? rect.left : rect.right; } private static final class ViewReference { diff --git a/app/src/main/java/org/thoughtcrime/securesms/recipients/ui/managerecipient/ManageRecipientFragment.java b/app/src/main/java/org/thoughtcrime/securesms/recipients/ui/managerecipient/ManageRecipientFragment.java index e96dba1599..02d80d822e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/recipients/ui/managerecipient/ManageRecipientFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/recipients/ui/managerecipient/ManageRecipientFragment.java @@ -54,6 +54,7 @@ import org.thoughtcrime.securesms.util.DateUtils; import org.thoughtcrime.securesms.util.LifecycleCursorWrapper; import org.thoughtcrime.securesms.util.ServiceUtil; import org.thoughtcrime.securesms.util.Util; +import org.thoughtcrime.securesms.util.ViewUtil; import org.thoughtcrime.securesms.wallpaper.ChatWallpaperActivity; import java.util.Locale; @@ -351,7 +352,7 @@ public class ManageRecipientFragment extends LoggingFragment { threadPhotoRailView.setListener(mediaRecord -> startActivityForResult(MediaPreviewActivity.intentFromMediaRecord(requireContext(), mediaRecord, - ViewCompat.getLayoutDirection(threadPhotoRailView) == ViewCompat.LAYOUT_DIRECTION_LTR), + ViewUtil.isLtr(threadPhotoRailView)), REQUEST_CODE_RETURN_FROM_MEDIA)); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/ViewUtil.java b/app/src/main/java/org/thoughtcrime/securesms/util/ViewUtil.java index a7b43baaab..ff2c7645af 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/ViewUtil.java +++ b/app/src/main/java/org/thoughtcrime/securesms/util/ViewUtil.java @@ -19,6 +19,7 @@ package org.thoughtcrime.securesms.util; import android.annotation.SuppressLint; import android.app.Activity; import android.content.Context; +import android.content.res.Configuration; import android.content.res.Resources; import android.util.TypedValue; import android.view.Gravity; @@ -166,7 +167,7 @@ public final class ViewUtil { @SuppressLint("RtlHardcoded") public static void setTextViewGravityStart(final @NonNull TextView textView, @NonNull Context context) { - if (DynamicLanguage.getLayoutDirection(context) == View.LAYOUT_DIRECTION_RTL) { + if (isRtl(context)) { textView.setGravity(Gravity.RIGHT); } else { textView.setGravity(Gravity.LEFT); @@ -174,11 +175,27 @@ public final class ViewUtil { } public static void mirrorIfRtl(View view, Context context) { - if (DynamicLanguage.getLayoutDirection(context) == View.LAYOUT_DIRECTION_RTL) { + if (isRtl(context)) { view.setScaleX(-1.0f); } } + public static boolean isLtr(@NonNull View view) { + return isLtr(view.getContext()); + } + + public static boolean isLtr(@NonNull Context context) { + return context.getResources().getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_LTR; + } + + public static boolean isRtl(@NonNull View view) { + return isRtl(view.getContext()); + } + + public static boolean isRtl(@NonNull Context context) { + return context.getResources().getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_RTL; + } + public static float pxToDp(float px) { return px / Resources.getSystem().getDisplayMetrics().density; } @@ -212,21 +229,21 @@ public final class ViewUtil { } public static int getLeftMargin(@NonNull View view) { - if (ViewCompat.getLayoutDirection(view) == ViewCompat.LAYOUT_DIRECTION_LTR) { + if (isLtr(view)) { return ((ViewGroup.MarginLayoutParams) view.getLayoutParams()).leftMargin; } return ((ViewGroup.MarginLayoutParams) view.getLayoutParams()).rightMargin; } public static int getRightMargin(@NonNull View view) { - if (ViewCompat.getLayoutDirection(view) == ViewCompat.LAYOUT_DIRECTION_LTR) { + if (isLtr(view)) { return ((ViewGroup.MarginLayoutParams) view.getLayoutParams()).rightMargin; } return ((ViewGroup.MarginLayoutParams) view.getLayoutParams()).leftMargin; } public static void setLeftMargin(@NonNull View view, int margin) { - if (ViewCompat.getLayoutDirection(view) == ViewCompat.LAYOUT_DIRECTION_LTR) { + if (isLtr(view)) { ((ViewGroup.MarginLayoutParams) view.getLayoutParams()).leftMargin = margin; } else { ((ViewGroup.MarginLayoutParams) view.getLayoutParams()).rightMargin = margin; @@ -236,7 +253,7 @@ public final class ViewUtil { } public static void setRightMargin(@NonNull View view, int margin) { - if (ViewCompat.getLayoutDirection(view) == ViewCompat.LAYOUT_DIRECTION_LTR) { + if (isLtr(view)) { ((ViewGroup.MarginLayoutParams) view.getLayoutParams()).rightMargin = margin; } else { ((ViewGroup.MarginLayoutParams) view.getLayoutParams()).leftMargin = margin; @@ -268,7 +285,7 @@ public final class ViewUtil { } public static void setPaddingStart(@NonNull View view, int padding) { - if (view.getLayoutDirection() == View.LAYOUT_DIRECTION_LTR) { + if (isLtr(view)) { view.setPadding(padding, view.getPaddingTop(), view.getPaddingRight(), view.getPaddingBottom()); } else { view.setPadding(view.getPaddingLeft(), view.getPaddingTop(), padding, view.getPaddingBottom()); @@ -276,10 +293,10 @@ public final class ViewUtil { } public static void setPaddingEnd(@NonNull View view, int padding) { - if (view.getLayoutDirection() != View.LAYOUT_DIRECTION_LTR) { - view.setPadding(padding, view.getPaddingTop(), view.getPaddingRight(), view.getPaddingBottom()); - } else { + if (isLtr(view)) { view.setPadding(view.getPaddingLeft(), view.getPaddingTop(), padding, view.getPaddingBottom()); + } else { + view.setPadding(padding, view.getPaddingTop(), view.getPaddingRight(), view.getPaddingBottom()); } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/wallpaper/ChatWallpaperAlignmentDecoration.java b/app/src/main/java/org/thoughtcrime/securesms/wallpaper/ChatWallpaperAlignmentDecoration.java index 34d55c9f1c..4aeffa80a7 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/wallpaper/ChatWallpaperAlignmentDecoration.java +++ b/app/src/main/java/org/thoughtcrime/securesms/wallpaper/ChatWallpaperAlignmentDecoration.java @@ -7,6 +7,8 @@ import android.view.ViewGroup; import androidx.annotation.NonNull; import androidx.recyclerview.widget.RecyclerView; +import org.thoughtcrime.securesms.util.ViewUtil; + class ChatWallpaperAlignmentDecoration extends RecyclerView.ItemDecoration { @Override public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) { @@ -27,14 +29,14 @@ class ChatWallpaperAlignmentDecoration extends RecyclerView.ItemDecoration { int extraCellsNeeded = itemsPerRow - ((itemPosition + 1) % itemsPerRow); - setEnd(outRect, view.getLayoutDirection(), extraCellsNeeded * viewWidth); + setEnd(outRect, ViewUtil.isLtr(view), extraCellsNeeded * viewWidth); } else { super.getItemOffsets(outRect, view, parent, state); } } - private void setEnd(@NonNull Rect outRect, int layoutDirection, int end) { - if (layoutDirection == View.LAYOUT_DIRECTION_LTR) { + private void setEnd(@NonNull Rect outRect, boolean ltr, int end) { + if (ltr) { outRect.right = end; } else { outRect.left = end;