Working with the Android Framework Classes
This section gets into the good stuff — the nitty-gritty of Android development and its Android framework classes! Yes, activities and views are integral parts of the system, but they’re simply the “plumbing” that’s required in any modern operating system (in one capacity or another). The real fun is just about to start.
The following sections describe how to check the state of the phone ringer to determine whether it’s in normal mode (ringing loud and proud) or silent mode. At this point, you can begin to start toggling the phone’s ringer mode.
Getting good service
To access the Android ringer, you’ll need lots of access to the AudioManager
in Android, which is responsible for managing the ringer state, so you should initialize it in onCreate()
.
You first need to create a private class-level AudioManager
variable by the name of mAudioManager
. Type this name at the top of your class file, directly after the class declaration line, as shown in Listing 5-3.
Listing 5-3: Adding the Class-Level AudioManager Variable
package com.dummies.android.silentmodetoggle;
import android.app.Activity;
import android.media.AudioManager;
→4
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class MainActivity extends Activity {
private AudioManager mAudioManager;
→11
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setButtonClickListener();
mAudioManager = (AudioManager)getSystemService(AUDIO_SERVICE);
→20
}
private void setButtonClickListener() {
Button toggleButton = (Button)findViewById(R.id.toggleButton);
toggleButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// TODO Auto-generated method stub
}
});
}
}
This list briefly explains what the numbered lines:
→4 The import
statement that brings in the necessary package so that you can use AudioManager
.
→11 The private
class-level AudioManager
variable. Because it’s class wide, you can have access to it in other parts of the activity.
→20 Initializes the mAudioManager
variable by getting the service from the base Activity getSystemService()
method call.
Whoa! What’s getSystemService()
? By inheriting from the base Activity
class, AudioManager
receives all the benefits of being an activity, including access to the getSystemService()
method call. This method returns the base Java Object
class, so you have to cast it to the type of service you’re requesting.
This call returns all available system services that you might need to work with. All services that are returned can be found in the Context
class in the Android documentation, at http://d.android.com/reference/android/content/Context.html
. Popular system service types include
AUDIO_SERVICE
LOCATION_SERVICE
ALARM_SERVICE
Toggling Silent mode with AudioManager
After you have a class-wide instance of AudioManager
, you can start checking the state of the ringer and toggling the ringer. The code you need to add or modify is in bold in Listing 5-4.
Listing 5-4: Adding the Application Toggle to the App
package com.dummies.android.silentmodetoggle;
import android.app.Activity;
import android.graphics.drawable.Drawable;
import android.media.AudioManager;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
public class MainActivity extends Activity {
private AudioManager mAudioManager;
private boolean mPhoneIsSilent;
→14
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mAudioManager = (AudioManager)getSystemService(AUDIO_SERVICE);
checkIfPhoneIsSilent();
→23
setButtonClickListener()
→25
}
private void setButtonClickListener() {
Button toggleButton = (Button)findViewById(R.id.toggleButton);
toggleButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (mPhoneIsSilent) {
→32
// Change back to normal mode
mAudioManager
.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
mPhoneIsSilent = false;
} else {
// Change to silent mode
mAudioManager
.setRingerMode(AudioManager.RINGER_MODE_SILENT);
mPhoneIsSilent = true;
}
// Now toggle the UI again
toggleUi();
→44
}
});
}
/**
* Checks to see if the phone is currently in Silent mode.
*/
private void checkIfPhoneIsSilent() {
→53
int ringerMode = mAudioManager.getRingerMode();
if (ringerMode == AudioManager.RINGER_MODE_SILENT) {
mPhoneIsSilent = true;
} else {
mPhoneIsSilent = false;
}
}
/**
&
nbsp; * Toggles the UI images from silent to normal and vice versa.
&
nbsp; */
private void toggleUi() {
→66
ImageView imageView = (ImageView) findViewById(R.id.phone_icon);
Drawable newPhoneImage;
if (mPhoneIsSilent) {
newPhoneImage =
getResources().getDrawable(R.drawable.phone_silent);
} else {
newPhoneImage =
getResources().getDrawable(R.drawable.phone_on);
}
imageView.setImageDrawable(newPhoneImage);
}
@Override
→84
protected void onResume() {
super.onResume();
checkIfPhoneIsSilent();
toggleUi();
}
}
This list briefly explains what each new section of code does:
→14 Sets up a new class-level boolean
mPhoneIsSilent
variable to keep track of the ringer state.
→23 Calls the checkIfPhoneIsSilent()
method to initialize mPhone IsSilent
. The default value of a boolean
is false — which can be wrong if the phone is in Silent mode. This line figures out what happens when the ringer mode is toggled.
→25 The button event-handling code was moved to the bottom of the onCreate()
method because it depends on the setup of the mPhoneIsSilent
variable. Even though nothing is likely to happen, you should keep the code organized.
Clean code is manageable code.
→32 The code between Lines 32 and 44 handles a user tap on the toggle button, by checking to see whether the ringer is enabled via the class-level mPhoneIsSilent
variable.
If the ringer is silent, the code falls into the first if
block and changes the ringer mode to RINGER_MODE_NORMAL
, which turns the ringer back on. The mPhoneIsSilent
variable is also changed to false
for the next time this code runs.
If the ringer isn’t silent, the code falls into the else
code block. This code block turns the ringer mode from its current state to RINGER_MODE_SILENT
, which turns off the ringer. The else
block also sets the mPhoneIsSilent
variable to true
for the next time around.
→44 The toggleUi()
method changes the user interface to give the user a visual identifier that the mode on the phone has changed. Anytime the ringer mode changes, the toggleUi()
method needs to get called.
→53 The checkIfPhoneIsSilent()
method initializes the mPhone IsSilent
class-level variable in the onCreate()
method. If you fail to do this, your application doesn’t know what state the AudioManager
’s ringer is in. If the phone is silent, mPhoneIs Silent
gets set to true
; otherwise, it’s false
.
→66 This toggleUi()
method changes the ImageView
from the layout you created in Chapter 4, depending on the state of the ringer.
If the ringer is silent, the user interface displays an image showing that the phone ringer is off. If the phone’s ringer is in Normal mode, the image indicates that the phone ringer is on.
Both these images are in the resource directories. (See Chapter 4.) The ImageView
is found inside the layout, and after detecting the mode, the View
is updated by pulling the correct image from getResources().getDrawable(...)
and set with the set ImageDrawable(...)
call on the ImageView
. This method updates the image that’s displayed on the ImageView
onscreen.
→84 The onResume()
method is overridden for your application to correctly identify its state. The mPhoneIsSilent
variable keeps track of the phone’s ringer state, but only for the class. The person using your application also needs to know what state the phone is in, so onResume()
calls toggleUi()
to toggle the user interface.
The toggleUi()
call is strategically placed in the onResume()
method for a simple reason: to assume that the user opens the Silent Toggle Mode application and then returns to the Home screen and turns off the phone using the phone controls. When the user returns to the activity, the activity is resumed and brought to the foreground. At that time, onResume()
is called to check the state of the ringer mode and update the user interface accordingly. If the user changed the mode, the app reacts as the user would expect.