Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Localization on Android #590

Merged
merged 10 commits into from
Oct 23, 2024
Merged

Conversation

filip131311
Copy link
Collaborator

@filip131311 filip131311 commented Oct 3, 2024

This PR adds localization on android.

Screen.Recording.2024-10-03.at.16.47.57.mov

Additional context:

How Android changes the locale settings when the user does it in the settings app?

Android changes the memory responsible for holding information about locale and tigers a change in two types of persistent storage, one is system prop persist.sys.locale and the second one is system_locales prop in system level settings.
Before user changes the settings both of those fields are empty. When Android boots it either sets a locale to the default one or to the one specified in one of the persistent locations, it seems that if only one location exist android will still retrive the information, but conflict between persist.sys.locale and system_locales leads to unpredictable behavior.

How to change the properties with adb?

adb allows us to change system properties including persist.sys.locale granted we have a root access, this is achieved either by using adb root command or su command inside shell. The root access is only possible on emulators without GMS (google mobile services). adb also allows us to chage system settings using adb shell settings command and it does not require root access, but permanent state change of system_settings require -writable-system flag to be added on emulator boot, so we do it.

How emulator command changes settings when using -change-locale option?

Underneath emulator calls adb shell su 0 setprop persist.sys.locale ${locale}.

Uncovered case:

Because of the above I did not find a way to reliably change persist.sys.locale and scenario in which user manually changes locale (in the settings app).

Test Plan:

  1. Changing localization while using the device
  • turn on IDE and select android device
  • check if localization settings are disabled during boot process:
Screenshot 2024-10-11 at 18 13 35
  • change devices localization after it was booted up
  1. Changing localization while using other available device
  • turn on IDE and select ios device
  • change devices localization after it was booted up
  • switch devices to android and check if the localization was configured correctly

Copy link

vercel bot commented Oct 3, 2024

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
radon-ide ✅ Ready (Inspect) Visit Preview 💬 Add feedback Oct 23, 2024 6:03pm

]);

// if user did not use the device before it might not have system_locales property
// as en-US is the default locale we assume that no value is the same as en-US
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"we assume that no value is the same as en-US" I don't understand this part.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If there is no value and the user selected locale is en-US I don't want to trigger locale change as it is already a correct one


// it is necessary to use SIGTERM 9 as it would take to much time otherwise and would degrade user experience
// having said that use this function with caution only in scenarios when you are sure that no user data will be lost
private async resetDevice() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

forcefullyResetDevice to signify this isn't typical reboot sequence?

// If the device uses google mobile services persist.sys.locale can not be changed, as it requires a root access
// TODO: Find a way to change or remove persist.sys.locale without root access. note: removing the whole
// data/property/persistent_properties file would also work as we persist device settings globally in Radon IDE
private async changeLocale(newLocale: Locale): Promise<boolean> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't it always returning true? What does the return value mean?

]);

if (!stdout) {
return true;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add some logging here such that we can diagnose it for the users who may've set the language using settings app

Comment on lines 127 to 146
// If persist.sys.locale exist try to set it to match the newLocale.
try {
await exec(ADB_PATH, [
"-s",
this.serial!,
"shell",
"su",
"0",
"setprop",
"persist.sys.locale",
locale,
]);
} catch (e) {
// this is expected if device is using google mobile services
Logger.debug(
"CHANGE LOCALE - Device is not allowing root access, moving on without modifying persist.sys.locale"
);
}

return true;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should be ok to remove this part. It is unlikely that someone would change the language via settings, and even if they do, it is unlikely you can actually use sudo on Android devices as it is only available on pure AOSP builds which are rarely used in practice

Copy link
Member

@kmagiera kmagiera left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please see my inline comments and add test plan to PR description.

I believe the way you tested this was by changing it while the Android device was booted. But what happen when you change language on iOS and then switch to Android, or when you change the language before the device is fully booted.

]);

// this is needed to make sure that changes will persist
await exec(ADB_PATH, ["shell", "sync"]);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why we don't pass "-s", this.serial here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it was a mistake thank you

// this is needed to make sure that changes will persist
await exec(ADB_PATH, ["shell", "sync"]);

if (stdout) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would feel more natural if we made this check before the other exec call given you use a transient stdout variable

Copy link
Member

@kmagiera kmagiera left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Almost there, I left a few more comments inline

Comment on lines 190 to 191
// it is necessary to use SIGTERM 9 as it would take to much time otherwise and would degrade user experience
// having said that use this function with caution only in scenarios when you are sure that no user data will be lost
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For method documentation we use ``/** */` comments format, but this doesn't seem to be one actually. If you want to document method it should be structured in a way that describes what the method does rather than what is necessary and for what. For example, method docs would say something along the lines "This method restarts the emulator process using SIGKILL signal. Should be used for the situations when quick reboot is necessary and when we don't care about the emulator's process state"

On the other hand, if you want to comment why we use "9", this could be an in-line comment in the code block directly preceeding the kill call, and it could state: "We use 9 (SIGKILL) to terminate the process immediatly, as terminating it gracefully typically takes some significant time"

Comment on lines 198 to 200
// We have to initially boot the device because we use adb shell to change the devices locale
// alternative would be to use -change-locale option on the emulator, but that option restarts the device too
// the -change-locale option is not covering all cases read more about it in this.changeLocale
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment doesn't belong here. Why you explain stuff related to changing locale in a place that isn't super relevant. Here we're already using an abstraction, that is "changeSetting" method which returns whether the emulator process should be rebooted. Discussing internals of changeSetting at this level is an abstraction leak.

return (
<>
<Label>Device Localization</Label>
<DropdownMenu.Item
disabled={projectState.status !== "running"}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

similar change already landed in #643 – we likely want to use that one instead

return true;
}

// this method changes device locale in two ways, firstly it modifies system_locales setting,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please read my other comment about method level comments I posted below.

Copy link
Member

@kmagiera kmagiera left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a couple more inline comments Accepting to unblock this but please address the comments before merging

]);

// if user did not use the device before it might not have system_locales property
// as en-US is the default locale we assume that no value is the same as en-US
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand what does it mean "no value is the same as en-US"

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I modified the comment to explain it better

return true;
}

/** This method changes device locale by modifying system_locales system setting. */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/** This method changes device locale by modifying system_locales system setting. */
/**
* This method changes device locale by modifying system_locales system setting.
*/


if (stdout) {
Logger.warn(
"persist.sys.locale detected while changing locale. It might indicate that the user has changed locale settings in the settings application, which will prevent localization change."
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"persist.sys.locale detected while changing locale. It might indicate that the user has changed locale settings in the settings application, which will prevent localization change."
"Updating locale will not take effect as the device has altered locale via system settings which always takes precedence over the device setting the IDE uses."

Comment on lines 192 to 194
/** This method restarts the emulator process using SIGKILL signal.
* Should be used for the situations when quick reboot is necessary
* and when we don't care about the emulator's process state */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/** This method restarts the emulator process using SIGKILL signal.
* Should be used for the situations when quick reboot is necessary
* and when we don't care about the emulator's process state */
/**
* This method restarts the emulator process using SIGKILL signal.
* Should be used for the situations when quick reboot is necessary
* and when we don't care about the emulator's process state
*/

@@ -144,6 +222,7 @@ export class AndroidEmulatorDevice extends DeviceBase {
"-no-boot-anim",
"-grpc-use-token",
"-no-snapshot-save",
"-writable-system",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is this option? why are we adding it here? It should be explained in PR description

@filip131311 filip131311 merged commit cccc52c into main Oct 23, 2024
4 checks passed
@filip131311 filip131311 deleted the @Filip131311/AddAndroidLocalization branch October 23, 2024 18:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants