Drastically reduce number of projection instances we create.

Via SimplePool
fork-5.53.8
Alex Hart 2021-10-25 14:12:08 -03:00 zatwierdzone przez GitHub
rodzic 98fce53cf1
commit b34bb2e7d7
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
12 zmienionych plików z 145 dodań i 64 usunięć

Wyświetl plik

@ -57,6 +57,7 @@ import org.thoughtcrime.securesms.util.CachedInflater;
import org.thoughtcrime.securesms.util.DateUtils;
import org.thoughtcrime.securesms.util.MessageRecordUtil;
import org.thoughtcrime.securesms.util.Projection;
import org.thoughtcrime.securesms.util.ProjectionList;
import org.thoughtcrime.securesms.util.StickyHeaderDecoration;
import org.thoughtcrime.securesms.util.ThemeUtil;
import org.thoughtcrime.securesms.util.ViewUtil;
@ -704,7 +705,7 @@ public class ConversationAdapter
}
@Override
public @NonNull List<Projection> getColorizerProjections(@NonNull ViewGroup coordinateRoot) {
public @NonNull ProjectionList getColorizerProjections(@NonNull ViewGroup coordinateRoot) {
return getBindable().getColorizerProjections(coordinateRoot);
}
}

Wyświetl plik

@ -122,6 +122,7 @@ import org.thoughtcrime.securesms.util.InterceptableLongClickCopyLinkSpan;
import org.thoughtcrime.securesms.util.LongClickMovementMethod;
import org.thoughtcrime.securesms.util.MessageRecordUtil;
import org.thoughtcrime.securesms.util.Projection;
import org.thoughtcrime.securesms.util.ProjectionList;
import org.thoughtcrime.securesms.util.SearchUtil;
import org.thoughtcrime.securesms.util.StringUtil;
import org.thoughtcrime.securesms.util.ThemeUtil;
@ -221,6 +222,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
private Colorizer colorizer;
private boolean hasWallpaper;
private float lastYDownRelativeToThis;
private ProjectionList colorizerProjections = new ProjectionList(3);
public ConversationItem(Context context) {
this(context, null);
@ -530,6 +532,10 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
if (conversationRecipient != null) {
conversationRecipient.removeForeverObserver(this);
}
bodyBubble.setVideoPlayerProjection(null);
bodyBubble.setQuoteViewProjection(null);
cancelPulseOutlinerAnimation();
}
@ -588,12 +594,17 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
}
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) {
Projection projection = Projection.relativeToViewRoot(child, null);
return (int) projection.getY() + projection.getHeight();
int bottom = (int) projection.getY() + projection.getHeight();
projection.release();
return bottom;
}
@Override
@ -1719,8 +1730,8 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
}
@Override
public @NonNull List<Projection> getColorizerProjections(@NonNull ViewGroup coordinateRoot) {
List<Projection> projections = new LinkedList<>();
public @NonNull ProjectionList getColorizerProjections(@NonNull ViewGroup coordinateRoot) {
colorizerProjections.clear();
if (messageRecord.isOutgoing() &&
!hasNoBubble(messageRecord) &&
@ -1731,9 +1742,9 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
Projection videoToBubble = bodyBubble.getVideoPlayerProjection();
if (videoToBubble != null) {
Projection videoToRoot = Projection.translateFromDescendantToParentCoords(videoToBubble, bodyBubble, coordinateRoot);
projections.addAll(Projection.getCapAndTail(bodyBubbleToRoot, videoToRoot));
colorizerProjections.addAll(Projection.getCapAndTail(bodyBubbleToRoot, videoToRoot));
} 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);
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)
{
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

Wyświetl plik

@ -63,11 +63,19 @@ public class ConversationItemBodyBubble extends LinearLayout {
}
public void setQuoteViewProjection(@Nullable Projection quoteViewProjection) {
if (this.quoteViewProjection != null) {
this.quoteViewProjection.release();
}
this.quoteViewProjection = quoteViewProjection;
clipProjectionDrawable.setProjections(getProjections());
}
public void setVideoPlayerProjection(@Nullable Projection videoPlayerProjection) {
if (this.videoPlayerProjection != null) {
this.videoPlayerProjection.release();
}
this.videoPlayerProjection = videoPlayerProjection;
clipProjectionDrawable.setProjections(getProjections());
}

Wyświetl plik

@ -39,6 +39,7 @@ import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.util.DateUtils;
import org.thoughtcrime.securesms.util.IdentityUtil;
import org.thoughtcrime.securesms.util.Projection;
import org.thoughtcrime.securesms.util.ProjectionList;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.ThemeUtil;
import org.thoughtcrime.securesms.util.Util;
@ -59,7 +60,9 @@ import java.util.concurrent.ExecutionException;
public final class ConversationUpdateItem extends FrameLayout
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;
@ -221,8 +224,8 @@ public final class ConversationUpdateItem extends FrameLayout
}
@Override
public @NonNull List<Projection> getColorizerProjections(@NonNull ViewGroup coordinateRoot) {
return Collections.emptyList();
public @NonNull ProjectionList getColorizerProjections(@NonNull ViewGroup coordinateRoot) {
return EMPTY_PROJECTION_LIST;
}
@Override

Wyświetl plik

@ -1,12 +1,12 @@
package org.thoughtcrime.securesms.conversation.colors
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
* generating its own projection.
*/
interface Colorizable {
fun getColorizerProjections(coordinateRoot: ViewGroup): List<Projection>
fun getColorizerProjections(coordinateRoot: ViewGroup): ProjectionList
}

Wyświetl plik

@ -40,4 +40,9 @@ class ColorizerView @JvmOverloads constructor(
super.draw(canvas)
}
}
override fun onDetachedFromWindow() {
super.onDetachedFromWindow()
projections.forEach { it.release() }
}
}

Wyświetl plik

@ -98,8 +98,10 @@ class RecyclerViewColorizer(private val recyclerView: RecyclerView) {
if (child != null) {
val holder = parent.getChildViewHolder(child)
if (holder is Colorizable) {
holder.getColorizerProjections(parent).forEach {
c.drawPath(it.path, holePunchPaint)
holder.getColorizerProjections(parent).use { list ->
list.forEach {
c.drawPath(it.path, holePunchPaint)
}
}
}
}

Wyświetl plik

@ -21,7 +21,6 @@ import androidx.recyclerview.widget.RecyclerView
import com.airbnb.lottie.SimpleColorFilter
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.conversation.ConversationAdapter
import org.thoughtcrime.securesms.util.Projection
import org.thoughtcrime.securesms.util.SetUtil
import org.thoughtcrime.securesms.util.ThemeUtil
import org.thoughtcrime.securesms.util.ViewUtil
@ -157,9 +156,17 @@ class MultiselectItemDecoration(
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()
projections.forEach { it.applyToPath(path) }
projections.use { list ->
list.forEach {
it.applyToPath(path)
}
}
canvas.save()
canvas.clipPath(path, Region.Op.DIFFERENCE)
@ -341,13 +348,16 @@ class MultiselectItemDecoration(
parent.forEach { child ->
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)
child.getColorizerProjections(parent).forEach {
path.op(it.path, Path.Op.DIFFERENCE)
child.getColorizerProjections(parent).use { list ->
list.forEach {
path.op(it.path, Path.Op.DIFFERENCE)
}
}
if (child.canPlayContent()) {
val mp4GifProjection = child.getGiphyMp4PlayableProjection(child.rootView as ViewGroup)
path.op(mp4GifProjection.path, Path.Op.DIFFERENCE)
mp4GifProjection.release()
}
}
}

Wyświetl plik

@ -105,6 +105,8 @@ public final class GiphyMp4ProjectionRecycler implements GiphyMp4PlaybackControl
}
holder.setCorners(projection.getCorners());
projection.release();
}
private void startPlayback(@NonNull RecyclerView parent, @NonNull GiphyMp4ProjectionPlayerHolder holder, @NonNull GiphyMp4Playable giphyMp4Playable) {

Wyświetl plik

@ -35,6 +35,7 @@ import org.thoughtcrime.securesms.sms.MessageSender;
import org.thoughtcrime.securesms.util.DateUtils;
import org.thoughtcrime.securesms.util.ExpirationUtil;
import org.thoughtcrime.securesms.util.Projection;
import org.thoughtcrime.securesms.util.ProjectionList;
import org.whispersystems.libsignal.util.guava.Optional;
import java.sql.Date;
@ -250,7 +251,7 @@ final class MessageHeaderViewHolder extends RecyclerView.ViewHolder implements G
}
@Override
public @NonNull List<Projection> getColorizerProjections(@NonNull ViewGroup coordinateRoot) {
public @NonNull ProjectionList getColorizerProjections(@NonNull ViewGroup coordinateRoot) {
return conversationItem.getColorizerProjections(coordinateRoot);
}

Wyświetl plik

@ -9,6 +9,7 @@ import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.util.Pools;
import androidx.recyclerview.widget.RecyclerView;
import org.signal.core.util.logging.Log;
@ -24,30 +25,41 @@ import java.util.Objects;
*/
public final class Projection {
private final float x;
private final float y;
private final int width;
private final int height;
private final Corners corners;
private final Path path;
private final RectF rect;
private float x;
private float y;
private int width;
private int height;
private Corners corners;
private Path path;
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.y = y;
this.width = width;
this.height = height;
this.corners = corners;
this.path = new Path();
rect = new RectF();
rect.set(x, y, x + width, y + height);
path.reset();
if (corners != null) {
path.addRoundRect(rect, corners.toRadii(), Path.Direction.CW);
} else {
path.addRect(rect, Path.Direction.CW);
}
return this;
}
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) {
return new Projection(x + xTranslation, y, width, height, corners);
return set(x + xTranslation, y, width, height, corners);
}
public @NonNull Projection translateY(float yTranslation) {
return new Projection(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);
return set(x, y + yTranslation, width, height, 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);
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) {
@ -132,7 +121,7 @@ public final class Projection {
view.getDrawingRect(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) {
@ -143,7 +132,7 @@ public final class Projection {
root.offsetDescendantRectToMyCoords(toProject, 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) {
@ -153,7 +142,7 @@ public final class Projection {
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) {
@ -187,11 +176,47 @@ public final class Projection {
}
return Arrays.asList(
new Projection(topX, topY, topWidth, topHeight, topCorners),
new Projection(bottomX, bottomY, bottomWidth, bottomHeight, bottomCorners)
acquireAndSet(topX, topY, topWidth, topHeight, topCorners),
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 {
private final float topLeft;
private final float topRight;

Wyświetl plik

@ -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() }
}
}