Monthly Archives: October 2015

Android Studio Permanently Change Debug Configuration for Working Directory $MODULE_DIR$ and app:assembleDebugUnitTest

On Mac OS X, Android Studio’s default debug Unit Test build configuration generally doesn’t run with default settings complaining that:

AndroidManifest.xml not found or not a file; it should point to your project’s AndroidManifest.xml

To fix this error you need to edit your debug configuration to set Working Directory as $MODULE_DIR$ and it makes builds faster to set Before Launch as gradle :app:assembleDebugUnitTest

To set these Debug build configuration settings permanently go to Android Studio Menu -> Run -> Edit Configurations… -> click on the little wrench and cog icon to Edit Defaults, JUnit should be selected if you’re currently on a Unit Test and change the working Directory to $MODULE_DIR$ and Before Launch: Gradle-aware Make and choosing :app:assembleDebugUnitTest. Remove the plain-jane “Make” from the list as well.

android-studio-menu-edit-configurations
android-studio-debug-edit-configuration-screen

Android AsyncTask return result

To get Android AsyncTask to return a result use a callback method (Observer pattern) by following these steps.

  1. Define a constructor for our async class which extends AsyncTask (we’re required to subclass/extend AsyncTask for use). Let’s call our AsyncTask class MyAsyncTask.
  2. Constructor parameter takes a class which will handle the AsyncTask result.  Usually an Activity or Fragment, but could be a Robolectric Unit Test class for example.
  3. Declare a member variable/private field to hold the handling Activity/Fragment/Test. We’ll call it ResultListener.  The constructor will assign its parameter input to this member variable.
  4. Declare an Interface within  MyAsyncTask. Let’s call it ResultListener
  5. ResultListener defines a single method that our handling class must implement.  Let’s name the method handleAsyncResult and in this case it’s going to take a single boolean as an input parameter.
  6. In onPostExecute, call our listener class handler method, supplying a value to the input parameter as appropriate for the outcome of doInBackground.

Here’s a concrete example of an Android AsyncTask returning a result:

 

public class MyAsyncTask<T> extends AsyncTask<T, Void, Boolean> {
    private final String TAG = this.getClass().getName();
    ResultListener listener;

    public interface ResultListener {
        void handleAsyncResult(boolean result);
    }

    WebProxy proxy;

    public MyAsyncTask(ResultListener listener) {
        this.listener = listener;
    }

    @Override
    protected Boolean doInBackground(T... params) {
        // do interesting long running things here, Network, database, etc.
        Log.i(TAG, String.format("doInBack: sending %s via Retrofit", params.getClass().getName()));
        return true;
    }

    @Override
    protected void onPostExecute(Boolean success) {
        listener.handleAsyncResult(success);
    }
}

As a bonus this AsyncTask uses a Type parameter <T> as input, so it can handle different input types for the AsyncTask.execute(input). This will make your AsyncTask more reusable and easy to extend for future use.

When MyAsyncTask completes doInBackground, it will pass a boolean to onPostExecute which we’re going to send along to our handling class through listener.handleAsyncResult(success).

Within our handling class (supplied to our AsyncTask constructor) we’ll need to do two things:

  1. Make our class implement our Interface by adding  “implements MyAsyncTask.ResultListener” after the class name.
  2. Define a method within our handling class with a signature that matches MyAsyncTask.ResultListener.

Here’s an example for our implementing class:

public class Test implements MyAsyncTask.ResultListener {
private boolean asyncResult;

@Override
public void handleAsyncResult(boolean result) {
    asyncResult = result;
}


@Test
public void firstAsyncTest() throws Exception {
    MyAsyncTask<Checkin> myTask = new MyAsyncTask<>(this);
    myTask.execute(someArrayOfTypeT);
    assertThat(asyncResult).isTrue();
}

}

Retrofit error 415 400 object with Date field Fix @JsonFormat annotation

Retrofit error 415 or error 400 on an object with a Date field can be fixed by using @JsonFormat annotation with the proper date pattern format specified in the annotation.

java.util.Date toString() (for my locale/region) returns a string date format of MMM dd, yyyy hh:mm:ss aa

Example: Oct 22, 2015 11:09:55 PM

For Retrofit / Jackson to serialize / deserialize a date (java.util.Date) properly, you must annotate your Date fields with the corresponding date pattern:

@JsonFormat(shape= JsonFormat.Shape.STRING, pattern = "MMM dd, yyyy hh:mm:ss aa")

Pay special attention to the uppercase / lowercase lettering of each date part.  Two digit date of month must be LOWERCASE (i.e. “dd” not “DD”).  Otherwise it will be interpreted as a date of year which can be three digits.  (I was getting bizarre JSON serialization JSON deserialization results such as Oct 22 becoming Dec 362 by having the wrong case on my date part of the date format (i.e. “DD”.)

For the full list of date format parts that Jackson (fasterxml) uses see:

http://docs.oracle.com/javase/1.5.0/docs/api/java/text/SimpleDateFormat.html

H2 Web Console to In Memory Database – Spring Boot

To get an H2 Database Web Console accessing an in-memory database running on Spring Boot:

  1. Register H2’s WebServlet (with UrlMapping /console/*) to your Spring project in a Configuration annotated class. Restart your Application.
  2. Open a web page to http://localhost:8080/console/
  3. Be sure you’re accessing the correct database JDBC URL (default would be jdbc:h2:mem:testdb)

(Credit: Spring Framework Guru)

 

import org.h2.server.web.WebServlet;
import org.springframework.boot.context.embedded.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class H2ConsoleWebConfiguration {
 @Bean
 ServletRegistrationBean h2servletRegistration() {
 ServletRegistrationBean registrationBean = new ServletRegistrationBean(new WebServlet());
 registrationBean.addUrlMappings("/console/*");
 return registrationBean;
 }
}

Robolectric reference

Robolectric Android testing Fragments and more

private ReminderManagerFragment startReminderManagerFragment() {
    final ReminderManagerFragment fragment = new ReminderManagerFragment();
    SupportFragmentTestUtil.startVisibleFragment(fragment);
    return fragment;
}

@Test
public void reminderManagerTest() throws Exception {
    // by default there should be 3 Reminder rows
    ReminderManagerFragment fragment = startReminderManagerFragment();
    assertThat(fragment).isNotNull();
    Button addButton = (Button) fragment.getView().findViewById(R.id.reminder_add_button);
    assertThat(addButton).isNotNull();

    List<Reminder> reminders = getReminders(TestValues.BillyUser);
    assertThat(reminders.size()).isEqualTo(3);

    // add a reminder, assert reminders = 4
    addButton.performClick();

    //assertThat(reminders.size()).isEqualTo(4);
    TimePickerFragment pickerFragment =
            (TimePickerFragment) fragment.getFragmentManager()
                    .findFragmentByTag(ReminderManagerFragment.TIME_DIALOG);
    assertThat(pickerFragment).isNotNull();

    reminders = getReminders(TestValues.BillyUser);
    assertThat(reminders.size()).isEqualTo(4);

    AlertDialog pickerDialog = (AlertDialog) pickerFragment.getDialog();

    assertThat(pickerDialog).isNotNull();
    assertThat(pickerDialog.getButton(AlertDialog.BUTTON_POSITIVE)).isNotNull();

    Button pickerOKButton = (Button) pickerDialog.getButton(AlertDialog.BUTTON_POSITIVE);
    pickerOKButton.performClick();

    // check that an alarm was set
    ShadowAlarmManager shadowAlarmManager = shadowOf(AlarmFactory.getAlarmManager(mCtx));
    // shadow AlarmManager should return 0 alarms
    List<ShadowAlarmManager.ScheduledAlarm> shadowAlarms = shadowAlarmManager.getScheduledAlarms();
    Log.i(TAG, "alarms currently set: " + shadowAlarms.size());
    assertThat(shadowAlarms.size()).isGreaterThan(0);

 

Try changing TimePicker Hour and Minutes and resubmit AlertDialog (TimePickerDialog), they key method being ((TimePickerDialog) pickerDialog).updateTime(hh,mm);

// try adding a second reminder & alarm
addButton.performClick();

pickerFragment =
        (TimePickerFragment) fragment.getFragmentManager()
                .findFragmentByTag(ReminderManagerFragment.TIME_DIALOG);

assertThat(pickerFragment).isNotNull();

reminders = getReminders(TestValues.BillyUser);
assertThat(reminders.size()).isEqualTo(5);

pickerDialog = (AlertDialog) pickerFragment.getDialog();


assertThat(pickerDialog).isNotNull();

((TimePickerDialog) pickerDialog).updateTime(18, 30);

pickerOKButton = (Button) pickerDialog.getButton(AlertDialog.BUTTON_POSITIVE);
pickerOKButton.performClick();

shadowAlarms = shadowAlarmManager.getScheduledAlarms();
for (ShadowAlarmManager.ScheduledAlarm sAlarm :
        shadowAlarms) {
    Log.i(TAG, Dates.getBasicDate(new Date(sAlarm.triggerAtTime)) + " " +
            sAlarm.operation.toString());
}
Log.i(TAG, "alarms currently set: " + shadowAlarms.size());
assertThat(shadowAlarms.size()).isGreaterThan(1);

More to come

Most efficient Mac browser Safari

Safari is the most efficient Mac browser using the least amount of battery power (amperage) compared to Firefox and Chrome on Apple MacBooks.  In a quick test of watching YouTube videos in browsers here’s how much battery/energy each browser used:

  • Safari: 1250 mA
  • Firefox: 1600mA
  • Chrome: 3600mA

Chrome is far and away the most power hungry web browser on Mac OS X, using nearly 3X the processing power and battery usage than Safari.

Obviously if you’re trying to maximize battery life on your MacBook, use Safari browser as its the most efficient.

To test this yourself, use the System Information application (Apple logo top right corner, About this Mac, More Info…, System Report, Power and look for the Amperage (mA) value).

Robotium reference

Enter text EditText / text field

solo.enterText((EditText) solo.getView(R.id.email_edittext), "baduser@gmail.com");

Click Button

solo.clickOnButton("Login");

Check for Toast Text Message

assertTrue(solo.waitForText(getActivity().getResources()
        .getString(R.string.msg_login_failed)));

 

 

More to come…

Android Robolectric Support Fragment FragmentTestUtil

To use Android Support Fragment v4 in Robolectric 3.0 you must add gradle dependency in /app/build.gradle

testCompile 'org.robolectric:shadows-support-v4:3.0'

Then import into your Robolectric testing java class

import org.robolectric.shadows.support.v4.SupportFragmentTestUtil;

then you can create/start android support v4 fragments within your Robolectric testing java class for unit testing:

SupportFragmentTestUtil.startVisibleFragment(fragment);

Cross posted to StackOverflow Android Robolectric Support Fragment.