Skip to content

Commit 1a512a2

Browse files
author
Lukas Koebis
committed
Push Translation
added locale/language detection localeIdentifier gets automatically populated whenever an installation is saved/updated
1 parent 56d7970 commit 1a512a2

File tree

2 files changed

+109
-26
lines changed

2 files changed

+109
-26
lines changed

Parse/src/main/java/com/parse/ParseInstallation.java

Lines changed: 51 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@
1111
import android.content.Context;
1212
import android.content.pm.PackageInfo;
1313
import android.content.pm.PackageManager;
14+
import android.text.TextUtils;
1415

1516
import java.util.Arrays;
1617
import java.util.Collections;
1718
import java.util.List;
19+
import java.util.Locale;
1820
import java.util.TimeZone;
1921

2022
import bolts.Continuation;
@@ -36,12 +38,13 @@ public class ParseInstallation extends ParseObject {
3638
private static final String KEY_DEVICE_TOKEN = "deviceToken";
3739
private static final String KEY_PUSH_TYPE = "pushType";
3840
private static final String KEY_TIME_ZONE = "timeZone";
41+
private static final String KEY_LOCALE = "localeIdentifier";
3942
private static final String KEY_APP_VERSION = "appVersion";
4043
/* package */ static final String KEY_CHANNELS = "channels";
4144

4245
private static final List<String> READ_ONLY_FIELDS = Collections.unmodifiableList(
4346
Arrays.asList(KEY_DEVICE_TYPE, KEY_INSTALLATION_ID, KEY_DEVICE_TOKEN, KEY_PUSH_TYPE,
44-
KEY_TIME_ZONE, KEY_APP_VERSION, KEY_APP_NAME, KEY_PARSE_VERSION,
47+
KEY_TIME_ZONE, KEY_LOCALE, KEY_APP_VERSION, KEY_APP_NAME, KEY_PARSE_VERSION,
4548
KEY_APP_IDENTIFIER));
4649

4750
// TODO(mengyan): Inject into ParseInstallationInstanceController
@@ -108,6 +111,7 @@ public String getInstallationId() {
108111
updateTimezone();
109112
updateVersionInfo();
110113
updateDeviceInfo();
114+
updateLocaleIdentifier();
111115
}
112116
}
113117

@@ -165,8 +169,8 @@ public Task<Void> then(Task<Void> task) throws Exception {
165169
// time zones from devices reporting other formats.
166170
private void updateTimezone() {
167171
String zone = TimeZone.getDefault().getID();
168-
if ((zone.indexOf('/') > 0 || zone.equals("GMT")) && !zone.equals(get("timeZone"))) {
169-
performPut("timeZone", zone);
172+
if ((zone.indexOf('/') > 0 || zone.equals("GMT")) && !zone.equals(get(KEY_TIME_ZONE))) {
173+
performPut(KEY_TIME_ZONE, zone);
170174
}
171175
}
172176

@@ -180,25 +184,65 @@ private void updateVersionInfo() {
180184
String appVersion = pkgInfo.versionName;
181185
String appName = pm.getApplicationLabel(pm.getApplicationInfo(packageName, 0)).toString();
182186

183-
if (packageName != null && !packageName.equals(get("appIdentifier"))) {
187+
if (packageName != null && !packageName.equals(get(KEY_APP_IDENTIFIER))) {
184188
performPut(KEY_APP_IDENTIFIER, packageName);
185189
}
186-
if (appName != null && !appName.equals(get("appName"))) {
190+
if (appName != null && !appName.equals(get(KEY_APP_NAME))) {
187191
performPut(KEY_APP_NAME, appName);
188192
}
189-
if (appVersion != null && !appVersion.equals(get("appVersion"))) {
193+
if (appVersion != null && !appVersion.equals(get(KEY_APP_VERSION))) {
190194
performPut(KEY_APP_VERSION, appVersion);
191195
}
192196
} catch (PackageManager.NameNotFoundException e) {
193197
PLog.w(TAG, "Cannot load package info; will not be saved to installation");
194198
}
195199

196-
if (!VERSION_NAME.equals(get("parseVersion"))) {
200+
if (!VERSION_NAME.equals(get(KEY_PARSE_VERSION))) {
197201
performPut(KEY_PARSE_VERSION, VERSION_NAME);
198202
}
199203
}
200204
}
201205

206+
/*
207+
* Save locale in the following format:
208+
* [language code]-[country code]
209+
*
210+
* The language codes are two-letter lowercase ISO language codes (such as "en") as defined by
211+
* <a href="http://en.wikipedia.org/wiki/ISO_639-1">ISO 639-1</a>.
212+
* The country codes are two-letter uppercase ISO country codes (such as "US") as defined by
213+
* <a href="http://en.wikipedia.org/wiki/ISO_3166-1_alpha-3">ISO 3166-1</a>.
214+
*
215+
* Note that Java uses several deprecated two-letter codes. The Hebrew ("he") language
216+
* code is rewritten as "iw", Indonesian ("id") as "in", and Yiddish ("yi") as "ji". This
217+
* rewriting happens even if you construct your own {@code Locale} object, not just for
218+
* instances returned by the various lookup methods.
219+
*/
220+
private void updateLocaleIdentifier() {
221+
final Locale locale = Locale.getDefault();
222+
223+
String language = locale.getLanguage();
224+
String country = locale.getCountry();
225+
226+
if (TextUtils.isEmpty(language)) {
227+
return;
228+
}
229+
230+
// rewrite depreciated two-letter codes
231+
if (language.equals("iw")) language = "he"; // Hebrew
232+
if (language.equals("in")) language = "id"; // Indonesian
233+
if (language.equals("ji")) language = "yi"; // Yiddish
234+
235+
String localeString = language;
236+
237+
if (!TextUtils.isEmpty(country)) {
238+
localeString = String.format(Locale.US, "%s-%s", language, country);
239+
}
240+
241+
if (!localeString.equals(get(KEY_LOCALE))) {
242+
performPut(KEY_LOCALE, localeString);
243+
}
244+
}
245+
202246
// TODO(mengyan): Move to ParseInstallationInstanceController
203247
/* package */ void updateDeviceInfo() {
204248
updateDeviceInfo(ParsePlugins.get().installationId());

Parse/src/test/java/com/parse/ParseInstallationTest.java

Lines changed: 58 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import org.robolectric.res.builder.RobolectricPackageManager;
2424

2525
import java.util.Arrays;
26+
import java.util.Locale;
2627
import java.util.TimeZone;
2728

2829
import bolts.Task;
@@ -46,6 +47,7 @@ public class ParseInstallationTest {
4647
private static final String KEY_APP_NAME = "appName";
4748
private static final String KEY_APP_IDENTIFIER = "appIdentifier";
4849
private static final String KEY_TIME_ZONE = "timeZone";
50+
private static final String KEY_LOCALE_IDENTIFIER = "localeIdentifier";
4951
private static final String KEY_APP_VERSION = "appVersion";
5052

5153
@Before
@@ -57,6 +59,28 @@ public void setUp() {
5759
public void tearDown() {
5860
ParseObject.unregisterSubclass(ParseInstallation.class);
5961
ParseCorePlugins.getInstance().reset();
62+
ParsePlugins.reset();
63+
}
64+
65+
private void mocksForUpdateBeforeSave() {
66+
// Mock currentInstallationController to make setAsync work
67+
ParseCurrentInstallationController controller =
68+
mock(ParseCurrentInstallationController.class);
69+
when(controller.isCurrent(any(ParseInstallation.class))).thenReturn(true);
70+
ParseCorePlugins.getInstance().registerCurrentInstallationController(controller);
71+
// Mock package manager
72+
RobolectricPackageManager packageManager =
73+
spy(RuntimeEnvironment.getRobolectricPackageManager());
74+
doReturn("parseTest").when(packageManager).getApplicationLabel(any(ApplicationInfo.class));
75+
RuntimeEnvironment.setRobolectricPackageManager(packageManager);
76+
ParsePlugins.Android plugins = mock(ParsePlugins.Android.class);
77+
// Mock installationId
78+
InstallationId installationId = mock(InstallationId.class);
79+
when(installationId.get()).thenReturn("installationId");
80+
when(plugins.installationId()).thenReturn(installationId);
81+
// Mock application context
82+
when(plugins.applicationContext()).thenReturn(RuntimeEnvironment.application);
83+
ParsePlugins.set(plugins);
6084
}
6185

6286
@Test
@@ -71,6 +95,7 @@ public void testImmutableKeys() {
7195
"deviceTokenLastModified",
7296
"pushType",
7397
"timeZone",
98+
"localeIdentifier",
7499
"appVersion"
75100
};
76101

@@ -146,24 +171,9 @@ public void testHandleFetchResultAsync() throws Exception {
146171

147172
@Test
148173
public void testUpdateBeforeSave() throws Exception {
149-
// Mock currentInstallationController to make setAsync work
150-
ParseCurrentInstallationController controller =
151-
mock(ParseCurrentInstallationController.class);
152-
when(controller.isCurrent(any(ParseInstallation.class))).thenReturn(true);
153-
ParseCorePlugins.getInstance().registerCurrentInstallationController(controller);
154-
// Mock package manager
155-
RobolectricPackageManager packageManager =
156-
spy(RuntimeEnvironment.getRobolectricPackageManager());
157-
doReturn("parseTest").when(packageManager).getApplicationLabel(any(ApplicationInfo.class));
158-
RuntimeEnvironment.setRobolectricPackageManager(packageManager);
159-
ParsePlugins.Android plugins = mock(ParsePlugins.Android.class);
160-
// Mock installationId
161-
InstallationId installationId = mock(InstallationId.class);
162-
when(installationId.get()).thenReturn("installationId");
163-
when(plugins.installationId()).thenReturn(installationId);
164-
// Mock application context
165-
when(plugins.applicationContext()).thenReturn(RuntimeEnvironment.application);
166-
ParsePlugins.set(plugins);
174+
mocksForUpdateBeforeSave();
175+
176+
Locale.setDefault(new Locale("en", "US"));
167177

168178
ParseInstallation installation = new ParseInstallation();
169179
installation.updateBeforeSave();
@@ -183,7 +193,9 @@ public void testUpdateBeforeSave() throws Exception {
183193
assertEquals(appVersion, installation.getString(KEY_APP_VERSION));
184194
// Make sure we update device info
185195
assertEquals("android", installation.getString(KEY_DEVICE_TYPE));
186-
assertEquals(installationId.get(), installation.getString(KEY_INSTALLATION_ID));
196+
assertEquals("installationId", installation.getString(KEY_INSTALLATION_ID));
197+
// Make sure we update the locale identifier
198+
assertEquals("en-US", installation.getString(KEY_LOCALE_IDENTIFIER));
187199
}
188200

189201
// TODO(mengyan): Add other testUpdateBeforeSave cases to cover all branches
@@ -255,6 +267,33 @@ public void testGetCurrentInstallation() throws Exception {
255267
verify(controller, times(1)).getAsync();
256268
}
257269

270+
@Test
271+
public void testLocaleIdentifierSpecialCases() throws Exception {
272+
mocksForUpdateBeforeSave();
273+
274+
ParseInstallation installation = new ParseInstallation();
275+
276+
// Deprecated two-letter codes (Java issue).
277+
Locale.setDefault(new Locale("iw", "US"));
278+
installation.updateBeforeSave();
279+
assertEquals("he-US", installation.getString(KEY_LOCALE_IDENTIFIER));
280+
281+
Locale.setDefault(new Locale("in", "US"));
282+
installation.updateBeforeSave();
283+
assertEquals("id-US", installation.getString(KEY_LOCALE_IDENTIFIER));
284+
285+
Locale.setDefault(new Locale("ji", "US"));
286+
installation.updateBeforeSave();
287+
assertEquals("yi-US", installation.getString(KEY_LOCALE_IDENTIFIER));
288+
289+
// No country code.
290+
Locale.setDefault(new Locale("en"));
291+
installation.updateBeforeSave();
292+
assertEquals("en", installation.getString(KEY_LOCALE_IDENTIFIER));
293+
}
294+
295+
296+
258297
// TODO(mengyan): Add testFetchAsync, right now we can not test super methods inside
259298
// testFetchAsync
260299
}

0 commit comments

Comments
 (0)