Dagger2, a visual approach

In this post I’m not going to explain what Dagger is, but I’m just showing a visual example of it is used inside an Android Application.

What we want to do

We want to use SharedPreferences inside our MainActivity

How

  1. Create SharedPreferences class
  2. Create a @Module that provides that class
  3. Create a @Component that injects the Modules into our Activity
  4. Let’s instantiate the Component inside out Application
  5. Let’s @Inject our MySharedPreferences into the Activiy and use it

See image for more details

[Unity] Coroutine, forever running

We are going to see how to instantiate Game Objects without freezing the game UI.

What we need to do is to create a Coroutine, it is just a method that has IEnumerator as a return type.

public class GameController : MonoBehaviour {

public GameObject hazard;
public float spawnWait;

void Start () {
    StartCoroutine (SpawnWaves ());
}

IEnumerator SpawnWaves () {
while(true) {

     Vector3 spawnPosition = new Vector3 (…);

     Quaternion spawnRotation = Quaternion.identity;

     Instantiate (hazard, spawnPosition, spawnRotation);

        yield return new WaitForSeconds (spawnWait);

   }
}
}

As you can see from the code, I also added yield return new WaitForSeconds () after instantiate the game object, so we can avoid to instantiate all of them at same time.

 

[Unity] Keep a gameObject into a specific area

If we have a gameObject that needs to move into a specific area, we can use the Mathf.Clamp(value, min, max), this check that the value we have is min < x < max.

In the example below, we take the gameObject position X and Z and said that must be inside a range.

    [...]

  Rigidbody rb;

  void Start() {
rb = GetComponent<Rigidbody>();
}

  void FixedUpdate() {

float moveHorizontal = Input.GetAxis (“Horizontal”);
float moveVertical = Input.GetAxis (“Vertical”);

Vector3 movement = new Vector3 (moveHorizontal, 0.0f, moveVertical);
rb.velocity = movement * speed;

rb.position = new Vector3 (
                  Mathf.Clamp(rb.position.x, boundary.xMin, boundary.xMax),
                 0.0f,
                 Mathf.Clamp(rb.position.z, boundary.zMin, boundary.zMax)
             );

}

[Unity] Serializable classes for a better interface

If we are going to have a long list of “public” params, so it looks something like this:

we can organize them by grouping into a class (in this case called Boundary), so we can have a better and clear game interface like this:

 

How to do it?

Just create a new class and remember to add [System.Serializable] on top of your class otherwise Unity is not able to recognise it and you are not going to see anything on the interface

[System.Serializable]
public class Boundary {
public float xMin, xMax, zMin, zMax;
}

public class PlayerController : MonoBehaviour {

public Boundary boundary;

[...]

// Use it like this: boundary.xMin, etc..

 

}

 

 

Android interface

How to communicate through an interface in Android between an activity and a custom view.

In this example we want to press a Button inside a custom-view and do something to another view on the activity layout.

 

Layout activity:

[...]
<com.savinoordine.CustomView
android:id="@+id/custom_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>

<View
android:id="@+id/view"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
[...]
// END ACTIVITY LAYOUT

Custom view Layout :

[...]
<Button
  android:id="@+id/buttom"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content" />
[...]
// END CUSTOM-VIEW LAYOUT

 

 

public class CustomView {
 private View mView;

 private void init() {
    mButton = (Button) findViewById(R.id.button);
 mButton.setOnClickListener(new OnClickListener() {
      @Override
      public void onClick(View v) {
      //when click is done, it is called the interface method that
      //it is implemented in activity (not in custom view) so view is shown up/more
        if (mOnButtonListener != null) {
            mOnButtonListener.onButtonPressed();
        }
    }
  });

    //set the listener
    public void setListener(OnButtonListener listener) {
      mOnButtonListener = listener;
    }

    //interface that communicate with the activity
    interface OnButtonListener {
      void onButtonPressed();
    }
  }
}

Inside the activity where the view has to be shown/other we have to implement the interface method.

[...] implements CustomView.OnButtonListener {

  //onCreate method
    mCustomView = (CustomView) findViewById(R.id.custom_view);
    mCustomView.setListener(this);
mView = (View) findViewById(R.id.view);

  //implement interface
  @Override
  public void onButtonPressed() {
   //do something with the mView
  }
}

Grant|Revoke permission with adb [Android M]

Hey there, Android M RC is almost out and one of the new feature is “manage permissions“, let’s see hot the grant or revoke a permission with adb. In this example, I am going to show how to revoke the camera permission at the Google Camera app.

First of all, let’s connect a phone on your computer and let’s see how many apps are installed:

>> ./adb shell pm list packages

You will get a list of package names:

[...]
com.google.android.GoogleCamera
[...]

 

Now we are going to get the list of all the permissions:

>> ./adb shell pm list permissions -d -g
[...]
group:android.permission-group.CAMERA
  permission:android.permission.CAMERA
[...]

And here how to revoke the permission:

>> ./adb shell pm revoke com.google.android.GoogleCamera  android.permission.CAMERA

and here how to grant it back:

>> ./adb shell pm grant com.google.android.GoogleCamera android.permission.CAMERA

 

 

 

OpenSTF, share your testing devices and.. [part-1]

As a mobile QA Engineer, every times that a new features is created I need to check it on many devices (with different screen size, different O.S, and so on) what do I need to do in this case? Take every single devices, connect it to my computer, and begin testing…. Simple right? What can be wrong, nothing? The world is not always bright! Let’s see:

  • I do not find the device
  • Or it has battery low
  • Or I borrowed it to a collegue and he/she forget to give it back to me
  • I waste time to find, plug/unplaug the cable
  • [The list can be much longer, better stop here... You already got what I want to say]

Finally STF came to me! So far, my team and I try it with a raspberry PI, I can say it worked fine and we all got a positive feedback from it. So we want to push it at the next level and build our Smartphone Testing Farm. Some (so far) pro/cons of STF:

Pro:

  • Devices always connected, fully charged and available
  • Easy to use
  • Sharable with everybody (Designers, Boss, …)

Cons:

  • Need to invest some money for the smartphone farm (Hub usb, computer, cables)
  • The persone that use the device, need to release it when it is done, people can forget, so the devices keep locked

- Next -

  • Build a smartphone farm and use it in depth
  • Using SPOON to execute all the automated tests on all the devices

- Reference -

STF Website: OpenSTF

STF project source: github.com/openstf/stf

Spoon website: square.github.io/spoon/ 

 

To be continued…

MODIFY /etc/hosts on Genymotion device

Need to be a root user:

 sudo su

Once you are a root user, need to execute:

./adb shell

When you are in, open the file and edit it.

 vi /etc/hosts

Espresso Google – Let’s see some examples

Doubt about Android testing? I show you what I did…
After long time using Robotium, I decide to try Google Espresso and I have to say I’m happy of this change.

Why I’m happy about it?

Pro Espresso:

    Byebye solo.sleep()! Yes you read well, Espresso understand when the UI is still running before let you fail the test
    Fast. Fast. Faaaaast.

Pro Robotium:

    Much easy to write code. The learning curve is faster than Espresso
    Easy to read test. They look more readable even from a non technical person

….But I did not find good example of Espresso, so I decide to create a public repository on Github with many simple (and not only) examples about using Espresso. Clone it or just start watching it: https://github.com/onivas/EspressoPlayGround

Here a fast Espresso sheet: https://code.google.com/p/android-test-kit/wiki/EspressoV2CheatSheet

How to get a View while testing [with Android Espresso]

I was trying Google Espresso for testing Android apps (it is pretty nice and fast), but I got stuck while I was trying to tap a custom (in my case was a checkbox and a linked text) view and the onView(withId(R.id.checkbox_id)).perform(click()); fails every times. Text link was clicked but checkbox wasn’t checked.

Question? Can I get the view and use coords to perform click?
Answer: Yes!
Note: The custom view is not on Activity test rule

Let’s see how to do:

@RunWith(AndroidJUnit4.class)
@LargeTest
public class EspressoTest {

  @Rule
  public ActivityTestRule mHomeRule = new ActivityTestRule<>(Home.class);
/**
 * Need to add HONEYCOMB because the clickXY() action needs
 * YOUR_ACTIVITY_NAME = the Activity that contains the view
 */
  @TargetApi(Build.VERSION_CODES.HONEYCOMB)
  @Test
  public void letsClickWithCoords(){
// Click the button that open the activity that contains our custom view
  onView(withId(R.id.open_activity)).perform(click());
Instrumentation.ActivityMonitor monitor =  getInstrumentation().addMonitor(YOUR_ACTIVITY_NAME.class.getName(), null, false);
  Activity currentActivity = getInstrumentation().waitForMonitorWithTimeout(monitor, 5);
 [..do something until the view is visible…]
 View v = currentActivity.findViewById(R.id.checkbox_id);
 onView(withId(R.id.paid_options_tos)).perform(clickXY(v.getX(), v.getY()));
 }

 [...]
 public static ViewAction clickXY(final float x, final float y){
   return new GeneralClickAction(
   Tap.SINGLE,
   new CoordinatesProvider() {
    @Override
    public float[] calculateCoordinates(View view) {
     final int[] screenPos = new int[2];
     view.getLocationOnScreen(screenPos);
     final float screenX = screenPos[0] + x;
     final float screenY = screenPos[1] + y;
     float[] coordinates = {screenX, screenY};
     return coordinates;
     }
   },
   Press.FINGER);
 }