kopia lustrzana https://github.com/ryukoposting/Signal-Android
Drastically reduce number of projection instances we create.
Via SimplePoolfork-5.53.8
rodzic
98fce53cf1
commit
b34bb2e7d7
|
@ -57,6 +57,7 @@ import org.thoughtcrime.securesms.util.CachedInflater;
|
||||||
import org.thoughtcrime.securesms.util.DateUtils;
|
import org.thoughtcrime.securesms.util.DateUtils;
|
||||||
import org.thoughtcrime.securesms.util.MessageRecordUtil;
|
import org.thoughtcrime.securesms.util.MessageRecordUtil;
|
||||||
import org.thoughtcrime.securesms.util.Projection;
|
import org.thoughtcrime.securesms.util.Projection;
|
||||||
|
import org.thoughtcrime.securesms.util.ProjectionList;
|
||||||
import org.thoughtcrime.securesms.util.StickyHeaderDecoration;
|
import org.thoughtcrime.securesms.util.StickyHeaderDecoration;
|
||||||
import org.thoughtcrime.securesms.util.ThemeUtil;
|
import org.thoughtcrime.securesms.util.ThemeUtil;
|
||||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||||
|
@ -704,7 +705,7 @@ public class ConversationAdapter
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NonNull List<Projection> getColorizerProjections(@NonNull ViewGroup coordinateRoot) {
|
public @NonNull ProjectionList getColorizerProjections(@NonNull ViewGroup coordinateRoot) {
|
||||||
return getBindable().getColorizerProjections(coordinateRoot);
|
return getBindable().getColorizerProjections(coordinateRoot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -122,6 +122,7 @@ import org.thoughtcrime.securesms.util.InterceptableLongClickCopyLinkSpan;
|
||||||
import org.thoughtcrime.securesms.util.LongClickMovementMethod;
|
import org.thoughtcrime.securesms.util.LongClickMovementMethod;
|
||||||
import org.thoughtcrime.securesms.util.MessageRecordUtil;
|
import org.thoughtcrime.securesms.util.MessageRecordUtil;
|
||||||
import org.thoughtcrime.securesms.util.Projection;
|
import org.thoughtcrime.securesms.util.Projection;
|
||||||
|
import org.thoughtcrime.securesms.util.ProjectionList;
|
||||||
import org.thoughtcrime.securesms.util.SearchUtil;
|
import org.thoughtcrime.securesms.util.SearchUtil;
|
||||||
import org.thoughtcrime.securesms.util.StringUtil;
|
import org.thoughtcrime.securesms.util.StringUtil;
|
||||||
import org.thoughtcrime.securesms.util.ThemeUtil;
|
import org.thoughtcrime.securesms.util.ThemeUtil;
|
||||||
|
@ -221,6 +222,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
|
||||||
private Colorizer colorizer;
|
private Colorizer colorizer;
|
||||||
private boolean hasWallpaper;
|
private boolean hasWallpaper;
|
||||||
private float lastYDownRelativeToThis;
|
private float lastYDownRelativeToThis;
|
||||||
|
private ProjectionList colorizerProjections = new ProjectionList(3);
|
||||||
|
|
||||||
public ConversationItem(Context context) {
|
public ConversationItem(Context context) {
|
||||||
this(context, null);
|
this(context, null);
|
||||||
|
@ -530,6 +532,10 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
|
||||||
if (conversationRecipient != null) {
|
if (conversationRecipient != null) {
|
||||||
conversationRecipient.removeForeverObserver(this);
|
conversationRecipient.removeForeverObserver(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bodyBubble.setVideoPlayerProjection(null);
|
||||||
|
bodyBubble.setQuoteViewProjection(null);
|
||||||
|
|
||||||
cancelPulseOutlinerAnimation();
|
cancelPulseOutlinerAnimation();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -588,12 +594,17 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int getProjectionTop(@NonNull View child) {
|
private static int getProjectionTop(@NonNull View child) {
|
||||||
return (int) Projection.relativeToViewRoot(child, null).getY();
|
Projection projection = Projection.relativeToViewRoot(child, null);
|
||||||
|
int y = (int) projection.getY();
|
||||||
|
projection.release();
|
||||||
|
return y;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int getProjectionBottom(@NonNull View child) {
|
private static int getProjectionBottom(@NonNull View child) {
|
||||||
Projection projection = Projection.relativeToViewRoot(child, null);
|
Projection projection = Projection.relativeToViewRoot(child, null);
|
||||||
return (int) projection.getY() + projection.getHeight();
|
int bottom = (int) projection.getY() + projection.getHeight();
|
||||||
|
projection.release();
|
||||||
|
return bottom;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1719,8 +1730,8 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NonNull List<Projection> getColorizerProjections(@NonNull ViewGroup coordinateRoot) {
|
public @NonNull ProjectionList getColorizerProjections(@NonNull ViewGroup coordinateRoot) {
|
||||||
List<Projection> projections = new LinkedList<>();
|
colorizerProjections.clear();
|
||||||
|
|
||||||
if (messageRecord.isOutgoing() &&
|
if (messageRecord.isOutgoing() &&
|
||||||
!hasNoBubble(messageRecord) &&
|
!hasNoBubble(messageRecord) &&
|
||||||
|
@ -1731,9 +1742,9 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
|
||||||
Projection videoToBubble = bodyBubble.getVideoPlayerProjection();
|
Projection videoToBubble = bodyBubble.getVideoPlayerProjection();
|
||||||
if (videoToBubble != null) {
|
if (videoToBubble != null) {
|
||||||
Projection videoToRoot = Projection.translateFromDescendantToParentCoords(videoToBubble, bodyBubble, coordinateRoot);
|
Projection videoToRoot = Projection.translateFromDescendantToParentCoords(videoToBubble, bodyBubble, coordinateRoot);
|
||||||
projections.addAll(Projection.getCapAndTail(bodyBubbleToRoot, videoToRoot));
|
colorizerProjections.addAll(Projection.getCapAndTail(bodyBubbleToRoot, videoToRoot));
|
||||||
} else {
|
} else {
|
||||||
projections.add(bodyBubbleToRoot);
|
colorizerProjections.add(bodyBubbleToRoot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1743,7 +1754,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
|
||||||
{
|
{
|
||||||
Projection footerProjection = getActiveFooter(messageRecord).getProjection(coordinateRoot);
|
Projection footerProjection = getActiveFooter(messageRecord).getProjection(coordinateRoot);
|
||||||
if (footerProjection != null) {
|
if (footerProjection != null) {
|
||||||
projections.add(footerProjection.translateX(bodyBubble.getTranslationX()));
|
colorizerProjections.add(footerProjection.translateX(bodyBubble.getTranslationX()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1752,10 +1763,14 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
|
||||||
quoteView != null)
|
quoteView != null)
|
||||||
{
|
{
|
||||||
bodyBubble.setQuoteViewProjection(quoteView.getProjection(bodyBubble));
|
bodyBubble.setQuoteViewProjection(quoteView.getProjection(bodyBubble));
|
||||||
projections.add(quoteView.getProjection(coordinateRoot).translateX(bodyBubble.getTranslationX() + this.getTranslationX()));
|
colorizerProjections.add(quoteView.getProjection(coordinateRoot).translateX(bodyBubble.getTranslationX() + this.getTranslationX()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return projections.stream().map(p -> p.translateY(this.getTranslationY())).collect(Collectors.toList());
|
for (int i = 0; i < colorizerProjections.size(); i++) {
|
||||||
|
colorizerProjections.get(i).translateY(getTranslationY());
|
||||||
|
}
|
||||||
|
|
||||||
|
return colorizerProjections;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -63,11 +63,19 @@ public class ConversationItemBodyBubble extends LinearLayout {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setQuoteViewProjection(@Nullable Projection quoteViewProjection) {
|
public void setQuoteViewProjection(@Nullable Projection quoteViewProjection) {
|
||||||
|
if (this.quoteViewProjection != null) {
|
||||||
|
this.quoteViewProjection.release();
|
||||||
|
}
|
||||||
|
|
||||||
this.quoteViewProjection = quoteViewProjection;
|
this.quoteViewProjection = quoteViewProjection;
|
||||||
clipProjectionDrawable.setProjections(getProjections());
|
clipProjectionDrawable.setProjections(getProjections());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setVideoPlayerProjection(@Nullable Projection videoPlayerProjection) {
|
public void setVideoPlayerProjection(@Nullable Projection videoPlayerProjection) {
|
||||||
|
if (this.videoPlayerProjection != null) {
|
||||||
|
this.videoPlayerProjection.release();
|
||||||
|
}
|
||||||
|
|
||||||
this.videoPlayerProjection = videoPlayerProjection;
|
this.videoPlayerProjection = videoPlayerProjection;
|
||||||
clipProjectionDrawable.setProjections(getProjections());
|
clipProjectionDrawable.setProjections(getProjections());
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,7 @@ import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.util.DateUtils;
|
import org.thoughtcrime.securesms.util.DateUtils;
|
||||||
import org.thoughtcrime.securesms.util.IdentityUtil;
|
import org.thoughtcrime.securesms.util.IdentityUtil;
|
||||||
import org.thoughtcrime.securesms.util.Projection;
|
import org.thoughtcrime.securesms.util.Projection;
|
||||||
|
import org.thoughtcrime.securesms.util.ProjectionList;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
import org.thoughtcrime.securesms.util.ThemeUtil;
|
import org.thoughtcrime.securesms.util.ThemeUtil;
|
||||||
import org.thoughtcrime.securesms.util.Util;
|
import org.thoughtcrime.securesms.util.Util;
|
||||||
|
@ -59,7 +60,9 @@ import java.util.concurrent.ExecutionException;
|
||||||
public final class ConversationUpdateItem extends FrameLayout
|
public final class ConversationUpdateItem extends FrameLayout
|
||||||
implements BindableConversationItem
|
implements BindableConversationItem
|
||||||
{
|
{
|
||||||
private static final String TAG = Log.tag(ConversationUpdateItem.class);
|
private static final String TAG = Log.tag(ConversationUpdateItem.class);
|
||||||
|
private static final ProjectionList EMPTY_PROJECTION_LIST = new ProjectionList();
|
||||||
|
|
||||||
|
|
||||||
private Set<MultiselectPart> batchSelected;
|
private Set<MultiselectPart> batchSelected;
|
||||||
|
|
||||||
|
@ -221,8 +224,8 @@ public final class ConversationUpdateItem extends FrameLayout
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NonNull List<Projection> getColorizerProjections(@NonNull ViewGroup coordinateRoot) {
|
public @NonNull ProjectionList getColorizerProjections(@NonNull ViewGroup coordinateRoot) {
|
||||||
return Collections.emptyList();
|
return EMPTY_PROJECTION_LIST;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
package org.thoughtcrime.securesms.conversation.colors
|
package org.thoughtcrime.securesms.conversation.colors
|
||||||
|
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import org.thoughtcrime.securesms.util.Projection
|
import org.thoughtcrime.securesms.util.ProjectionList
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Denotes that a class can be colorized. The class is responsible for
|
* Denotes that a class can be colorized. The class is responsible for
|
||||||
* generating its own projection.
|
* generating its own projection.
|
||||||
*/
|
*/
|
||||||
interface Colorizable {
|
interface Colorizable {
|
||||||
fun getColorizerProjections(coordinateRoot: ViewGroup): List<Projection>
|
fun getColorizerProjections(coordinateRoot: ViewGroup): ProjectionList
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,4 +40,9 @@ class ColorizerView @JvmOverloads constructor(
|
||||||
super.draw(canvas)
|
super.draw(canvas)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onDetachedFromWindow() {
|
||||||
|
super.onDetachedFromWindow()
|
||||||
|
projections.forEach { it.release() }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -98,8 +98,10 @@ class RecyclerViewColorizer(private val recyclerView: RecyclerView) {
|
||||||
if (child != null) {
|
if (child != null) {
|
||||||
val holder = parent.getChildViewHolder(child)
|
val holder = parent.getChildViewHolder(child)
|
||||||
if (holder is Colorizable) {
|
if (holder is Colorizable) {
|
||||||
holder.getColorizerProjections(parent).forEach {
|
holder.getColorizerProjections(parent).use { list ->
|
||||||
c.drawPath(it.path, holePunchPaint)
|
list.forEach {
|
||||||
|
c.drawPath(it.path, holePunchPaint)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,6 @@ import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.airbnb.lottie.SimpleColorFilter
|
import com.airbnb.lottie.SimpleColorFilter
|
||||||
import org.thoughtcrime.securesms.R
|
import org.thoughtcrime.securesms.R
|
||||||
import org.thoughtcrime.securesms.conversation.ConversationAdapter
|
import org.thoughtcrime.securesms.conversation.ConversationAdapter
|
||||||
import org.thoughtcrime.securesms.util.Projection
|
|
||||||
import org.thoughtcrime.securesms.util.SetUtil
|
import org.thoughtcrime.securesms.util.SetUtil
|
||||||
import org.thoughtcrime.securesms.util.ThemeUtil
|
import org.thoughtcrime.securesms.util.ThemeUtil
|
||||||
import org.thoughtcrime.securesms.util.ViewUtil
|
import org.thoughtcrime.securesms.util.ViewUtil
|
||||||
|
@ -157,9 +156,17 @@ class MultiselectItemDecoration(
|
||||||
|
|
||||||
val parts: MultiselectCollection = child.conversationMessage.multiselectCollection
|
val parts: MultiselectCollection = child.conversationMessage.multiselectCollection
|
||||||
|
|
||||||
val projections: List<Projection> = child.getColorizerProjections(parent) + if (child.canPlayContent()) listOf(child.getGiphyMp4PlayableProjection(parent)) else emptyList()
|
val projections = child.getColorizerProjections(parent)
|
||||||
|
if (child.canPlayContent()) {
|
||||||
|
projections.add(child.getGiphyMp4PlayableProjection(parent))
|
||||||
|
}
|
||||||
|
|
||||||
path.reset()
|
path.reset()
|
||||||
projections.forEach { it.applyToPath(path) }
|
projections.use { list ->
|
||||||
|
list.forEach {
|
||||||
|
it.applyToPath(path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
canvas.save()
|
canvas.save()
|
||||||
canvas.clipPath(path, Region.Op.DIFFERENCE)
|
canvas.clipPath(path, Region.Op.DIFFERENCE)
|
||||||
|
@ -341,13 +348,16 @@ class MultiselectItemDecoration(
|
||||||
parent.forEach { child ->
|
parent.forEach { child ->
|
||||||
if (child is Multiselectable && child.conversationMessage == inFocus.conversationMessage) {
|
if (child is Multiselectable && child.conversationMessage == inFocus.conversationMessage) {
|
||||||
path.addRect(child.left.toFloat(), child.top.toFloat(), child.right.toFloat(), child.bottom.toFloat(), Path.Direction.CW)
|
path.addRect(child.left.toFloat(), child.top.toFloat(), child.right.toFloat(), child.bottom.toFloat(), Path.Direction.CW)
|
||||||
child.getColorizerProjections(parent).forEach {
|
child.getColorizerProjections(parent).use { list ->
|
||||||
path.op(it.path, Path.Op.DIFFERENCE)
|
list.forEach {
|
||||||
|
path.op(it.path, Path.Op.DIFFERENCE)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (child.canPlayContent()) {
|
if (child.canPlayContent()) {
|
||||||
val mp4GifProjection = child.getGiphyMp4PlayableProjection(child.rootView as ViewGroup)
|
val mp4GifProjection = child.getGiphyMp4PlayableProjection(child.rootView as ViewGroup)
|
||||||
path.op(mp4GifProjection.path, Path.Op.DIFFERENCE)
|
path.op(mp4GifProjection.path, Path.Op.DIFFERENCE)
|
||||||
|
mp4GifProjection.release()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -105,6 +105,8 @@ public final class GiphyMp4ProjectionRecycler implements GiphyMp4PlaybackControl
|
||||||
}
|
}
|
||||||
|
|
||||||
holder.setCorners(projection.getCorners());
|
holder.setCorners(projection.getCorners());
|
||||||
|
|
||||||
|
projection.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startPlayback(@NonNull RecyclerView parent, @NonNull GiphyMp4ProjectionPlayerHolder holder, @NonNull GiphyMp4Playable giphyMp4Playable) {
|
private void startPlayback(@NonNull RecyclerView parent, @NonNull GiphyMp4ProjectionPlayerHolder holder, @NonNull GiphyMp4Playable giphyMp4Playable) {
|
||||||
|
|
|
@ -35,6 +35,7 @@ import org.thoughtcrime.securesms.sms.MessageSender;
|
||||||
import org.thoughtcrime.securesms.util.DateUtils;
|
import org.thoughtcrime.securesms.util.DateUtils;
|
||||||
import org.thoughtcrime.securesms.util.ExpirationUtil;
|
import org.thoughtcrime.securesms.util.ExpirationUtil;
|
||||||
import org.thoughtcrime.securesms.util.Projection;
|
import org.thoughtcrime.securesms.util.Projection;
|
||||||
|
import org.thoughtcrime.securesms.util.ProjectionList;
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
|
|
||||||
import java.sql.Date;
|
import java.sql.Date;
|
||||||
|
@ -250,7 +251,7 @@ final class MessageHeaderViewHolder extends RecyclerView.ViewHolder implements G
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NonNull List<Projection> getColorizerProjections(@NonNull ViewGroup coordinateRoot) {
|
public @NonNull ProjectionList getColorizerProjections(@NonNull ViewGroup coordinateRoot) {
|
||||||
return conversationItem.getColorizerProjections(coordinateRoot);
|
return conversationItem.getColorizerProjections(coordinateRoot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ import android.view.ViewGroup;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.core.util.Pools;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import org.signal.core.util.logging.Log;
|
import org.signal.core.util.logging.Log;
|
||||||
|
@ -24,30 +25,41 @@ import java.util.Objects;
|
||||||
*/
|
*/
|
||||||
public final class Projection {
|
public final class Projection {
|
||||||
|
|
||||||
private final float x;
|
private float x;
|
||||||
private final float y;
|
private float y;
|
||||||
private final int width;
|
private int width;
|
||||||
private final int height;
|
private int height;
|
||||||
private final Corners corners;
|
private Corners corners;
|
||||||
private final Path path;
|
private Path path;
|
||||||
private final RectF rect;
|
private RectF rect;
|
||||||
|
|
||||||
public Projection(float x, float y, int width, int height, @Nullable Corners corners) {
|
private Projection() {
|
||||||
|
x = 0f;
|
||||||
|
y = 0f;
|
||||||
|
width = 0;
|
||||||
|
height = 0;
|
||||||
|
corners = null;
|
||||||
|
path = new Path();
|
||||||
|
rect = new RectF();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Projection set(float x, float y, int width, int height, @Nullable Corners corners) {
|
||||||
this.x = x;
|
this.x = x;
|
||||||
this.y = y;
|
this.y = y;
|
||||||
this.width = width;
|
this.width = width;
|
||||||
this.height = height;
|
this.height = height;
|
||||||
this.corners = corners;
|
this.corners = corners;
|
||||||
this.path = new Path();
|
|
||||||
|
|
||||||
rect = new RectF();
|
|
||||||
rect.set(x, y, x + width, y + height);
|
rect.set(x, y, x + width, y + height);
|
||||||
|
path.reset();
|
||||||
|
|
||||||
if (corners != null) {
|
if (corners != null) {
|
||||||
path.addRoundRect(rect, corners.toRadii(), Path.Direction.CW);
|
path.addRoundRect(rect, corners.toRadii(), Path.Direction.CW);
|
||||||
} else {
|
} else {
|
||||||
path.addRect(rect, Path.Direction.CW);
|
path.addRect(rect, Path.Direction.CW);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public float getX() {
|
public float getX() {
|
||||||
|
@ -86,35 +98,12 @@ public final class Projection {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public boolean equals(Object o) {
|
|
||||||
if (this == o) return true;
|
|
||||||
if (o == null || getClass() != o.getClass()) return false;
|
|
||||||
final Projection that = (Projection) o;
|
|
||||||
return Float.compare(that.x, x) == 0 &&
|
|
||||||
Float.compare(that.y, y) == 0 &&
|
|
||||||
width == that.width &&
|
|
||||||
height == that.height &&
|
|
||||||
Objects.equals(corners, that.corners);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public int hashCode() {
|
|
||||||
return Objects.hash(x, y, width, height, corners);
|
|
||||||
}
|
|
||||||
|
|
||||||
public @NonNull Projection translateX(float xTranslation) {
|
public @NonNull Projection translateX(float xTranslation) {
|
||||||
return new Projection(x + xTranslation, y, width, height, corners);
|
return set(x + xTranslation, y, width, height, corners);
|
||||||
}
|
}
|
||||||
|
|
||||||
public @NonNull Projection translateY(float yTranslation) {
|
public @NonNull Projection translateY(float yTranslation) {
|
||||||
return new Projection(x, y + yTranslation, width, height, corners);
|
return set(x, y + yTranslation, width, height, corners);
|
||||||
}
|
|
||||||
|
|
||||||
public @NonNull Projection withDimensions(int width, int height) {
|
|
||||||
return new Projection(x, y, width, height, corners);
|
|
||||||
}
|
|
||||||
|
|
||||||
public @NonNull Projection withHeight(int height) {
|
|
||||||
return new Projection(x, y, width, height, corners);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static @NonNull Projection relativeToParent(@NonNull ViewGroup parent, @NonNull View view, @Nullable Corners corners) {
|
public static @NonNull Projection relativeToParent(@NonNull ViewGroup parent, @NonNull View view, @Nullable Corners corners) {
|
||||||
|
@ -122,7 +111,7 @@ public final class Projection {
|
||||||
|
|
||||||
view.getDrawingRect(viewBounds);
|
view.getDrawingRect(viewBounds);
|
||||||
parent.offsetDescendantRectToMyCoords(view, viewBounds);
|
parent.offsetDescendantRectToMyCoords(view, viewBounds);
|
||||||
return new Projection(viewBounds.left, viewBounds.top, view.getWidth(), view.getHeight(), corners);
|
return acquireAndSet(viewBounds.left, viewBounds.top, view.getWidth(), view.getHeight(), corners);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static @NonNull Projection relativeToViewRoot(@NonNull View view, @Nullable Corners corners) {
|
public static @NonNull Projection relativeToViewRoot(@NonNull View view, @Nullable Corners corners) {
|
||||||
|
@ -132,7 +121,7 @@ public final class Projection {
|
||||||
view.getDrawingRect(viewBounds);
|
view.getDrawingRect(viewBounds);
|
||||||
root.offsetDescendantRectToMyCoords(view, viewBounds);
|
root.offsetDescendantRectToMyCoords(view, viewBounds);
|
||||||
|
|
||||||
return new Projection(viewBounds.left, viewBounds.top, view.getWidth(), view.getHeight(), corners);
|
return acquireAndSet(viewBounds.left, viewBounds.top, view.getWidth(), view.getHeight(), corners);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static @NonNull Projection relativeToViewWithCommonRoot(@NonNull View toProject, @NonNull View viewWithCommonRoot, @Nullable Corners corners) {
|
public static @NonNull Projection relativeToViewWithCommonRoot(@NonNull View toProject, @NonNull View viewWithCommonRoot, @Nullable Corners corners) {
|
||||||
|
@ -143,7 +132,7 @@ public final class Projection {
|
||||||
root.offsetDescendantRectToMyCoords(toProject, viewBounds);
|
root.offsetDescendantRectToMyCoords(toProject, viewBounds);
|
||||||
root.offsetRectIntoDescendantCoords(viewWithCommonRoot, viewBounds);
|
root.offsetRectIntoDescendantCoords(viewWithCommonRoot, viewBounds);
|
||||||
|
|
||||||
return new Projection(viewBounds.left, viewBounds.top, toProject.getWidth(), toProject.getHeight(), corners);
|
return acquireAndSet(viewBounds.left, viewBounds.top, toProject.getWidth(), toProject.getHeight(), corners);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static @NonNull Projection translateFromDescendantToParentCoords(@NonNull Projection descendantProjection, @NonNull View descendant, @NonNull ViewGroup parent) {
|
public static @NonNull Projection translateFromDescendantToParentCoords(@NonNull Projection descendantProjection, @NonNull View descendant, @NonNull ViewGroup parent) {
|
||||||
|
@ -153,7 +142,7 @@ public final class Projection {
|
||||||
|
|
||||||
parent.offsetDescendantRectToMyCoords(descendant, viewBounds);
|
parent.offsetDescendantRectToMyCoords(descendant, viewBounds);
|
||||||
|
|
||||||
return new Projection(viewBounds.left, viewBounds.top, descendantProjection.width, descendantProjection.height, descendantProjection.corners);
|
return acquireAndSet(viewBounds.left, viewBounds.top, descendantProjection.width, descendantProjection.height, descendantProjection.corners);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static @NonNull List<Projection> getCapAndTail(@NonNull Projection parentProjection, @NonNull Projection childProjection) {
|
public static @NonNull List<Projection> getCapAndTail(@NonNull Projection parentProjection, @NonNull Projection childProjection) {
|
||||||
|
@ -187,11 +176,47 @@ public final class Projection {
|
||||||
}
|
}
|
||||||
|
|
||||||
return Arrays.asList(
|
return Arrays.asList(
|
||||||
new Projection(topX, topY, topWidth, topHeight, topCorners),
|
acquireAndSet(topX, topY, topWidth, topHeight, topCorners),
|
||||||
new Projection(bottomX, bottomY, bottomWidth, bottomHeight, bottomCorners)
|
acquireAndSet(bottomX, bottomY, bottomWidth, bottomHeight, bottomCorners)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We keep a maximum of 125 Projections around at any one time.
|
||||||
|
*/
|
||||||
|
private static final Pools.SimplePool<Projection> projectionPool = new Pools.SimplePool<>(125);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Acquire a projection. This will try to grab one from the pool, and, upon failure, will
|
||||||
|
* allocate a new one instead.
|
||||||
|
*/
|
||||||
|
private static @NonNull Projection acquire() {
|
||||||
|
Projection fromPool = projectionPool.acquire();
|
||||||
|
if (fromPool != null) {
|
||||||
|
return fromPool;
|
||||||
|
} else {
|
||||||
|
return new Projection();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Acquire a projection and set its fields as specified.
|
||||||
|
*/
|
||||||
|
private static @NonNull Projection acquireAndSet(float x, float y, int width, int height, @Nullable Corners corners) {
|
||||||
|
Projection projection = acquire();
|
||||||
|
projection.set(x, y, width, height, corners);
|
||||||
|
|
||||||
|
return projection;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Projections should only be kept around for the absolute maximum amount of time they are needed.
|
||||||
|
*/
|
||||||
|
public void release() {
|
||||||
|
projectionPool.release(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public static final class Corners {
|
public static final class Corners {
|
||||||
private final float topLeft;
|
private final float topLeft;
|
||||||
private final float topRight;
|
private final float topRight;
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
package org.thoughtcrime.securesms.util
|
||||||
|
|
||||||
|
import java.io.Closeable
|
||||||
|
|
||||||
|
class ProjectionList(size: Int = 0) : ArrayList<Projection>(size), Closeable {
|
||||||
|
override fun close() {
|
||||||
|
forEach { it.release() }
|
||||||
|
}
|
||||||
|
}
|
Ładowanie…
Reference in New Issue