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
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.
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]);
}
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.
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.
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;