Time zone, Region, UTC picker
- Extract most common view related codes into BaseTimeZoneAdapter and BaseTimeZonePicker. Subclass handles the text formatting and order. - Search view is added compared to previous version of time zone picker - SpannableUtil is added to preserve spannable when formatting String resource. - Fix the bug using GMT+<arabic> as time zone id. b/73132985 - Fix Talkback treating flags on screens as a separate element Bug: 72146259 Bug: 73132985 Bug: 73952488 Test: mm RunSettingsRoboTests Change-Id: I42c6ac369199c09d11e7f5cc4707358fa4780fed
This commit is contained in:
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.datetime.timezone;
|
||||
|
||||
import android.support.v7.widget.RecyclerView.AdapterDataObserver;
|
||||
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
@RunWith(SettingsRobolectricTestRunner.class)
|
||||
public class BaseTimeZoneAdapterTest {
|
||||
|
||||
@Test
|
||||
public void testFilter() throws InterruptedException {
|
||||
TestItem US = new TestItem("United States");
|
||||
TestItem HK = new TestItem("Hong Kong");
|
||||
TestItem UK = new TestItem("United Kingdom", new String[] { "United Kingdom",
|
||||
"Great Britain"});
|
||||
TestItem secretCountry = new TestItem("no name", new String[] { "Secret"});
|
||||
List<TestItem> items = new ArrayList<>();
|
||||
items.add(US);
|
||||
items.add(HK);
|
||||
items.add(UK);
|
||||
items.add(secretCountry);
|
||||
|
||||
TestTimeZoneAdapter adapter = new TestTimeZoneAdapter(items);
|
||||
assertSearch(adapter, "", items.toArray(new TestItem[items.size()]));
|
||||
assertSearch(adapter, "Unit", US, UK);
|
||||
assertSearch(adapter, "kon", HK);
|
||||
assertSearch(adapter, "brit", UK);
|
||||
assertSearch(adapter, "sec", secretCountry);
|
||||
}
|
||||
|
||||
private void assertSearch(TestTimeZoneAdapter adapter , String searchText, TestItem... items)
|
||||
throws InterruptedException {
|
||||
Observer observer = new Observer(adapter);
|
||||
adapter.getFilter().filter(searchText);
|
||||
observer.await();
|
||||
assertThat(adapter.getItemCount()).isEqualTo(items.length);
|
||||
for (int i = 0; i < items.length; i++) {
|
||||
assertThat(adapter.getItem(i)).isEqualTo(items[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private static class Observer extends AdapterDataObserver {
|
||||
|
||||
private final CountDownLatch mLatch = new CountDownLatch(1);
|
||||
private final TestTimeZoneAdapter mAdapter;
|
||||
|
||||
public Observer(TestTimeZoneAdapter adapter) {
|
||||
mAdapter = adapter;
|
||||
mAdapter.registerAdapterDataObserver(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChanged() {
|
||||
mAdapter.unregisterAdapterDataObserver(this);
|
||||
mLatch.countDown();
|
||||
}
|
||||
|
||||
public void await() throws InterruptedException {
|
||||
mLatch.await(2L, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
private static class TestTimeZoneAdapter extends BaseTimeZoneAdapter<TestItem> {
|
||||
|
||||
public TestTimeZoneAdapter(List<TestItem> items) {
|
||||
super(items, position -> {}, Locale.US, false);
|
||||
}
|
||||
}
|
||||
|
||||
private static class TestItem implements BaseTimeZoneAdapter.AdapterItem {
|
||||
|
||||
private final String mTitle;
|
||||
private final String[] mSearchKeys;
|
||||
|
||||
TestItem(String title) {
|
||||
this(title, new String[] { title });
|
||||
}
|
||||
|
||||
TestItem(String title, String[] searchKeys) {
|
||||
mTitle = title;
|
||||
mSearchKeys = searchKeys;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getTitle() {
|
||||
return mTitle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getSummary() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIconText() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCurrentTime() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getSearchKeys() {
|
||||
return mSearchKeys;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.datetime.timezone;
|
||||
|
||||
import android.content.Context;
|
||||
import android.icu.util.TimeZone;
|
||||
|
||||
import com.android.settings.datetime.timezone.model.TimeZoneData;
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
|
||||
import com.google.common.truth.Truth;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Config;
|
||||
import org.robolectric.annotation.Implementation;
|
||||
import org.robolectric.annotation.Implements;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
@RunWith(SettingsRobolectricTestRunner.class)
|
||||
@Config(shadows = { BaseTimeZoneInfoPickerTest.ShadowDataFormat.class })
|
||||
public class BaseTimeZoneInfoPickerTest {
|
||||
@Implements(android.text.format.DateFormat.class)
|
||||
public static class ShadowDataFormat {
|
||||
|
||||
public static String sTimeFormatString = "";
|
||||
|
||||
@Implementation
|
||||
public static String getTimeFormatString(Context context) {
|
||||
return sTimeFormatString;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify the summary, title, and time label in a time zone item are formatted properly.
|
||||
*/
|
||||
@Test
|
||||
public void createAdapter_matchTimeZoneInfoAndOrder() {
|
||||
ShadowDataFormat.sTimeFormatString = "HH:MM";
|
||||
BaseTimeZoneInfoPicker picker = new TestBaseTimeZoneInfoPicker();
|
||||
BaseTimeZoneAdapter adapter = picker.createAdapter(mock(TimeZoneData.class));
|
||||
Truth.assertThat(adapter.getItemCount()).isEqualTo(2);
|
||||
|
||||
BaseTimeZoneAdapter.AdapterItem item1 = adapter.getItem(0);
|
||||
Truth.assertThat(item1.getTitle().toString()).isEqualTo("Los Angeles");
|
||||
Truth.assertThat(item1.getSummary().toString()).isEqualTo("Pacific Time (GMT-08:00)");
|
||||
Truth.assertThat(item1.getCurrentTime())
|
||||
.hasLength(ShadowDataFormat.sTimeFormatString.length());
|
||||
|
||||
BaseTimeZoneAdapter.AdapterItem item2 = adapter.getItem(1);
|
||||
Truth.assertThat(item2.getTitle().toString()).isEqualTo("New York");
|
||||
Truth.assertThat(item2.getSummary().toString()).isEqualTo("Eastern Time (GMT-05:00)");
|
||||
Truth.assertThat(item2.getCurrentTime())
|
||||
.hasLength(ShadowDataFormat.sTimeFormatString.length());
|
||||
}
|
||||
|
||||
public static class TestBaseTimeZoneInfoPicker extends BaseTimeZoneInfoPicker {
|
||||
|
||||
public TestBaseTimeZoneInfoPicker() {
|
||||
super(0, 0, false, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TimeZoneInfo> getAllTimeZoneInfos(TimeZoneData timeZoneData) {
|
||||
TimeZoneInfo zone1 = new TimeZoneInfo.Builder(
|
||||
TimeZone.getFrozenTimeZone("America/Los_Angeles"))
|
||||
.setGenericName("Pacific Time")
|
||||
.setStandardName("Pacific Standard Time")
|
||||
.setDaylightName("Pacific Daylight Time")
|
||||
.setExemplarLocation("Los Angeles")
|
||||
.setGmtOffset("GMT-08:00")
|
||||
.setItemId(0)
|
||||
.build();
|
||||
TimeZoneInfo zone2 = new TimeZoneInfo.Builder(
|
||||
TimeZone.getFrozenTimeZone("America/New_York"))
|
||||
.setGenericName("Eastern Time")
|
||||
.setStandardName("Eastern Standard Time")
|
||||
.setDaylightName("Eastern Daylight Time")
|
||||
.setExemplarLocation("New York")
|
||||
.setGmtOffset("GMT-05:00")
|
||||
.setItemId(1)
|
||||
.build();
|
||||
|
||||
return Arrays.asList(zone1, zone2);
|
||||
}
|
||||
|
||||
// Make the method public
|
||||
@Override
|
||||
public BaseTimeZoneAdapter createAdapter(TimeZoneData timeZoneData) {
|
||||
return super.createAdapter(timeZoneData);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Locale getLocale() {
|
||||
return Locale.US;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Context getContext() {
|
||||
return RuntimeEnvironment.application;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.datetime.timezone;
|
||||
|
||||
import com.android.settings.datetime.timezone.model.TimeZoneData;
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
|
||||
import libcore.util.CountryZonesFinder;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@RunWith(SettingsRobolectricTestRunner.class)
|
||||
public class FixedOffsetPickerTest {
|
||||
|
||||
@Test
|
||||
public void getAllTimeZoneInfos_containsUtcAndGmtZones() {
|
||||
List regionList = Collections.emptyList();
|
||||
CountryZonesFinder finder = mock(CountryZonesFinder.class);
|
||||
when(finder.lookupAllCountryIsoCodes()).thenReturn(regionList);
|
||||
|
||||
FixedOffsetPicker picker = new FixedOffsetPicker() {
|
||||
@Override
|
||||
protected Locale getLocale() {
|
||||
return Locale.US;
|
||||
}
|
||||
};
|
||||
List<TimeZoneInfo> infos = picker.getAllTimeZoneInfos(new TimeZoneData(finder));
|
||||
List<String> tzIds = infos.stream().map(info -> info.getId()).collect(Collectors.toList());
|
||||
tzIds.contains("Etc/Utc");
|
||||
tzIds.contains("Etc/GMT-12");
|
||||
tzIds.contains("Etc/GMT+14");
|
||||
}
|
||||
}
|
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.datetime.timezone;
|
||||
|
||||
import com.android.settings.datetime.timezone.BaseTimeZoneAdapter.AdapterItem;
|
||||
import com.android.settings.datetime.timezone.model.TimeZoneData;
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
|
||||
import libcore.util.CountryZonesFinder;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@RunWith(SettingsRobolectricTestRunner.class)
|
||||
public class RegionSearchPickerTest {
|
||||
|
||||
@Test
|
||||
public void createAdapter_matchRegionName() {
|
||||
List regionList = new ArrayList();
|
||||
regionList.add("US");
|
||||
CountryZonesFinder finder = mock(CountryZonesFinder.class);
|
||||
when(finder.lookupAllCountryIsoCodes()).thenReturn(regionList);
|
||||
|
||||
RegionSearchPicker picker = new RegionSearchPicker() {
|
||||
@Override
|
||||
protected Locale getLocale() {
|
||||
return Locale.US;
|
||||
}
|
||||
};
|
||||
BaseTimeZoneAdapter adapter = picker.createAdapter(new TimeZoneData(finder));
|
||||
assertEquals(1, adapter.getItemCount());
|
||||
AdapterItem item = adapter.getItem(0);
|
||||
assertEquals("United States", item.getTitle().toString());
|
||||
assertThat(Arrays.asList(item.getSearchKeys())).contains("United States");
|
||||
}
|
||||
}
|
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.datetime.timezone;
|
||||
|
||||
import android.icu.text.Collator;
|
||||
|
||||
import com.android.settings.datetime.timezone.RegionZonePicker.TimeZoneInfoComparator;
|
||||
import com.android.settings.datetime.timezone.TimeZoneInfo.Formatter;
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
@RunWith(SettingsRobolectricTestRunner.class)
|
||||
public class RegionZonePickerTest {
|
||||
|
||||
@Test
|
||||
public void compareTimeZoneInfo_matchGmtOrder() {
|
||||
Date now = new Date(0); // 00:00 1, Jan 1970
|
||||
Formatter formatter = new Formatter(Locale.US, now);
|
||||
TimeZoneInfo timeZone1 = formatter.format("Pacific/Honolulu");
|
||||
TimeZoneInfo timeZone2 = formatter.format("America/Los_Angeles");
|
||||
TimeZoneInfo timeZone3 = formatter.format("America/Indiana/Marengo");
|
||||
TimeZoneInfo timeZone4 = formatter.format("America/New_York");
|
||||
|
||||
TimeZoneInfoComparator comparator =
|
||||
new TimeZoneInfoComparator(Collator.getInstance(Locale.US), now);
|
||||
|
||||
// Verify the sorted order
|
||||
List<TimeZoneInfo> list = Arrays.asList(timeZone4, timeZone2, timeZone3, timeZone1);
|
||||
Collections.sort(list, comparator);
|
||||
assertThat(list).isEqualTo(Arrays.asList(timeZone1, timeZone2, timeZone3, timeZone4));
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.datetime.timezone;
|
||||
|
||||
import android.text.Spannable;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.testutils.SettingsRobolectricTestRunner;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
@RunWith(SettingsRobolectricTestRunner.class)
|
||||
public class SpannableUtilTest {
|
||||
|
||||
@Test
|
||||
public void testFormat() {
|
||||
Spannable spannable = SpannableUtil.getResourcesText(
|
||||
RuntimeEnvironment.application.getResources(), R.string.zone_info_offset_and_name,
|
||||
"GMT+00:00", "UTC");
|
||||
assertThat(spannable.toString()).isEqualTo("UTC (GMT+00:00)");
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user