There are a number of advanced Android topics that are beyond the scope of this book, but it's good for you to know about them so you can continue learning on your own.
This chapter will cover the more specialized areas of programming for Android, and give a summary of what is available and how it is implemented, as well as provide some resources for finding more information on implementing these attributes in your future Android applications. The examples, where given, will be short and sweet, to give you a taste of what is to come.
As we discussed in Chapter 7, Android has its own collection of user-interface widgets that can be used to easily populate your layouts with functional elements that allow your users to interface with the program logic that defines what your application does. These widgets have their own package called android.widget
that can be imported into your application and used without further modification.
Android extends this widget capability to its programmers by allowing us to also create our own widgets that can be used by Android as mini-application portals or views that float on the Android home screen, or even in other applications (just like the standard UI widgets). If you remember, user interface elements are Widgets that are sub-classed from View
objects.
Widgets can be used to provide cool little extras for the Android homescreen, such as weather reports, MP3 players, calendars, stopwatches, maps, or snazzy clocks and similar micro-utilities.
To create an app widget, you utilize the Android AppWidgetProvider
class, which extends the BroadcastReceiver
class. To create your own app widget, you need to extend this class and override one or more of its key methods in order to implement your custom app widget functionality. Key methods of the AppWidgetProvider
class include the following:
To create an app widget, you need to create an AppWidgetProviderInfo
object that will contain the metadata and parameters for the app widget. These are details such as the user interface layout, how frequently it is updated or refreshed, and the convenience class that it is sub-classed from (AppWidgetProvider). This can all be defined via XML, which should be no surprise.
The AppWidgetProvider
class defines all of the methods that allow your application to interface with the app widget class via broadcast events, making it a broadcast receiver. These broadcast events, as we discussed in Chapter 11, will update the widget, with some frequency if required, as well as enabling (turning it on), disabling (turning it off), and even deleting it if required.
App widgets also (optionally) offer a configuration activity that can launch itself when the user first installs your app widget. This activity adds a user interface layout that allows your users to modify the app widget settings before (or at the time of) its launch.
The app widget must be declared in the AndroidManifest.xml file, so that the application has registered it with the OS for communications, as it is a broadcast receiver, so we need the following code in our manifest:
<receiver android:name="ExampleAppWidgetProvider" > <intent-filter> <action android:name="android.appwidget.action.APPWIDGET_UPDATE/> </intent-filter> <meta-data android:name="android.appwidget.provider" android:resource="@xml/example_appwidget_info /> </receiver>
Notice that the receiver
tag specifies an XML file in the /res/xml folder that sets the parameters for the look and operation of the widget, in a file called example_appwidget_info.xml, which contains the following XML mark-up code:
<appwidget-provider xmlns:android=http://schemas.android.com/apk/res/android android:minWidth="294dp" android:minHeight="72dp" android:updatePeriodMillis="80000000" android:initialLayout="@layout/example_appwidget" android:configure="com.example.android.ExampleAppWidgetConfigure" > </appwidget-provider>
The minWidth
and minHeight
attributes define the size of the widget.
updatePeriodMillis
defines the update period in milliseconds.
The updatePeriodMillis
value should be set as high as possible, as updates consume battery power, and are called even if the smartphone is in sleep mode, which means that the phone is powered on to make the update. The initialLayout
attribute calls the XML file that defines the app widget layout itself. You need to define an initialLayout
XML file for your app widget in the /res/layout folder, or your app widget will be empty. This should all be old hat to you now after Chapter 6.
The last android:configure
attribute is optional, and calls the activity that is needed to configure the UI layout and options settings for the widget on start-up. App widget layouts are based on remote views, which support only the main the following three layout classes in Android:
LinearLayout
RelativeLayout
FrameLayout
The following widget classes are also supported in the initialLayout
XML file:
AnalogClock
Button
Chronometer
ImageButton
ImageView
ProgressBar
TextView
More information can be found at the App Widget Design Guidelines page at:
http://developer.android.com/guide/practices/ui_guidelines/widget_design.html
General Information on App Widgets can be found at:
http://developer.android.com/guide/topics/appwidgets/index.html
Location-based services and Google Maps are both very important OS capabilities when it comes to a smartphone device. You can access all location and maps related capabilities inside of Android via the android.location
package, which is a collection of classes or routines for dealing with maps and locations, and via the Google Maps external library, which we will cover in the next section.
The central component of the location services network is the LocationManager
system service. This Android system service provides the APIs necessary to determine the location and (if supported) bearing of the underlying device's GPS and accelerometer hardware functionality.
Similar to other Android systems services, the LocationManager
is not instantiated directly, but is instead requested as an instance from the system by calling the getSystemService(Context)
method, which then returns a handle to the new LocationManager
instance, like this:
getSystemService(Context.LOCATION_SERVICE)
Once a LocationManager
has been established inside of your application, you will be able to do the following three things in your application:
Query for a list of all LocationProvider
s for the last known user location.
Register (or unregister) for periodic updates of the user's current location.
Register (or unregister) for a given Intent to be fired once the device is within certain proximity of a specified latitude or longitude specified in meters.
Google provides an external library called Google Maps that makes it relatively easy to add powerful mapping functions to your Android applications. It is a Java package called com.google.android.maps
, and it contains classes that allow for a wide variety of functions relating to downloading, rendering, and caching map tiles, as well as a variety of user control systems and display options.
One of the most important classes in the maps package is MapView
class, a subclass of ViewGroup
, which displays a map using data supplied from the Google Maps service. Essentially this class is a wrapper providing access to the functions of the Google Maps API, allowing your applications to manipulate Google Maps through MapView
methods that allow maps and their data to be accessed much as though you would access any other View
object.
The MapView
class provides programmers with all of the various user interface assets that can be used to create and control Google Maps data. When your application passes focus to your MapView
object, it automatically allows your users to zoom into, and pan around, the map using gestures or keypresses. It can also handle network requests for additional map tiles or an entirely new map.
Before you can write a Google Maps-based application, you must obtain a Google Maps API key to identify your app:
To begin with, you need to provide Google with the signature of your application. To do so, run the following at the command line (this is again a Windows example):
keytool -list -keystore C:users<username>.androiddebug.keystore
When prompted, the password is android
. Here is what you should see:
Enter keystore password: Keystore type: JKS Keystore provider: SUN Your keystore contains 1 entry androiddebugkey, 21-Jan-2011, PrivateKeyEntry, Certificate fingerprint (MD5): <fingerprint>
Copy the fingerprint. You'll need it in the next step.
Go to http://code.google.com/android/maps-api-signup.html
and enter the fingerprint in the "My certificate's MD5 fingerprint:" box.
Accept the terms and conditions, then click Generate API Key.
On the next page, note your API key.
Now that we have our key, here are the basic steps for implementing a Google Maps app:
First you would want to create a new project and Activity called MyGoogleMap
, with a Project Build Target of Google APIs
for version 1.5. We need to do this to use the Google Maps classes.
You may have to install the Google APIs using the Android SDK and AVD Manager. They are listed as Google APIs by Google Inc.
In the AndroidManifest.xml file within the <application>
tag use the <uses-library>
tag to point to the Google Maps library address specified above as follows:
<uses-library android:name="com.google.android.maps" />
Also in the AndroidManifest.xml file and within the <application>
tag, use the <uses-permission>
tag to request permission to access the Internet as follows:
<uses-permission android:name="android.permission.INTERNET" />
Next you would want to define some simple user interface elements within your main.xml layout definition, using a basic linear layout with a vertical parameter specified, and then a Google Maps MapView
user interface element with the clickable
parameter set to true
, allowing the user to navigate the map, as follows:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/mainlayout"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<com.google.android.maps.MapView
android:id="@+id/mapview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:clickable="true"
android:apiKey="Your Maps API Key
"
/>
</LinearLayout>
Now enter your unique Google Maps API key that was assigned to you in the apiKey
parameter in the last parameter of the MapView
tag.
Next open your MyGoogleMap.java
activity and extend your class to use a special sub-class of the Activity
class called the MapActivity
class, as follows:
public class MyGoogleMapextends MapActivity {...}
One of the primary methods of the MapActivity
class is the isRouteDisplayed()
method, which must be implemented, and once it is, you will be able to pan around a map, so add this little bit of code as follows to complete your basic map:
@Override protected boolean isRouteDisplayed() { return false; }
At the top of your MyGoogleMap
class instantiate two handles for the MapView
and the ZoomTool
controls (LinearLayout
) we are going to add next, as follows:
LinearLayout linearLayout; MapView mapView;
Next in your onCreate()
method, initialize your MapView
UI element and add the ZoomControls
capability to it via the setBuiltInZoomContols()
method as follows:
mapView = (MapView) findViewById(R.id.mapview); mapView.setBuiltInZoomControls(true);
Note that we are using the built-in MapView
zoom controls so we do not have to write any code and yet when we run this basic application the user will be able to zoom the MapView
via zoom controls that will appear when the user touches the map and then disappear after a short time-out period (of non-use).
Compile and run your MyGoogleMap
application in the Android emulator.
It is important to note that the external Google Maps library is not an integral part of the Android OS, but is actually something that is hosted externally to the smartphone environment and requires access externally via a Google Maps key that you must apply for and secure before your applications utilize this service from Google. This is the same way that this works for using Google Maps from a web site; it's just that the MapView
class fine-tunes this for Android usage. To learn more about the Google Maps external library visit:
http://code.google.com/android/add-ons/google-apis
Google has built its business model on one major service that it has always offered: search. It should be no surprise that search is thus a well-supported core service in Android. Android users can search for any data that is available to them on their Android handset or across the Internet.
Android, not surprisingly, provides a seamless, consistent search experience across the board, and Android provides a robust search implementation framework for you to implement search functions inside of your Android applications.
The Android search framework provides an interface for search that includes both the interaction and the search itself, so that you do not have to define a separate Activity in Android. The advantage of this is that the use of search in your application will not interrupt your current Activity.
Using Android search puts a search dialog at the top of the screen, pushing other content down on the screen as it is utilized. Once you have everything set up to use this capability in Android, you can integrate your application with search by providing search suggestions based on your app or recent user queries, offer you own custom application specific search suggestions in the system-wide quick search function, and even turn on voice search functions.
Search in Android is handled by the SearchManager
class; however, that class is not used directly, but rather is accessed via an Intent specified in XML or via your Java code via the context.getSystemService(context.SEARCH_SERVICE)
code construct. Here are the basic steps to set-up capability for a search within your AndroidManifest.xml file.
Specify an <intent-filter>
in the <activity>
section of the AndroidManifest.xml:
<intent-filter> <action android:name="android.intent.action.SEARCH" />
</intent-filter> <meta-data android:name="android.app.searchable" android:resource="@xml/searchable" />
Next, create the res/xml/searchable.xml file specified in the <meta-data>
tag in step 1.
Inside searchable.xml, create a <searchable>
tag with the following data:
<searchable xmlns:android="http://schemas.android.com/apk/res/android" android:label="@string/search_label" android:searchSuggestAuthority="dictionary" android:searchSuggestIntentAction="android.intent.action.VIEW"> </searchable>
Now in res/values/strings.xml, add a string called search_label
.
Now you are ready to implement a search in your application as described here:
http://developer.android.com/guide/topics/search/search-dialog.html
Note that most Android phones and devices come with a search button built in, which will pop up the search dialog. You can also provide a button to do this, in a menu maybe. That's for you to experiment with.
Android has a significant number of ways for you to save data on your smartphone, from private data storage for your application, called shared preferences, to internal storage on your smartphone device's memory chips, to external storage via your smartphone device's external storage (HD card or mini HDD), to network connection (Network Attached Storage) via your own network server, to an entire DBMS (Database Management System) via open source SQLite private databases.
Shared preferences are persistent data pairs that remain in memory even if your application is killed (or crashes), and thus this data remains persistent across multiple user sessions. The primary use of shared preferences is to store user preferences for a given user's Android applications and this is a main reason why they persist in memory between application runs.
To set your application's shared preferences Android provides us with the SharedPreferences
class. This class can be used to store any primitive data types, including Booleans (on/off, visible/hidden), floats, integers, strings, and longs. Note that the data created with this class will remain persistent across user sessions with your application even if your application is killed (the process is terminated or crashes).
There are two methods in the SharedPreferences
class that are used to access the preferences; if you have a single preference file use getPreferences()
and if you have more than one preference files, you can name each and use getSharedPreferences(name)
and access them by name. Here is an example of the code in use, where we retrieve a screen name. The settings.getString()
call returns the screenName
parameter, or the name Android Fan if the setting is not set:
public static final String PREFS_NAME = "PreferenceFile"; ... @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0); String screenName = settings.getString("screenName", "Android Fan"); // do something with the screen name. }
We can set the screen name with the following:
SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0); SharedPreferences.Editor editor = settings.edit(); editor.putString("screenName", screenName); editor.commit();
Accessing internal memory storage on Android is done a bit differently, as that memory is unique to your application and cannot be directly accessed by the user or by other applications. When the application is uninstalled these files are deleted from memory. To access files in memory use the openFileOutput()
with the name of the file and the operation needed, which will return a FileOutputStream
object which you can use the read(), write()
and close()
methods to manipulate the data into and out of the file. Here is some example code showing this concept:
String FILENAME = "hello_file"; String string = "hello world!"; FileOutputStream fos = openFileOutput(FILENAME, Context.MODE_PRIVATE); fos.write(string.getBytes()); fos.close();
The method that is used for accessing external memory on an Android device is getExternalStorageState()
. It checks to see whether the media (usually an SD card or internal micro HDD) is in place (inserted in the case of an SD card) and available for usage. Note that files written to external removable storage media can also be accessed outside of Android and applications by PCs or other computing devices that can read the SD card format. This means there is no security in place on files that are written to external removable storage devices.
The most common way to store data for your application, and the most organized and sharable, is to create and utilize a MySQL Lite database. This is how Android stores and accesses its own data for users who utilize its internal applications such as the Contacts list or Database. Any private database you create for your application will be accessible to all parts of your application, but not to other parts of other developer's applications unless you give permission for them to access it. I will briefly outline how it would be done here, and you can research these methods on the developer.android site for more details.
The way to create a new SQL database in Android is to create a subclass of the SQLiteOpenHelper
class and then override the onCreate()
method. This method allows one to create a tabular structure within the desired database format that will support your application's optimal data structure. Here is some example code from the Android Developer site showing the SQLiteOpenHelper
implemented.
public class DictionaryOpenHelper extends SQLiteOpenHelper { private static final int DATABASE_VERSION = 2; private static final String DICTIONARY_TABLE_NAME = "dictionary"; private static final String DICTIONARY_TABLE_CREATE = "CREATE TABLE " + DICTIONARY_TABLE_NAME + " (" + KEY_WORD + " TEXT, " + KEY_DEFINITION + " TEXT);"; DictionaryOpenHelper(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); } @Override public void onCreate(SQLiteDatabase db) { db.execSQL(DICTIONARY_TABLE_CREATE); } }
To write and read from the custom database structure, you would utilize the getWritableDatabase()
and getReadableDatabase()
methods, which both return a SQLiteDatabase
object that represents the database structure and provides methods for performing SQLite database operations.
To perform SQLite database queries on your new SQLite database you would use the SQLiteDatabase_Query
methods, which accept all common data query parameters such as the table to query and the groupings, columns, rows, selections, projection, and similar concepts that are mainstream in database programming.
As of Android version 2.2 (API Level 8), Google has introduced support for secure enterprise applications via its Android Device Administration API. This API provides developers with employee device administration at a lower system level, allowing the creation of "security aware" applications that are necessary in MIS enterprise applications that require that IT maintain a tight level of control over the employees Android Smartphone devices at all times.
A great example of this is the Android e-mail application, which has been upgraded in OS version 2.2 to implement these security features to provide more robust e-mail exchange security and support. Exchange Administrators can now implement and enforce password protection policies in the Android e-Mail application spanning both alphanumeric passwords and simpler numeric PINs across all of the devices in their organization.
IT administrators can go as far as to remotely restore the factory defaults on lost or stolen handsets, clearing sensitive passwords and wiping clean proprietary data. E-mail Exchange End-Users can now sync their e-Mail and calendar data as well.
The Android Camera
class is used to control the built-in camera that is in every Android smartphone. This Camera
class is used to set image capture settings and parameters, start and stop the preview modes, take the actual picture and retrieve frames of video in real-time for encoding to a video stream or file. The Camera
class is a client for the camera service, which manages the camera hardware.
To access your Android device's camera, you need to declare a permission in your AndroidManifest.xml that allows the camera features to be included in your application. You need to use the <uses-feature>
tag to declare any camera features that you wish to access in your application so that Android knows to activate them for use in your application. The following XML AndroidManifest.xml entries allow the camera to be used and define it as a feature along with the auto-focus capabilities:
<uses-permission android:name="android.permission.CAMERA" /> <uses-feature android:name="android.hardware.camera" /> <uses-feature android:name="android.hardware.camera.autofocus"/>
The developer.android website has plenty of Java code for you to experiment with.
One of the most impressive capabilities of the Android OS is its ability to "render" 3D graphics in real-time using only the open source OpenGL (Open Source Graphics Language) ES 1.0 API, and in later releases of Android, the OpenGL ES 1.1 and 1.2 APIs. OpenGL ES stands for OpenGL for Embedded Systems.
OpenGL ES is an optimized embedded devices version of the OpenGL 1.3 API that is used on Computers and Game Consoles. OpenGL ES is highly optimized for use in embedded devices, much like the Android Dalvik Virtual Machine optimizes your code by making sure there is no "fat" that the Smartphone CPU and memory need to deal with, a streamlining of sorts. OpenGL ES 1.0 is feature parallel to the full OpenGL 1.3 standard, so if what you want to do on Android is doable in OpenGL 1.3, it should be possible to do it in OpenGL ES 1.0.
The Android OpenGL ES 1.0 is a custom implementation but is somewhat similar to the J2ME JSR239 OpenGL ES API, with some minor deviations from this specification due to its use with the Java Micro Edition (JavaME) for cell phones.
To access the OpenGL ES 1.0 API, you need to write your own custom subclass of the View Class and obtain a handle to an OpenGL Context, which will then provide you with access to the OpenGL ES 1.0 functions and operations. This is done in the onDraw() method of the custom View class that you create, and once you have a handle to the OpenGL Object, you can use that object's methods to access and call the OpenGL ES functional operations.
More information on OpenGL ES can be found at www.khromos.org/opengles/
Information about version 1.0 can be found at www.khronos.org/opengles/1_X/
Android Developer Documents do in fact exist for OpenGL ES 1.0 and 1.1 at
http://developer.android.com/reference/javax/microedition/khronos/opengles/package-summary.html
One of the coolest and most advanced concepts in the SDK is a facial recognition class called FaceDetector
.
FaceDetector
automatically identified faces of subjects inside of a Bitmap
graphic object. I would suggest using PNG24 (24-bit PNG) for the highest quality source data for this operation.
You create a FaceDetector
object by using the public constructor FaceDetector
:
public FaceDetector (width integer, height integer, maxFaces integer)
The method you use to find faces in the bitmap file is findFaces(Bitmap bitmap, Face[] faces)
, which returns the number of faces successfully found.
The SoundPool
class is great for game development and audio playback applications on Android because it manages a pool of Audio Resources in an optimal fashion for Android Apps that use a lot of audio or where audio is a critical part of the end-user's overall experience.
A SoundPool is a collection of audio "samples," such as sound effects or short songs which need to be loaded into Android memory from an external resource either inside the application's. APK file or from an external file or the internal file system.
The cool thing about the SoundPool is that it works hand in hand with the MediaPlayer Class that we looked at in Chapter 8 to decode the audio into a raw PCM mono or stereo 16-bit CD quality audio stream. This makes it easier for an application to include compressed audio in it's APK and then decompress it on application start-up, load it into memory, and then play it back without hiccups when it is called or triggered within the application code.
It gets even more interesting. It turns out that SoundPool can also control the number of audio assets that are being simultaneously "rendered" or turned from data values into audio sound waves. Essentially this means that the SoundPool is an Audio "Mixing Console" that can be used to layer audio in real-time to create custom mixes based on your gameplay or other applications programming logic.
SoundPool defines a maxStreams parameter that limits the number of parallel audio streams that can be played so that you can put a "cap" on the amount of processing overhead that is used to mixdown audio in your application, in case this starts to affect the visual elements that are also possibly rendering in real-time on the screen. If the maxStreams value is exceeded then the SoundPool turns off individual audio streams based on their priority values, or if none are assigned, based on the age of the audio stream.
Individual audio streams within the SoundPool can be looped infinitely (a value of −1) or any number of discreet times (0 to ...) and also counts from zero so a loop setting of three plays the audio loop four times. Playback rates can also be scaled from 0.5 to 2.0, or at half the pitch to twice the pitch, allowing real-time pitch shifting and with some clever programming one could simulate effects such as Doppler via fairly simple Java code. Samples can also be pitch shifted to give a range of sound effect tones or create keyboard-like synthesizers.
SoundPool also lets you assign a Priority to your individual audio samples, with higher numbers getting higher priority. Priority only comes into play when the maxStreams value specified in the SoundPool Object is hit and an audio sample needs to be removed from the playback queue to make room for another audio sample playback request with a higher priority level. Be sure to prioritize your audio samples so that you can have complete control of your audio and effects mixing during real-time playback.
In Chapter 8 we discussed the Android MediaPlayer
class, which is commonly used to play back audio or video files. Android can also record audio and media files at a high level of fidelity and the counterpart to the MediaPlayer
class for this is, logically, the MediaRecorder
class. It is important to note that MediaRecorder
does not currently work on the Android smartphone emulators.
There are five main MediaRecorder
classes that control the process of media recording. They are as follows (note that these are defined inside the MediaRecorder
class, hence the dot notation):
You construct a MediaRecorder
object and operate on it using the public methods such as prepare(), release(), reset(), setAudioChannels(), setCamera(), setOutputFile()
, and a plethora of other methods that control how the new media data is captured and stored on your Android device.
More information on the MediaRecorder
class can be found at
http://developer.android.com/reference/media/MediaRecorder.html
There are a lot of great features in Android that we simply do not have enough time to cover in one book, or that are too high complex for an absolute beginners' book. That doesn't mean that you should not investigate all the cool features that Android has to offer on your own, however, so this chapter introduced some that are very powerful and advanced for a mobile phone operating system.
Where graphics are concerned there is no more powerful open source graphics library than OpenGL and Android implements the latest OpenGL ES 1.2 technology just like HTML5 does currently. Since Android phones have guilt-in GPU hardware, this means that you can render real-time 3D on the fly to visualize just about anything you want to within your application and in three dimensions to boot!
There are many other interesting areas to be discovered in Android as well, from creating your own widgets to creating your own MySQLite databases to using the SmartPhone Camera to the Face Recognition to the SoundPool Audio Engine for games and the Media Recorder to capture your own new media assets. All of this is covered in detail on the developer.android.com
website be sure to explore there at length to enhance your knowledge of the thousands of interesting features in Android OS with many more to come!
98.82.120.188