diff --git a/lib/image-editor/src/main/java/org/signal/imageeditor/core/model/ElementStack.java b/lib/image-editor/src/main/java/org/signal/imageeditor/core/model/ElementStack.java index ab8c0974db..c2e4001c50 100644 --- a/lib/image-editor/src/main/java/org/signal/imageeditor/core/model/ElementStack.java +++ b/lib/image-editor/src/main/java/org/signal/imageeditor/core/model/ElementStack.java @@ -6,7 +6,9 @@ import android.os.Parcelable; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import java.util.ArrayList; import java.util.Arrays; +import java.util.List; import java.util.Stack; /** @@ -20,6 +22,12 @@ import java.util.Stack; */ final class ElementStack implements Parcelable { + /** + * A full stack can blow past the ~1MB Binder transaction limit when several edited images are + * persisted together in saved state, crashing the app and discarding the draft. + */ + private static final int PERSISTED_LIMIT = 10; + private final int limit; private final Stack stack = new Stack<>(); @@ -121,14 +129,30 @@ final class ElementStack implements Parcelable { @Override public void writeToParcel(Parcel dest, int flags) { + List persisted = entriesToPersist(); + dest.writeInt(limit); - final int count = stack.size(); - dest.writeInt(count); - for (int i = 0; i < count; i++) { - dest.writeByteArray(stack.get(i)); + dest.writeInt(persisted.size()); + for (byte[] entry : persisted) { + dest.writeByteArray(entry); } } + /** + * Keeps the oldest snapshot so undo can still reach the original state, plus the most recent + * entries. + */ + private @NonNull List entriesToPersist() { + if (stack.size() <= PERSISTED_LIMIT) { + return stack; + } + + List persisted = new ArrayList<>(PERSISTED_LIMIT); + persisted.add(stack.get(0)); + persisted.addAll(stack.subList(stack.size() - (PERSISTED_LIMIT - 1), stack.size())); + return persisted; + } + boolean stackContainsStateDifferentFrom(@NonNull EditorElement element) { if (stack.isEmpty()) return false;