Thursday, October 31, 2013

A Mission to Android - Creating a Widget

So my mission continues and it's time to get my hands dirty and start coding the widget. I think everybody knows that a widget is a small program which can be placed on the home or the lock screen. A widget can show information or provide functions to interact with the system. To summarize a widget is just another means to interact with an app running in the background.

Overview

In today's post I will create the base class for my widget. During this post I hope to give you some inside on how a widget provider works and how it interacts with the android system. You will see how a view is prepared for display in a widget and on a side note you will get an overview into the log system of android.

Coding the AppWidgetProvider

Widget Lifecycle

  1. Widget is added for the first time to an AppWidgetHost like the home or lock screen. This is the time to allocate resources and start services needed for the operation of the widget.
  2. Widget needs to be updated or a new instance of the widget is added to an AppWidgetHost. This method is not called on the first addition of a widget instance. So make sure that any preparation for layouting is also done in the onEnabled() method.
  3. Widget is removed from an AppWidgetHost.
  4. Last instance of a widget is removed from an AppWidgetHost and the AppWidgetProvider is no longer needed. This is the right time to cleanup resources and stop any sticky services.
  5. Called when the widget is displayed or when it is resized. This is where you should calculate sizes and adjust views accordingly. Only available in API level 16 and higher.

All widgets are specialized broadcast receivers which execute stuff depending on special intents they receive from Android. Some of these intents are ACTION_APPWIDGET_UPDATE, ACTION_APPWIDGET_DELETED, ACTION_APPWIDGET_ENABLED, ACTION_APPWIDGET_DISABLED and more. You can get an overview taking a look at the AppWidgetManager documentation.

To ease creation and handling of widgets android provides a specialized class AppWidgetProvider which extends BroadcastReceiver and provides methods to hook into the life cycle of a widget. All you have to do is extend it and implement the methods.
If you take a look at the sources for AppWidgetProvider you will see that all life cycle methods are called from within the onReceive method by handling intents send from the OS.

So here is the code for my widget

/*
 * (c) Copyright 2013 Stefan Langer
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package de.element34.e34clock;

import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.Context;
import android.util.Log;
import android.widget.RemoteViews;

public class E34ClockWidget extends AppWidgetProvider {
    private static final String TAG = "e34clock.E34ClockWidget";

    @Override
    public void onEnabled(Context context) {
        super.onEnabled(context);
        Log.d(TAG, "E34ClockWidget created!");
    }

    @Override
    public void onDisabled(Context context) {
        super.onDisabled(context);
        Log.d(TAG, "E34ClockWidget completely removed!");
    }

    @Override
    public void onDeleted(Context context, int[] appWidgetIds) {
        super.onDeleted(context, appWidgetIds);
        Log.d(TAG,"Deleting an instance of widget!");
    }

    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
        Log.d(TAG, "Updating widgets!");
        RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.clock_layout);
        appWidgetManager.updateAppWidget(appWidgetIds, views);
        super.onUpdate(context, appWidgetManager, appWidgetIds);
    }
}

The code is pretty straight forward and doesn't do anything seriouse yet. First thing to notice is that we extend AppWidgetProvider and as discussed earlier this gives us a couple of methods to interact with the lifecycle of the widgets. Important to note here is that this class will not handle a specific instance of your widget but all instances. The idea is that all widgets will present the same state of the application so there is no need for individual control of a single widget.

When the first instance of your widget is created the OS calls the onEnabled method giving you the chance to setup any resources you may need to interact with the backend process. For each new instance being created or whenever your widget needs to be updated do to events in the OS the onUpdate method is called. When an instance is deleted from the home- or lockscreen the onDeleted method is called. When the last instance is deleted and the OS no longer needs to interact with your widget the onDisabled method is called giving you a chance to cleanup and release all resources.

For now I simply log a message using the log system from android. This is exposed through the static object Log.

The log system supports 5 log levels. The list shows the log levels in descending order from most verbose to least verbose. When the log level is set all log levels that are lower in the list are also included, e.g. when the level is INFO the levels WARN and ERROR are also printed.

  • VERBOSE - exposed through the v method
  • DEBUG - exposed through the d method
  • INFO - exposed via the i method
  • WARN - exposed via the w method
  • ERROR - exposed via the e method
Each log method is prefixed with a tag. This tag can later be used to filter the log and see only messages relevant to your code. The tag is a simple string. It does not imply any hierarchy in the log system as does the jdk or log4j logging system. The string is simply prefixed to the log message to ease grepping of log output. A good convention is to save the prefix in a static final variable and reuse this throughout the class. I use TAG throughout my code as the name for this variable.

For the widget to be able to display something I have to setup the initial view. The place to do this is in the onUpdate method as this gets called whenever the screen needs to be updated. Be aware that the onUpdate method is not called when the widget is first enabled. If you need to do view customization which divert from your layout you have to also call your update code from onEnabled.

    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
        Log.d(TAG, "Updating widgets!");
        RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.clock_layout);
        appWidgetManager.updateAppWidget(appWidgetIds, views);
        super.onUpdate(context, appWidgetManager, appWidgetIds);
    }

RemoteViews

A class that describes a view hierarchy that can be displayed in another process. The hierarchy is inflated from a layout resource file, and this class provides some basic operations for modifying the content of the inflated hierarchy.

Unlike in an Activity I do not have direct access to the View instead I have to create an instance of RemoteViews. This RemoteViews reads the layout xml and inflates it into a view hierarchy. I then use the AppWidgetManager to dispatch the views to all instances of the widget. You can steer which widgets are updated by specifying only the ids of the widget to update. Each id represents one instance of the widget. In my code I always treat all instances the same way and update every single one.

Resources

You can find further and more detailed information about developing widgets at App Widgets | Android Developers. For widget design take a look at Widgets | Android Developers and for design guide lines got to App Widget Design Guidelines

Outlook

In the next post I will post about the layout for the widget and I will talk about how android handles resources like images, strings and dimensions.

As always if you have any feedback please leave a comment. If you found errors or stuff I should do differently please tell me as this is also an endeavor for me to learn android.

Yours truely

Stefan Langer

Creative Commons License

Wednesday, October 30, 2013

A Mission to Android - The Android Project

Over the past days I have started my mission to android. The goal creating a functional clock home screen widget. Last week I posted about my design and now that I have a plan it is time to get the idea realized in code. So the first thing I had to find out is how to create a widget in android.

I went through all sorts of different sources on the internet. Among others I read the guides on android developer, went through diverse tutorials and caught up on stuff that has happened since Ginger Bread , - my last try at developing for android-. As hours turned in to days I realized that I have lots of work ahead of me and so I decided to break up the steps and present them in steps that are hopefully easy to digest.

Overview

In this post I will go over how I setup the android project using Android Studio. I decided to use Android Studio even though it is still in an early release phase but since it is the future why not go for it. It seems to be stable enough for my purposes. So I downloaded the application and installed it on my development machines. This also downloads and installs a copy of the Android SDK. Once that was done I was ready to fire up Android Studio and create my project.

Creating an Android Project

Before I can actually create a widget I have to create a android project of which the widget is part of. The easiest way to get started is by simply using the "New Project" feature in Android Studio.

Now I have to choose the name for my project and the included module as well as the base package for the java code. I named my project and module E34Clock. I also have to choose the target and minimal Android SDK. For my project I decided to go with Ice Cream Sandwich as the minimal supported sdk. This corresponds to sdk level 14. The target of my application is level 18 which corresponds to Jelly Bean 4.3.3. Be careful which versions you choose because depending on this your app will have to run on different android versions and you might have to support multiple API calls due to version changes. This also impacts for which devices your app will be displayed in the app store later on.

Since I want to create widget I created a project that contained a single blank activity which I will later use for customizing of the widget.

In the last step I have to name the activity and the corresponding layouts.

Pressing "Finish" will create the typical android project structure and setup a gradle build system to build your app without needing an IDE.

The src/main/java/ folder holds all relevant classes for your app. The src/main/res/ folder holds all assets, images, xml files your application needs. We will get back to this when we start creating the application.

The most important file is the AndroidManifest.xml file. This file describes the join points of your app with the Android OS and the user.
Among other things you define your activities, services your receivers as well as the permissions your application needs. This file also tells Android which SDK version you support and which version your code is. I will come back to this file many times during the course of this journey.

<!--
  ~ (c) Copyright 2013 Stefan Langer
  ~
  ~    Licensed under the Apache License, Version 2.0 (the "License");
  ~    you may not use this file except in compliance with the License.
  ~    You may obtain a copy of the License at
  ~
  ~        http://www.apache.org/licenses/LICENSE-2.0
  ~
  ~    Unless required by applicable law or agreed to in writing, software
  ~    distributed under the License is distributed on an "AS IS" BASIS,
  ~    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  ~    See the License for the specific language governing permissions and
  ~    limitations under the License.
  -->
<manifest android:versioncode="1" 
  android:versionname="1.0" 
  package="de.element34.e34clock" 
  xmlns:android="http://schemas.android.com/apk/res/android">

    <uses-sdk android:minsdkversion="14" 
      android:targetsdkversion="18"/>

    <application android:allowbackup="true" 
      android:icon="@drawable/ic_launcher" 
      android:label="@string/app_name" 
      android:theme="@style/AppTheme">
        <activity android:label="E34ClockSettings" 
          android:name=".ClockSettingsActivity">
          <intent-filter>
              <action android:name="android.intent.action.MAIN" />
              <category android:name="android.intent.category.LAUNCHER"/>
          </intent-filter>
        </activity>
    </application>
</manifest>

Since I created the project with a blank activity this activity is defined here.

    <application android:allowbackup="true" 
      android:icon="@drawable/ic_launcher" 
      android:label="@string/app_name" 
      android:theme="@style/AppTheme">
        <activity android:label="E34ClockSettings" 
          android:name=".ClockSettingsActivity">
          <intent-filter>
              <action android:name="android.intent.action.MAIN" />
              <category android:name="android.intent.category.LAUNCHER"/>
          </intent-filter>
        </activity>
    </application>

The activity consists of the name of the activity class and the label this activity is known by. The "." in front of the activity name tells Android to use the package named in the package attribute of the Manifest tag. Additionally we define an intent filter which defines on which intent we will react. For now we simply specify that the activity supports the MAIN action in the LAUNCHER category. This tells Android to include this activity in the app screen. When the displayed launcher icon is pressed it opens the activity. I will explain intents and intent-filters in detail when we comeback to them during coding of the widget.

Running this application by pressing the launcher icon gives you a simple blank activity which can be started but doesn't do anything.

Lookout

In the next post I will start creating the code for the widget. Hope to see you then.

Yours truely

Stefan Langer

Creative Commons License

Sunday, October 27, 2013

A Mission to Android - The Journey Begins


So I fired up my pencil and picked up a piece of paper and started drawing the layout of my widget. At first I had just the picture of an analog clock in my head. So I did some research. I picked up my phone and looked at the widgets I'm currently using. My main clock is from HD widgets and represents a digital clock. Further it indicates the current weather and shows me alarm time and battery level.
Since I liked it I had to incorporate this information into my own widget.
Next I took a look at the different clock widgets and status widgets on the play store. I took note of the things I liked and incorporated them into my draft.

Digitizing the Draft

Now that I knew what I wanted to achieve I fired up Inkscape and started transfering the paper draft into a digital form. Inkscape is an open source program to create Scalable Vector Graphics.

My first drafts




The current design


None of this is set in stone and I will most likely come back and redesign parts or all of it. 

Tips And Tricks   

Last and not least I want to tell you what has helped me to create my design.

  • Always start with pen and paper. I find it a lot easier to draft something on paper it helps to sort out your thoughts and the haptic of a pen and the feel of paper make it easier to be creative.
  • Use scalable vector graphics when designing iconic images or when the images you are creating are not too complicated. This will ease exporting different scaled graphics for use in different layouts. It also makes it easy to move things around and create alternative versions of the same thing.
  • Create alternative layouts to get a feel for your design. I often find alternative versions more interesting then my original idea.
  • Create a raster which gives you the scale of the screen you are designing for. This raster will help you later create the layout in code and make alignment easier. When creating the raster keep different rules in mind like Rule of Third or The Golden Ratio. Try to incorporate them into your design to get a pleasing look.
  • Make yourself a mask that resembles your screen and make that mask a multiple of the resolution you are targeting. I often find it nice to have a mask that has as the width a multiple of the dip (Device independent Pixels) of your target screen. This way you can simply read off sizeings and don't have to calculate them. Or calculation is a simple division without any floating values.
  • Be ready to break out of standards but always keep in mind that there is a reason why these standards have been established. Not all new things are good things ... but you will never know if you don't try new things.
  • If you don't like it chances are others won't like it either.

Hope you enjoyed this post and I hope to hear from your design tips.

Yours truely

Stefan Langer

E34Clock on Github
Creative Commons License

Saturday, October 26, 2013

First obstacles on the journey to android nirvana

If you are able to, develop on the real hardware! Trust me it will save you lots of pain.

I do have a phone but since it is my everyday phone I do not want to test my software while in early alpha state. Besides I'm doing this as a hobbist and not as a professional so my resources are limited and I do not have the money to buy me the devices to test different constellations.

Quit pro quo I have to use the emulator. (If you feel like supporting me feel free to donate or send a device my way ;) ) So I have to resort to the emulator.
I'm developing on a windows as well as on a linux machine. If you have the choice use the linux machine to develope on.  The emulator on windows seems to be very unreliable, at least in my setup. Sometimes it just hangs other times it needs hours, yes hours, to start up. Then from time to time it just starts up and works. Deleting the images doesn't always resolve the problem.

My strongest guess is that this has to do with the limited amount of memory I can allocate for the image running in the emulator on windows, - a meager 768Mb just doesn't cut it -, but this is just a wild guess.

On linux I have not experienced such sluggishness. It is slow but at least it works reliable. The atom emulation doesn't seem to resolve the problem either. - Installing the hardware acceleration from Intel didn't work so I cannot say anything about using it. - Same behaviour. It might be my hardware but a I7 with 4 physical cores and hyperthreading and 16GB should be enough to run an ARM emulator reliably.

So if you use the emulator be patient and bring lots of time with you. If you do not have the time then bring money to buy a device.

Yours truely
Stefan Langer

Creative Commons License

Friday, October 25, 2013

A Mission to Android

Currently I'm very unhappy with my home screen on my android device, a Nexus 4. So I started looking around for new widgets to replace my current clock setup and information widget on the home screen. After searching the play store for proper replacements I just didn't quite find the one that gives me what I want and is not too cost intensive. 
So the natural response was to create my own. This would give me the perfect opportunity to update my rudimentary android experience and get a widget that is customized to my needs.

Creating the widget and blogging about it


After having started into the endeavor and having the first running prototypes on the emulator I got the idea to write about this mission and maybe just maybe somebody else can use this experience to gain some insight into android development and learn a thing or two. 
So here we are: Me writing about how I code this thing and You reading about it!

I hope to regularly blog about this mission and I hope you enjoy reading it and maybe you can give me some tips, criticism and feedback about my widget, the code and this blog.

So bare with me and I hope to see you again. 

Code and Licenses

As this mission evolves I'm going to push my code to github.com. You are welcome to grab the code, fork it, play with it and send me back pull requests. 
If I succeed I might actually publish the resulting widget to the play store. Until then you are on your own to install the widget on your own device. I take no responsibility for any damage or problems the code might cause. 
All graphics are published under a Creative Commons Attribution-ShareAlike 3.0 Unported License. The code is published under a Apache License, Version 2.0.

Resources

E34Clock on Github

The code is licensed under the Apache License, Version 2.0

All image work is additionally licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.


Yours truely

Stefan Langer

Creative Commons License