BatteryMonitor Application

Exclusive offer: get 50% off this eBook here
iPad Enterprise Application Development BluePrints

iPad Enterprise Application Development BluePrints — Save 50%

Design and build your own enterprise applications for the iPad with this book and ebook.

$29.99    $15.00
by Steven F Daniel | November 2012 | Enterprise Articles

The BatteryMonitor application allows you to monitor the state and battery levels of your iOS device using the APIs that come with the iOS SDK. Each iOS device represents a unique set of properties that include the device's current physical orientation, its model name, and its battery state. It also provides access to the onboard hardware.

This article by Steven F Daniel, author of iPad Enterprise Application Development BluePrints, we will be taking a closer look at how we can use the Core Graphics framework to create and draw a gauge that will be use to present and visualize the total amount of battery life remaining on the iOS device, and then start to design the user interface for our app.

(For more resources related to this topic, see here.)

Overview of the technologies

The BatteryMonitor application makes reference to two very important frameworks to allow for drawing of graphics to the iOS device's view, as well as composing and sending of e-mail messages, directly within the application.

In this article, we will be making use of the Core Graphics framework that will be responsible for handling the creation of our battery gauge to allow the contents to be filled based on the total amount of battery life remaining on the device. We will then use the MessageUI framework that will be responsible for composing and sending e-mails whenever the application has determined that the battery levels fall below the 20 percent threshold. This is all handled and done directly within our app.

We will make use of the UIDevice class that will be used to gather the device information for our iOS device. This class enables you to recover device-specific values, including the model of the iOS device that is being used, the device name, and the OS name and version. We will then use the MFMailComposeViewController class object to directly open up the e-mail dialog box within the application.

The information that you can retrieve from the UIDevice class is shown in the following table:

Type

Description

System name

This returns the name of the operating system that is currently in use. Since all current generation iOS devices run using the same OS, only one will be displayed; that is iOS 5.1.

System version

This lists the firmware version that is currently installed on the iOS device; that is, 4.3, 4.31, 5.01, and so on.

Unique identifier

The unique identifier of the iOS device generates a hexadecimal number to guarantee that it is unique for each iOS device, and does this by applying an internal hash to several of its hardware specifiers, including the device's serial number.

This unique identifier is used to register the iOS devices at the iOS portal for provisioning of distribution of software apps. Apple is currently phasing out and rejecting apps that access the Unique Device Identifier on an iOS device to solve issues with piracy, and has suggested that you should create a unique identifier that is specific to your app.

Model

The iOS model returns a string that describes its platform; that is, iPhone, iPod Touch, and iPad.

Name

This represents the assigned name of the iOS device that has been assigned by the user within iTunes. This name is also used to create the localhost names for the device, particularly when networking is used.

For more information on the UIDevice class, you can refer to the Apple Developer Documentation that can be found and located at the following URL: https://developer.apple.com/library/ios/#DOCUMENTATION/UIKit/Reference/UIDevice_Class/Reference/UIDevice.html.

Building the BatteryMonitor application

Monitoring battery levels is a common thing that we do in our everyday lives. The battery indicator on the iPhone/iPad lets us know when it is time for us to recharge our iOS device. In this section, we will look at how to create an application that can run on an iOS device to enable us to monitor battery levels on an iOS device, and then send an e-mail alert when the battery levels fall below the threshold.

We first need to create our BatteryMonitor project. It is very simple to create this in Xcode. Just follow the steps listed here.

  1. Launch Xcode from the /Xcode4/Applications folder.

  2. Choose Create a new Xcode project, or File | New Project.

  3. Select the Single View Application template from the list of available templates.

  4. Select iPad from under the Device Family drop-down list.

  5. Ensure that the Use Storyboard checkbox has not been selected.

  6. Select the Use Automatic Reference Counting checkbox.

  7. Ensure that the Include Unit Tests checkbox has not been selected.

  8. Click on the Next button to proceed with the next step in the wizard.

  9. Enter in BatteryMonitor as the name for your project.

  10. Then click on the Next button to proceed with the next step of the wizard.

  11. Specify the location where you would like to save your project.

  12. Then, click on the Save button to continue and display the Xcode workspace environment.

Now that we have created our BatteryMonitor project, we need to add the MessageUI framework to our project. This will enable us to send e-mail alerts when the battery levels fall below the threshold.

Adding the MessageUI framework to the project

As we mentioned previously, we need to add the MessageUI framework to our project to allow us to compose and send an e-mail directly within our iOS application, whenever we determine that our device is running below the allowable percentage.

To add the MessageUI framework, select Project Navigator Group, and follow the simple steps outlined here:

  1. Click and select your project from Project Navigator.

  2. Then, select your project target from under the TARGETS group.

  3. Select the Build Phases tab.

  4. Expand the Link Binary With Libraries disclosure triangle.

  5. Finally, use + to add the library you want.

  6. Select MessageUI.framework from the list of available frameworks.

Now that we have added MessageUI.framework into our project, we need to start building our user interface that will be responsible for allowing us to monitor the battery levels of our iOS device, as well as handle sending out e-mails when the battery levels fall below the agreed threshold.

Creating the main application screen

The BatteryMonitor application doesn't do anything at this stage; all we have done is created the project and added the MessageUI framework to handle the sending of e-mails when our battery levels are falling below the threshold.

We now need to start building the user interface for our BatteryMonitor application. This screen will consist of a View controller, and some controls to handle setting the number of bars to be displayed, as well as whether the monitoring of the battery should be enabled or disabled.

  1. Select the ViewController.xib file from Project Navigator.

  2. Set the value of Background of the View controller to read Black Color.

  3. Next, from Object Library, select-and-drag a (UILabel) Label control, and add this to our view.

  4. Modify the Text property of the control to Battery Status:.

  5. Modify the Font property of the control to System 42.0.

  6. Modify the Alignment property of the control to Center.

  7. Next, from Object Library, select-and-drag another (UILabel) Label control, and add this to our view directly underneath the Battery Status label.

  8. Modify the Text property of the control to Battery Level:.

  9. Modify the Font property of the control to System 74.0.

  10. Modify the Alignment property of the control to Center.

Now that we have added our label controls to our view controller, our next step is to start adding the rest of our controls that will make up our user interface. So let's proceed to the next section.

Adding the Enable Monitoring UISwitch control

Our next step is to add a switch control to our view controller; this will be responsible for determining whether or not we are to monitor our battery levels and send out alert e-mails whenever our battery life is running low on our iOS device. This can be achieved by following these simple steps:

  1. From Object Library, select-and-drag a (UILabel) Label control, and add this to the bottom right-hand corner of our view controller.

  2. Modify the Text property of the control to Enable Monitoring:.

  3. Modify the Font property of the control to System 17.0.

  4. Modify the Alignment property of the control to Left.

  5. Next, from Object Library, select-and-drag a (UISwitch) Switch control to the right of the Enable Monitoring label.

  6. Next, from the Attributes Inspector section, change the value of State to On.

  7. Then, change the value of On Tint to Default.

Now that we have added our Enable Monitoring switch control to our BatteryMonitor View controller, our next step is to add the Send E-mail Alert switch that will be responsible for sending out e-mail alerts if it has determined that the battery levels have fallen below our threshold. So, let's proceed with the next section.

Adding the Send E-mail Alert UISwitch control

Now, we need to add another switch control to our view that will be responsible for sending e-mail alerts. This can be achieved by following these simple steps:

  1. From Object Library, select-and-drag another (UILabel) Label control, and add this underneath our Enable Monitoring label.

  2. Modify the Text property of the control to Send E-mail Alert:.

  3. Modify the Font property of the control to System 17.0.

  4. Modify the Alignment property of the control to Left.

  5. Next, from Object Library, select-and-drag a (UISwitch) Switch control to the right of the Send Email Alert label.

  6. Next, from the Attributes Inspector section, change the value of State to On.

  7. Then, change the value of On Tint to Default.

    To duplicate a UILabel and/or UISwitch control and have them retain the same attributes, you can use the keyboard shortcut Command + D. You can then update the Text label for the newly added control.

Now that we have added our Send E-mail Alert button to our BatteryMonitor view controller, our next step is to add the Fill Gauge Levels switch that will be responsible for filling our battery gauge when it has been set to ON.

Adding the Fill Gauge Levels UISwitch control

Now, we need to add another switch control to our view that will be responsible for determining whether our gauge should be filled to show the amount of battery remaining. This can be achieved by following these simple steps:

  1. From Object Library, select-and-drag another (UILabel) Label control, and add this underneath our Send E-mail Alert label.

  2. Modify the Text property of the control to Fill Gauge Levels:.

  3. Modify the Font property of the control to System 17.0.

  4. Modify the Alignment property of the control to Left.

  5. Next, from Object Library, select-and-drag a (UISwitch) Switch control to the right of the Fill Gauge Levels label.

  6. Next, from the Attributes Inspector section, change the value of State to On.

  7. Then, change the value of On Tint to Default.

Now that we have added our Fill Gauge Levels switch control to our BatteryMonitor view controller, our next step is to add the Increment Bars stepper that will be responsible for increasing the number of bar cells within our battery gauge.

iPad Enterprise Application Development BluePrints Design and build your own enterprise applications for the iPad with this book and ebook.
Published: September 2012
eBook Price: $29.99
Book Price: $49.99
See more
Select your format and quantity:

Adding the Increment Bars UIStepper control

Next, we need to add another control to our view that will allow the user to specify the number of battery bars that should be displayed for our battery gauge. This can be achieved by following these simple steps:

  1. From Object Library, select-and-drag another (UILabel) Label control, and add this underneath our Fill Gauge Levels label.

  2. Modify the Text property of the control to Increment Bars:.

  3. Modify the Font property of the control to System 17.0.

  4. Modify the Alignment property of the control to Left.

  5. Next, from Object Library, select-and-drag a (UIStepper) Stepper control to the right of the Increment Bars label.

  6. Next, from the Attributes Inspector section, change the Minimum value to 0.

  7. Then, change the Maximum value to 100.

  8. Next, set the Current value to 0 and the Step increment to 1.

Now that we have added our Increment Bars stepper control to our BatteryMonitor view controller, our next step is to add an TextView control that will be used to display information about the device, such as its model and the version.

Adding the System Information (UITextView) control

Now, we need to add another control to our view that will be responsible for showing iOS device specific information. This can be achieved by following these simple steps:

  1. From Object Library, select-and-drag a (UITextView) TextView control, and add this to the left of the Enable Monitoring label.

  2. Next, from the Attributes Inspector section, modify the Text property of the control to System Information goes here....

  3. Change the Font property of the control to System 14.0.

  4. Modify the Alignment property of the control to Left.

  5. Change the Capitalization property to Sentences.

Now that we have added all of our form controls and have built our user interface, our next step is to create our very own custom UIView subclass that will be used to display a visual representation of how much battery we have remaining on our iOS device.

  1. Select the BatteryMonitor folder, choose File | New | New File… or press Command + N.

  2. Select the Objective-C class template from the list of available templates.

  3. Click on the Next button to proceed with the next step within the wizard.

  4. Enter in BatteryGauge as the name of the file to create.

  5. Ensure that you have selected UIView as the type of subclass to be created from the Subclass dropdown list.

  6. Ensure that you have selected the Targeted for iPad option.

  7. Click on the Next button to proceed with the next step of the wizard.

  8. Then, click on the Create button to save the file to the folder location specified.

Now that we have created our BatteryGauge class, we need to drag a new UIView controller and update this to use our newly created BatteryGauge class, rather than the default UIViewController class.

  1. Select the ViewController.xib file from the BatteryMonitor folder.

  2. From Object Library, select-and-drag a (UIView) View control, and add this to the center of our View controller.

  3. Click-and-select the (UIView) controller that we just added to our view.

  4. Click on the Identity Inspector section, and change the value of the Custom Class property to read BatteryGauge.

Our next step is to create the Outlet events for each of our controls that have been added to our View controller. Creating these will allow us to access these controls within our code and make modifications to the control properties. To create an Outlet, follow these simple steps:

  1. Open Assistant Editor by choosing Navigate | Open in Assistant Editor, or press the Option + Command + , keys.

  2. Ensure that the ViewController.h interface file is displayed to the left of ViewController.xib.

  3. Select the Enable Monitoring (UISwitch) control, then hold down the Control key, and drag it into the ViewController.h interface file.

  4. Choose Outlet from the Connection dropdown list for the connection to be created.

  5. Enter in enableMonitoring for the name of the Outlet property to be created.

  6. Choose Strong from the Storage dropdown list.

  7. Repeat steps 3 to 6 to create IBOutlets for the Battery Status, Battery Level, Enable Monitoring, Send E-mail Alert, Fill Gauge Levels, Increment Bars, System Info, and Battery Gauge controls, while providing the following naming for each, as follows: lblBatteryStatus, lblBatteryLevel, enableMonitoring, sendEmailAlert, fillGauge, totalNoBars, tvSystemInfo, and batteryMeter.

Now that we have created the Outlet events for our controls, we need to create the associated Action events for those Outlets. Creating these actions allows an event to be fired when the button has been pressed. To create an Action, follow these simple steps:

  1. With the ViewController.h interface file still displayed to the left of the ViewController.xib View Controller, select the Enable Monitoring (UISwitch) control, then hold down the Control key, and drag it into the ViewController.h interface file.

  2. Choose Action from the Connection dropdown for the connection to be created.

  3. Enter in enableMonitoring for the name of the method to be created.

  4. Repeat steps 2 to 3 to create IBActions for the Enable Monitoring, Send E-mail Alert, Fill Gauge Levels, Increment Bars, and Battery Gauge controls, while providing the following naming for each, as follows: enableMonitoring, sendEmailAlert, fillGauge, totalNoBars, and batteryMeter.

Now that we have successfully connected up each of our controls, and created the required outlets and associated action methods, we can start taking a look at building the functionality for our BatteryMonitor application, so that it has the ability to display the battery levels for our iOS device and e-mail when the threshold reaches 20 percent.

Building the Battery Monitor functionality

Well done! You have made it this far; we have successfully finished building the user interface for both the Battery Monitor and Battery Gauge screens. Our next step is to start implementing the methods that will be used by each of our controls.

Each of these controls will be responsible for handling the monitoring of our iOS device's battery, with the ability to fill and clear our gauge, increase the number of battery cells present, as well as manually send e-mails when the device's battery level reaches the threshold.

Implementing the View Controller class

We are now ready to start adding additional content to our ViewController class. We need to import some interface header files and declare some objects that we will be using throughout our application. We will also need to extend our class in order to provide us with the functionality to compose in-app e-mailing.

  1. Open the ViewController.h interface file, located within the BatteryMonitor folder, and enter in the following highlighted code sections:

    //ViewController.h //BatteryMonitor //Created by Steven F Daniel on 21/02/12. //Copyright (c) 2012 GenieSoft Studios. All rights reserved. #import <UIKit/UIKit.h> #import <UIKit/UIDevice.h> #import <MessageUI/MessageUI.h> #import "BatteryGauge.h" @interface ViewController : UIViewController <MFMailComposeViewControllerDelegate> { IBOutlet UITextView *tvSystemInfo; IBOutlet UILabel *lblBatteryLevel; IBOutlet UILabel *lblBatteryStatus; IBOutlet UISwitch *sendEmailAlert; IBOutlet UISwitch *enableMonitoring; IBOutlet UISwitch *fillGauge; IBOutlet UIStepper *totalNoBars; IBOutlet BatteryGauge *batteryMeter; } @property (strong, nonatomic) IBOutlet UITextView *tvSystemInfo; @property (strong, nonatomic) IBOutlet UILabel *lblBatteryLevel; @property (strong, nonatomic) IBOutlet UILabel *lblBatteryStatus; @property (strong, nonatomic) IBOutlet UISwitch *sendEmailAlert; @property (strong, nonatomic) IBOutlet UISwitch *enableMonitoring; @property (strong, nonatomic) IBOutlet UISwitch *fillGauge; @property (strong, nonatomic) IBOutlet UIStepper *totalNoBars; @property (strong, nonatomic) IBOutlet BatteryGauge *batteryMeter; @property (strong, nonatomic) UIDevice *currentDevice; @end

    In the preceding code snippet, we import the interface file header information for our UIDevice.h, MessageUI.h, and BatteryGauge.h interface files, so that we can access their class methods. We extended our class, so that we can include the class protocol for MFMailComposeViewControllerDelegate, as well as its methods to enable us to compose and send e-mails directly within our application.

  2. We then declared each outlet for each of the controls within our view, as well as declared a new outlet instance of our BatteryGauge control, so that we can display the total amount of battery life that is left on the iOS device.

  3. Next, open the ViewController.m implementation file, located within the BatteryMonitor folder, and modify the viewDidLoad method as shown in the following code snippet:

    - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, // typically from a nib. // Enable monitoring of the battery status [[UIDevice currentDevice] setBatteryMonitoringEnabled:YES]; // Initialise our Stepper to use the default // number of bars. [totalNoBars setMinimumValue:1]; [totalNoBars setMaximumValue:20]; [totalNoBars setValue:batteryMeter.numBars]; // Initialize the background color for our Bar [batteryMeter setNormalBarColor:[UIColor greenColor]]; // Get the current status of the iOS device battery. [self determineBatteryStatus]; // Request to be notified when battery charge // or state changes [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(determineBatteryStatus) name:UIDeviceBatteryLevelDidChangeNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(determineBatteryStatus) name:UIDeviceBatteryStateDidChangeNotification object:nil]; }

    In the preceding code snippet, we enable the monitoring for our iOS device by setting the batteryMonitoringEnabled property to YES, so that our application can be notified of changes when the battery state changes.

  4. We then initialize and set the minimum and maximum values for our UIStepper control, and initialize the total number of bars to the default values represented by our BatteryGauge class. In our next step, we initialize our BatteryGauge and fill the color to green, before making a call to the determineBatteryStatus function in order to determine the current status of the battery.

  5. Finally, we initialize our UIDeviceBatteryLevelDidChangeNotification and UIDeviceBatteryStateDidChangeNotification methods to make a call to our determineBatteryStatus function over-and-over, whenever a change in the battery level or battery state has been detected. Change in the battery state is determined whenever the iOS device has been plugged into a power source, or it has been unplugged.

Implementing the determineBatteryStatus: method

Now, that we have set up our Battery Monitor View controller and have initialized everything correctly, we are ready to start implementing the method that will be responsible for determining the status of the battery when it has been called by the notification methods.

  1. Open the ViewController.m implementation file, located within the BatteryMonitor folder, and enter in the following code for the determineBatteryStatus function:

    // Handle displaying of the battery status. - (void)determineBatteryStatus { NSString *OutputString; NSArray *batteryStatus = [NSArray arrayWithObjects: @"Battery State cannot be determined.", @"Battery is in use. Discharging.", @"Battery is currently being charged.", @"Battery is fully charged.", nil]; // Determine the current status of the iOS Device Battery. switch ([[UIDevice currentDevice] batteryState]) { case UIDeviceBatteryStateUnknown: OutputString = [batteryStatus objectAtIndex:0]; break; case UIDeviceBatteryStateUnplugged: OutputString = [batteryStatus objectAtIndex:1]; break; case UIDeviceBatteryStateCharging: OutputString = [batteryStatus objectAtIndex:2]; break; case UIDeviceBatteryStateFull: OutputString = [batteryStatus objectAtIndex:3]; break; default: OutputString = [batteryStatus objectAtIndex:0]; break; } // Check to determine the state of the battery. // If it cannot be determined. if ([[UIDevice currentDevice] batteryState] == UIDeviceBatteryStateUnknown) { batteryMeter.value = -1; lblBatteryStatus.text = OutputString; lblBatteryLevel.text = [NSString stringWithFormat:@"Battery Level: %0.2f%%\n", 0]; tvSystemInfo.text = @""; tvSystemInfo.editable = NO; } else { // Get the Battery State and Battery Level and // display to the screen. NSString *SystemInfo = [NSString stringWithFormat:@"Device Model: %@\nDevice Name: %@\nSystem Name: %@\nSystem Version %@\nMultitasking Supported: %@\n", [[UIDevice currentDevice] model], [[UIDevice currentDevice] name], [[UIDevice currentDevice] systemName], [[UIDevice currentDevice] systemVersion], currentDevice.multitaskingSupported ? @"YES": @"NO"]; lblBatteryStatus.text = OutputString; lblBatteryLevel.text = [NSString stringWithFormat: @"Battery Level: %0.2f%%\n", [[UIDevice currentDevice] batteryLevel] * 100]; tvSystemInfo.text = SystemInfo; tvSystemInfo.editable = NO; // Show the battery level meter. batteryMeter.value = [[UIDevice currentDevice] batteryLevel]; } // Determine the level of battery life remaining, and // Notify the user accordingly. if (([[UIDevice currentDevice] batteryLevel] * 100) <= 20) { if (sendEmailAlert.on == YES) { [self sendEmailAlert]; } else { UIAlertView *alertMessage = [[UIAlertView alloc] initWithTitle:@"Battery Status" message:@"Your Battery life is below 20%. Please recharge your iOS Device." delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil]; [alertMessage show]; } } }

    In the preceding code snippet, we start by setting up an NSArray object to store the string value representations of our batterystate, and then use the batteryState property of the UIDevice class that represents the current iOS device to determine what the current status of the battery is. We then perform a check to ensure that we managed to determine the status of our battery. If for some reason we are unable to determine this, we initialize our battery gauge's value to -1, so that it doesn't display anything within the bar, and set our battery Status and Level fields to their defaults.

    If we are able to determine the state of the battery, we obtain the device model, the name of the identifying device, the systemName property to identify the operating system that is currently running on the iOS device, and systemVersion to determine the current version of the operating system that is installed, as well as determine whether the device provides support for multitasking.

  2. We then work out current battery level of the iOS device as a percentage, and then update our batteryMeter value property to refl ect the current battery level on the iOS device. We then perform a check to see if our battery levels reading is less than or equal to 20 percent.

  3. In our final steps, we check to see if we have enabled sending of alerts, and if this true, we make a call to the sendEmailAlert function to display the e-mail composition sheet, where the information relating to the battery state is pre-populated within the body of the message. Alternatively, if the sendEmailAlert option is turned off, we create a new instance of the UIAlertView class, and display a warning message to the user.

Implementing the enableMonitoring: method

Now, that we have set up our BatteryMonitor View controller and have initialized everything correctly, we are ready to start implementing a method that will be responsible for recording the audio when the user presses the Start Recording button.

Open the ViewController.m implementation file, located within the BatteryMonitor folder, locate the enableMonitoring method, and enter in the following code snippet:

// Enable monitoring of the iOS battery. - (IBAction)enableMonitoring:(id)sender { if (enableMonitoring.on == YES) { // Turn on monitoring of the iOS battery. [[UIDevice currentDevice] setBatteryMonitoringEnabled:YES]; sendEmailAlert.on = YES; sendEmailAlert.enabled = YES; } else { // Turn off monitoring of the iOS battery. [[UIDevice currentDevice] setBatteryMonitoringEnabled:NO]; sendEmailAlert.on = NO; sendEmailAlert.enabled = NO; // Display an alert message to let the user // know that monitoring is disabled. UIAlertView *alertMessage = [[UIAlertView alloc] initWithTitle: @"Battery Monitoring" message: @"Monitoring of the iOS Battery has been switched off. You will no longer receive alert notifications." delegate: nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; // Show the alert message box. [alertMessage show]; } }

In the preceding code snippet, we perform a check on the value of the enableMonitoring switch, to determine if we are currently monitoring our iOS device battery. If the value of our enableMonitoring switch is off, we disable battery monitoring for our iOS device and disable our sendEmailAlert switch to prevent e-mails from being sent. We also create an instance of the UIAlertView dialog box to notify the user that battery monitoring has been turned off and e-mail alerts will no longer be sent. Alternatively, if enableMonitoring is turned back on, we re-enable battery monitoring on the device and enable the sendEmailAlert buttons.

iPad Enterprise Application Development BluePrints Design and build your own enterprise applications for the iPad with this book and ebook.
Published: September 2012
eBook Price: $29.99
Book Price: $49.99
See more
Select your format and quantity:

Implementing the sendEmailAlert: method

Next, we need to implement a method that will be responsible for displaying the in-app e-mail composition sheet when the battery level of our iOS device falls below our 20 percent mark.

  1. Open the ViewController.m implementation file, located within the BatteryMonitor folder, locate the sendEmailAlert method, and enter in the following code snippet:

    - (IBAction)sendEmailAlert:(id)sender { // Perform a check to see if we are set up for // sending email alerts if (sendEmailAlert.on == YES) { MFMailComposeViewController *mailComposer = [[MFMailComposeViewController alloc] init]; mailComposer.mailComposeDelegate = self; // Check to make sure that we are set up to send mail if ([MFMailComposeViewController canSendMail]) { [mailComposer setToRecipients:[NSArray arrayWithObjects: @"youremail@yourdomain.com",nil]]; [mailComposer setSubject:@"Battery Status"]; [mailComposer setMessageBody:@"Your iOS device is running on less than 20% of battery.\nPlease recharge your device." isHTML:NO]; [mailComposer.navigationBar setTintColor:[UIColor redColor]]; mailComposer.modalPresentationStyle = UIModalPresentationFormSheet; [self presentModalViewController:mailComposer animated:YES]; } else { // Error sending the email message, so // notify the user. UIAlertView *alertMessage = [[UIAlertView alloc] initWithTitle:@"Failure" message:@"Your device hasn't been set up for email" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil]; [alertMessage show]; } } }

    In the preceding code snippet, we start by determining if we are able to send e-mail messages by checking the status of the sendEmailAlert switch control. Next, we create a new object instance of the MFMailComposeViewController class, which controls the mail dialog view, thus allowing the user to compose and send an e-mail without leaving the application. We then change the color of the mail composition sheet using the navigationBar:setTintColor: method of the controller to red, and then set the subject heading and body of our e-mail message.

  2. We then set the controller's mailComposeDelegate to self, so that our controller receives the mailComposeController:didFinishWithResult:error: message from the MFMailComposeViewControllerDelegate protocol when the user finishes with the e-mail dialog box.

  3. Finally, we call the controller's presentModalViewController:animated: method to display the e-mail dialog box.

    //========================================================= // Dismiss our Mail view controller when the user finishes //========================================================= - (void) mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error { NSString *emailMessage = nil; // Notifies users about errors associated with // the interface switch (result) { case MFMailComposeResultCancelled: emailMessage = @"Email sending has been cancelled"; break; case MFMailComposeResultSaved: emailMessage = @"Email draft saved successfully"; break; case MFMailComposeResultSent: emailMessage = @"Email sent successfully."; break; case MFMailComposeResultFailed: emailMessage = @"Email sending failure."; break; default: emailMessage = @"Problem sending the email."; break; } //Display the alert dialog based on the message derived // from the preceding case statement. UIAlertView *alert = [[UIAlertView alloc] initWithTitle: @"Battery Monitor Email" message: emailMessage delegate: nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; [alert show]; // make the MFMailComposeViewController disappear [self dismissModalViewControllerAnimated:YES]; }

    In the preceding code snippet, we declare the mailComposeController: delegate. The mailComposeController:didFinishWithResult:error: method is called when the user finishes with the e-mail dialog box, either by sending an e-mail or by cancelling out of this view. Next, we determine the type of the error that was received by the delegate, and then assign this to an NSString object variable emailMessage.

  4. In our final step, we declare an instance of the UIAlertView dialog box to display the error message, before calling the dismissModalViewControllerAnimated: method of our view controller.

Implementing the fillGauge: method

Next, we need to start implementing the method that will be responsible for filling our battery gauge control to represent the level of battery life remaining, when the user sets the Fill Gauge Levels option to On, and Off accordingly.

Open the ViewController.m implementation file, located within the BatteryMonitor folder, locate the fillGauge method and enter in the following code snippet:

// Handles coloring of the battery bar. - (IBAction)fillGauge:(id)sender { if (fillGauge.on == YES) { // Set the bar color to green and update the display. [batteryMeter setNormalBarColor:[UIColor greenColor]]; [batteryMeter setNeedsDisplay]; totalNoBars.enabled = YES; } else { // Set the bar color to gray and update the display. [batteryMeter setNormalBarColor:[UIColor blackColor]]; [batteryMeter setNeedsDisplay]; totalNoBars.enabled = NO; } }

In the preceding code snippet, we perform a check on our fillGauge object control to see if we are currently filling our battery gauge. If we are, we set the normalBarColor property of our battery gauge to green, and then make a call to the setNeedsDisplay method to redraw our UIView, so that the changes are refl ected.

Alternatively, if we have determined that we have turned off our fillGauge control, we set the color of our battery gauge to black, and again call the setNeedsDisplay method to update the display, and then disable our Increment Bars control.

Implementing the totalNoBars: method

Next, we need to start implementing the method that will be responsible for incrementing the total number of bars to display within our Battery Gauge control.

Open the ViewController.m implementation file, located within the BatteryMonitor folder, locate the totalNoBars method, and enter in the following code snippet:

// Handle Incrementing and Decrementing our Battery Bars - (IBAction)totalNoBars:(id)sender { NSInteger iTotalBars = totalNoBars.value; // We need to ensure that our bars are within our range if (totalNoBars.value >= 7 && totalNoBars.value <= 20) { iTotalBars++; } else { // We need to check that we don't fall below our default iTotalBars = (iTotalBars < 7) ? iTotalBars = 7 : iTotalBars--; } // Update our Number of bars accordingly [batteryMeter setNumBars:iTotalBars]; [batteryMeter setNeedsDisplay]; }

In the preceding code snippet, we need to check to ensure that the number of bars within our battery meter doesn't exceed the total allowable number. This is achieved by checking the value of our totalNoBars object, whilst checking to see if it falls within our allowable range prior to incrementing its value.

When reducing the total number of bars within the battery gauge, we will need to check to ensure that we don't exceed the minimum value of the control. This is achieved by using the ternary operator, which is represented as a question (?) mark. Finally, we assign the total number of bars to our setNumBars method of our BatteryMeter class, and then redraw the display by calling the setNeedsDisplay method.

Implementing the Battery Gauge class

In our final step, we need to implement the class that will be used to display a graphical visual representation of our battery levels when the device has determined that the battery state has changed.

  1. Open the BatteryGauge.h interface file, located within the BatteryMonitor folder, and enter in the following code snippet:

    // BatteryGauge.h // BatteryMonitor // Created by Steven F Daniel on 21/02/12. // Copyright (c) 2012 GenieSoft Studios. All rights reserved. #import <UIKit/UIKit.h> // Interface file structure for our Battery Gauge @interface BatteryGauge : UIView { @private float m_flValue, // Current value being displayed m_flFillValue, // Current Bar fill value last seen m_flMaxLimit, // The bars maximum fill limit m_flMinLimit; // The bars minimum fill limit int m_iNumBars, // Number of bar segments m_iOnIdx, // The index of the bar to turn on m_iOffIdx, // The index of the bar to turn off m_iFillBarIdx; // The index of the bar to fill UIColor *m_clrOBorder, // Color of outer border *m_clrIBorder, // Color of inner border *m_clrBackgrd, // Background color of gauge *m_clrNormal; // Normal segment color } // Create the Getters and Setters for the variables. @property (readwrite, nonatomic) float value; @property (readwrite, nonatomic) float maxLimit; @property (readwrite, nonatomic) float minLimit; @property (readwrite, nonatomic) int numBars; @property (readonly, nonatomic) float fillValue; @property (readwrite, retain) UIColor *oBorderColor; @property (readwrite, retain) UIColor *iBorderColor; @property (readwrite, retain) UIColor *backgrndColor; @property (readwrite, retain) UIColor *normalBarColor; // Battery Gauge Class Methods -(void) setDefaults; -(void) drawBar:(CGContextRef)a_ctx withRect:(CGRect) a_rect andColor:(UIColor *)a_clr barLit:(BOOL)a_IsBarlit; @end

    In the preceding code snippet, we declare a new instance of our UIView subclass, as our BatteryGauge will act as a view within our view controller on our main screen. Next, we declare a collection of private class variables that will be used within our implementation file, as well as define the object properties that can be set and accessed from our Battery Monitor view controller.

  2. Open the BatteryGauge.m implementation file, located within the BatteryMonitor folder, and enter in the following code snippet:

    // BatteryGauge.m // BatteryMonitor // Created by Steven F Daniel on 21/02/12. // Copyright (c) 2012 GenieSoft Studios. All rights reserved. #import "BatteryGauge.h" @implementation BatteryGauge // Synthesized getters and setters properties @synthesize maxLimit = m_flMaxLimit; @synthesize minLimit = m_flMinLimit; @synthesize numBars = m_iNumBars; @synthesize fillValue = m_flFillValue; @synthesize oBorderColor = m_clrOBorder; @synthesize iBorderColor = m_clrIBorder; @synthesize backgrndColor = m_clrBackgrnd; @synthesize normalBarColor = m_clrNormal;

    In the preceding code snippet, we use the @synthesize class directive to have it automatically generate the setters and getters for each of the properties that we have declared within the interface file.

  3. In the following code snippet, we create an initWithCoder: method object, to initialize the battery gauge class and then check to ensure that it has been initialized correctly, prior to making a call to our setDefaults method to initialize Battery Gauge.

    // Initializes the instance when brought from nib, etc. -(id) initWithCoder:(NSCoder *)aDecoder { self = [super initWithCoder:aDecoder]; if (self) { // Assign default values [self setDefaults]; } return self; }

  4. In the following code snippet, we create a Method value: object that we can use to pass in, and set and retrieve the value of our battery gauge.

    // Method: value accessor -(float) value { return m_flValue; }

  5. In the following code snippet, we create a Method setValue: object that determines when the bars within the battery gauge are to be shown as active battery cells or inactive battery cells. A check is performed to determine which bar should be lit within the gauge. We then check our fRedrawBar variable to see if the display needs to be redrawn, by calling our setNeedsDisplay method to redraw our UIView.

    // Method: value setter -(void) setValue:(float)a_value { BOOL fRedrawBar = false; // take a copy of our current bar value m_flValue = a_value; // Point at which bars need to light up int iOnIdx = (m_flValue >= m_flMinLimit) ? 0 : m_iNumBars; if ( iOnIdx != m_iOnIdx ) { m_iOnIdx = iOnIdx; fRedrawBar = true; } // Point at which bars no longer require to be lit int iOffIdx = ((m_flValue - m_flMinLimit) / (m_flMaxLimit - m_flMinLimit)) * m_iNumBars; if (iOffIdx != m_iOffIdx ) { m_iOffIdx = iOffIdx; fRedrawBar = true; } // Yes, save the fill value of our bars index m_iFillBarIdx = MIN(m_iOffIdx, m_iNumBars - 1); m_flFillValue = a_value; // Determine if we need to redraw the display if (fRedrawBar == true) { [self setNeedsDisplay]; } }

  6. In the following code snippet, we create a setNumBars(int)a_iNumBars: method object, to initialize and set the total number of bars to display to the UIView by making a call to the setValue method, passing the current battery level reading.

    // Sets the number of bars for our battery gauge - (void) setNumBars:(int)a_iNumBars { // save a copy of the value and then update the bars. m_iNumBars = a_iNumBars; [self setValue:m_flValue]; }

  7. In the following code snippet, we create a setDefaults: function that will be used to initialize the battery gauge when it is first displayed. This function sets the default number of bars to be displayed, as well as the frame and background colors of the gauge.

    // Configures the default settings for our battery gauge -(void) setDefaults { // Initialize the Maximum/Minimum limits for our gauge m_flMaxLimit = 1.0f; m_flMinLimit = 0.0f; m_flValue = 0.0f; // Set the defaults for our gauge m_iNumBars = 20; m_iOffIdx = 0; m_iOnIdx = 0; // Set our gauge default colors m_clrBackgrnd = [UIColor blackColor]; m_clrOBorder = [UIColor grayColor]; m_clrIBorder = [UIColor blackColor]; m_clrNormal = [UIColor greenColor]; m_iFillBarIdx = -1; m_flFillValue = -INFINITY; }

  8. In the following code snippet, we use the drawRect: method to draw each of our battery cells, and then determine which ones need to be filled in and which ones should not be filled in. We first need to work out the boundaries of our battery gauge control, and then calculate the height and width of each of the bars that need to be placed between each of the bars, using the controller's bounds property.

    // Function to draw the Battery Gauge -(void) drawRect:(CGRect)rect { CGContextRef ctx; // Graphics context CGRect rectBounds, // Bounds for the rectangle rectBar; // Rectangle for the bar size_t iBarSize; // Size of each bar to be lit // Determine the boundaries of our bar rectBounds = self.bounds; // Adjust the height of our bar iBarSize = rectBounds.size.height / m_iNumBars; rectBounds.size.height = iBarSize * m_iNumBars; // Compute the width and height sizes of our bar rectBar.size.width = rectBounds.size.width - 2; rectBar.size.height = iBarSize; // Obtain the current graphics context of our view. ctx = UIGraphicsGetCurrentContext(); CGContextClearRect(ctx, self.bounds); // Fill in the background for each of our bars. CGContextSetFillColorWithColor( ctx,m_clrBackgrnd.CGColor); CGContextFillRect(ctx, rectBounds); // Initialize each of our bars, //including their line with CGContextSetStrokeColorWithColor(ctx,m_clrIBorder .CGColor); CGContextSetLineWidth(ctx, 1.0); // Cycle through the total number of bars and draw each // one and lighting up those that need to be lit. for (int iX = 0; iX < m_iNumBars; ++iX ) { // Determine the position of this bar. rectBar.origin.x = rectBounds.origin.x + 1; rectBar.origin.y = CGRectGetMaxY(rectBounds) – (iX + 1) * iBarSize; // Draw top and bottom borders for each of the bars CGContextAddRect(ctx, rectBar); CGContextStrokePath(ctx); // Determine the fill color for each of our bars UIColor *clrFill = m_clrNormal; // Determine if the bar should be filled BOOL fIsBarLit = ((iX >= m_iOnIdx && iX < m_iOffIdx) || iX == m_iFillBarIdx); // Fill the interior for each of our bars CGContextSaveGState(ctx); CGRect rectFill = CGRectInset(rectBar, 1.0, 1.0); CGPathRef clipPath = CGPathCreateWithRect(rectFill, NULL); CGContextAddPath(ctx, clipPath); CGContextClip(ctx); // Call our function to draw and fill each of our //bars, checking to see if the bar is should be //filled in. if (fIsBarLit) { // Draw the bar as a solid fill color CGContextSetFillColorWithColor(ctx, clrFill.CGColor); CGContextFillRect(ctx, rectFill); } else { // Draw the bar as background color. CGColorRef fillClr = CGColorCreateCopyWithAlpha(clrFill.CGColor, 0.2f); CGContextSetFillColorWithColor(ctx, m_clrBackgrnd.CGColor); CGContextFillRect(ctx, rectFill); CGContextSetFillColorWithColor(ctx, fillClr); CGContextFillRect(ctx, rectFill); CGColorRelease(fillClr); } CGContextRestoreGState(ctx); CGPathRelease(clipPath); } // Finally, draw a nice border around our gauge control CGContextSetStrokeColorWithColor(ctx,m_clrOBorder .CGColor); CGContextSetLineWidth(ctx, 2.0); CGContextAddRect(ctx, CGRectInset(rectBounds, 1, 1)); CGContextStrokePath(ctx); }

  9. Our next step is to obtain the current graphics context for our view using the UIGraphicsGetCurrentContext function, and then set the background color for each of our bars with the specified background color. Next, we perform a loop to create each bar determined by the m_iNumBars variable. We then determine the x and y positions for the placement of each of the bars, use CGContextAddRect to draw the top and bottom borders of each bar, and use the CGContextStrokePath function to draw our bar to the graphics window.

  10. We then move on to determine if the bar should be lit and at what position within the gauge this should happen, and then call the CGContextSaveGState method to push a copy of the current graphics state onto the graphics stack for the current context to fill the bar. We, then we set the style of the bar, and add this to the current graphics context.

  11. Finally, we draw the bar to our view, determining whether it should be filled in or not, by checking the fIsBarLit variable.

    If the bar is to be lit, we use the CGContextSetFillColorWithColor method to fill the bar, and add this to our current graphics context. If the bar does not need to be filled in, we use the CGContextCreateCopyWithAlpha method to create a copy of an existing Quartz color, then substitute a new alpha value and use this to fill the cell within the gauge. Since we have used the CGContextCreateCopyWithAlpha method, we will need to release this once we have finished with it.

    - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrienta tion)interfaceOrientation { // Return YES for supported orientations return(interfaceOrientation== UIInterfaceOrientationPortrait); }

    In the preceding code snippet, we force the device to always display in a portrait mode when the device has been rotated. We do this by checking the interfaceOrientation variable of the iOS device, so that it will only allow support for the portrait mode, by setting this to the value of the UIInterfaceOrientationPortrait type.

    For more information relating to the UIViewController, UIView, CGColor, and CGContext classes, you can refer to the Apple Developer Connection Documentation located at the following URLs:

     

Finishing up

Congratulations, we have finally implemented the methods for our BatteryMonitor application. Next, we are ready to build and run our application by choosing Product | Run from the Product menu, or alternatively pressing Command + R. The follwoing screenshot shows the BatteryMonitor application running on an iOS Device, displaying the e-mail composition sheet when the Compose button has been pressed on the toolbar. As you can see, it contains the pre-populated Subject and Body message.

From this screenshot, you can amend the subject header and include additional content within the body of the message. Once you have finished composing your e-mail, click on the Send button to have your e-mail sent. You will then be presented with a dialog letting you know that your email has been sent successfully.

Summary

In this article, we learned how to use the UIDevice class to derive device-related information in order to monitor battery levels for our iOS device, using the batteryMonitoringEnabled as well as the batteryState methods.

We then looked at how to create a custom UIViewController subclass, to display a graphical representation of our battery levels, using the batteryState method that comes as a part of the UIDevice class. At the end, we looked at how we can use the MFMailComposeViewController class to allow the user to send e-mails directly within the app, whenever the battery levels fall below the 20 percent threshold.

Resources for Article :


Further resources on this topic:


About the Author :


Steven F Daniel

Steven F. Daniel is originally from London, England, but lives in Australia.

He is the owner and founder of GENIESOFT STUDIOS (http://www.geniesoftstudios.com/), a software development company based in Melbourne, Victoria, that currently develops games and business applications for the iOS, Android, and Windows platforms.

Steven is an experienced software developer with more than 13 years of experience developing desktop and web-based applications for a number of companies including, insurance, banking and finance, oil and gas, and local and state government.

Steven is always interested in emerging technologies, and is a member of the SQL Server Special Interest Group (SQLSIG) and the Java Community. He has been the co-founder and Chief Technology Officer (CTO) of SoftMpire Pty Ltd., a company that focused primarily on developing business applications for the iOS and Android platforms.

He is the author of Xcode 4 iOS Development Beginner's Guide, iOS 5 Essentials, and iPad Enterprise Application Development Blueprints.

You can check out his blog at http://geniesoftstudios.com/blog/, or follow him on twitter at http://twitter.com/GenieSoftStudio.

Books From Packt


 Flash iOS Apps Cookbook
Flash iOS Apps Cookbook

iOS 5 Essentials
iOS 5 Essentials

Core Data iOS Essentials
Core Data iOS Essentials

Unity iOS Essentials
Unity iOS Essentials

Unity iOS Game Development Beginners Guide
Unity iOS Game Development Beginners Guide

iOS Development using MonoTouch Cookbook
iOS Development using MonoTouch Cookbook

UDK iOS Game Development Beginner's Guide
UDK iOS Game Development Beginner's Guide

Xcode 4 iOS Development Beginner's Guide
Xcode 4 iOS Development Beginner's Guide


No votes yet

Post new comment

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
w
C
P
Q
X
W
Enter the code without spaces and pay attention to upper/lower case.
Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software