AppWidgets
are small views or widgets that can be embedded in another
application. The containing application is called App Widget Host.
One example of host application is the Home Screen application. When
you long-press the home screen and selecting Widgets option will
present you a list of widgets available. This is a two part series on
how to create App Widgets. In this part I will stick on to the basics
of creating the widget. In the second part I will explain how to
provide more advanced topics.
We
can create our own App Widgets by extending AppWidgetProvider class,
which is actually a BroadcastReceiver with
action android.appwidget.action.APPWIDGET_UPDATE.
To create an App Widget we extends this class and override
the onUpdate method.
Then we have to specify the App Widget in AndroidManifest.xml file
using the<receiver> tag.
Finally we have to describe the App Widget in
using AppWidgetProviderInfo object
in an XML file.
Creating AppWidget
To
create and App Widget, we create a class extending AppWidgetProvider.
The AppWidgetProvider class
has following methods:
void onEnabled(Context context)
void onDisabled(Context context)
void onDeleted(Context context, int[] appWidgetIds)
void onUpdate(Context context,AppWidgetManager appWidgetManager, int[] appWidgetIds)
void onReceive(Context context, Intent intent)
The
method onEnabled is
called when an instance is create for the first time, i.e. when the
user add the widget for the first time. It will not be called for
subsequent additions. In this method we can perform any startup
tasks.
The
method onDisabled is
called when the last instance of the widget is deleted. This method
is to do some cleanup tasks.
The onDeleted is
called when each instance of the widget is deleted.
The onUpdate method
is first called when the widget is added to the host. After that this
method will be called after the specified time intervals. This is the
most important method of the App Widget. In this method we update the
view with the data we want to display. If the data is readily
available, we can display it in this method itself, if the data is
not available and need to be fetched then it is better to create a
Service application which actually fetch the data and update the
widget. This is to avoid the ANR (Application Not Responding) error.
We can update the widgets
usingAppWidgetManager’s updateAppWidget() method.
Declaring the App Widget
We
have to declare the App Widget in the AndroidManifest.xml file using
the <receiver> tag.
As I told you before the AppWidgetProvider is actually is a
BroadcastReceiver. Anything that can be done using this class can
also be done using the BroadcastReceiver. Following snippet specifies
the GPS App Widget:
<receiver android:name=".GPSWidgetProvider">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/gpswidgetinfo" />
</receiver>
Everything
is same as specifying BroadcastReceiver except the meta-data section,
here we describe our App Widget in a separate XML file.
Describing the App Widget
App
Widget description is specified in a separate XML file. In this XML
file we specify the minimum width and height of the widget, update
period, widget layout, configuration screen layout, etc. Following
snippet describes the GPS App Widget:
<appwidget-provider xmlns:android="http://schemas>android>com/apk/res/android"
android:minWidth="294dp"
android:minHeight="72dp"
android:updatePeriodMillis="900000"
android:initialLayout="@layout/gpswidget">
</appwidget-provider>
The minWidth specifies
the minimum width the widget, minHeight specifies
the minimum height of the widget. TheupdatePeriodMillis specifies
the update period in milliseconds. The initialLayout specifies
the widget’s layout.
EXAMPLE
The
example application provided is a widget that displays the GPS
coordinates the device. The GPS coordinates are reverse geo-coded to
get the name of location and will be displayed if it is available. To
reverse geo-code the location I used the class Geocoder.
The widget will be updated in every 15 minutes.
In Manifest Write down following code...
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.samples.gpswidget"
android:versionCode="1"
android:versionName="1.0" >
<application
android:enabled="true"
android:icon="@drawable/icon"
android:label="@string/app_name" >
<activity
android:label="@string/app_name"
android:name=".InfoActivity" >
<intent-filter >
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name=".GPSWidgetProvider" >
<intent-filter >
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/gpswidgetinfo" />
</receiver>
<service android:name=".GPSWidgetProvider$GPSWidgetService" >
</service>
</application>
<uses-sdk
android:minSdkVersion="3"
android:targetSdkVersion="8" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
</manifest>
In Source Code Package create 3 Class AppLog,....
1)AppLog
package com.samples.gpswidget;
import android.util.Log;
public class AppLog {
private static final String APP_TAG = "GPSWidget";
public static int logString(String message){
return Log.i(APP_TAG, message);
}
}
2)GPSWidgetProvider
package com.samples.gpswidget;
import java.util.List;
import android.app.PendingIntent;
import android.app.Service;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.location.Address;
import android.location.Criteria;
import android.location.Geocoder;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.IBinder;
import android.widget.RemoteViews;
public class GPSWidgetProvider extends AppWidgetProvider { @Override public void onDeleted(Context context, int[] appWidgetIds) { super.onDeleted(context, appWidgetIds); } @Override public void onDisabled(Context context) { super.onDisabled(context); } @Override public void onEnabled(Context context) { super.onEnabled(context); } @Override public void onReceive(Context context, Intent intent) { super.onReceive(context, intent); } @Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { super.onUpdate(context, appWidgetManager, appWidgetIds);
final int N = appWidgetIds.length;
for (int i=0; i<N; i++) {
int appWidgetId = appWidgetIds[i];
Intent intent = new Intent(context, InfoActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.gpswidget);
views.setOnClickPendingIntent(R.id.txtInfo, pendingIntent);
appWidgetManager.updateAppWidget(appWidgetId, views);
}
context.startService(new Intent(context,GPSWidgetService.class)); }
public static class GPSWidgetService extends Service{ private LocationManager manager = null;
private LocationListener listener = new LocationListener() { @Override public void onStatusChanged(String provider, int status, Bundle extras) {} @Override public void onProviderEnabled(String provider) {} @Override public void onProviderDisabled(String provider) {}
@Override public void onLocationChanged(Location location) { AppLog.logString("Service.onLocationChanged()");
updateCoordinates(location.getLatitude(),location.getLongitude());
stopSelf(); } };
@Override public IBinder onBind(Intent intent) { return null; } @Override public void onCreate() { super.onCreate();
AppLog.logString("Service.onCreate()");
manager = (LocationManager)getSystemService(LOCATION_SERVICE); } @Override public void onStart(Intent intent, int startId) { super.onStart(intent, startId);
waitForGPSCoordinates(); }
@Override public void onDestroy() { stopListening();
AppLog.logString("Service.onDestroy()");
super.onDestroy(); } public int onStartCommand(Intent intent, int flags, int startId) { waitForGPSCoordinates();
AppLog.logString("Service.onStartCommand()");
return super.onStartCommand(intent, flags, startId); }
private void waitForGPSCoordinates() { startListening(); }
private void startListening(){ AppLog.logString("Service.startListening()");
final Criteria criteria = new Criteria(); criteria.setAccuracy(Criteria.ACCURACY_COARSE); criteria.setAltitudeRequired(false); criteria.setBearingRequired(false); criteria.setCostAllowed(true); criteria.setPowerRequirement(Criteria.POWER_LOW); final String bestProvider = manager.getBestProvider(criteria, true); if (bestProvider != null && bestProvider.length() > 0) { manager.requestLocationUpdates(bestProvider, 500, 10, listener); } else { final List<String> providers = manager.getProviders(true); for (final String provider : providers) { manager.requestLocationUpdates(provider, 500, 10, listener); } } }
private void stopListening(){ try { if (manager != null && listener != null) { manager.removeUpdates(listener); } manager = null; } catch (final Exception ex) { } }
private void updateCoordinates(double latitude, double longitude){ Geocoder coder = new Geocoder(this); List<Address> addresses = null; String info = "";
AppLog.logString("Service.updateCoordinates()"); AppLog.logString(info);
try {
addresses = coder.getFromLocation(latitude, longitude, 2);
if(null != addresses && addresses.size() > 0){
int addressCount = addresses.get(0).getMaxAddressLineIndex();
if(-1 != addressCount){
for(int index=0; index<=addressCount; ++index){
info += addresses.get(0).getAddressLine(index);
if(index < addressCount)
info += ", ";
}
}
else
{
info += addresses.get(0).getFeatureName() + ", " + addresses.get(0).getSubAdminArea() + ", " + addresses.get(0).getAdminArea();
}
}
AppLog.logString(addresses.get(0).toString()); } catch (Exception e) { e.printStackTrace(); }
coder = null; addresses = null;
if(info.length() <= 0){ info = "lat " + latitude + ", lon " + longitude; } else{ info += ("\n" + "(lat " + latitude + ", lon " + longitude + ")"); }
RemoteViews views = new RemoteViews(getPackageName(), R.layout.gpswidget);
views.setTextViewText(R.id.txtInfo, info);
ComponentName thisWidget = new ComponentName(this, GPSWidgetProvider.class);
AppWidgetManager manager = AppWidgetManager.getInstance(this);
manager.updateAppWidget(thisWidget, views); } }
}
import java.util.List;
import android.app.PendingIntent;
import android.app.Service;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.location.Address;
import android.location.Criteria;
import android.location.Geocoder;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.IBinder;
import android.widget.RemoteViews;
public class GPSWidgetProvider extends AppWidgetProvider { @Override public void onDeleted(Context context, int[] appWidgetIds) { super.onDeleted(context, appWidgetIds); } @Override public void onDisabled(Context context) { super.onDisabled(context); } @Override public void onEnabled(Context context) { super.onEnabled(context); } @Override public void onReceive(Context context, Intent intent) { super.onReceive(context, intent); } @Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { super.onUpdate(context, appWidgetManager, appWidgetIds);
final int N = appWidgetIds.length;
for (int i=0; i<N; i++) {
int appWidgetId = appWidgetIds[i];
Intent intent = new Intent(context, InfoActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.gpswidget);
views.setOnClickPendingIntent(R.id.txtInfo, pendingIntent);
appWidgetManager.updateAppWidget(appWidgetId, views);
}
context.startService(new Intent(context,GPSWidgetService.class)); }
public static class GPSWidgetService extends Service{ private LocationManager manager = null;
private LocationListener listener = new LocationListener() { @Override public void onStatusChanged(String provider, int status, Bundle extras) {} @Override public void onProviderEnabled(String provider) {} @Override public void onProviderDisabled(String provider) {}
@Override public void onLocationChanged(Location location) { AppLog.logString("Service.onLocationChanged()");
updateCoordinates(location.getLatitude(),location.getLongitude());
stopSelf(); } };
@Override public IBinder onBind(Intent intent) { return null; } @Override public void onCreate() { super.onCreate();
AppLog.logString("Service.onCreate()");
manager = (LocationManager)getSystemService(LOCATION_SERVICE); } @Override public void onStart(Intent intent, int startId) { super.onStart(intent, startId);
waitForGPSCoordinates(); }
@Override public void onDestroy() { stopListening();
AppLog.logString("Service.onDestroy()");
super.onDestroy(); } public int onStartCommand(Intent intent, int flags, int startId) { waitForGPSCoordinates();
AppLog.logString("Service.onStartCommand()");
return super.onStartCommand(intent, flags, startId); }
private void waitForGPSCoordinates() { startListening(); }
private void startListening(){ AppLog.logString("Service.startListening()");
final Criteria criteria = new Criteria(); criteria.setAccuracy(Criteria.ACCURACY_COARSE); criteria.setAltitudeRequired(false); criteria.setBearingRequired(false); criteria.setCostAllowed(true); criteria.setPowerRequirement(Criteria.POWER_LOW); final String bestProvider = manager.getBestProvider(criteria, true); if (bestProvider != null && bestProvider.length() > 0) { manager.requestLocationUpdates(bestProvider, 500, 10, listener); } else { final List<String> providers = manager.getProviders(true); for (final String provider : providers) { manager.requestLocationUpdates(provider, 500, 10, listener); } } }
private void stopListening(){ try { if (manager != null && listener != null) { manager.removeUpdates(listener); } manager = null; } catch (final Exception ex) { } }
private void updateCoordinates(double latitude, double longitude){ Geocoder coder = new Geocoder(this); List<Address> addresses = null; String info = "";
AppLog.logString("Service.updateCoordinates()"); AppLog.logString(info);
try {
addresses = coder.getFromLocation(latitude, longitude, 2);
if(null != addresses && addresses.size() > 0){
int addressCount = addresses.get(0).getMaxAddressLineIndex();
if(-1 != addressCount){
for(int index=0; index<=addressCount; ++index){
info += addresses.get(0).getAddressLine(index);
if(index < addressCount)
info += ", ";
}
}
else
{
info += addresses.get(0).getFeatureName() + ", " + addresses.get(0).getSubAdminArea() + ", " + addresses.get(0).getAdminArea();
}
}
AppLog.logString(addresses.get(0).toString()); } catch (Exception e) { e.printStackTrace(); }
coder = null; addresses = null;
if(info.length() <= 0){ info = "lat " + latitude + ", lon " + longitude; } else{ info += ("\n" + "(lat " + latitude + ", lon " + longitude + ")"); }
RemoteViews views = new RemoteViews(getPackageName(), R.layout.gpswidget);
views.setTextViewText(R.id.txtInfo, info);
ComponentName thisWidget = new ComponentName(this, GPSWidgetProvider.class);
AppWidgetManager manager = AppWidgetManager.getInstance(this);
manager.updateAppWidget(thisWidget, views); } }
}
3)
InfoActivity
package com.samples.gpswidget;
import android.app.Activity;
import android.os.Bundle;
public class InfoActivity extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
import android.app.Activity;
import android.os.Bundle;
public class InfoActivity extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
In
Layout folder create 2 xml
1)
gpswidget.xml
<?xml version="1.0"
encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent">
<LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="@drawable/back" android:padding="10dip">
<ImageView android:layout_width="wrap_content" android:layout_height="fill_parent" android:src="@drawable/widgeticon"/>
<TextView android:layout_width="fill_parent" android:layout_height="fill_parent" android:id="@+id/txtInfo" android:text="Waiting for GPS coordinates..." android:textColor="#FFFFFFFF" android:gravity="center_horizontal|center_vertical"/>
</LinearLayout>
</LinearLayout>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent">
<LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="@drawable/back" android:padding="10dip">
<ImageView android:layout_width="wrap_content" android:layout_height="fill_parent" android:src="@drawable/widgeticon"/>
<TextView android:layout_width="fill_parent" android:layout_height="fill_parent" android:id="@+id/txtInfo" android:text="Waiting for GPS coordinates..." android:textColor="#FFFFFFFF" android:gravity="center_horizontal|center_vertical"/>
</LinearLayout>
</LinearLayout>
2)
main.xml
<?xml version="1.0"
encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="10dip">
<ImageView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:src="@drawable/widgeticon"
android:scaleType="fitCenter"/> <TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:text="@string/app_name"
android:textSize="20dip"
android:textStyle="bold"
android:padding="10dip"/>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:text="@string/app_info"/>
</LinearLayout>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="10dip">
<ImageView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:src="@drawable/widgeticon"
android:scaleType="fitCenter"/> <TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:text="@string/app_name"
android:textSize="20dip"
android:textStyle="bold"
android:padding="10dip"/>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:text="@string/app_info"/>
</LinearLayout>
In
xml folder create gpswidgetinfo.xml and write down the following
code...
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="294dp"
android:minHeight="72dp"
android:updatePeriodMillis="900000"
android:initialLayout="@layout/gpswidget">
</appwidget-provider>
android:minWidth="294dp"
android:minHeight="72dp"
android:updatePeriodMillis="900000"
android:initialLayout="@layout/gpswidget">
</appwidget-provider>
In
string.xml file write down following code
<?xml version="1.0"
encoding="utf-8" standalone="no"?>
<resources>
<string name="app_name">GPS Widget</string>
<string name="app_info">GPS Widget is a sample application to demonstrate the use of Android AppWidget.\n\nThe widget shows the GPS coordinates of the device\'s position. The widget refreshes the position in 15 minutes interval</string>
</resources>
<resources>
<string name="app_name">GPS Widget</string>
<string name="app_info">GPS Widget is a sample application to demonstrate the use of Android AppWidget.\n\nThe widget shows the GPS coordinates of the device\'s position. The widget refreshes the position in 15 minutes interval</string>
</resources>
Run
the above example...........
No comments:
Post a Comment