How to change theme from another app resource in android?
Asked Answered
R

3

8

I know there is a way to set themes by defining in styles.xml and use it like that

setTheme(android.R.style.MyTheme);

However, I want to get themes from another app which I developed as well. I know the resources names and actually I am able to get theme id with this code block;

Resources res = getPackageManager().getResourcesForApplication("com.example.theme");
int resThemeId = res.getIdentifier("my_theme","style","com.example.theme");

When I debug, I see that resThemeId is not zero.

Then, I need the final command to set this theme. Before super.onCreate() function, I try to implement this method but it seems it is not working

setTheme(resThemeId);

But instead of this, if I write below statement, I works fine

setTheme(android.R.style.Theme_Holo_Light);

So, what should I do to use a theme from different package resource?

Rapallo answered 26/1, 2017 at 11:1 Comment(3)
You can get the resource id from another package but those resources don't exist in your APK. Loading resources using PackageManager#getResourcesForApplication(String packageName) should work for drawables, strings, bools, etc. However, I don't believe it is possible, and definitely not recommended, to load another APK's theme.Suttee
While I can get drawables, strings, booleans from another package resources, I expect to get themes as well. Why is it impossible?Rapallo
It is possible (see my answer). You need to override getResrouces to return the other app's resources so you can apply the theme. This will also return all strings, layouts, drawables and other resources from the other application, therefore, it is not recommended.Suttee
S
4

So, what should I do to use a theme from different package resource?

You shouldn't do this for many reasons. I wrote a simple project that shows that it is indeed possible as long as the package contains the resources your activity uses.

See: https://github.com/jaredrummler/SO-41872033


Basically, you would need to return the package's resources from the activity:

public class MainActivity extends AppCompatActivity {

  Resources resources;

  @Override protected void onCreate(Bundle savedInstanceState) {

    int themeResId = getResources().getIdentifier("AppTheme", "style", "com.example.theme");
    if (themeResId != 0) {
      setTheme(themeResId);
    }

    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
  }

  @Override public Resources getResources() {
    if (resources == null) {
      try {
        resources = getPackageManager().getResourcesForApplication("com.example.theme");
      } catch (PackageManager.NameNotFoundException e) {
        resources = super.getResources();
      }
    }
    return resources;
  }

}

This is just to show that it is possible. Again, I recommend that you avoid this.

Suttee answered 31/1, 2017 at 2:53 Comment(3)
Is it possible to change resources at runtime with this way? I mean, I want to set original resources after setting theme from another resource?Rapallo
I don't think that is possible, but I also didn't think applying a theme from another package was possible. That's why I wouldn't recommend this solution. You don't want to use another package's resources for the layout and any drawables in your activity. What exactly are you trying to achieve with this?Suttee
I actually try to write a theme manager and different apk's which includes some themes (Themes includes background images, default sounds, app icons etc.) When I open theme manager app, I can retrieve drawables and list them from themes apk's accordingly. However, I also want to change some application themes (like Settings app) when I change theme. (I want to set primary, accent colors etc.) By the way, I am working on AOSP project and I can change Settings code easily. All I want is changing Settings theme from one of my theme application resources.Rapallo
C
4

As already mentioned in a comment you can access resources from other applications, but using another applications theme will not work.


Since having proof is always a good thing let's have a look at the source code (I used API 24 sources)

Calling setTheme() on an Activity will invoke initializeTheme() in the ContextThemeWrapper parent class, which will end up calling onApplyThemeResource(..) which in turn will try to load the actual theme data from resources by calling theme.applyStyle(resId, true)

Following the chain through the wrapper Resources.Theme we can see in ResourcesImpl.ThemeImpl the following, where AssetManager is called to load the style into the theme:

void applyStyle(int resId, boolean force) {
    synchronized (mKey) {
        AssetManager.applyThemeStyle(mTheme, resId, force);

        mThemeResId = resId;
        mKey.append(resId, force);
    }
}

This is where you try and fail to load the foreign theme from your other app.


Since most of the methods you would need to use are static calls or package local methods it does not seem that there is any way to achieve what you want, (e.g. applying or creating a new Theme)

Even if you get a hold of the other application's AssetManager by using getAssets() on a context there is no accessible method to create or apply themes.

So the only way to use another app's resources would be to add the resources to yours.

Cali answered 30/1, 2017 at 18:52 Comment(1)
How about sharedUserId? If I put sharedUserId for both application and sign with same certificate, what would happen? I tried but no luck. Maybe I am doing wrong somewhere in the codeRapallo
S
4

So, what should I do to use a theme from different package resource?

You shouldn't do this for many reasons. I wrote a simple project that shows that it is indeed possible as long as the package contains the resources your activity uses.

See: https://github.com/jaredrummler/SO-41872033


Basically, you would need to return the package's resources from the activity:

public class MainActivity extends AppCompatActivity {

  Resources resources;

  @Override protected void onCreate(Bundle savedInstanceState) {

    int themeResId = getResources().getIdentifier("AppTheme", "style", "com.example.theme");
    if (themeResId != 0) {
      setTheme(themeResId);
    }

    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
  }

  @Override public Resources getResources() {
    if (resources == null) {
      try {
        resources = getPackageManager().getResourcesForApplication("com.example.theme");
      } catch (PackageManager.NameNotFoundException e) {
        resources = super.getResources();
      }
    }
    return resources;
  }

}

This is just to show that it is possible. Again, I recommend that you avoid this.

Suttee answered 31/1, 2017 at 2:53 Comment(3)
Is it possible to change resources at runtime with this way? I mean, I want to set original resources after setting theme from another resource?Rapallo
I don't think that is possible, but I also didn't think applying a theme from another package was possible. That's why I wouldn't recommend this solution. You don't want to use another package's resources for the layout and any drawables in your activity. What exactly are you trying to achieve with this?Suttee
I actually try to write a theme manager and different apk's which includes some themes (Themes includes background images, default sounds, app icons etc.) When I open theme manager app, I can retrieve drawables and list them from themes apk's accordingly. However, I also want to change some application themes (like Settings app) when I change theme. (I want to set primary, accent colors etc.) By the way, I am working on AOSP project and I can change Settings code easily. All I want is changing Settings theme from one of my theme application resources.Rapallo
S
1

Have you seen this demo: Multiple Theme Material Design

You can check this demo for runtime theme change.

Hope it will helps you.

Spermatozoid answered 31/1, 2017 at 10:15 Comment(1)
The question asked to change the theme from a different package installed on the device. This changes the app theme as pre-defined in the current package's styles. While this is the recommended way of applying themes, it does not answer the OP's question.Suttee

© 2022 - 2024 — McMap. All rights reserved.