Merge "Don't trigger full relayout if DateTimeView doesn't change" into tm-dev
This commit is contained in:
@@ -32,6 +32,7 @@ import android.content.res.TypedArray;
|
|||||||
import android.database.ContentObserver;
|
import android.database.ContentObserver;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
|
import android.text.TextUtils;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.util.PluralsMessageFormatter;
|
import android.util.PluralsMessageFormatter;
|
||||||
import android.view.accessibility.AccessibilityNodeInfo;
|
import android.view.accessibility.AccessibilityNodeInfo;
|
||||||
@@ -230,7 +231,7 @@ public class DateTimeView extends TextView {
|
|||||||
|
|
||||||
// Set the text
|
// Set the text
|
||||||
String text = format.format(new Date(time));
|
String text = format.format(new Date(time));
|
||||||
setText(text);
|
maybeSetText(text);
|
||||||
|
|
||||||
// Schedule the next update
|
// Schedule the next update
|
||||||
if (display == SHOW_TIME) {
|
if (display == SHOW_TIME) {
|
||||||
@@ -258,7 +259,7 @@ public class DateTimeView extends TextView {
|
|||||||
boolean past = (now >= mTimeMillis);
|
boolean past = (now >= mTimeMillis);
|
||||||
String result;
|
String result;
|
||||||
if (duration < MINUTE_IN_MILLIS) {
|
if (duration < MINUTE_IN_MILLIS) {
|
||||||
setText(mNowText);
|
maybeSetText(mNowText);
|
||||||
mUpdateTimeMillis = mTimeMillis + MINUTE_IN_MILLIS + 1;
|
mUpdateTimeMillis = mTimeMillis + MINUTE_IN_MILLIS + 1;
|
||||||
return;
|
return;
|
||||||
} else if (duration < HOUR_IN_MILLIS) {
|
} else if (duration < HOUR_IN_MILLIS) {
|
||||||
@@ -308,7 +309,19 @@ public class DateTimeView extends TextView {
|
|||||||
mUpdateTimeMillis = mTimeMillis - millisIncrease * count + 1;
|
mUpdateTimeMillis = mTimeMillis - millisIncrease * count + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setText(result);
|
maybeSetText(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets text only if the text has actually changed. This prevents needles relayouts of this
|
||||||
|
* view when set to wrap_content.
|
||||||
|
*/
|
||||||
|
private void maybeSetText(String text) {
|
||||||
|
if (TextUtils.equals(getText(), text)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setText(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -16,14 +16,20 @@
|
|||||||
|
|
||||||
package android.widget;
|
package android.widget;
|
||||||
|
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
import androidx.test.InstrumentationRegistry;
|
import androidx.test.InstrumentationRegistry;
|
||||||
import androidx.test.annotation.UiThreadTest;
|
import androidx.test.annotation.UiThreadTest;
|
||||||
import androidx.test.filters.SmallTest;
|
import androidx.test.filters.SmallTest;
|
||||||
import androidx.test.runner.AndroidJUnit4;
|
import androidx.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
@SmallTest
|
@SmallTest
|
||||||
public class DateTimeViewTest {
|
public class DateTimeViewTest {
|
||||||
@@ -39,7 +45,33 @@ public class DateTimeViewTest {
|
|||||||
dateTimeView.detachedFromWindow();
|
dateTimeView.detachedFromWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@UiThreadTest
|
||||||
|
@Test
|
||||||
|
public void noChangeInRelativeText_doesNotTriggerRelayout() {
|
||||||
|
// Week in the future is chosen because it'll result in a stable string during this test
|
||||||
|
// run. This should be improved once the class is refactored to be more testable in
|
||||||
|
// respect of clock retrieval.
|
||||||
|
final long weekInTheFuture = System.currentTimeMillis() + Duration.ofDays(7).toMillis();
|
||||||
|
final TestDateTimeView dateTimeView = new TestDateTimeView();
|
||||||
|
dateTimeView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||||
|
ViewGroup.LayoutParams.WRAP_CONTENT));
|
||||||
|
dateTimeView.setShowRelativeTime(true);
|
||||||
|
dateTimeView.setTime(weekInTheFuture);
|
||||||
|
// View needs to be measured to request layout, skipping this would make this test pass
|
||||||
|
// always.
|
||||||
|
dateTimeView.measure(View.MeasureSpec.makeMeasureSpec(200, View.MeasureSpec.UNSPECIFIED),
|
||||||
|
View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.UNSPECIFIED));
|
||||||
|
dateTimeView.reset();
|
||||||
|
|
||||||
|
// This should not change the text content and thus no relayout is expected.
|
||||||
|
dateTimeView.setTime(weekInTheFuture + 1000);
|
||||||
|
|
||||||
|
Assert.assertFalse(dateTimeView.wasLayoutRequested());
|
||||||
|
}
|
||||||
|
|
||||||
private static class TestDateTimeView extends DateTimeView {
|
private static class TestDateTimeView extends DateTimeView {
|
||||||
|
private boolean mRequestedLayout = false;
|
||||||
|
|
||||||
TestDateTimeView() {
|
TestDateTimeView() {
|
||||||
super(InstrumentationRegistry.getContext());
|
super(InstrumentationRegistry.getContext());
|
||||||
}
|
}
|
||||||
@@ -51,5 +83,18 @@ public class DateTimeViewTest {
|
|||||||
void detachedFromWindow() {
|
void detachedFromWindow() {
|
||||||
super.onDetachedFromWindow();
|
super.onDetachedFromWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void requestLayout() {
|
||||||
|
super.requestLayout();
|
||||||
|
mRequestedLayout = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean wasLayoutRequested() {
|
||||||
|
return mRequestedLayout;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reset() {
|
||||||
|
mRequestedLayout = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user