Przygotujemy aplikacj�-widget, kt�rego jedyn� funkcj� b�dzie pokazywanie zegara.

1. Z menu File, New, Other... tworzymy projekt typu Android Application Project (jak zwykle).
  a. API 4 (Android 1.6)
  b. Nazwa: ZegarekWidget
  c. Przestrze� nazw: pl.umk.fizyka.zegarekwidget

  d. W kolejnym kroku kreatora odznaczamy "Create Activity" 
     - aplikacja nie b�dzie mia�a aktywno�ci.

2. Po uwtorzeniu projektu, musimy do niego doda� klas�: menu File, New, Class
  a. Pakiet: pl.umk.fizyka.zegarekwidget
  b. Nazwa klasy: Main
  c. Dziedziczy po (pole Superclass): android.appwidget.AppWidgetProvider
  e. Klikamy Finish.

Uzyskamy:

package pl.umk.fizyka.zegarekwidget;

import android.appwidget.AppWidgetProvider;

public class Main extends AppWidgetProvider {

}

3. Klas� ZegarekWidget uzupe�niamy o metod� onUpdate, z 

package pl.umk.fizyka.zegarekwidget;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ComponentName;
import android.content.Context;
import android.widget.RemoteViews;

//wygodniejszy od BroadcastReceiver w przypadku widgetow
public class Odbiorca extends AppWidgetProvider 
{
    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)
    {
	ComponentName tenWidget = new ComponentName(context, Odbiorca.class);
	int[] wszystkieWidgety = appWidgetManager.getAppWidgetIds(tenWidget);
	for (int widget : wszystkieWidgety) 
	{
		DateFormat format = SimpleDateFormat.getTimeInstance(SimpleDateFormat.MEDIUM, Locale.getDefault()); //import java.text.DateFormat;        

		RemoteViews rv = new RemoteViews(context.getPackageName(), R.layout.main);        
		rv.setTextViewText(R.id.textView1, format.format(new Date()));
               
		appWidgetManager.updateAppWidget(widget, rv);
	}
    }
}

Poza onUpdate s� metody onEnabled, onDisable i onDeleted.

4. Tworzymy plik XML opisuj�cy widok = interface okna:
  a. Z menu File, New, Other... -> Android XML Layout File
  b. W kreatorze podajmy nazw� pliku main.xml
  c. zaznaczmy root element: LinearLayout
  d. Finish.

  e. W pliku XML ustalmy konktetn� wysoko�� i szeroko�� okna i wstawmy zegar analogowy
     oraz TextView, na kt�rym b�dziemy dodatkowo wy�wietla� czas:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/linearLayout1"
    android:layout_width="180dp"
    android:layout_height="220dp"
    android:orientation="vertical"     
    android:background="@drawable/background"   
    >
    <!-- android:background="#99AAAAAA" -->

    <AnalogClock
        android:id="@+id/analogClock1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="top|center_horizontal"
        android:scrollY="-10dp"
        />


    <TextView
        android:id="@+id/textView1"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_gravity="top|center_horizontal"
        android:layout_margin="10dp"
        android:gravity="center_horizontal|center_vertical"
        android:text="@string/zegar_init"
        android:textColor="@android:color/black"
        android:textSize="12pt" />

</LinearLayout>

  f. U�ywany �a�cuch definiujemy w res/values/strings.xml

<resources>
    <string name="app_name">ZegarekWidget</string>
    <string name="zegar_init">--:--:--</string>
</resources>

Widget nie mo�e u�ywa� ka�dego widoku (mo�liwe to FrameLayout, LinearLayout i RelativeLayout).
Dopuszczalne kontrolki to AnalogClock, Button, Chromometer, ImageButton, ImageView, ProgressBar i TextView. 
Od Androida 3.0 widok�w i kontrolek jest wi�cej.

Obrazek background.png pobieramy z 
http://developer.android.com/guide/practices/ui_guidelines/widget_design.html
lub bezpo�rednio z 
http://kasperholtze.com/wp-content/uploads/2009/11/background.png
i zapisujemy do res/drawable-hdpi.

5. Definiujemy plik XML opisuj�cego dostawc�:
  a. W katalogu res tworzymy podkatalog xml,
  b. w nim tworzymy plik dostawca.xml:

<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:initialLayout="@layout/main"
    android:minWidth="100dp"
    android:minHeight="200dp"
    android:updatePeriodMillis="1000"
    />

Aktualizacja ma nast�powa� co sekund� (1000 ms). Co taki czas ma by� wywo�ywana 
metoda onUpdate. To o wiele za cz�sto. szybko padnie bateria, bo telefon nie bedzie
zasypial, ale my od razu bedziemy widzieli efekt dzialania widgetu (w teorii).
Tak naprawd� system nie gwarantuje od�wie�ania widgetu co taki czas. Mo�e to by� znacznie
rzadziej!!! W szczeg�lno�ci minimalny okres od�wie�ania to 30 min = 1800000 ms.

Inna metoda aktualizacji widgetu korzysta z AlarmManager (zob. poni�ej i
http://www.vogella.com/articles/AndroidWidgets/article.html).

6. Modyfikujemy plik manifestu - rejestrujemy widget:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="pl.umk.fizyka.zegarekwidget"
    android:versionCode="1"
    android:versionName="1.0">

    <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="15" />

    <application android:label="@string/app_name"
        android:icon="@drawable/ic_launcher"
        android:theme="@style/AppTheme">
        
	<receiver 
		    android:name="Odbiorca" 
		    android:label="Zegarek">
             <intent-filter>
                 <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
             </intent-filter>
             <meta-data
                android:name="android.appwidget.provider"
                android:resource="@xml/dostawca" />
         </receiver>
        
    </application>

</manifest>

Ten wpis oznacza, �e rejestrujemy klas� Odbiorca jako odbiorce komunikat APPWIDGET_UPDATE
i ustala metadane dla widgetu.

7. Uruchom widget w normalny spos�b. Aplikacja si� nie uruchomi (nie ma aktywno�ci), ale
zostanie umieszczona w emulatorze lub urz�dzeniu. W�wczas mo�emy j� umie�cic na ekranie.
B�dzie dost�pna w�r�d Widget�w pod nazw� Zegarek (label z manifestu).

W zale�no�ci od urz�dzenia aplikacja mo�e si� nie od�wie�a� (dotyczy to tekstu, bo zegarek
ma chyba w�asny w�tek). Na emulatorze onUpdate w og�le nie jest uruchamiana.

Komentarz z http://kasperholtze.com/android/how-to-make-a-simple-android-widget/:
Please note that this is a very bad practice to set updatePeriodMillis to a high frequency 
(or low value) like this. At every updatePeriodMillis the phone will be waken up to deliver 
the call to the receiver�s onUpdate which will effectively prevent your phone from sleeping 
at all. What you shall do is to implement the other widget events as well and properly catch 
the moment when your first widget is created (and the last is removed) and deliver your 
updates using a non-wakeup type AlarmManager periodic callback or an AsyncTask, from a 
separate service. Beside this there is an other minor problem, as updatePeriodMillis updates 
will not be synced to a whole second boundary, resulting in seconds displayed being 
potentially skewed by 0-999 milliseconds.

----------

Klikni�cie widgetu - od�wie�enie.

8. Nale�y uzupe�ni� metod� onUpdate:

public class Odbiorca extends AppWidgetProvider 
{
    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)
    {
	for (int widgetId : appWidgetIds) 
	{
		DateFormat format = SimpleDateFormat.getTimeInstance(SimpleDateFormat.MEDIUM, Locale.getDefault()); //import java.text.DateFormat;        

		RemoteViews rv = new RemoteViews(context.getPackageName(), R.layout.main);        
		rv.setTextViewText(R.id.textView1, format.format(new Date()));

		//klikniecie (czy to najlepsze miejsce?)
		Intent intent = new Intent(context, Odbiorca.class);
		intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
	        intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
		PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
		rv.setOnClickPendingIntent(R.id.linearLayout1, pendingIntent);
		//
			
		appWidgetManager.updateAppWidget(widgetId, rv);
	}
    }
}

------------------

Od�wie�anie widgetu za pomoc� us�ugi (AlarmManager)

9. Do katalogu pl.umk.fizyka.zegarekwidget dodaj klase:
   - nazwa: AktualizujWidgetService
   - klasa bazowa: android.app.Service
   - napisz abstrakcyjne metody (jest tylko onBind)

10. W tej klasie definiujemy metod� onStart:

package pl.umk.fizyka.zegarekwidget;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.Timer;
import java.util.TimerTask;

import android.app.PendingIntent;
import android.app.Service;
import android.appwidget.AppWidgetManager;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
import android.widget.RemoteViews;

public class AktualizujWidgetService extends Service 
{
	Timer timer;
	
	@Override
	public void onStart(final Intent intent, int startId) 
	{
		final Context context = this.getApplicationContext();
		
		timer=new Timer();		
		timer.scheduleAtFixedRate(
				new TimerTask()
				{
					@Override
					public void run() 
					{
						//znaczna czesc tego kodu powinna byc wylaczona
						//i uwspolniona z metoda Odbiorca.onUpdate!!!
						
						AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);

					    int[] allWidgetIds = intent.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS);
					    //ComponentName tenWidget = new ComponentName(getApplicationContext(),Odbiorca.class);
					    //int[] allWidgetIds2 = appWidgetManager.getAppWidgetIds(tenWidget);

					    for (int widgetId : allWidgetIds) 
					    {	    	
					    	DateFormat format = SimpleDateFormat.getTimeInstance(SimpleDateFormat.MEDIUM, Locale.getDefault()); //import java.text.DateFormat;        

							RemoteViews rv = new RemoteViews(context.getPackageName(), R.layout.main);        
							rv.setTextViewText(R.id.textView1, format.format(new Date()));

							//klikniecie
							Intent clickIntent = new Intent(context,Odbiorca.class);
							clickIntent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
							clickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS,allWidgetIds);
							PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, clickIntent,PendingIntent.FLAG_UPDATE_CURRENT);
							
							rv.setOnClickPendingIntent(R.id.linearLayout1, pendingIntent);

							appWidgetManager.updateAppWidget(widgetId, rv);
					    }
					};
				}, 
				0, 1000); //co 1000 ms		
		
	    	    stopSelf();

	    super.onStart(intent, startId);
	  }

	
	@Override
	public IBinder onBind(Intent arg0) {
		// TODO Auto-generated method stub
		return null;
	}

}


11. Deklarujemy us�ug� w pliku manifestu:

<application android:label="@string/app_name"
        android:icon="@drawable/ic_launcher"
        android:theme="@style/AppTheme">
        
    <service android:name="AktualizujWidgetService" />

    ...

12. I wreszcie zmieniamy metod� onUpdate widgetu (plik Odbiorca.java) tak, �eby
    ogranicza�a si� do uruchamiania us�ugi:

public class Odbiorca extends AppWidgetProvider 
{
    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)
    {
		ComponentName thisWidget = new ComponentName(context,Odbiorca.class);
		int[] allWidgetIds = appWidgetManager.getAppWidgetIds(thisWidget);
		
		Intent intent = new Intent(context,AktualizujWidgetService.class);
		intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, allWidgetIds);
		context.startService(intent);
    }
}

Komentarz:
The AlarmManager allows you to be more resource efficient and to have a higher 
frequency of updates. To use this approach you define a service and schedule 
this service via the AlarmManager regularly. This service updates the widget.