App Widget / Lockscreen / Text Clock

Text Clock – Part 6

In the previous article we fixed some subtle issues with the appearance of our App Widget. Next we’re going to look to extend out App Widget to include some features specific to newer versions of Android while maintaining backward compatibility.

The first thing that we’ll look at is adding our widget to the lock screen. The ability to add widgets to the lock screen was introduced in Android 4.2 and is actually really easy to add. All it requires is a couple of lines added to res/xml/appwidget-info.xml:




Both of these attributes are new to 4.2, but will be completely ignored by older versions, so we maintain our backwards compatibility without having to do anything.

The widgetCategory attribute allows us to specify which kind(s) of widget we’re providing. In our case we ware offering a standard home_screen widget, but also a keyguard widget which will appear on the lock screen. The default value on 4.2 devices is home_screen only, hence the behaviour that we had without this attribute.

The initialKeyguardLayout attribute allows us to specify the layout that we want to use for the lock screen. Initially, we’ll use the same layout as the home screen widget.

If we run this, we can now add a lock screen widget by swiping left on the lock screen, pressing the “+” button, and selecting Text Clock from the list of available widgets:

select-lockscreen

When we install this our lock screen looks like this:

lockscreen-initial

This is OK, but the time is a little lost in the frame, so we should consider making it larger. Actually, we don’t need to separate it from other components as we do on the home screen so we can actually remove the background altogether. We can supply a separate layout in res/layout/keyguard.xml:





    

    

    

This also requires some new styles to be added:




    

    

    

    

We also want to use Roboto Light when it is available on the device, so we also need to change res/values-v16/styles.xml:




    

    

We also need to change res/xml/appwidget-info.xml to use this new layout initially:





While this will set the initial layout, we’ll have a problem when the widget updates because of the following line in the updateTime() method in our TextClockService class:

RemoteViews v = new RemoteViews( getPackageName(), R.layout.appwidget );

This will apply the home screen widget layout every time the widget is updated. Fortunately, we can check the type of widget during the update, and use the appropriate layout:

private static final int WIDGET_CATEGORY_KEYGUARD = 2;

private void updateTime( Calendar date )
{
    Log.d( TAG, "Update: " + dateFormat.format( date.getTime() ) );
    AppWidgetManager manager = AppWidgetManager.getInstance( this );
    ComponentName name = new ComponentName( this, TextClockAppWidget.class );
    int[] appIds = manager.getAppWidgetIds( name );
    String[] words = TimeToWords.timeToWords( date );
    for ( int id : appIds )
    {
        Bundle options = manager.getAppWidgetOptions( id );
        int layoutId = R.layout.appwidget;
        if(options != null)
        {
            int type = options.getInt( "appWidgetCategory", 1 );
            if(type == WIDGET_CATEGORY_KEYGUARD)
            {
                layoutId = R.layout.keyguard;
            }
        }
        RemoteViews v = new RemoteViews( getPackageName(), 
            layoutId);
        updateTime( words, v );
        manager.updateAppWidget( id, v );
    }

}

For each widget instance, we determine the type from an AppWidgetOptions Bundle that we obtain from the AppWidgetManager. We default to type 1 (which is a home screen widget). While we could improve the readability of our code by using the constant AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD instead of the magic number 2 for our WIDGET_CATEGORY_KEYGUARD constant, this would actually break backwards compatibility because the Android constant was introduced in API 17, so will cause an error when running on earlier versions.

When we now run this we can see our new layout on the lock screen:

lockscreen-correct

We now have a lockscreen widget available on 4.2 and later devices. This version of the app can now be released on Google Play as version 1.1.0.

In the next article we’ll look at extending the app further with another new feature in Android 4.2.

The source code for this article can be found here, and TextClock is available from Google Play.

© 2013 – 2014, Mark Allison. All rights reserved.

Copyright © 2013 Styling Android. All Rights Reserved.
Information about how to reuse or republish this work may be available at http://blog.stylingandroid.com/license-information.

2 Comments

  1. Hi Mark,

    Did you try to use AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD and got an error on a device with Android < API 17?

    Since AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD is a constant (static final int), it should be inlined at compile time and thus not cause an error on older devices… The same way you can use android.os.Build.VERSION_CODES.JELLY_BEAN_MR1 when checking versions on a gingerbread device.

    Thanks for the guides, always interesting.
    Deluxe

Leave a Reply

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.