Modify Comparator in ZonePicker

The previous method "compareTo" isn't locale-sensitive, it cannot
sort the String in some other languages. So Collator is recommended
to be applyed here.

Bug: Sort doesn't work in some languages.
Test: make RunSettingsRoboTests -j40 ROBOTEST_FILTER=ZonePickerComparatorTest

Change-Id: Id107ab938cceefc77f9fb6918a0445fc92a0fcb7
Signed-off-by: tiansiming <tiansiming@xiaomi.com>
This commit is contained in:
tiansiming
2017-10-30 21:39:48 +08:00
committed by siming tian
parent 3d8b442e8d
commit 3b8c4cd52e
2 changed files with 137 additions and 2 deletions

View File

@@ -22,6 +22,7 @@ import android.app.AlarmManager;
import android.app.ListFragment; import android.app.ListFragment;
import android.content.Context; import android.content.Context;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.VisibleForTesting;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu; import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
@@ -38,6 +39,7 @@ import com.android.settings.core.instrumentation.Instrumentable;
import com.android.settings.core.instrumentation.VisibilityLoggerMixin; import com.android.settings.core.instrumentation.VisibilityLoggerMixin;
import com.android.settingslib.datetime.ZoneGetter; import com.android.settingslib.datetime.ZoneGetter;
import java.text.Collator;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.HashMap; import java.util.HashMap;
@@ -257,15 +259,21 @@ public class ZonePicker extends ListFragment implements Instrumentable {
mVisibilityLoggerMixin.onPause(); mVisibilityLoggerMixin.onPause();
} }
private static class MyComparator implements Comparator<Map<?, ?>> { @VisibleForTesting
static class MyComparator implements Comparator<Map<?, ?>> {
private final Collator mCollator;
private String mSortingKey; private String mSortingKey;
private boolean mSortedByName;
public MyComparator(String sortingKey) { public MyComparator(String sortingKey) {
mCollator = Collator.getInstance();
mSortingKey = sortingKey; mSortingKey = sortingKey;
mSortedByName = ZoneGetter.KEY_DISPLAY_LABEL.equals(sortingKey);
} }
public void setSortingKey(String sortingKey) { public void setSortingKey(String sortingKey) {
mSortingKey = sortingKey; mSortingKey = sortingKey;
mSortedByName = ZoneGetter.KEY_DISPLAY_LABEL.equals(sortingKey);
} }
public int compare(Map<?, ?> map1, Map<?, ?> map2) { public int compare(Map<?, ?> map1, Map<?, ?> map2) {
@@ -282,7 +290,11 @@ public class ZonePicker extends ListFragment implements Instrumentable {
return -1; return -1;
} }
return ((Comparable) value1).compareTo(value2); if (mSortedByName) {
return mCollator.compare(value1, value2);
} else {
return ((Comparable) value1).compareTo(value2);
}
} }
private boolean isComparable(Object value) { private boolean isComparable(Object value) {

View File

@@ -0,0 +1,123 @@
package com.android.settings.datetime;
import com.android.settings.datetime.ZonePicker;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.TestConfig;
import com.android.settingslib.datetime.ZoneGetter;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.annotation.Config;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.TimeZone;
import static com.google.common.truth.Truth.assertThat;
@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class ZonePickerComparatorTest {
// Strings in Chinese are sorted by alphabet order of their Pinyin.
// "伦敦" -> "lundun"; "纽约" -> "niuyue"; "悉尼" -> "xini"
// "开罗" -> "kailuo"; "雅典" -> "yadian"; "上海" -> "shanghai"
private static final String[] TEST_CHINESE_NAME =
new String[]{"伦敦", "纽约", "悉尼", "开罗", "雅典", "上海"};
private static final String[] ORDERED_CHINESE_NAME =
new String[]{"开罗", "伦敦", "纽约", "上海", "悉尼", "雅典"};
private static final String[] TEST_ENGLISH_NAME =
new String[]{"London", "New York", "Sydney", "Cairo", "Athens", "Shanghai"};
private static final String[] ORDERED_ENGLISH_NAME =
new String[]{"Athens", "Cairo", "London", "New York", "Shanghai", "Sydney"};
private static final Locale INIT_LOCALE = Locale.getDefault();
private Map<String, List> mTestDataMap;
private List<Map<String, Object>> mTestList;
@Before
public void setUp() {
mTestDataMap = new HashMap<>();
mTestDataMap.put("zh_CN", Arrays.asList(TEST_CHINESE_NAME));
mTestDataMap.put("en_US", Arrays.asList(TEST_ENGLISH_NAME));
}
@After
public void tearDown() {
Locale.setDefault(INIT_LOCALE);
}
@Test
public void testComparator_sortChineseString() {
String sortKey = ZoneGetter.KEY_DISPLAY_LABEL;
mTestList = getMockZonesList("zh_CN");
Locale.setDefault(new Locale("zh"));
final ZonePicker.MyComparator comparator = new ZonePicker.MyComparator(sortKey);
assertThat(comparator).isNotNull();
Collections.sort(mTestList, comparator);
for (int i = 0; i < mTestList.size(); i++) {
assertThat(mTestList.get(i).get(sortKey).toString())
.isEqualTo(ORDERED_CHINESE_NAME[i]);
}
}
@Test
public void testComparator_sortEnglishString() {
String sortKey = ZoneGetter.KEY_DISPLAY_LABEL;
mTestList = getMockZonesList("en_US");
Locale.setDefault(new Locale("en"));
final ZonePicker.MyComparator comparator = new ZonePicker.MyComparator(sortKey);
assertThat(comparator).isNotNull();
Collections.sort(mTestList, comparator);
for (int i = 0; i < mTestList.size(); i++) {
assertThat(mTestList.get(i).get(sortKey).toString())
.isEqualTo(ORDERED_ENGLISH_NAME[i]);
}
}
@Test
public void testComparator_sortInteger() {
String sortKey = ZoneGetter.KEY_OFFSET;
// TestList of any locale can be selected to test integer sorting.
mTestList = getMockZonesList("en_US");
final ZonePicker.MyComparator comparator = new ZonePicker.MyComparator(sortKey);
assertThat(comparator).isNotNull();
Collections.sort(mTestList, comparator);
for (int i = 0; i < mTestList.size(); i++) {
assertThat(mTestList.get(i).get(sortKey)).isEqualTo(i);
}
}
private List<Map<String, Object>> getMockZonesList(String locale) {
List<Map<String, Object>> zones = new ArrayList<>();
List<String> testData = mTestDataMap.get(locale);
TimeZone tz = TimeZone.getDefault();
int testSize = testData.size();
for (int i = 0; i < testSize; i++) {
zones.add(createMockDisplayEntry(tz, "GMT+08:00",
testData.get(i), testSize - i - 1));
}
return zones;
}
private Map<String, Object> createMockDisplayEntry(
TimeZone tz, CharSequence gmtOffsetText, CharSequence displayName, int offsetMillis) {
Map<String, Object> map = new HashMap<>();
map.put(ZoneGetter.KEY_ID, tz.getID());
map.put(ZoneGetter.KEY_DISPLAYNAME, displayName.toString());
map.put(ZoneGetter.KEY_DISPLAY_LABEL, displayName);
map.put(ZoneGetter.KEY_GMT, gmtOffsetText.toString());
map.put(ZoneGetter.KEY_OFFSET_LABEL, gmtOffsetText);
map.put(ZoneGetter.KEY_OFFSET, offsetMillis);
return map;
}
}