File IO & Menu Up Navigation

We continue to evolve navigation support in the app, providing an 'up' button in the action bar to allow navigation from the ResidenceActivity to the ResidenceListActivity.

Up Button

All screens should offer a navigation route to their parent screens by pressing on the Up button located in the action bar as shown, for example, here in Figure 1.

Figure 1: MyRent Up button

Pressing the Up button should route one to the logical parent screen. The parent screen is declared in the manifest file.

In the case of MyRent, a call to setDisplayHomeAsUpEnabled() in the ResidenceFragment facilitates switching to the ResidenceListFragment screen when the Up button is pressed.

The following steps describe the process in detail.

IntentHelper

In order to support enhanced navigation, we define an additional Helper method in the IntentHelper class:

  public static void navigateUp(Activity parent)
  {
    Intent upIntent = NavUtils.getParentActivityIntent(parent);
    NavUtils.navigateUpTo(parent, upIntent);
  }

Add an import statement for NavUtils:

import android.support.v4.app.NavUtils;

Here, for reference purposes, is the complete class:

package org.wit.android.helpers;
import java.io.Serializable;

import android.app.Activity;
import android.content.Intent;
import android.support.v4.app.NavUtils;

public class IntentHelper
{
  public static void startActivity (Activity parent, Class classname)
  {
    Intent intent = new Intent(parent, classname);
    parent.startActivity(intent);
  }   

  public static void startActivityWithData (Activity parent, Class classname, String extraID, Serializable extraData)
  {
    Intent intent = new Intent(parent, classname);
    intent.putExtra(extraID, extraData);
    parent.startActivity(intent);
  }  

  public static void startActivityWithDataForResult (Activity parent, Class classname, String extraID, Serializable extraData, int idForResult)
  {
    Intent intent = new Intent(parent, classname);
    intent.putExtra(extraID, extraData);
    parent.startActivityForResult(intent, idForResult);
  }

  public static void navigateUp(Activity parent)
  {
    Intent upIntent = NavUtils.getParentActivityIntent(parent);
    NavUtils.navigateUpTo(parent, upIntent);
  }
}

ResidenceActivity

New we can make use of the helper we just introduced. We wish to support the 'up' style navigation:

Figure 1: New Residence menu item & Up button

First introduce the helper method into ResidenceActivity:

import static org.wit.android.helpers.IntentHelper.navigateUp;

Add the statement:

getSupportActionBar().setDisplayHomeAsUpEnabled(true);

to onCreate following setContentView(...) as indicated in the following code extract:

  @Override
  public void onCreate(Bundle savedInstanceState)
  {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_residence);
    getSupportActionBar().setDisplayHomeAsUpEnabled(true);
    ...
  }

Now we override the onOptionsItemSelected method:

  @Override
  public boolean onOptionsItemSelected(MenuItem item)
  {
    switch (item.getItemId())
    {
      case android.R.id.home:  navigateUp(this);
                               return true;
    }
    return super.onOptionsItemSelected(item);
  }

This import statement is required:

import android.view.MenuItem;

For naming consistency we have changed the layout name from activity_myrent to activity_residence.

  • Use the menu refactor command to change the name of the layout in res/layout.

Try this now - does it work as in Figure 1 above. Not Yet! - we need one more step...

Full class to this point for reference purposes:

package org.wit.myrent.activities;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.MenuItem;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.DatePicker;
import android.widget.EditText;

import org.wit.myrent.R;
import org.wit.myrent.app.MyRentApp;
import org.wit.myrent.models.Portfolio;
import org.wit.myrent.models.Residence;

import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import android.app.DatePickerDialog;
import android.view.View;
import static org.wit.android.helpers.IntentHelper.navigateUp;



public class ResidenceActivity extends AppCompatActivity implements TextWatcher,
    CompoundButton.OnCheckedChangeListener,
    View.OnClickListener,
    DatePickerDialog.OnDateSetListener


{
  private EditText geolocation;
  private Residence residence;

  private CheckBox rented;
  private Button dateButton;

  private Portfolio portfolio;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_residence);
    getSupportActionBar().setDisplayHomeAsUpEnabled(true);

    geolocation = (EditText) findViewById(R.id.geolocation);
    residence = new Residence();

    // Register a TextWatcher in the EditText geolocation object
    geolocation.addTextChangedListener(this);

    dateButton = (Button) findViewById(R.id.registration_date);
    dateButton  .setOnClickListener(this);

    rented = (CheckBox) findViewById(R.id.isrented);

    MyRentApp app = (MyRentApp) getApplication();
    portfolio = app.portfolio;
    Long resId = (Long) getIntent().getExtras().getSerializable("RESIDENCE_ID");
    residence = portfolio.getResidence(resId);
    if (residence != null) {
      updateControls(residence);
    }
  }

  public void updateControls(Residence residence) {
    geolocation.setText(residence.geolocation);
    rented.setOnCheckedChangeListener(this);

    dateButton.setText(residence.getDateString());
  }

  @Override
  public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

  }

  @Override
  public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {

  }

  @Override
  public void afterTextChanged(Editable editable) {
    residence.setGeolocation(editable.toString());
  }

  @Override
  public void onCheckedChanged(CompoundButton compoundButton, boolean isChecked) {
    Log.i(this.getClass().getSimpleName(), "rented Checked");
    residence.rented = isChecked;
  }

  @Override
  public void onClick(View view) {
    switch (view.getId())
    {
      case R.id.registration_date      : Calendar c = Calendar.getInstance();
        DatePickerDialog dpd = new DatePickerDialog (this, this, c.get(Calendar.YEAR), c.get(Calendar.MONTH), c.get(Calendar.DAY_OF_MONTH));
        dpd.show();
        break;
    }
  }

  @Override
  public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
    Date date = new GregorianCalendar(year, monthOfYear, dayOfMonth).getTime();
    residence.date = date.getTime();
    dateButton.setText(residence.getDateString());
  }

  @Override
  public void onPause()
  {
    super.onPause();
    portfolio.saveResidences();
  }

  @Override
  public boolean onOptionsItemSelected(MenuItem item)
  {
    switch (item.getItemId())
    {
      case android.R.id.home:  navigateUp(this);
        return true;
    }
    return super.onOptionsItemSelected(item);
  }

}

AndroidManifest

The final piece of the puzzle is the layout in the manifest the parent/child relationship between the ResidenceListActivity and ResidenceActivity classes:

    <activity
      android:name=".activities.ResidenceActivity"
      android:label="@string/app_name" >  
      <meta-data android:name="android.support.PARENT_ACTIVITY" 
                 android:value=".activities.ResidenceListActivity"/>  
    </activity>

In the above we are establishing this relationship. The navigation mechanism should work as expected now.

Here is the complete manifest file for reference purposes:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="org.wit.myrent">

  <application
      android:name=".app.MyRentApp"
      android:allowBackup="true"
      android:icon="@mipmap/ic_launcher"
      android:label="@string/app_name"
      android:theme="@style/AppTheme">

    <activity
        android:name=".activities.ResidenceListActivity"
        android:label="@string/app_name" >
      <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
    </activity>

    <activity
        android:name=".activities.ResidenceActivity"
        android:label="@string/app_name">
        <meta-data android:name="android.support.PARENT_ACTIVITY" 
                   android:value=".activities.ResidenceListActivity"/>
    </activity>
  </application>

</manifest>

Test the back button as indicated in Figure 1.

Figure 1: Test back button

The application at the end of this lab is available for reference here: myrent-05