Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to change theme from another app resource in android?

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?

like image 700
Berkay92 Avatar asked Jan 26 '17 11:01

Berkay92


2 Answers

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.

like image 96
David Medenjak Avatar answered Oct 12 '22 09:10

David Medenjak


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.

like image 33
Jared Rummler Avatar answered Oct 12 '22 11:10

Jared Rummler