Settings

Settings allow a user to modify application features and behaviour. In this lab we demonstrate the use of settings to input a username, password pair, the size of the list of residences to download from the cloud and the frequency at which this list is automatically refreshed by a service or services. Services will be the subject of a future lab.

Settings

Layout

Create a file settings.xml in a new folder xml in res with the following content:

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
    <EditTextPreference 
        android:key="username" 
        android:summary="@string/username_summary" 
        android:title="@string/username"/>

    <EditTextPreference 
        android:key="password"
        android:summary="@string/password_summary"
        android:title="@string/password"
        android:inputType="textPassword"/>

    <EditTextPreference
        android:key="nmr_residences"
        android:summary="@string/nmr_residences_summary"
        android:title="@string/nmr_residences"
        android:inputType="text"/>

    <EditTextPreference
        android:key="refresh_interval"
        android:summary="@string/set_refresh_interval_summary"
        android:title="@string/set_refresh_interval"
        android:inputType="text"/>

</PreferenceScreen>

This layout references a number of strings - such as username, password and so on. Here is the additional content to be added to res/values/strings.xml to satisfy these references::

  <string name="username_summary">Please enter your user name</string>
  <string name="username">Username</string>
  <string name="password_summary">You may set your password here</string>
  <string name="password">Password</string>
  <string name="nmr_residences">Configure Downloads</string>
  <string name="nmr_residences_summary">How many Residences to store locally?</string>
  <string name="set_refresh_interval">Refresh</string>
  <string name="set_refresh_interval_summary">Frequency of cloud updates (minutes)</string>

Activity-Fragment

Next we shall introduce the settings activity-fragment pair. Locate in a new package org.wit.myrent.settings. You may create this package by placing a new folder named settings in myrent.

First create the SettingsActivity class:

package org.wit.myrent.settings;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.Menu;

import org.wit.myrent.R;

public class SettingsActivity extends AppCompatActivity
{
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if (savedInstanceState == null) {
      SettingsFragment fragment = new SettingsFragment();
      getFragmentManager().beginTransaction()
          .add(android.R.id.content, fragment, fragment.getClass().getSimpleName())
          .commit();
    }
  }

  @Override
  public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.residencelist, menu);
    return true;
  }

}

Next create the skeleton of the associated fragment class: SettingsFragment.

package org.wit.myrent.settings;

import android.os.Bundle;
import android.preference.PreferenceFragment;
import org.wit.myrent.R;

public class SettingsFragment extends PreferenceFragment
{
  @Override
  public void onCreate(Bundle savedInstanceState)  {
    super.onCreate(savedInstanceState);
    addPreferencesFromResource(R.xml.settings);
  }
}

Add a SharedPreference field and associated import:

import android.content.SharedPreferences;
  private SharedPreferences prefs;

Override onStart and initialize the SharePreference field:

  @Override
  public void onStart()
  {
    super.onStart();
    prefs = PreferenceManager
        .getDefaultSharedPreferences(getActivity());
  }

Add the required import statement:

import android.preference.PreferenceManager;

Add the following menu-handler code to onOptionsItemSelected(MenuItem item) in ResidenceListFragment:

      case R.id.action_settings:
        startActivity(new Intent(getActivity(), SettingsActivity.class));
        return true;

Import SettingsActivity:

import org.wit.myrent.settings.SettingsActivity;

Add a new activity node to the manifest file:

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

Test by compiling and installing onto the emulator or device. Check that the settings menu can be displayed.

SettingsFragment (continued)

Here we shall implement the SharedPreferences.OnSharedPreferenceChangeListener interface:

public class SettingsFragment extends PreferenceFragment implements SharedPreferences.OnSharedPreferenceChangeListener 
{
  ...
  ...
}

Implement the interface's method:


  @Override
  public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {

  }

Register the listener in onStart:

  @Override
  public void onStart()
  {
    super.onStart();
    prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());

    prefs.registerOnSharedPreferenceChangeListener(this);
  }

Unregister the listener in onStop:


  @Override
  public void onStop()
  {
    super.onStop();
    prefs.unregisterOnSharedPreferenceChangeListener(this);
  }

SettingsFragment (continued)

Enable up button in onCreate:

    setHasOptionsMenu(true);

Add the menu handler for the up button:

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

These imports are required:

import android.view.MenuItem;
import org.wit.myrent.R;
import static org.wit.android.helpers.IntentHelper.navigateUp;

Settings pane

On launching MyRent the user is presented with the residence list view and it is here we decide to facilitate access to settings. This is illustrated in Figure 1:

Figure 1: Settings pane accessible from list view

The default settings menu item has already been included as shown in Figure 2:

Figure 2: Default settings menu item

Add a log statement and associated import to SettingsFragment.onSharedPreferenceChanged:

import static org.wit.android.helpers.LogHelpers.info;
 info(getActivity(), "Setting change - key : value = " + key + " : " + sharedPreferences.getString(key, ""));

Create a logCat filter as shown in Figure 3.

Figure 3: logcat filter for Settings

Build and test by exercising this new menu option. It should be possible to display the settings pane as demonstrated in Figure 1.

Introduce a test value for each of the four items in the settings pane. The output in the logcat pane should include something similar to that shown in Figure 4.

Figure 4: logcat displays result of changed settings

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