Android app development course Unit 5- + Enabling inter-app communication. BroadcastReceivers, ContentProviders. App Widgets 1
But first... just a bit more of Intents! Up to now we have been working with explicit Intents to launch a new Activity or Service. startactivity(new Intent(context, MyActivity.class)) startservice(new Intent(context, MyService.class)) But we can also use implicit Intents to do so. Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse( tel:555-1234 )); It defines an action... and it can deal with specific data (optional)! 2
Implicit Intents Implicit Intents Define an action android.intent.action.action_call android.intent.action.show_view org.uab.deic.cursandroid.view_info Are mapped to an Intent Filter, which defines what actions an Activity is able to deal with <activity android:name=".mainactivity"> <intent-filter> <action android:name="android.intent.action.main"/> <category android:name="android.intent.category.launcher"/> </intent-filter> </activity> 3
Implicit Intents Android defines some standard actions: ACTION_CALL ACTION_EDIT ACTION_MAIN ACTION_SYNC ACTION_BATTERY_LOW ACTION_HEADSET_PLUG ACTION_SCREEN_ON ACTION_TIMEZONE_CHANGED...among others, defined within the Intent class! 4
Implicit Intents Intent Filters Filters an Intent according to 3 attributes: action: the action to perform category: context within which the action makes sense data: data type it is able to handle The data type may be specified using the following schemes: android:mimetype defines the data type (e.g. html) An URI with a specific pattern scheme://host:port/path 5
Implicit Intents Categories LAUNCHER DEFAULT ALTERNATIVE SELECTED_ALTERNATIVE BROWSABLE TAB HOME PREFERENCE...among others also described in the Intent class! 6
Implicit Intents Filtering process All Intent Filters of all applications are queried Those that don't match the action and category are eliminated It must match at least ONE action It must match ALL categories Those whose data tag don't match or are incompatible with the URI specified by the Intent are eliminated All the remaining options are offered to the users, who should chose the most appropriate one 7
You might find useful Linkify Helper class that parses a TextView and creates links inside it If the text matches an URL-like pattern, a link is created which contains the following action startactivity(new Intent(Intent.ACTION_VIEW, uri)) The URI contains the actual link created TextView textview = (TextView) findviewbyid(r.id.generalinfo_text); Linkify.addLinks(textView, Linkify.ALL); 8
You might find useful PendingIntent Intent designed to be executed a posteriori, not necessarily from the same application. It is executed with the same permissions and identity as if it were executed from the application itself. Intent intent = new Intent(context, SessionDetailsActivity.class); intent.putextra("number_of_session", sessionid); intent.putextra("titleactionbar", context.getresources().getstring(r.string.session_text)); PendingIntent launchintent = PendingIntent.getActivity(context, 0, intent, 0); 9
Activity 5.1 5.1.1 Add an Intent Filter to the Activity hosting the form in order to handle implicit Intents. 5.1.2 Create a new Android project. 5.1.3 Add a Button to the MainActivity of the new project to start the Activity hosting the form using an implicit Intent. 10
BroadcastReceivers Intents may alert of the occurrence of an system event. Also known as Broadcast Events To create a new Broadcast Event we should call the following method sendbroadcast(intent) These events are captured within BroadcastReceivers! 11
BroadcastReceivers A BroadcastReceiver Captures those events it was registered for. Decides who should continue handling the event! Is active during a very small time frame (~10 seconds). Typically: Starts an Activity Starts an Service Creates a Notification Updates some content (if it doesn't require much computation) 12
BroadcastReceivers BroadcastReceivers can be declared in the Manifest file... <receiver android:name=".services.uabdroidreceiver"> <intent-filter> <action android:name="org.uab.deic.uabdroid.update_intent"/> </intent-filter> <intent-filter> <action android:name="org.uab.deic.uabdroid.alarm_intent"/> </intent-filter> </receiver> 13
BroadcastReceivers...or created dynamically in code. IntentFilter filter = new IntentFilter(UABDroidReceiver.UPDATE_INTENT); filter.addaction(uabdroidreceiver.alarm_intent); UABDroidReceiver receiver = new UABDroidReceiver(); registerreceiver(receiver, filter); Then we can unregister them also dynamically unregister(receiver) 14
BroadcastReceivers What we could find inside a BroadcastReceiver is... public class UABDroidReceiver extends BroadcastReceiver { public static final String UPDATE_INTENT = "org.uab.deic.uabdroid.update_intent"; public static final String ALARM_INTENT = "org.uab.deic.uabdroid.alarm_intent"; @Override public void onreceive(context context, Intent intent) { } } if ( intent.getaction().equalsignorecase(update_intent) ) { Intent startintent = new Intent(context, UpdateService.class); context.startservice(startintent); } else if (intent.getaction().equalsignorecase(alarm_intent)) { Intent startintent = new Intent(context, AlarmService.class); context.startservice(startintent); } 15
BroadcastReceivers There are Broadcast Events generated by the system ACTION_BOOT_COMPLETED ACTION_(CAMERA MEDIA)_BUTTON ACTION_(DATE TIME)_CHANGED ACTION_MEDIA_(EJECT MOUNTED UNMOUNTED) ACTION_NEW_OUTGOING_CALLS ACTION_SCREEN_(ON OFF) ACTION_TIMEZONE_CHANGED ACTION_BATTERY_(CHANGED LOW OKAY) CONNECTIVITY_ACTION (ConnectivityManager) 16
Activity 5.2 5.2.1 Create a BroadcastReceiver within the application containing the form, capable of filtering an action defined by yourselves. 5.2.2 In its onreceive() method it should start the Activity hosting the form. 5.2.3 From the new project created in the previous activity, generate a Broadcast Event with your custom action. 17
ContentProviders Usually, all the storage options available in Android are accessible only by the same application creating them (or at least this is the typical scenario). Sometimes we need to share information with other applications (e.g. our contacts list). ContentProviders Enables Android applications to share data with third parties. Define a standard data access protocol. 18
ContentProviders To access the contents of a ContentProvider We need a ContentResolver which we can access by calling getcontentresolver() of the Context class We need different query methods based on the type of data we are interested in We need a standard reference to access the data source URI: Uniform Resource Identificator 19
ContentProviders URI Formatted according to the pattern below Where A: prefix that indicates the access type B: authority or specific provider ID C: path to determine the type of the requested data D: specific register (optional) 20
ContentProviders ContentResolver Depending if the provider returns a cursor or a stream, we call one of the following methods query(uri, projection, selection, args, order) (cursors) openinputstream(uri) (files) We could also add new data or modify existing registers if the ContentProvider allows it insert(uri, values) (insert data) update(uri, values, where, args) (update registers) openoutputstream(uri) (files) 21
ContentProviders There are some Providers already implemented in Android Browser CallLog ContactsContract MediaStore Settings UserDictionary 22
ContentProviders In order to create our own ContentProvider, we must Decide which data we want to share, get from others (insert operation), modify or eliminate Create a new classing extending ContentProvider Define the structure of the URIs to access the data Use an UriMatcher to handle incoming URIs and decide what action should be performed Override the corresponding methods in ContentProvider according to the data they should act upon and the UriMatcher 23
ContentProviders Example public class SessionsProvider extends ContentProvider { public static final Uri CONTENT_URI = Uri.parse( "content://org.uab.deic.provider.uabdroid/sessions"); private static final int SESSIONS = 1; private static final int SINGLE_SESSION = 2; private static final UriMatcher urimatcher; static { urimatcher = new UriMatcher(UriMatcher.NO_MATCH); urimatcher.adduri("org.uab.deic.provider.uabdroid", "sessions", SESSIONS); urimatcher.adduri("org.uab.deic.provider.uabdroid", "sessions/#", SINGLE_SESSION); } // 24
ContentProviders @Override public Cursor query(uri uri, String[] projection, String selection, String[] selectionargs, String sortorder) { SQLiteQueryBuilder querybuilder = new SQLiteQueryBuilder(); querybuilder.settables(databaseadapter.db_table_sessions); switch ( urimatcher.match(uri) ) { case SINGLE_SESSION: querybuilder.appendwhere( DatabaseAdapter.KEY_ROWID + "=" + uri.getlastpathsegment()); break; default: break; } //... Cursor cursor = querybuilder.query(database, projection, selection, selectionargs, null, null, sortorder); cursor.setnotificationuri(getcontext().getcontentresolver(), uri); } return cursor; 25
ContentProviders We must declare the ContentProvider in the Manifest file <provider android:name=".services.sessionsprovider" android:authorities="org.uab.deic.provider.uabdroid"/> 26
Activity 5.3 5.3.1 Create a ContentProvider to encapsulate the SQLite DB we have been working with in the previous sessions. 5.3.2 Define an URI to get the name of all the applications stored in the DB. 27
App Widgets The App Widgets are also known as Home Screen Widgets Are a set of small Views which can be executed in another application (Home Screen / Launcher). Periodically updated. We can create and publish them using the AppWidgetProvider class(direct implementation of BroadcastReceiver). 28
App Widgets To create a new widget we need To declare it in the Manifest file using the <receiver> tag To create an XML file in /res/xml containing the widget's configuration parameters To define its layout (in the same way we define an Activity's layout) To create a class extending AppWidgetProvider and implement the methods onreceive() onupdate() 29
App Widgets Declaring the App Widget in the Manifest <receiver android:name=".services.nextsessionwidget" android:label="@string/next_session_widget_label"> <intent-filter> <action android:name="android.appwidget.action.appwidget_update" /> </intent-filter> <meta-data android:name="android.appwidget.provider" android:resource="@xml/nextsession_widget_info"/> </receiver> 30
App Widgets XML widget configuration file <?xml version="1.0" encoding="utf-8"?> <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" android:initiallayout="@layout/nextsession_widget" android:minwidth="294dp" android:minheight="142dp" android:label="@string/next_session_widget_label" android:updateperiodmillis="172800000" /> 31
App Widgets AppWidgetProvider implementation public class NextSessionWidget extends AppWidgetProvider { @Override public void onupdate(context context, AppWidgetManager appwidgetmanager, int[] appwidgetids) { super.onupdate(context, appwidgetmanager, appwidgetids); updatesessioninfo(context, appwidgetmanager, appwidgetids); } @Override public void onreceive(context context, Intent intent) { super.onreceive(context, intent); } } private void updatesessioninfo(context context, AppWidgetManager appwidgetmanager, int[] appwidgetids) { //... } 32
App Widgets Things you should take into consideration We can't update the content of the widget's Views directly (their executed in a different application) We need a RemoteViews object We need a ContentProvider to access the data in our application We can't use any View to create a widget's layout! We can create an initial configuration screen for the first time the widget is created 33
App Widgets final int N = appwidgetids.length; for (int i = 0; i < N; i++) { RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.nextsession_widget); ContentResolver cr = context.getcontentresolver(); Cursor cursor = cr.query(sessionsprovider.content_uri, null, null, null, null); //... Intent intent = new Intent(context, SessionDetailsActivity.class); intent.putextra("number_of_session", sessionid); PendingIntent pendingintent = PendingIntent.getActivity(context, 0, intent, 0); views.setonclickpendingintent(r.id.next_session_widget_layout, pendingintent); //... views.settextviewtext(r.id.next_session_name, title); views.settextviewtext(r.id.next_session_description, content.substring(3)); views.settextviewtext(r.id.next_session_date, date + " - " + hour); } appwidgetmanager.updateappwidget(appwidgetids[i], views); 34
App Widgets Layouts we can use for an App Widget FrameLayout LinearLayout RelativeLayout GridLayout 35
App Widgets Views we can use for an AppWidget AnalogClock Button Chronometer ImageButton ImageView ProgressBar TextView ViewFlipper ListView GridView StackView AdapterViewFlipper 36
Activity 5.4 5.4.1 Extend the functionality of our DB ContentProvider to return a single element given its ID. 5.4.2 Create a simple App Widget to show the info of the register with ID = 1 (the first register) in your applications DB. 37
If you want to know more... Professional Android Application Development. Chapters 5, 7 i 10 Pro Android. Chapters 5, 14, 21, 22, 27 i 31 Android Developers: Intents and Intent Filters Android Developers: Content Providers Android Developers: App Widgets 38