Testing TextView text colour using Robolectric for Android - android

I'm trying to TDD/test the text colour of a textView for android. However all of the properties seem to return either 0 or null, does anyone know why?
The code creating the text view:
public void setupTextView() {
LinearLayout layout = (LinearLayout) findViewById(R.id.layout);
TextView textView = new TextView(this);
textView.setText(job.getName());
if (job.getLastBuild().getBuildStatus().equals("SUCCESS")) {
textView.setTextColor(Color.parseColor("#007000"));
} else {
textView.setTextColor(Color.parseColor("#FF0000"));
}
layout.addView(textView);
}
I've ran the application and the code above works.
The properties I've tried accessing in the test code:
#Test
public void firstTextViewShouldReflectPassingJobStatus() throws Exception {
LinearLayout layout = layout = (LinearLayout) activity.findViewById(R.id.layout);
TextView gomoTextView = (TextView) layout.getChildAt(0);
System.out.println(gomoTextView.getCurrentTextColor()); //Returns 0
System.out.println(gomoTextView.getTextColors()); //Returns null
System.out.println(gomoTextView.getSolidColor()); //Returns 0
System.out.println(gomoTextView.getCurrentHintTextColor()); //Returns 0
//I also tried using `Robolectric.shadowOf()`:
ShadowTextView shadowGomoTextView = Robolectric.shadowOf(gomoTextView);
System.out.println(shadowGomoTextView.getTextColorHexValue()); //Returns 0
System.out.println(shadowGomoTextView.getHintColorHexValue()); //Returns null
}
Update to answer comments
I have a before in the unit test class which calls onCreate():
private LinearLayout layout;
private HomeActivity activity;
#Before
public void setUp() throws Exception {
activity = spy(new HomeActivity());
Jenkins mockJenkins = TestUtilities.getTestJenkins();
when(activity.getJenkins()).thenReturn(mockJenkins);
activity.onCreate(null);
layout = (LinearLayout) activity.findViewById(R.id.layout);
}
And the the onCreate method in the HomeActivity class:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Jenkins jenkins = getJenkins();
displayJenkins(jenkins);
}
And then display jenkins calls a load of other methods which include setupTextView()

Looking to the sources it's not implemented yet. I would suggest you to implement your own shadow as described here.
Robolectric 2.0 has been promoted to the alpha state. I think you issue should be fixed during release since they are going to use as much as possible real Android source code.

Related

Prepare Unity without showing UnityPlayer

I'm integrating Unity as a subview in a native Android app.
I'd need to prepare Unity when the app starts, but without showing it, because I need to change between scenes when the user taps a button, without showing the Unity screen presentation.
The flow is:
User chooses a scene in Activity A -> Display scene in PlayGameActivity with UnityPlayer.UnitySendMessage, without Unity splash/loading screen
In iOS I did it like this:
class AppDelegate: UIResponder, UIApplicationDelegate {
var currentUnityController: UnityAppController!
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
self.currentUnityController = UnityAppController()
self.currentUnityController.application(application, didFinishLaunchingWithOptions: launchOptions)
return true
}
But I don't find something similar in Android.
This is how I'm showing the UnityPlayer in a subview:
public class PlayGameActivity extends UnityPlayerActivity {
private static final String TAG = "PlayGameActivity";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_play_game);
// Create the UnityPlayer
mUnityPlayer = new UnityPlayer(this);
int glesMode = mUnityPlayer.getSettings().getInt("gles_mode", 1);
boolean trueColor8888 = false;
mUnityPlayer.init(glesMode, trueColor8888);
// Add the Unity view
RelativeLayout layout = (RelativeLayout) findViewById(R.id.container_unity_play_game_activity);
RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) layout.getLayoutParams();
layout.addView(mUnityPlayer.getView(), 0, lp);
String unityScene = "some_scene";
Log.d(TAG, "calling scene " + unityScene);
UnityPlayer.UnitySendMessage("AController", "AMethodToChangeScene", unityScene);
}
}
I tried changing scene in an Activity with the player and the buttons below, and it works, because I wait for the player to be ready. Unity does receive the message of changing scene and does so after loading itself.
So is there a way to init Unity without showing it like in iOS? Or a way to know when the UnityPlayer is ready/isn't showing the splash screen?
I tested an approach that I think may work for you.
First I made a two View variables so that the views can be manipulated throughout the class.
public class PlayGameActivity extends UnityPlayerActivity {
private static final String TAG = "PlayGameActivity";
private View playerView;
private RelativeLayout layout;
RelativeLayout.LayoutParams lp
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_play_game);
// Create the UnityPlayer
mUnityPlayer = new UnityPlayer(this);
int glesMode = mUnityPlayer.getSettings().getInt("gles_mode", 1);
boolean trueColor8888 = false;
mUnityPlayer.init(glesMode, trueColor8888);
//MODIFIED VERSION OF YOUR CODE
playerView = mUnityPlayer.getView();
// Add the Unity view SLIGHTY MODIFIED
layout = (RelativeLayout) findViewById(R.id.container_unity_play_game_activity);
lp = (RelativeLayout.LayoutParams) layout.getLayoutParams();
String unityScene = "some_scene";
Log.d(TAG, "calling scene " + unityScene);
UnityPlayer.UnitySendMessage("AController", "AMethodToChangeScene", unityScene);
}
}
Then in my test, I had two buttons with listeners set up. The first button let me send a message to Unity,
Button theButton = (Button)findViewById(R.id.button);
theButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mUnityPlayer.UnitySendMessage("CallThis", "MessageFromAndroid", "HI!");
}
});
Then the second button did the following,
Button good = (Button)findViewById(R.id.button2);
good.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
layout.addView(playerView);
mUnityPlayer.requestFocus();
}
});
So the basic idea is don't add mUnityPlayer using layout.addView() to the view until you are ready. You could have your program call UnitySendMessage, and then from within Unity make a call into Android that runs the second line from the button I made. That is, just replace that button I used with a function that Unity can call. You're probably familiar with it already but I'll link to the Android Scripting API anyway.
EDIT: I ran another test and it is not necessary to put mUnityPlayer.requestFocus() in the method that adds the UnityPlayer to your view.

How do I refactor findViewById without class cast exception?

Usually when I have many elements in my android app, onCreate looks like this:
onCreate(){
ImageButton b1 = (ImageButton)findViewById(R.id.b1) ;
ImageButton b2 = (ImageButton)findViewById(R.id.b2) ;
ImageVuew v3 = (ImageButton)findViewById(R.id.v3) ;
ViewSwitcher v4 = (ViewSwitcher)findViewbyId(R.id.v4) ;
TextView v5 = (TextView)findViewById(R.id.v5) ;
//and so on
}
Android requires to do this class cast for every text,image,button etc in the app. But text,image,button,switcher are all subclasses of View class!
I try to add all views into one array of Views and loop through like this:
View[]clickableViews = {forkImageView, patronImageView,cabelImageView1,cabelImageView2, bulb_switcher,doublePlugImageView,kettleBaseImageView,kettleSwitcher} ;
int []image_views_ids = {R.id.forkImage, R.id.patronImage, R.id.bulb_switcher, R.id.cabel1, R.id.cabel2, R.id.longcabel, R.id.kettle_base, R.id.kettleSwitcher};
for( int i = 0 ; i < clickableViews.length;i++){
clickableViews[i] = findViewById(image_views_ids[i]);
}
It may throw class cast exception
Is there a way to still do it smart way?
Try the library Butterknife, I think its what you are looking for. It will make your code cleaner :)
The example from the website is:
class ExampleActivity extends Activity {
#InjectView(R.id.title) TextView title;
#InjectView(R.id.subtitle) TextView subtitle;
#InjectView(R.id.footer) TextView footer;
#Override public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.simple_activity);
ButterKnife.inject(this);
// TODO Use "injected" views...
}
}
You should cast into View class,too.
Your code will be like:
View[]clickableViews = {forkImageView, patronImageView,cabelImageView1,cabelImageView2, bulb_switcher,doublePlugImageView,kettleBaseImageView,kettleSwitcher} ;
int []image_views_ids = {R.id.forkImage, R.id.patronImage, R.id.bulb_switcher, R.id.cabel1, R.id.cabel2, R.id.longcabel, R.id.kettle_base, R.id.kettleSwitcher};
for( int i = 0 ; i < clickableViews.length;i++){
clickableViews[i] =(View)findViewById(image_views_ids[i]);
}

Updating LinearLayout from other class in Android

I have a class which uses other classes to build up a FrameLayout. One is for Navigation through a building, the other for displaying schematics with sensors of it, and the other one to display sensordata. I build up the whole frame one time, and want to make the sensordata visible in the sensorview part of the frame. Lets say I have 5 sensors, and when I click on one the sensorview shows up the sensordata. I could just make 5 sensorviewframes on top of each other, initiating them invisible, and just make the one visible which was selected via a click on a sensor.
I wanted to ask, is it possible to change the LinearLayout containing the TextViews in a different class with an update method?
I already tried it, but with my code it doesn't work at the moment.
public static SensorBar Create_SensorBar_Layout(Context myContext, ObjectStructure objStruct, ObjectView objView, List<SensorDevice> listofCurrentSensordevices)
{
// Init
LinearLayout SensorBarLinearLayout = new LinearLayout(myContext);
LinearLayout.LayoutParams layoutParamsSensorBar = new LinearLayout.LayoutParams(
200, 653);
layoutParamsSensorBar.setMargins(5, 5, 5, 5);
SensorBarLinearLayout.setOrientation(LinearLayout.VERTICAL);
SensorBarLinearLayout.setLayoutParams(layoutParamsSensorBar);
SensorBarLinearLayout.setBackgroundResource(R.drawable.window_frame);
SensorBarLinearLayout.setPadding(4,4,4,4);
LinearLayout SensorBarData = new LinearLayout(myContext);
LinearLayout.LayoutParams layoutParamsSensorBarData = new LinearLayout.LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
SensorBarData.setOrientation(LinearLayout.VERTICAL);
SensorBarData.setLayoutParams(layoutParamsSensorBarData);
//--- Button Headline ---
Button buttonNavBarHeadline = new Button(myContext);
buttonNavBarHeadline.setText("Sensordata");
buttonNavBarHeadline.setTextColor(Color.BLACK);
buttonNavBarHeadline.setBackgroundResource(R.layout.mainview_window_headline);
buttonNavBarHeadline.setTextAppearance(myContext, R.style.headline3);
//Layout buildup
SensorBarLinearLayout.addView(buttonNavBarHeadline);
SensorBarLinearLayout.addView(SensorBarData);
return new SensorBar(SensorBarLinearLayout, SensorBarData);
}
This is the Sensorbar, and I want to have the LinearLayout SensorBarData to be dynamically swapped out by clicking on the sensorbuttons.
public void updateSensorBar(Context myContext, ObjectStructure objStruct, List<SensorDevice> listofCurrentSensordevices, int activeSensor)
{
LinearLayout linearlayoutSensorvalueTextviews = new LinearLayout(myContext);
... (additional Textviews for Sensordata, which get added with addview())
setSensorBarData(linearlayoutSensorvalueTextviews);
}
This is used by an OnClick event.
public void setSensorBarData(LinearLayout SensorBarData) { this.dataSensorBar = SensorBarData; }
This is used by the updateSensorBar to update the LinearLayout.
I would be glad for any help.
Define an interface and use a callback to let the activity know that a sensor has been updated.
public Interface SensorUpdatedListener {
void onSensorUpdated();
}
In your SensorBar class.
ArrayList<SensorUpdatedListener > listeners = new ArrayList<SensorUpdatedListener >();
...
public void setSensorUpdatedListener(SensorUpdatedListener listener){
listeners.add(listener);
}
In your sensor bar update method:
for (SensorUpdatedListener listener:listeners){
listener.onSensorUpdated();
}
In your Activity:
public class Test extends Activity implements SensorUpdatedListener {
...
#Override
public void onCreate(Bundle savedInstanceState)
{
...
sensorBar.setSensorUpdatedListener(this);
...
}
public void onSensorUpdated(){
// do whatever you need to do
}
You could improve the SensorBar class by adding removeSensorUpdatedListener and checking that you do not add the same listener twice in setSensorUpdatedListener.

Android app Crash

Why is this:
public class HelpTab extends Activity
{
LinearLayout helpLayout; //was changed to LinearLayout helpLayout = new LinearLayout(this);
TextView helpText = new TextView(this);
Button tips = new Button(this);
Button walkThrough = new Button(this);
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
buttonCreator();
setContentView(helpLayout);
}
public void buttonCreator()
{
//Button featuress defined in here (setText("") and adding them to the layout, addView();)
}
Causing my program to crash?
I have looked at the code extensively and I can't put my finger on it, and the debugger also says source not found when it opens the new page tab thing to tell me what is happening.
Try calling setContentView(helpLayout); first and then buttonCreator();
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(helpLayout);
buttonCreator();
}
Assuming that you are trying to initialize your button inside buttonCreater() with respect to a button you have declared in your helplayout, you might run into Null Pointer Exception.

Android - Setting an ImageView content from another class

Here's the thing:
I have two classes: Main and control.java
the Main class is an Activity class where I build my app and the control class I just use for variables controls that I must access from other classes.
The problem is: In class Main I got 2 methods, and I have an ImageView in each of them, I need to set the image view resource of the second method on a click listener of the first one. Like this:
public void first() {
final ImageView first = (ImageView) findViewById(R.id.myview);
first.setBackgroundResource(R.drawable.myimage);
}
public void second() {
final ImageView second = (ImageView) findViewById(R.id.myview2);
//And then, I want something like this: first.setBackgroundResource(first);
}
Thanks guys!
Why don't you just do something like:
public void second() {
final ImageView second = (ImageView) findViewById(R.id.myview2);
final ImageView first = (ImageView) findViewById(R.id.myview);
first.setBackgroundResource(R.drawable.myimage);
}
Otherwise, you'd have to use a private/public class variable and define it outside the method.
I admit to being a bit confused by your question but I think below is at least the start of what you're looking for
#Override
protected void onCreate(Bundle savedInstanceState) {
control.setImageView((ImageView) findViewById(R.id.myview));
second = (ImageView) findViewById(R.id.myview2);
}
public void first() {
control.getImageView().setBackgroundResource(R.drawable.myimage);
}
public void second() {
second.setBackgroundDrawable(control.getImageView().getDrawable());
}
ImageView second;

Categories

Resources