Android :: How to change theme from other apk programmatically - android

I have a apps named: preference, and i want to make themes for this apps. My AndroidManifest.xml of preference is:
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name="com.example.preference.MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
And in the MainActivity.java: I received theme change button click by:
themeChange = (Button) findViewById(R.id.themeChange);
themeChange.setOnClickListener(this);
I have a theme application which has PinkTheme (styles.xml) and the package name is com.example.theme.
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<style name="AppBaseTheme" parent="android:Theme.Light">
<!--
Theme customizations available in newer API levels can go in
res/values-vXX/styles.xml, while customizations related to
backward-compatibility can go here.
-->
</style>
<style name="PinkTheme" parent="AppBaseTheme" >
<item name="android:textColor">#FF69B4</item>
<item name="android:typeface">monospace</item>
<item name="android:textSize">40sp</item>
<item name="android:windowBackground">#008000</item>
</style>
</resources>
And the onClick() of my preference is:
public void onClick(View v) {
// TODO Auto-generated method stub
switch(v.getId()){
case R.id.themeChange:
Resources res = null;
try {
res = getPackageManager().getResourcesForApplication("com.example.theme");
} catch (NameNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(null != res) {
int sId = res.getIdentifier("com.example.theme:style/PinkTheme", null, null);
Theme themeObject = res.newTheme(); // theme object
themeObject.applyStyle(sId, true); // Place new attribute values into the theme
getTheme().setTo(themeObject);
}
break;
default:
break;
}
}
I have received theme Object of the theme package and try to setTheme of the preference application. But its not working. Please help me that: how to set theme from others application to my current application programmatically.

If you want to change settings in one application from another, then probably the easiest way to do it is to put a theme ID into an intent and send that intent to your MainActivity (or to an IntentService) where the receiving app can process the data. For example when the intent arrives, you can process it like you do a click event in your "onClick" logic.
For example, an app can create an intent like this:
Intent intent = new Intent("android.intent.action.MAIN");
intent.setComponent(new ComponentName("your.package", "your.package.component"));
intent.putExtra("theme_id", "theme_1");
startActivity(intent);
Then in your activity, use getIntent().getStringExtra("theme_id") to get the data passed to your app.

You would need to use the application's resources to load the theme. I have answered this in another thread here: https://stackoverflow.com/a/41948943/1048340
Here is an example where the package "com.example.theme" is installed and we use the app's resources and theme style in another app:
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;
}
}
See here for a working project on GitHub.
This can lead to problems because all layouts, drawables, strings, etc. will be loaded from the other application's resources. Therefore, you should avoid using a theme from another package and instead copy the resources and theme to your own project.

Related

Can i change app logos and colors based on customer type?

let's suppose that customer A wants his app to be blue, while user B wants his app to be red, both app, are the same in execution, except for the colors and image logos. So, to change the app's colors based on customer login would be a violation of googles terms ?
Make in values folder a themes.xml file (like styles.xml)
There you can define 2 or more themes with colors that can you set later in your app for some type of user:
<resources>
<style name="AppTheme.White" parent="Theme.AppCompat.Light.NoActionBar">
<item name="colorPrimary">#color/white</item>
...
</style>
<style name="AppTheme.Black" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="colorPrimary">#color/black</item>
...
</style>
</resources>
Set in your AndroidManifest.xml your theme in each activity that should be affected:
...
<activity android:name="com.example.YourApp.MainActivity"
...
android:theme="#style/AppTheme.White"/>
...
Make a class for saving the states, called Utility.class:
public class Utility {
public static void setTheme(Context context, int theme) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
prefs.edit().putInt(context.getString(R.string.prefs_theme_key), theme).apply();
}
public static int getTheme(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
return prefs.getInt(context.getString(R.string.prefs_theme_key), 1);
}
}
And in your TargetActivity.class you will set the method to apply the states with your specific user type:
public void updateTheme() {
if (Utility.getTheme(getApplicationContext()) <= 1) {
setTheme(R.style.AppTheme_White);
} else if (Utility.getTheme(getApplicationContext()) == 2) {
setTheme(R.style.AppTheme_Black);
}
}
To set the saved theme at start of the app just type that into your MainActivity.class:
private final static int THEME_WHITE = 1;
private final static int THEME_BLACK = 2;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
updateTheme();
}
public void updateTheme() {
if (Utility.getTheme(getApplicationContext()) <= THEME_WHITE) {
setTheme(R.style.AppTheme_White);
} else if (Utility.getTheme(getApplicationContext()) == THEME_BLACK) {
setTheme(R.style.AppTheme_Black);
}
}
That's how you work with different Themes. I think your question is answered by now :)
PS: Setting different colors for users isn't a violation against the terms of google. Google itself gave each letter a different color. ;)

ActionBarCompat: Hide ActionBar before activity is created (bug?)

So I was using the ActionBarSherlock and decided to switch to the new ActionBarCompat. With ABS, hiding the ActionBar was possible using the way described in this post:
How to hide action bar before activity is created, and then show it again?
But, with the ActionBarCompat the app crashes on API14, because when you set android:windowActionBar as false the getSupportActionBar() method returns null, even if you have declared the getWindow().requestFeature(Window.FEATURE_ACTION_BAR); into the onCreate() method.
Funny thing is that if you call getActionBar() instead, you get the object and everything works fine.
So, is that a bug or am I missing something? Any ideas are welcome!
styles.xml file:
<style name="Theme.MyApp" parent="#style/Theme.AppCompat.Light.DarkActionBar">
<item name="android:windowActionBar">false</item>
<item name="android:windowTitleSize">0dp</item>
</style>
MyActivity.java file:
...
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Get the action bar feature. This feature is disabled by default into the theme
// for specific reasons.
getWindow().requestFeature(Window.FEATURE_ACTION_BAR);
...
// By default the action bar is hidden.
getSupportActionBar().hide();
}
I got stuck with the same problem and, it seems to me, found a reason of this strange behavior. I looked through source of support library and got this:
Appcompat checks a value of mHasActionBar variable before creating new action bar in ActionBarActivityDelegate
final ActionBar getSupportActionBar() {
// The Action Bar should be lazily created as mHasActionBar or mOverlayActionBar
// could change after onCreate
if (mHasActionBar || mOverlayActionBar) {
if (mActionBar == null) {
mActionBar = createSupportActionBar();
...
And we can change its value by calling supportRequestWindowFeature(int featureId) which is delegated by ActionBarActivity to a ActionBarActivityDelegate.
There are base delegate class ActionBarDelegateBase and its descendants ActionBarDelegateHC, ActionBarActivityDelegateICS, ActionBarActivityJB, one of which is chosen according to a version of running android. And method supportRequestWindowFeature is actually works fine almost in all of them, but it's overridden in ActionBarActivityDelegateICS like that
#Override
public boolean supportRequestWindowFeature(int featureId) {
return mActivity.requestWindowFeature(featureId);
}
So it has no effect on the variable mHasActionBar, that's why getSupportActionBar() returns null.
We almost there. I came to two different solutions.
First way
import source project of appcompat from git
change overridden method in ActionBarActivityDelegateICS.java to something like this
#Override
public boolean supportRequestWindowFeature(int featureId) {
boolean result = mActivity.requestWindowFeature(featureId);
if (result) {
switch (featureId) {
case WindowCompat.FEATURE_ACTION_BAR:
mHasActionBar = true;
case WindowCompat.FEATURE_ACTION_BAR_OVERLAY:
mOverlayActionBar = true;
}
}
return result;
}
place this line in activity's onCreate method before getSupportActionBar()
supportRequestWindowFeature(WindowCompat.FEATURE_ACTION_BAR);
Second way
import project of appcompat from android SDK (which is with empty src directory)
add this method to your activity
private void requestFeature() {
try {
Field fieldImpl = ActionBarActivity.class.getDeclaredField("mImpl");
fieldImpl.setAccessible(true);
Object impl = fieldImpl.get(this);
Class<?> cls = Class.forName("android.support.v7.app.ActionBarActivityDelegate");
Field fieldHasActionBar = cls.getDeclaredField("mHasActionBar");
fieldHasActionBar.setAccessible(true);
fieldHasActionBar.setBoolean(impl, true);
} catch (NoSuchFieldException e) {
Log.e(LOG_TAG, e.getLocalizedMessage(), e);
} catch (IllegalAccessException e) {
Log.e(LOG_TAG, e.getLocalizedMessage(), e);
} catch (IllegalArgumentException e) {
Log.e(LOG_TAG, e.getLocalizedMessage(), e);
} catch (ClassNotFoundException e) {
Log.e(LOG_TAG, e.getLocalizedMessage(), e);
}
}
call requestFeature() in onCreate method of your activity like this
if (Build.VERSION.SDK_INT >= 11) {
requestFeature();
}
supportRequestWindowFeature(WindowCompat.FEATURE_ACTION_BAR);
I used the second way. That's all.
I use this to hide ActionBar in AppCompat:
style.xml
<style name="Theme.AppCompat.Light.NoActionBar" parent="#style/Theme.AppCompat.Light">
<item name="android:windowNoTitle">true</item>
</style>
AndroidManifest.xml:
<activity
android:name=".Splash"
android:label="#string/title_activity_splash"
android:theme="#style/Theme.AppCompat.Light.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
I don`t know if I understood exactly your question, but here I go.
I think that you need to use both: getSupportActionBar() to old versions and getActionBar() to newest versions. It`s not a bug.
You need to verify the device version before use the methods.
I hope I was able to help.
Does your activity extends ActionBarActivity? Probably it doesn't and that's why it's running with the getActionbar() method.

Use theme from framework-res.apk

In my app I want to use a theme which is defined in the framework-res.apk. I decompiled an other which uses this theme and I found this in the styles.xml
<style name="DefaultSettingsTheme" parent="#com.sonyericsson.uxp:style/SEMCTheme">
<item name="android:directionality">leftToRight</item>
</style>
If I try to use this in my app it comes to an error because eclipse does not know that this theme is aviable in an other apk. How can I use this theme without rebuilding it?
I haven't tested this, but hope it works:
public class MyActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String packageName = ""; // package name of the app of which you want to access the resources;
String resourceName = ""; // name of the resource you want to access
int theme = 0;
theme = getResources().getIdentifier(resourceName, "style", packageName);
if (theme != 0) {
setTheme(theme);
}
setContentView(R.layout.main);
}
}

Black screen before Splash screen appear in android

We know that when the app do some long process like downloading some information from internet it could show a splash screen before loading the application and when the app is loaded completely it will display the main page.
In splash screen activity we must load long processes in threads to avoid showing black screen before loading app.
I had done all of them. but also the black screen appears before showing app.
This is my onCreate method of the splash screen activity:
protected override void OnCreate (Bundle bundle)
{
try {
base.OnCreate (bundle);
//_dt = DateTime.Now.AddSeconds (_splashTime);
SetContentView (Resource.Layout.Splash );
FirstLoadPB= FindViewById <ProgressBar >(Resource .Id.FirstLoadPB );
FirstLoadingInfo= FindViewById <TextView >(Resource .Id.FirstLoadInfo );
LoadApplication ();
} catch (System.Exception ex) {
Common.HandleException (ex);
}
}
and this is the code of LoadApplication method:
public void LoadApplication()
{
new System.Threading.Thread (new ThreadStart (() =>
{
//Some Codes to load applications- Downloading from web and accessing the storage(Because was many codes - about 100 line- i was clear them.
}
)
).Start ();
}
I don't understand why the black screen appears and how should to avoid from this now.
I have some code that access to storage in oncreate of my application class. Maybe the issue's root cause be from there.There fore i shared its code:
public override void OnCreate ()
{
try {
base.OnCreate ();
_typeOfShow = new MapViewType ();
ListingTypes = new Dictionary<int,ListingTypeItem> ();
OfflineMode =false;
PropertyShowWasShown = false;
MeasutingUnitsChanged =false;
if(RplXmlSettings .Instance .getVal (AppConstants .XmlSettingShowOnCurrentLocationKey )== "True")
typeOfShow .ShowOnCurrentLocation =true ;
else
typeOfShow .ShowOnCurrentLocation =false;
//StorageClass .ctx = ApplicationContext ;
FillDashboardOnResume =false;
//initlize image loader
ImageLoader = Com.Nostra13.Universalimageloader.Core.ImageLoader.Instance;
Options = new DisplayImageOptions.Builder ()
.ShowImageForEmptyUri (Resource.Drawable.ic_tab_map)
.CacheOnDisc ()
.CacheInMemory ()
.ImageScaleType (ImageScaleType.InSampleInt)
.BitmapConfig (Bitmap.Config.Rgb565)
.Displayer (new FadeInBitmapDisplayer (300))
.Build ();
ImageLoaderConfiguration config;
ImageLoaderConfiguration .Builder builder =new ImageLoaderConfiguration
.Builder (ApplicationContext).ThreadPoolSize (3);
if(RplXmlSettings .Instance .getVal (AppConstants .XmlSettingMemoryCacheKey )== "True")
builder .ThreadPriority (4).MemoryCacheSize (1500000) ;// 1.5 Mb
builder .
DenyCacheImageMultipleSizesInMemory ().
DiscCacheFileNameGenerator (new Md5FileNameGenerator ()).
MemoryCache (new WeakMemoryCache()).
DiscCacheSize (15000000);
config = builder .Build ();
ImageLoader.Init (config);
} catch (Exception ex) {
Common .HandleException (ex);
}
}
OK.Long story short.Now the question is this-- Really what is the root cause of this black screen. Is this from splash activity or from application class. And How we can solve it and avoid form showing this?
Add a theme with the background you are using to your application tag in the manifest file to prevent the black screen to be drawn.
theme.xml
<resources>
<!-- Base application theme is the default theme. -->
<style name="Theme" parent="android:style/Theme" />
<style name="Theme.MyAppTheme" parent="Theme">
<item name="android:windowNoTitle">true</item>
<item name="android:windowContentOverlay">#null</item>
<item name="android:windowBackground">#drawable/my_app_background</item>
</style>
</resources>
AndroidManifest.xml
....
<application
android:name="#string/app_name"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/Theme.MyAppTheme"
>
....
Read why there is a black screen here
This initial screen that you see is called the "Preview" screen. You can disable this completely by declaring this in your theme:
android:windowDisablePreview
<style name="Theme.MyTheme" parent="android:style/Theme.Holo">
<!-- This disables the black preview screen -->
<item name="android:windowDisablePreview">true</item>
</style>
An explanation of how to handle this screen is posted here: http://cyrilmottier.com/2013/01/23/android-app-launching-made-gorgeous/
Add this line in your AndroidManifest.xml to the Launcher Activity:
android:theme="#android:style/Theme.Translucent.NoTitleBar.Fullscreen
You can solve this bug by converting image as a brush(color).
Add new file xml(splash_bg.xml) file in the drawable folder, like this.
<?xml version="1.0" encoding="utf-8" ?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<color android:color="#color/splash_bg_color"/>
</item>
<item>
<bitmap
android:src="#drawable/splash_screen"
android:tileMode="disabled"
android:gravity="center"/>
</item>
</layer-list>
Now add a new style, and apply splash_bg.xml as a background color.
<style name="Theme.SplashBg" parent="android:Theme">
<item name="android:windowBackground">#drawable/splash_bg</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowContentOverlay">#null</item>
</style>
Apply this new style to your main launcher activity or splash screen.
[Activity(Label = "label", MainLauncher = true, Theme = "#style/Theme.SplashBg")]
public class SplashScreenActivity : Activity
If you call some "heavy code" in onCreate the screen will appear black until it is done loading. You might consider using AsyncTask and make the onCreate handle setContentView etc, and make the AsyncTask handle "the heavy code".
the better solution to avoid this problem is using AsyncTask, here is a sample code that i use in one of my ListActivity:
private class YoutubeTask extends AsyncTask<URL, Integer, String> {
protected void onPreExecute() {
super.onPreExecute();
mLoadingProgress.startAnimation(mDisappear);
mLoadingProgress.setVisibility(View.GONE);
showDialogProgress();
}
protected String doInBackground(URL... url) {
youtubeData = VersionParser.readFromUrl(url[0]);;
try {
JSONObject jsono = new JSONObject(youtubeData);
JSONObject feed = jsono.getJSONObject("feed");
JSONArray entry = feed.getJSONArray("entry");
for(int i = 0 ; i < entry.length() ; i++ ){
JSONObject item = entry.getJSONObject(i);
JSONArray AUTHOR = item.getJSONArray(TAG_AUTHOR);
JSONObject Author = AUTHOR.getJSONObject(0);
JSONObject author = Author.getJSONObject("name");
String author_name = author.getString(TAG_TITRE);
JSONObject Statistics = item.getJSONObject("yt$statistics");
String Views = Statistics.getString(TAG_VIEWS);
JSONObject Media = item.getJSONObject("media$group");
JSONObject MediaTitle = Media.getJSONObject("media$title");
String title = MediaTitle.getString(TAG_TITRE);
JSONObject DURATION = Media.getJSONObject("yt$duration");
String duration = DURATION.getString(TAG_DURATION);
JSONArray Thumbinail = Media.getJSONArray("media$thumbnail");
JSONObject IMAGE = Thumbinail.getJSONObject(0);
String image = IMAGE.getString(TAG_CONTENT);
String id = image.substring(22,33);
map = new HashMap<String, String>();
map.put(TAG_TITRE , title );
map.put(TAG_ID , id );
map.put(TAG_DURATION , duration );
map.put(TAG_IMAGE , image);
map.put(TAG_VIEWS , Views );
map.put(TAG_AUTHOR , author_name);
CURRENCY.add(map);
}
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(String result) {
dismisDialogProgress();
mListView.setVisibility(View.VISIBLE);
mListView.startAnimation(mAppear);
mAdapter = new MAdapter(youtubeSearch.this , CURRENCY);
mListView.setSelector(R.drawable.home_bg);
mListView.setAdapter(mAdapter);
}
}
and inside the onCreate Methode implement this:
#Override
public void onCreate(Bundle savedInstanceState) {
if (Build.VERSION.SDK_INT < 11)
setTheme(android.R.style.Theme_Black_NoTitleBar);
}
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
new YoutubeTask().execute(new URL("https://gdata.youtube.com/feeds/api/videos?q=Adele&max-results=15&v=2&alt=json"));
}
Here's some food for thought; maybe you don't have a sizeable initialization delay in your application at all; you might in fact, be waiting for the instant run service.
From what I've experienced, the symptoms of this are that your application shows a lengthy black screen whilst initializing, but upon debugging you find that none of your Application/Activity's onCreate methods have yet to even be called whilst it's visible.
This happens only when you use an activity as a Splash screen, if your app does not do any background operation like calling a api and stuff like that then use #maulikparmar method for standard splash screen(google recommended Way). But for activity method I only wrote a annotation in My splash screen activity , this worked for me very well
#SuppressLint("CustomSplashScreen")
public class SplashScreen extends AppCompatActivity {}
and also do android:windowDisablePreview = true in your theme (style.xml) of splash screen activity.
<item name="android:windowDisablePreview">true</item>

How does Android ActivityUnitTestCase incorporate the target App's AndroidManifest.xml?

I have an activity Let's say A
it is defined in a given application and it's corresponding manifest. This activity loads a contentView which it just loads via a static R index. Let's say R.layout.foo. That layout happens to have a component in there that looks on something that isn't the base android attrs. I am seeing that when a Test app runs this activity the theme and the styles within the theme are not filled with anything.
Sample Manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.foo.bar"
android:versionCode="1"
android:versionName="Test"
android:installLocation="auto">
<uses-sdk android:minSdkVersion="3" android:targetSdkVersion="8" />
<uses-permission android:name="android.permission.INTERNET" />
<application
android:icon="#drawable/app_icon"
android:label="#string/app_name"
android:description="#string/description"
android:theme="#style/Theme.Custom"
android:name=".MyApplicationObject">
<activity android:name=".activity.A"/>
<supports-screens
android:smallScreens="true"
android:normalScreens="true"
android:largeScreens="true"
android:anyDensity="true" />
</manifest>
Activity A
public class A extends Activity {
public void onCreate(Bundle a) {
setContentView(R.layout.foo);
}
}
A Layout, foo.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<com.foo.bar.CustomView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
</LinearLayout>
CustomView
public class CustomView extends RelativeLayout {
public CustomView(Context context, AttributeSet set) {
this(context, set, R.attr.CustomViewStyle);
}
public CustomView(Context c, AttributeSet set, int defStyle) {
super(c, set, defStyle);
TypedArray array = c.obtainStyledAttributes(set, R.styleable.CustomViewAttrs, defStyle, defStyle);
final int layout = array.getResourceId(R.styleable.CustomViewAttrs_layout, 0);
final Drawable icon = array.getDrawable(R.styleable.CustomViewAttrs_icon);
array.recycle();
if (layout == null) {
throw new IllegalStateException("WTF");
}
if (icon == null) {
throw new IllegalStateException("For real, WTF");
}
}
}
Some Resources in a Values file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Used to define a namespace for our special types -->
<declare-styleable name="CustomTypes">
<attr name="CustomViewStyle" format="reference"/>
</declare-styleable>
<!-- Used to define Attributes specific to our new View, "CustomView" -->
<declare-styleable name="CustomViewAttrs">
<attr name="layout" format="reference"/>
<attr name="anotherOne" format="reference"/>
</declare-styleable>
<!-- A usable style that we can reference later to pass to an instance of CustumView -->
<style name="CustomView">
<item name="layout">#layout/foo</item>
<item name="AnotherOne">#drawable/icon</item>
</style>
<!-- A Style to act as our Theme, referenced in our Manifest as the Theme for all activities -->
<style name="Theme.Custom" parent="android:Theme">
<item name="CustomViewStyle">#style/CustomView</item>
</style>
<resources>
This works fine, but when I use an ActivityUnitTest to load up an instance of A the values inside of the TypedArray are empty.
Some Test Class
public class ActivityTester extends ActivityUnitTestCase<A> {
public ActivityTester() {
super(A.class);
}
public void testOne() {
Intent intent = new Intent(getInstrumentation().getTargetContext(), A.class);
// This fails with my IllegalStateException
startActivity(intent, null, null);
}
}
Any idea how/if the target Application get's it's manifest parsed? It seems like the theme isn't even getting loaded. The documentation for startActivity() states that it will start the activity the same way that context.startActivity() would. I don't see that happening as it doesn't seem to respect the manifest data of the activity.
So after a lot of time spent trying to do this, I found that personally the best way to do this is to mock out the Theme itself.
public void setUp() {
ContextThemeWrapper context = new ContextThemeWrapper(getInstrumentation().getTargetContext(), R.style.Theme_MyTheme);
setActivityContext(context);
}
public void testOne() {
Intent intent = new Intent(getInstrumentation().getTargetContext(), A.class);
startActivity(intent, null, null);
}
Personally I don't like this, because it couples the unit test implementation to the stylistic nuances that I would like to offset to another role, (like a visual designer, or a graphic artist) and adds the possibility of the test being completely out of sync with the implementation that would be shipped. i.e. someone changes the Manifest files so that the the Theme resource that is associated with an Activity is different than what is being tested. This TestCase type just seems really short sighted since it could lead to a bunch of bad things like this. I mean you would end up with a bunch of ActivityUnitTestCase instances that test the base functionality and then some Instrumentation Test Cases for the same Activity, that just start it up or go through the transitions that might invoke a layout inflation. Not a real app being tested at that point.
You can use ActivityInstrumentationTestCase2 instead which is intended to tests Activities created using the system infrastructure:
import android.test.ActivityInstrumentationTestCase2;
public class ActivityTester extends ActivityInstrumentationTestCase2<ActivityTester> {
public ActivityTester() {
super(ActivityTester.class);
}
public void testOne() {
//Intent intent = new Intent(getInstrumentation().getTargetContext(), ActivityTester.class);
// This fails with my IllegalStateException
//startActivity(intent, null, null);
getActivity();
}
}
ActivityUnitTestCase is for unit test Activities in isolation.
There are some other errors in your code but I think they are the result of copying here eliminating some parts.

Categories

Resources