4

I need to change the language of the Operating system from my application (Installed as System app) and I am using reflection to get access to these classes

        public void setSystemLanguage (String langCode)
        {
            Locale loc;
            loc = Locale.forLanguageTag(langCode);
            try {
                Class<?> activityManagerNative = Class.forName("android.app.ActivityManagerNative");
                Object am = activityManagerNative.getMethod("getDefault", new Class[0]).invoke(activityManagerNative, new Object[0]);
                Object config = am.getClass().getMethod("getConfiguration", new Class[0]).invoke(am, new Object[0]);
                config.getClass().getDeclaredField("locale").set(config, loc);
                config.getClass().getDeclaredField("userSetLocale").setBoolean(config, true);
                am.getClass().getMethod("updateConfiguration", new Class[]{Configuration.class}).invoke(am, new Object[]{config});
            } catch (Exception e) {
                Log.e(LOG_TAG, Log.getStackTraceString(e));
            }
        }

My Issue is that ActivityManagerNative,Locale.locale and ActivityManagerNative.updateConfiguration() are deprecated. I tried the following code

  Object objIActMag, objActMagNative;
        Class clzIActMag = Class.forName("android.app.IActivityManager");
        Class clzActMagNative = Class.forName("android.app.ActivityManager");
        Method getDefault = clzActMagNative.getDeclaredMethod("getService");
        objIActMag = getDefault.invoke(clzActMagNative);
        Method getConfiguration = clzIActMag.getDeclaredMethod("getConfiguration");
        Configuration config = (Configuration) getConfiguration.invoke(objIActMag);
        LocaleList localeList = new LocaleList(locale);
        config.setLocale(localeList.get(0));
        config.getClass().getDeclaredField("locale").set(config, locale);
        config.getClass().getDeclaredField("userSetLocale").setBoolean(config, true);

        Class[] clzParams = { Configuration.class };
        Method updateConfiguration = clzIActMag.getDeclaredMethod(
                "updateConfiguration", clzParams);
        updateConfiguration.invoke(clzIActMag,config);
        BackupManager.dataChanged("com.android.providers.settings");

My problem is that I cannot find a replacement for the deprecated method updateConfiguration().I found a replacement for this method

Configuration overrideConfiguration = getBaseContext().getResources().getConfiguration();
overrideConfiguration.setLocales(LocaleList);
Context context  = createConfigurationContext(overrideConfiguration);
Resources resources = context.getResources();

But I am unsure of how to use the context from here as I need to change the SYSTEM language. Please note that this is not for changing the Application language.

The code to change the Locale in System from LocalePicker.java is

  public static void updateLocales(LocaleList locales) {
    try {
        final IActivityManager am = ActivityManager.getService();
        final Configuration config = am.getConfiguration();
        config.setLocales(locales);
        config.userSetLocale = true;

        am.updatePersistentConfiguration(config);        
        BackupManager.dataChanged("com.android.providers.settings");
    } catch (RemoteException e) {          
    }
}

Please find a replacement for the deprecated method updateConfiguration() so that I can Apply The changes to the SYSTEM

Rajan Kali
  • 12,627
  • 3
  • 25
  • 37
Phillen
  • 336
  • 5
  • 18
  • Possible duplicate of https://stackoverflow.com/q/25355330/2550246 – iamgopal Feb 15 '18 at 09:47
  • Please read the question before commenting.I have gone through these links and I could not find a solution. That is why I posted a question. – Phillen Feb 15 '18 at 09:54
  • Always mention the API versions you are targeting and using to build your project. – iamgopal Feb 15 '18 at 09:57
  • Please refer to this and create a wrapper for the context object https://stackoverflow.com/a/40704077/2550246 – iamgopal Feb 15 '18 at 10:00
  • Thanks. But this is not I need right now.I need to change language for the full system as I mentioned.Not just the app – Phillen Feb 15 '18 at 14:01

3 Answers3

3

I have found another way to implement this without reflection. Please understand this is only for system applications and for people who work in OS level.

import android.app.Activity;
import android.app.ActivityManager;
import android.app.IActivityManager;

Method to change language. Must be a system Application. with

android:sharedUserId="android.uid.system" 

in manifest

 public void changeLanguageSettings(Locale language/*Locale.GERMAN*/) {
        try {
            IActivityManager am = ActivityManager.getService();
            Configuration config = am.getConfiguration();
            config.setLocale(language);
            config.userSetLocale = true;
            am.updatePersistentConfiguration(config);
            BackupManager.dataChanged("com.android.providers.settings");

            Log.d("changelanguage", "success!");
        } catch (Exception e) {
            Log.d("changelanguage", "error-->", e);
        }
    }
Phillen
  • 336
  • 5
  • 18
  • How were you able to access ActivityManager.getService() without reflection? I'm currently using https://github.com/anggrayudi/android-hidden-api to access hidden/systemApi classes, but this does not make all hidden methods public. – Simon Raes Nov 21 '18 at 08:40
  • I am currently in OS development so I can make my application a system application which can access the hidden classes. – Phillen Nov 21 '18 at 13:20
  • I'm also working on a system app and it works fine on the device, but Android Studio still gives errors because it can't find the SystemAPI methods in the Android SDK. How did you get around that without reflection? – Simon Raes Nov 21 '18 at 16:07
  • How are you planning to build your System app? We use a separate build machine and issue source,lunch commands and mm to make the apk. So I just code in the studio even if SystemAPI methods cannot be resolved and then copy the codes to the build machine to generate apk file. – Phillen Nov 22 '18 at 06:38
  • @Phillen `getConfiguration` method is removed from recent android code do you know another way to get the configuration,https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/java/android/app/ActivityManager.java – nima moradi Dec 22 '20 at 08:32
0

While i found no direct way to change the language of the device using code, you could just use an Intent instead of doing all that implementation above.

startActivity(new Intent(android.provider.Settings.ACTION_LOCALE_SETTINGS));

this will display a list of the languages and you can just change it that way.

-1

Edit: This was tested Android M and havent been tested on latest versions.

Finally I have found it myself. Posting for others so they dont want to be in a mess.

    public void changeLanguageSettings(Context con, Locale language/*Locale.GERMAN*/) {
    try {

        Class<?> activityManagerNative = Class.forName("android.app.ActivityManager");
        Object am = activityManagerNative.getMethod("getService").invoke(activityManagerNative);
        Configuration config = (Configuration) am.getClass().getMethod("getConfiguration").invoke(am);

        config.setLocale(language);
        config.getClass().getDeclaredField("userSetLocale").setBoolean(config, true);
        am.getClass().getMethod("updatePersistentConfiguration", android.content.res.Configuration.class).invoke(am, config);
        BackupManager.dataChanged("com.android.providers.settings");

        Log.d("changelanguage", "success!");

    catch (Exception e) {
        Log.d("changelanguage", "error-->", e);
    }
}
Phillen
  • 336
  • 5
  • 18
  • getService method is not found by ActivityManger Class @Phillen – Masoud Darzi Nov 04 '19 at 11:00
  • as I said the log said that this method getService is not found. I've searched in andrid fragmework documention in ```http://androidxref.com/ ``` and you can see in this link ```http://androidxref.com/7.0.0_r1/xref/frameworks/base/core/java/android/app/ActivityManager.java``` that if you want to call getService method you must first call getDefault mehtod – Masoud Darzi Nov 05 '19 at 09:27
  • this is for android 7.0.0.r1 – Masoud Darzi Nov 05 '19 at 09:29