Creating a Clock Widget in Android with Custom Font.

By | September 10, 2013

Hi all

if you have been a regular visitor of this website you have seen that I have shown you how to create a simple widget, adding controls to it, adding event handlers in the views etc…
Do check this website for more tutorials on widgets.

You can find other tutorials by following this LINK.

This tutorial is also an important one on widgets.
People always find it difficult to customize their widgets with Custom Fonts. AS of now you cannot directly set the font in a TextView in a Widget. For that you have to go indirectly.

In this example I will show you how to create a Clock widget with Custom Font.

Custom Font in Android Widget

Custom Font in Android Widget

So we will start.

At first we will create the XML files.

acitvity_main.xml – This is our main layout which contains a button that creates the widget.

<relativelayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:background="@android:color/white" >

    <button android:id="@+id/create_widget"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:text="Create Widget"></button>

</relativelayout>

Now the layout for the Widget and the WidgetProvider.

my_widget_provider.xml

< ?xml version="1.0" encoding="utf-8"?>
<appwidget -provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:minWidth="250dip"
    android:minHeight="70dip"
    android:updatePeriodMillis="300000"
    android:configure="com.coderzheaven.customfontinwidget.SettingsPage" 
    android:initialLayout="@layout/widget_main"></appwidget> 

widget_main.xml

< ?xml version="1.0" encoding="utf-8"?>
<framelayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/widget_root"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:baselineAligned="false"
    android:orientation="vertical" >

    <imageview android:id="@+id/imageView_bg"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:scaleType="fitXY"
        android:contentDescription="@drawable/ic_launcher"></imageview>
    
    <imageview android:id="@+id/imageView_txt"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:scaleType="fitXY"
        android:contentDescription="@drawable/ic_launcher"></imageview>

</framelayout>

OK Now the AndroidManifest File.

Do look at my old posts for more explanation about the Mainfest files when you are using the widgets.

< ?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.coderzheaven.customfontinwidget"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses -sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="17"></uses>

    <application android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity android:name="com.coderzheaven.customfontinwidget.SettingsPage"
            android:configChanges="keyboardHidden|orientation"
            android:label="@string/app_name"
            android:theme="@android:style/Theme.Translucent" >
            <intent -filter>
                <action android:name="android.appwidget.action.APPWIDGET_CONFIGURE"></action>
            </intent>
        </activity>

        <receiver android:name=".RepeatingAlarm"
            android:process=":remote"></receiver>

        <!-- Broadcast Receiver that will process AppWidget Updates -->
        <receiver android:name="com.coderzheaven.customfontinwidget.MyAppWidgetProvider"
            android:label="@string/app_name" >
            <intent -filter>
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE"></action>
            </intent>

            <meta -data
                android:name="android.appwidget.provider"
                android:resource="@layout/my_widget_provider" />
        </receiver>
    </application>

</manifest>

Now create an XML file inside the drawable folder and name it theme0.xml and copy this code into it.

< ?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item><shape>
            <gradient android:angle="90" android:centerColor="#7700FF00" android:endColor="#3300FF00" android:startColor="#3300FF00"></gradient>

            <stroke android:width="1dp" android:color="#FF00FF00"></stroke>

            <corners android:radius="10dp"></corners>

            <padding android:bottom="10dp" android:left="10dp" android:right="10dp" android:top="10dp"></padding>
        </shape></item>

</selector>

Now our XML files are over.
Now we look at the java code.

we have 4 java classes
1. MyAppWidgetProvider.java
2. MyTimer.java
3. RepeatingAlarm.java
4. SettingsPage.java

SettingsPage.java

package com.coderzheaven.customfontinwidget;

import android.app.Activity;
import android.appwidget.AppWidgetManager;
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.RemoteViews;

public class SettingsPage extends Activity implements OnClickListener {

	int thisWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		getIdOfCurrentWidget(savedInstanceState);

		((Button) findViewById(R.id.create_widget)).setOnClickListener(this);

	}

	/**
	 * Get the Id of Current Widget from the intent from the Widget or if it is
	 * the first time
	 **/
	void getIdOfCurrentWidget(Bundle savedInstanceState) {
		setResult(RESULT_CANCELED);
		Bundle extras = getIntent().getExtras();
		if (extras != null) {
			thisWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID,
					AppWidgetManager.INVALID_APPWIDGET_ID);
		}
	}

	/**
	 * Update the widget on first run
	 * 
	 * @param widgetId
	 *            - the ID of current widget to be created
	 */
	public void updateWidget(int widgetId) {
		RemoteViews remoteViews = new RemoteViews(getPackageName(),
				R.layout.widget_main);

		MyTimer myTimer = new MyTimer(this);
		Bitmap bmp = myTimer.buildUpdate(myTimer.getTodaysTime());
		remoteViews.setImageViewBitmap(R.id.imageView_txt, bmp);

		// set a background
		remoteViews.setImageViewResource(R.id.imageView_bg, R.drawable.theme0);

		AppWidgetManager appWidgetManager = AppWidgetManager
				.getInstance(SettingsPage.this);
		// update the widget
		appWidgetManager.updateAppWidget(widgetId, remoteViews);
	}

	public void setResultDataToWidget(int result, int widgetId) {
		System.out.println("WID ID = " + widgetId);

		// update the widget on creation
		updateWidget(widgetId);

		// set the result back to widget
		Intent resultValue = new Intent();
		// pass the widget ID along with the intent so that we will get it on
		// the cofiguration activity
		resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetId);
		setResult(result, resultValue);
		finish();
	}

	@Override
	public void onClick(View v) {
		if (v.getId() == R.id.create_widget)
			setResultDataToWidget(Activity.RESULT_OK, thisWidgetId);
	}

}

MyAppWidgetProvider.java

package com.coderzheaven.customfontinwidget;

import android.app.AlarmManager;
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.Context;
import android.content.Intent;
import android.os.SystemClock;

public class MyAppWidgetProvider extends AppWidgetProvider {

	@Override
	public void onUpdate(Context context, AppWidgetManager appWidgetManager,
			int[] appWidgetIds) {

		Intent intent = new Intent(context, RepeatingAlarm.class);
		PendingIntent sender = PendingIntent
				.getBroadcast(context, 0, intent, 0);

		// We want the alarm to go off 1 seconds from now.
		long firstTime = SystemClock.elapsedRealtime();
		firstTime += 1000;

		// Schedule the alarm!
		AlarmManager am = (AlarmManager) context
				.getSystemService(Context.ALARM_SERVICE);
		am.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, firstTime, 1000,
				sender);

	}
}

MyTimer.java

package com.coderzheaven.customfontinwidget;

import java.util.Calendar;

import android.appwidget.AppWidgetManager;
import android.content.ComponentName;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Align;
import android.graphics.Typeface;
import android.widget.RemoteViews;

public class MyTimer {
	RemoteViews remoteViews;
	Context context;
	AppWidgetManager appWidgetManager;
	ComponentName thisWidget;

	public MyTimer(Context context) {

		appWidgetManager = AppWidgetManager.getInstance(context);

		this.context = context;

		remoteViews = new RemoteViews(context.getPackageName(),
				R.layout.widget_main);

		thisWidget = new ComponentName(context, MyAppWidgetProvider.class);

	}

	public synchronized void runAndUpdateTheWidget() {

		int[] allWidgetIds = appWidgetManager.getAppWidgetIds(thisWidget);

		for (final int appWidgetId : allWidgetIds) {

			System.out.println("UPDATING......" + getTodaysTime() + " ID = "
					+ appWidgetId);

			remoteViews.setImageViewBitmap(R.id.imageView_txt,
					buildUpdate(getTodaysTime()));
			appWidgetManager.updateAppWidget(appWidgetId, remoteViews);

		}

	}

	public Bitmap buildUpdate(String time) {
		int bmpWidth = 250;
		int bmpHeight = 100;
		Bitmap myBitmap = Bitmap.createBitmap(bmpWidth, bmpHeight,
				Bitmap.Config.ARGB_8888);
		Canvas myCanvas = new Canvas(myBitmap);
		Paint paint = new Paint();
		Typeface clock = Typeface.createFromAsset(context.getAssets(),
				"digital-7.ttf");
		paint.setAntiAlias(true);
		paint.setSubpixelText(true);
		paint.setTypeface(clock);
		paint.setStyle(Paint.Style.FILL);
		paint.setColor(Color.RED);
		paint.setTextSize(70); 
		paint.setTextAlign(Align.CENTER);
		myCanvas.drawText(time, bmpWidth / 2, bmpHeight / 2 + (bmpHeight / 4),
				paint);
		return myBitmap;
	}

	public String getTodaysTime() {
		final Calendar c = Calendar.getInstance();
		int hour = Integer
				.parseInt(convertToNormal(c.get(Calendar.HOUR_OF_DAY)));
		int minute = c.get(Calendar.MINUTE);
		int seconds = c.get(Calendar.SECOND);
		return new StringBuilder().append(pad(hour)).append(":")
				.append(pad(minute)).append(":").append(pad(seconds))
				.toString();
	}

	private static String pad(int c) {
		if (c >= 10)
			return String.valueOf(c);
		else
			return "0" + String.valueOf(c);
	}

	public String convertToNormal(int hour) {
		if (hour > 12)
			hour = hour - 12;

		return pad(hour);
	}
}

And the Broadcast receiver
RepeatingAlarm.java

package com.coderzheaven.customfontinwidget;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;

public class RepeatingAlarm extends BroadcastReceiver {
	@Override
	public void onReceive(Context context, Intent intent) {
		MyTimer myTimer = new MyTimer(context);
		myTimer.runAndUpdateTheWidget();
	}
}

Your Clock widget with custom Font is complete, Go on and run it and Check in the widgets area.

You can download the complete source code from this link.

Please leave your valuable comments on this post. We have put a lot of effort on creating this post for you.

8 thoughts on “Creating a Clock Widget in Android with Custom Font.

  1. Jess

    Hi:
    Great Job, nice tutorials!
    The link to the source code at the end of this page doesn’t work. Could you please correct it?

    Reply
  2. Pingback: Creating a Clock Widget in Android with Custom Font. - appgong

  3. David

    I shouldn’t need several pages of code to change a font. This is fucking insane

    Reply
    1. James Post author

      Its the complete Widget implementation,not just changing the font.

      Reply
    1. James Post author

      I have updated the link…please download again…
      Thanks fro visiting.

      Reply

Leave a Reply

Your email address will not be published. Required fields are marked *