Wednesday, December 31, 2014

Spread : Widget Button design

The default widget that has been created with our project is not what we're expecting. We will customize it so that it fits our needs.

Layout file

Open the file named spread_app_widget.xml in res->layout and select the text tab. Here we can see the graphical structure of the AppWidget : a RelativeLayout that fills the screen with a TextView to display text.

Widget size

We want it to be a button so it should not occupy much space on the home screen. The first thing to do is to modify the layout's size setting. By default, it is set  to match_parent which means that it will occupy the full screen. Change it to wrap_content.

...
android:layout_width="wrap_content"
android:layout_height="wrap_content"
...
You can immediatly see that the background colour is now applied to the TextView only. Speaking of background, remove the following line from the attribute list of the relative layout:

android:background="#09C"

Content

Alright, now we will replace the TextView with a button. To do so, delete the TextView and add the following:

<Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/Send_Button"
        android:layout_alignParentTop="true"
        android:layout_marginTop="4dp"
        android:layout_gravity="center_horizontal"
        android:paddingLeft="17dp"
        android:paddingRight="17dp"
        android:maxLength="20"
        android:clickable="true"
        android:text="@string/appwidget_text"
        android:singleLine="false"
        android:lines="4"
        android:textStyle="bold|italic"/>

All of the attributes won't be described here, simply use the editor's helper and google to find what you need. We defined a button that can accept multi-line text with a maximum size of 20 characters.

Add a background

To make it look like our push button, we will add an image as background. Drag and drop your image to your source tree under "drawable-nodpi" folder. You can now access it in your layout file with @drawable/<file_name_without_extension>.

android:background="@drawable/spread_button_up"

Add a style to our text

We want the text to be displayed in bold on the button. We will also define a maximum width so that the text remains on the button exclusively.
Open style.xml in res-> values and add the following:

<style name="config_message_style">
        <item name="android:textColor">#ccffffff</item>
        <item name="android:textStyle">bold</item>
        <item name="android:layout_width">35dip</item>
        <item name="android:singleLine">false</item>
    </style>

Finally, refer to this new style in the layout description:

 android:textAppearance="@style/config_message_style"

Here is what you should get:

Configuration Activity launcher

Alright, now I have a button that will be used to start the transmission of messages but before, I will need to configure my widget:

  •  Text message
  •  Contact list
An activity has been auto-generated for that purpose, I a going to look at it later. Here, I will add a small button right next to the big one that will show the configuration activity when pressed.

In the layout file, add the following lines:


<ImageButton
        style="?android:attr/buttonStyleSmall"
        android:layout_width="60dp"
        android:layout_height="20dp"
        android:id="@+id/Config_Button"
        android:layout_below="@+id/Send_Button"
        android:layout_alignRight="@+id/Send_Button"
        android:layout_alignEnd="@+id/Send_Button"
        android:clickable="true"/>
 As you can see, I am using here an ImageButton which could be used for the other button also. I want the settings button to look like a small cog so I will add a new image in drawable and refer to it in the ImageButton tag.
android:src="@drawable/spread_settings_button"
and add/replace these lines:
android:layout_width="15dp"
android:layout_height="15dp"
android:scaleType="centerInside"
android:background="@null"
android:adjustViewBounds="true" 

Here is the result on the Preview window:


Not so bad for a first version ^^

Tuesday, December 30, 2014

Spread : AppWidget

Description

Here is a VERY simple representation of our AppWidget class inherited from AppWidgetProvider.


A widget is (by default) owned by the home screen app meaning that the methods listed above will be called by the home screen.

onEnabled: called when the first instance of the widget is created
onDisabled: called when the last instance of the widget is deleted
onDeleted: should be called when an instance of widget is deleted from home screen but a known issue exists. This method does not seem to be called properly.
onUpdate: called regularly by the home screen (period is configurable in xml info file)
onReceive: Intent listener (see below)

Interactions

At first, I was lost with this object as I was looking for a way to add a click listener for a button. Well, unlike an Activity, you will have to deal with Intents here.
An Intent can be seen as a mail that can be sent to one or many objects throughout the system (broadcast). We will detail them in a further post.

So here is how the widget will interact with other activities:

Spread : First steps with Android Studio

Now that I know what I have to do, let's create a new project with Android Studio !

Create New Project

1. File -> New Project
2. Give it the name you want (Spread here) and click Next
3. On next window, select API 15 (which covers more than 84% of android devices out there)
4. Select "Blank Activity"
5. Click on Finish

Add an AppWidget

Now we need to create the home screen widget in the project. Right-click on java folder in your source tree and select Add->Widget->AppWidget
On the next window, configure the widget as shown below:
As you can see, we are creating a resizable home-screen widget with a configuration screen.
Click Finish.

And that's it for this post, we created our project successfully with Android Studio. This is what you should see in your source tree:

Cheers ! :)

Spread : an AppWidget to broadcast short messages to registered contacts

This is my first application for Android and instead of creating a simple activity that displays "Hello World" and some buttons, I'll try to make something that can be more useful (for me at least ^^).

Spread ? 

Yes, Spread. At some point, you have to give it a name and my imagination let me down today... so Spread it is ! The name gives me the thought of paint sprays where a push on a specific spot releases colour on a wide area. That's more or less what my app will do : a simple push to send a message to several contacts.

How ?

I want it to be a home screen widget with the look of a punch button with a simple message on it:

 A configuration activity will be created to configure:

  •  The message 
  •  The contact list that will receive it

When pushed, a progress bar will show up during message transmission.
The mode of transmission will be classical SMS. I will se later if I can do the same with popular communication apps (WhatsApp, Messenger, ...).

Where does the idea come from ?

The idea was born at the office when I was sick of texting my colleagues who worked on different floors that it was time to lunch, break, ... So I imagined a simple texting app that will alert all of them on a single button-push.


Android project, first things first : project files structure

When creating a new android project, a lot of files are generated and appears in our source tree view. Let's a look at what's inside.


Note: The content of java folder will be ignored here.

"XML is your ally"

Hope you like it beacuse XML is used almost everywhere ! Here is a quick description of all of them:

Info file

Defines the Application's main properties : minWidth, minHeight, initialLayout...

Manifest file

There are a lot of similitudes between the manifest file and a C# Assembly. It contains all information about application rights, package name, managed Intents, main components of the application (Activity, Receivers, ...)...
This file will require modifications during development.

Layout file

Graphical definition of an Activity/AppWidget. Most of the time, you will use the graphical interface to edit your screens but a bit of knowledge on layout files can be useful.

Resource files

These files contains user-defined strings, images, style sheets, dimensions... that can be accessed with an id.

<style name="config_message_style">
        <item name="android:textColor">#ccffffff</item>
        <item name="android:textStyle">bold</item>
        <item name="android:layout_width">35dip</item>
        <item name="android:singleLine">false</item>
    </style>

Referenced in a layout file like this:

<Button
        ...
        android:textAppearance="@style/config_message_style"
        ... />

All of those files are related to each other :


Why several folders with "same" names ?

The drawable folders contain images only with different resolutions (densities) in order to have a good rendering on all kind of devices (tablets, mobile phones, ...).

drawable - hdpi: ~240dpi
drawable - mdpi: ~160dpi
drawable - nodpi: ~160dpi (?)
drawable - xhdpi:~320dpi
drawable - xxhdpi:~480dpi

value-vXX indicates the values that should be used for Android API XX and higher.

Sunday, May 26, 2013

Raspberry Pi GPIOs

GPIO : General Purpose Input Output

Consider a GPIO as a pin whose behavior will be controlled by the software. The raspberry pi board has a 26-pin expansion header containing 17 GPIO pins that can be used to control external devices (lights, LCD display, ...) or to read information from the outside (temperature sensor, ADC output, etc ...).


As shown on the picture, some of the GPIOs are already used (depending on your kernel) for communication lines such as I2C, SPI or UART. It doesn't mean that we can't use them for other purposes, their usage can be customized.

GPIO voltage level

1 : High-Level : 3,3V
0 : Low-Level : 0V
Current is configurable from 2mA up to 16mA (for the whole block, no just only one pin)

Important note : there is no over-voltage protection circuit on the board. Be careful when plugging your active devices.

GPIO control

Two choices here :

  • usage of the kernel drivers in arch/arm/mach-bcm2708 (not included in vanilla kernel sources)
  • usage of a dedicated library installed in user space

Note : the raspberry pi is usually referred as bcm2835 but some of the drivers are located in bcm2708 directory. Technically bcm2708 is the chip family and bcm2835 is one of its implementation, the only one officially supported by linux.

Sunday, May 19, 2013

Build a minimalist root filesystem

During my research, I have seen many different tutorials to create a minimalist root filesystem. Some of them advise to copy files from the host's root filesystem and then proceed to customization, others use very handy tools like Buildroot and finally some people create it manually.

It is this last option that we will experiment here thanks to this twiki written by T.I.

Our root filesystem is based on BusyBox which offers the main linux command line utilities in a single executable.

Build BusyBox

Download the latest release of busybox on the official website and extract it to your working directory.
cd busybox-1.21.0
make menuconfig
Follow the instructions as detailed in the T.I. twiki to customize your binary. I have made some different choices here and there to add additional commands like fdisk. Do as you like, it does not really matter...

Build ...
ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- make
... and install it on the second partition of your SD Card :
make CONFIG_PREFIX=/media/<path_to_your_sd_card_p2> install
Here is what you should see on your partition after the last step :
bin  linuxrc  lost+found  sbin  usr

Create compulsory directories

The official rules to build a root filesystem are detailed in the Filesystem Hierarchy Standard (FHS). Here is a complete list of the top level directories :

bin : essential user command binaries
boot : files used by the bootloader
dev : devices files
etc : system configuration files
home : users home directory
lib : essential libraries (C library, kernel modules,...)
media : mount points for removable medias
mnt : mount points for temporarily mounted filesystems
opt : Add-on software packages
proc : virtual filesystem for kernel and process information
root : root user's home directory
sbin : essntial system administration binaries
sys : virtual filesystem for system information and control
tmp : temporary files
usr : secondary hierarchy containing most applications and documents useful to most users
var : variable data stored by daemons and utilities

We don't need all of them as we won't provide a multi-user environment. /home, /mnt, and /opt can be ommited.

Create the directories (as root)

cd /media/<path_to_your_sd_card_p2>
sudo mkdir dev dev/pts etc etc/init.d lib mnt opt proc root sys tmp var var/log
Optional : debug is needed by debugfs, add it if your kernel has been built with this option
sudo mkdir debug

Create a static node for console

Like Unix systems, every object in Linux is visible as a file (except for networking interfaces). As such, /dev contains device files (nodes) that represent the system devices. This directory needs to be populated either statically (old fashion way, every node has to be created manually with mknode) or dynamically (common way thanks to udev or mdev).

In our case, we will only add a node for the console.
mknod dev/console c 5 1
The rest of the nodes will be added by mdev which is part of BusyBox.
cd etc
gedit mdev.conf
audio       0:5 0666
console     0:5 0600
control.*   0:0 0660 @/bin/mv /dev/$MDEV /dev/snd/
dsp         0:5 0666
event.*     0:0 0600 @/bin/mv /dev/$MDEV /dev/input/
fb          0:5 0666
nfs         0:5 0770
null        0:0 0777
pcm.*       0:0 0660 @/bin/mv /dev/$MDEV /dev/snd/
rtc         0:0 0666
tty         0:5 0660
tty0*       0:5 0660
tty1*       0:5 0660
tty2*       0:5 0660
tty3*       0:5 0660
tty4*       0:5 0660
tty5*       0:5 0660
tty6*       0:5 0660
ttyS*       0:5 0640
urandom     0:0 0444
zero        0:0 0666

Create an fstab file to mount /proc and /dev/pts at boot

fstab is system configuration file used to list the available disks and disk partitions and describes how they are initialized. The mount command relies on this file to determine which option should be used when mounting a specific device.
# still in /etc
gedit fstab
proc            /proc           proc    defaults        0 0
none            /dev/pts        devpts  mode=0622       0 

Login utilities

/etc must contain the files group, passwd and hosts for login. For the moment, root only needs to be defined in group and hosts only needs to have the localhost registered.
gedit group
root:x:0:root
gedit passwd
root::0:0:root:/root:/bin/ash
gedit hosts
127.0.0.1       localhost

Create inittab

Read this post for information about inittab.
gedit inittab
::sysinit:/etc/init.d/rcS 

# /bin/ash
#
# Start an "askfirst" shell on the serial port
console::askfirst:-/bin/ash

# Stuff to do when restarting the init process
::restart:/sbin/init

# Stuff to do before rebooting
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a -r
::shutdown:/sbin/swapoff -a

Create init script

gedit init.d/rcS
#!/bin/sh
#   ---------------------------------------------
#   Common settings
#   ---------------------------------------------
HOSTNAME=MYPI
VERSION=1.0.0

hostname $HOSTNAME

#   ---------------------------------------------
#   Prints execution status.
#
#   arg1 : Execution status
#   arg2 : Continue (0) or Abort (1) on error
#   ---------------------------------------------
status ()
{
       if [ $1 -eq 0 ] ; then
               echo "[SUCCESS]"
       else
               echo "[FAILED]"

               if [ $2 -eq 1 ] ; then
                       echo "... System init aborted."
                       exit 1
               fi
       fi

}

#   ---------------------------------------------
#   Get verbose
#   ---------------------------------------------
echo ""
echo "    System initialization..."
echo ""
echo "    Hostname       : $HOSTNAME"
echo "    Filesystem     : v$VERSION"
echo ""
echo ""
echo "    Kernel release : `uname -s` `uname -r`"
echo "    Kernel version : `uname -v`"
echo ""


#   ---------------------------------------------
#   MDEV Support
#   (Requires sysfs support in the kernel)
#   ---------------------------------------------
echo -n " Mounting /proc             : "
mount -n -t proc /proc /proc
status $? 1

echo -n " Mounting /sys              : "
mount -n -t sysfs sysfs /sys
status $? 1

echo -n " Mounting /dev              : "
mount -n -t tmpfs mdev /dev
status $? 1

echo -n " Mounting /dev/pts          : "
mkdir /dev/pts
mount -t devpts devpts /dev/pts
status $? 1

echo -n " Enabling hot-plug          : "
echo "/sbin/mdev" > /proc/sys/kernel/hotplug
status $? 0

echo -n " Populating /dev            : "
mkdir /dev/input
mkdir /dev/snd

mdev -s
status $? 0

#   ---------------------------------------------
#   Disable power management
#   (Requires sysfs support in the kernel)
#   ---------------------------------------------
# echo -n " Disabling Power mgmt       : "
# echo -n "1" > /sys/power/cpuidle_deepest_state
# status $? 1

#   ---------------------------------------------
#   Turn off LCD after 1 hour of inactivity
#   (Requires sysfs support in the kernel)
#   ---------------------------------------------
# echo -n " Turn off LCD after 1 hour  : "
# echo -n "3600" > /sys/power/fb_timeout_value
# status $? 1


#   ---------------------------------------------
#   Mount the default file systems
#   ---------------------------------------------
echo -n " Mounting other filesystems : "
mount -a
status $? 0


#   ---------------------------------------------
#   Set PATH
#   ---------------------------------------------
export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin


#   ---------------------------------------------
#   Start other daemons
#   ---------------------------------------------
echo -n " Starting syslogd           : "
/sbin/syslogd
status $? 0

echo -n " Starting telnetd           : "
/usr/sbin/telnetd
status $? 0


#   ---------------------------------------------
#   Done!
#   ---------------------------------------------
echo ""
echo "System initialization complete."


make it executable
chmod +x rcS

Copy the dependencies 

We built BusyBox with the ARM cross toolchain as a C program without the -static option, which means that it will look for C libraries at runtime.We have to add them !

Note : Use ldd to list the dependencies of a binary

cd /media/<path_to_your_sd_card_p2>/lib
# Copy the C libraries
copy -r /usr/arm-linux-gnueabi/lib/* .
# Remove the debug informations from the libraries to save space
arm-linux-gnueabi-strip 

At this point, you have a valid root filesystem with the bare minimum. It does not include the kernel modules yet and if you want to add more executables, you'll also need to add their dependencies. The filesystem will get larger when these files are added.

First boot

Here is my display at first boot :


This time, there is no panic displayed. The kernel finds the init process and executes our script.
To access BusyBox press Enter :


 
biz.