Status Update
Comments
al...@google.com <al...@google.com>
ri...@google.com <ri...@google.com> #2
The issue is reproducible with core-ktx 1.2.0 and 1.3.0-rc01.
ri...@google.com <ri...@google.com> #3
The Typeface.weight is not a weight of the underlying font file. It is a display style. On older APIs, the display style is adjusted if the Typeface is created from single font. However, after moving to CustomFallbackBuilder, that adjustment is removed since it can crate Typeface from multiple style font files.
Looks like it is good to set display style by ResourcesCompat.getFont for backward compatibility.
jo...@gmail.com <jo...@gmail.com> #4
Hi Nona,
Can you please schedule a release after you merge the fix?
pr...@google.com <pr...@google.com> #5
Branch: androidx-master-dev
commit 3d6aa2e9b3243dcc4de1f54bd8d40339bd69cb05
Author: Seigo Nonaka <nona@google.com>
Date: Wed May 27 17:38:05 2020
Adjust the Typeface display style with the style of given font
This behavir is implicitly done by Typeface.Builder and
Typeface.createXXX function but not to be done by
Typeface.CustomFallbackBuilder since it is designed to be working
with multiple font files which has different style.
Looks like the style argument is ignored on older API implementation.
Bug: 156853883
Bug: 152023266
Test: ResourcesCompatTest#testGetFont_adjustDisplayStyle passes on 29
Test: ./gradlew core:core:connectedAndroidTest on API 29, 28, 23
Change-Id: I3a377c339a7aed50973cf11df86ddf0069f4ec25
A core/core/src/androidTest/assets/fonts/thin_italic.ttf
A core/core/src/androidTest/assets/fonts/thin_italic.ttx
M core/core/src/androidTest/java/androidx/core/content/res/ResourcesCompatTest.java
A core/core/src/androidTest/res/font/thin_italic.ttf
M core/core/src/main/java/androidx/core/graphics/TypefaceCompatApi29Impl.java
se...@gmail.com <se...@gmail.com> #7
Any way I can tell what version this will land in?
go...@google.com <go...@google.com>
ly...@gmail.com <ly...@gmail.com> #9
Great—works as expected, thanks!
sh...@gmail.com <sh...@gmail.com> #10
I call AppCompatDelegate.setApplicationLocales, but the strings are still in the device locales in all the cases I get the strings outside a fragment or activity.
On Android 13 it works well.
I noticed that when I get the strings by the activity's context, it works well, so why is not the application context updated on Android 12 and below like on Android 13+?
so...@gmail.com <so...@gmail.com> #11
ba...@gmail.com <ba...@gmail.com> #12
go...@google.com <go...@google.com>
po...@gmail.com <po...@gmail.com> #13
This also causes Intent.ACTION_LOCALE_CHANGED not being received
ma...@zentity.com <ma...@zentity.com> #14
Same problem. AppCompatDelegate implementation is broken, when you want to use it outside an activity.
There is no way to use AppCompatDelegate.setApplicationLocales
and AppCompatDelegate.getApplicationLocales
, when the Activity is not running. E.g from Application class, content provider, broadcast receiver, etc. These two calls are tightly bounded with the activity in compat code.
If you use custom localization library, you usually initialize it in Application class. But in Application class you can't retrieve currently set application locale on a pre-13 devices. AppCompatDelegate.getApplicationLocales
here returns empty locale list.
Also migration from custom locale storage to AppCompatDelegate
storage works only when the Activity
is running. This must be possible to do before starting the Activity
to prevent Activity recreation during migration.
de...@workerbase.com <de...@workerbase.com> #15
Any update on this issue?
I must say that this API and its documentation is so misleading for at least two reasons. First, because AppCompatDelegate.setApplicationLocales
naming makes you think that this will update the application context on all Android versions, and in fact it does it only on the last one out of 13. Second, for the fact that this issue is no where mentioned in any related documentation.
Good luck to all the devs that will learn or have learned this the hard way, like myself.
Either give us an option to not have to resort to workarounds like this
as...@google.com <as...@google.com> #16
Hey all,
Thank you for your feedback and for outlining these pain points. We don't have an update regarding the fact that the backward compatible library only works for the Activity and not the Application context on Android 12 and earlier devices.
Yes, agreed this needs to be documented. We expect to have this documented shortly.
as...@google.com <as...@google.com> #17
Hey all, we added text like this to the
For backward compatibility with previous Android versions, equivalent APIs are also available in AndroidX. However, the backward compatible APIs work with the AppCompatActivity context, not the application context, for Android 12 (API level 32) and earlier. Access the backward compatible APIs with Appcompat 1.6.0 or higher.
se...@gmail.com <se...@gmail.com> #18
I would suggest at least adding to the documentation about the attachBaseContext()
required in Application.kt, Services, activities that do not extend AppCompatActivity, etc. And a suggested implementation or gist would be very useful too.
This documentation could be added beneath, or as part of
Such as...
Application Context in Android 12 and lower
In order for application context to have the correct language resources, developers will need to handle attachBaseContext()
in Application.kt, Services, activities that do not extend AppCompatActivity (TODO: Where else is this needed???). The following code snippet shows how this may be implemented:
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(getContextForLanguage(base));
}
public static Context getContextForLanguage(Context context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) return context;
String languageTag = PreferenceManager.getDefaultSharedPreferences(context).getString(PREF_APP_LANGUAGE_TAG, "");
if (languageTag.isEmpty()) return context;
Locale locale = Locale.forLanguageTag(languageTag);
Locale.setDefault(locale);
Resources resources = context.getResources();
Configuration configuration = resources.getConfiguration();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
configuration.setLocales(new LocaleList(locale));
} else {
configuration.setLocale(locale);
}
return context.createConfigurationContext(configuration);
}
I'm not sure if this is the best implementation, but it has worked very well for our app with ~5m downloads (and supported in 22 languages). I think many developers are avoiding adding an in-app language picker for Android 12 and under due to the amount of testing and lack of documentation that increases the risk trying to find the correct implementation.
Thanks!
do...@gmail.com <do...@gmail.com> #19
ch...@gmail.com <ch...@gmail.com> #20
I would also like to point out that when setting locale to Traditional Chinese for Android 6 (not tested on earlier Android versions from KitKat to Lollipop), the following codes do not work even for Activity Context:
AppCompatDelegate.setApplicationLocales(LocaleListCompat.create(Locale.TRADITIONAL_CHINESE))
AppCompatDelegate.setApplicationLocales(LocaleListCompat.create(Locale.TAIWAN))
AppCompatDelegate.setApplicationLocales(LocaleListCompat.create(Locale("zh", "TW")))
AppCompatDelegate.setApplicationLocales(LocaleListCompat.create(Locale("zh_tw")))
The following works for Android 6:
AppCompatDelegate.setApplicationLocales(LocaleListCompat.create(Locale("zh-tw")))
as...@google.com <as...@google.com> #21
Hi
ca...@google.com <ca...@google.com> #22
We added new API (
Feel free to try it and let us know if there is any issue.
Here is the release note:
se...@gmail.com <se...@gmail.com> #23
Thanks! I just tested this and works great... on a side-note Services also need this added in attachBaseContext()
otherwise they can have the wrong context for notifications, strings, etc.
I didn't see any issues with upgrading users who have already selected a different language either - their context/strings looked correct with Application context 👍
se...@gmail.com <se...@gmail.com> #24
One issue I've found with ContextCompat.getContextForLanguage()
is that it doesn't update the default Locale - Locale.getDefault()
.
This can prove problematic in Application/Service classes, as well as it isn't inline with the other changes with language changes in AppCompatActivity
or in API 33+, which both adjust the Locale.getDefault()
to the users selected language.
I believe the default Locale should be updated similarly as done in AppCompatActivity/API 33+, no?
ca...@google.com <ca...@google.com> #25
Hi,
Thanks for your feedback. I agree that adding Locale.getDefault()
to ContextCompat.getContextForLanguage()
would help some developers who are not aware that Locale
is still not updated in other Android components. However, it doesn't make much sense from an API perspective. If someone just wants to get the context via ContextCompat.getContextForLanguage()
, they may not be aware that an unrelated object (Locale
) has also been changed. It looks fine in per-app locales cases for now, but we don't want someone to use this API to cause unexpected behavior someday. I think we can add some description in the docs to help other developers aware this so that app owners can add Locale.setDefault()
themselves.
se...@gmail.com <se...@gmail.com> #26
Good point, it doesn't make sense to set the default Locale in ContextCompat.getContextForLanguage()
. When you update its docs can you state that the per-app locale can be retrieved with LocaleManagerCompat.getApplicationLocales() outside of activity context to set default Locale with?
Otherwise I think developers are going to try to use AppCompatDelegate.getApplicationLocales() and not know there's another similar API...
ca...@google.com <ca...@google.com> #27
Thanks, I'll update it in the docs. If you want to set per-app locale to Locale
after ContextCompat.getContextForLanguage()
, you can consider getting per-app locale from Context
, which returns from ContextCompat.getContextForLanguage()
because its configuration already contains per-app locale and you can save one disk IO.
se...@gmail.com <se...@gmail.com> #28
Right, using LocaleManagerCompat.getApplicationLocales()
would lead to an extra disk IO.
So, basically an in-app implementation of this could be...
Context updatedContext = ContextCompat.getContextForLanguage(initialContext);
Locale updatedLocale = updatedContext.getResources().getConfiguration().locale; // using deprecated for example only
// Avoid setting default locale needlessly
if (!Locale.getDefault().equals(updatedLocale)) {
Locale.setDefault(updatedLocale);
}
return updatedContext;
Thanks!
[Deleted User] <[Deleted User]> #29
Using ContextCompat.getContextForLanguage(context)
and setting the base context in the Application
works great for the use case when the app is restarted. The problem we have is when we update the locale programmatically in the app with AppCompatDelegate
.
We are using the application context to retrieve strings across the whole app.
How can we make sure that this application context is using the app locale under the hood without restarting the whole application?
se...@gmail.com <se...@gmail.com> #30
I just opened another issue for per-app languages (affects Android 12 and under too):
[Deleted User] <[Deleted User]> #31
E.g.
- The user has configured multi-profile and when the application is launched multi-profile screen displays there are 3 user logins and each has a different locale, once any user is selected related locale should be set. For activity, it is working correctly but with the application context below Android 12, it picks the device locale for the application context string.
- For the same scenario, if a user selects the first user and then navigates to the second user then the application locale should also be refreshed.
Please suggest a solution or way to fix it otherwise it is difficult to migrate.
sh...@miniclip.com <sh...@miniclip.com> #32
ch...@beyls.net <ch...@beyls.net> #33
The current implementation of ContextCompat.getContextForLanguage(context)
has some major issues that make it hard to recommend:
- Each call performs a blocking disk I/O call which impacts performance, because
LocaleManagerCompat.getApplicationLocales(context)
(used internally) performs a disk I/O.ContextCompat.getString(context, resId)
suffers from the same issue because it callsContextCompat.getContextForLanguage(context)
internally. - The documentation suggests to call it in Application's
attachBaseContext()
, in which case a single I/O call would be acceptable. However, if the selected language is updated while the application is open, the Application context language will not be updated, so this technique doesn't work properly.
I suggest to implement some synchronized caching mechanism in AppLocalesStorageHelper
, similar to what AppCompatDelegate
does. This way, there should only be a single blocking disk I/O during the first call to ContextCompat.getContextForLanguage(context)
, and it can then be called repeatedly everywhere an Activity Context is not available.
The documentation should also be updated to mention the big limitation of calling ContextCompat.getContextForLanguage(context)
in Application's attachBaseContext()
.
As a workaround, I reimplemented ContextCompat.getContextForLanguage(context)
to use a cache internally that I also update when calling AppCompatDelegate.setApplicationLocales()
, but since that cache is not synchronized with AppCompatDelegate
's cache I get 2 blocking I/O reads in total.
ch...@gmail.com <ch...@gmail.com> #34
Any updates on issue described in the comment above?
Description
Version used: 1.6.0-beta01
Devices/Android versions reproduced on: OnePlus 9 Pro Android 12
Setting locale via AppCompatDelegate.setApplicationLocales doesnt work with application context on Android 12. In Android 13 the following snippet is using the in app language for both rows but on Android 12 first row is printed in phone locale and second one in app locale.
Log.d(TAG, applicationContext.getString(R.string.settings_change_button)) // Application context
Log.d(TAG, getString(R.string.settings_change_button)) // Activity context