Merge "Fix ActivityLeak through text reference" into main
diff --git a/core/java/android/text/DynamicLayout.java b/core/java/android/text/DynamicLayout.java
index 3bdaca9..e287bd9 100644
--- a/core/java/android/text/DynamicLayout.java
+++ b/core/java/android/text/DynamicLayout.java
@@ -622,7 +622,7 @@
sBuilder = null;
}
- if (reflowed == null) {
+ if (b == null) {
b = StaticLayout.Builder.obtain(text, where, where + after, getPaint(), getWidth());
}
@@ -641,7 +641,7 @@
.setAddLastLineLineSpacing(!islast)
.setIncludePad(false);
- reflowed = b.regenerate(true /* trackpadding */, reflowed);
+ reflowed = b.buildPartialStaticLayoutForDynamicLayout(true /* trackpadding */, reflowed);
int n = reflowed.getLineCount();
// If the new layout has a blank line at the end, but it is not
// the very end of the buffer, then we already have a line that
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index f843900..3d1895c 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -437,13 +437,25 @@
return result;
}
- /* package */ @NonNull StaticLayout regenerate(boolean trackpadding, StaticLayout recycle) {
+ /**
+ * DO NOT USE THIS METHOD OTHER THAN DynamicLayout.
+ *
+ * This class generates a very weird StaticLayout only for getting a result of line break.
+ * Since DynamicLayout keeps StaticLayout reference in the static context for object
+ * recycling but keeping text reference in static context will end up with leaking Context
+ * due to TextWatcher via TextView.
+ *
+ * So, this is a dirty work around that creating StaticLayout without passing text reference
+ * to the super constructor, but calculating the text layout by calling generate function
+ * directly.
+ */
+ /* package */ @NonNull StaticLayout buildPartialStaticLayoutForDynamicLayout(
+ boolean trackpadding, StaticLayout recycle) {
if (recycle == null) {
- return new StaticLayout(this, trackpadding, COLUMNS_ELLIPSIZE);
- } else {
- recycle.generate(this, mIncludePad, trackpadding);
- return recycle;
+ recycle = new StaticLayout();
}
+ recycle.generate(this, mIncludePad, trackpadding);
+ return recycle;
}
private CharSequence mText;
@@ -474,6 +486,37 @@
}
/**
+ * DO NOT USE THIS CONSTRUCTOR OTHER THAN FOR DYNAMIC LAYOUT.
+ * See Builder#buildPartialStaticLayoutForDynamicLayout for the reason of this constructor.
+ */
+ private StaticLayout() {
+ super(
+ null, // text
+ null, // paint
+ 0, // width
+ null, // alignment
+ null, // textDir
+ 1, // spacing multiplier
+ 0, // spacing amount
+ false, // include font padding
+ false, // fallback line spacing
+ 0, // ellipsized width
+ null, // ellipsize
+ 1, // maxLines
+ BREAK_STRATEGY_SIMPLE,
+ HYPHENATION_FREQUENCY_NONE,
+ null, // leftIndents
+ null, // rightIndents
+ JUSTIFICATION_MODE_NONE,
+ null // lineBreakConfig
+ );
+
+ mColumns = COLUMNS_ELLIPSIZE;
+ mLineDirections = ArrayUtils.newUnpaddedArray(Directions.class, 2);
+ mLines = ArrayUtils.newUnpaddedIntArray(2 * mColumns);
+ }
+
+ /**
* @deprecated Use {@link Builder} instead.
*/
@Deprecated