11 October, 2015

FFMpeg is Digital Meth -- Part 1


FFMpeg Options

Global Options






AVOptions

These options are specific to the given container, device or codec.  The '-profile' option above is an example of such an option.  These options are provided directly to the libavformat, libavdevice, and libavcodec libraries.

Main Options

'-fmt (input/output)'

FFMpeg normally auto detects the file format for input or output files, guessed from the file extension so often it is not required to specify the format.  The format can be explicitly specified by using '-fmt', for input or output files.

'-y (global)'

If the output file(s) already exist, FFMpeg will halt and present the user with the option to overwrite the file.  Specifying '-y' overwrites output files without user intervention.

'-t duration (input/output)'

This argument applies both to input and output files.  If specifying a duration as an input option (before -i), the result is limiting the duration of the data read from the input file.  When specified as an output option (before the output filename) the FFMpeg will stop writing after its reached the specified duration.

Specifying '-t 20' as an input file, with two output files will result in decoding and re-encoding the 1st 20 seconds of video creating two equivalent output files:

$ ffmpeg -y -t 20 -i big_buck_bunny_1080p_h264.mov -an /tmp/foo1.mov -an /tmp/foo2.mov

Repeating the command while specifying '-t 10' as an output argument to one of the files will result in one input file being 20 sec duration, the other a 10 second duration.

$ ffmpeg -y -t 20 -i big_buck_bunny_1080p_h264.mov -an /tmp/foo1.mov -an -t 10 /tmp/foo2.mov

'-fs fileSize (input/output)'

Another useful output option allows setting the file size limit.  The input file is read, writing the output file until the file size limit specified has been reached.  The result in the following case will be a video consisting of the first ~22 seconds of the input video.


$ ffmpeg -y -i big_buck_bunny_1080p_h264.mov -an -fs 10M /tmp/foo-10M.mov

$ ls -lh /tmp/foo-10M.mov

-rw-rw-r-- 1 user user 9.8M Sep  5 17:45 /tmp/foo-10M.mov

But what if you want to fast forward to 30 seconds into the input file followed by encoding the following 10 seconds? The '-ss' fits the bill when specified as an input file option.  When specified as an output file option, the end result is similar, accomplished by decoding but discarding the input until the timestamps position is reached.


$ ffmpeg -y -ss 30 -i big_buck_bunny_1080p_h264.mov -t 10 -an /tmp/foo-30-40.mov

Setting the timestamp

Python Progress Bar

Was recently writing some python to process some test cases.  One long'ish testcase would benefit from a progress bar, slapped one together below.

One thing to note, progress doesn't allow going backwards, but indicates in ASCII text the current progress by writing characters and a series of backspaces.



#!/usr/bin/python
import time
import sys
 
class ProgressBar():
  barLen_=0;
  progress_=0;
  def __init__(self,N=10):
    self.barLen_=N;
    print '['+' '*self.barLen_+']',
    print '\b'*(self.barLen_+2),
  def setProgress(self,x):
    sys.stdout.flush();
    k=int(x/100.0*self.barLen_);
    if (k > self.progress_):
      update='\b'+'.'*(k-self.progress_);
      print update,
      self.progress_=k;

N=50
p=ProgressBar(N);

for i in range(0,101):
  p.setProgress(i);
  time.sleep(.05);

The result is of the form:

user@river:~$ ./pBar 
[..............                                  ] 
Enjoy.

19 September, 2015

Limiting Network Bandwidth

Occasionally it's necessary to determine the affects of reduced network bandwidth. Authoring software that works for a networked system backed by Gigabit Ethernet as well as DSL requires testing on both forms of systems.  The alternative is to test on the most capable networking system and then test lower-bandwidth systems on the same network by artificially limiting the bandwidth.

Consulting the all-knowing Google provided a couple general options: trickle and wondershaper.  While there are other utilities, I mainly focused on these two.

Trickle is a 'lightweight user bandwidth shaper', it's particular value is the ability to limit processes independently and it doesn't require superuser privileges.


$ sudo apt-get install trickle


You can limit uploads and downloads to 100 KB/s for a command such as;

$ trickle -u 100 -d 100 wget http://download.blender.org/peach/bigbuckbunny_movies/big_buck_bunny_1080p_stereo.ogg


Independently, you could specify alternative limits for another command.  Trickle is limited to TCP sockets so if you need to limit bandwidth for UDP sockets you'll need to look for an alternative.  Applying system-wide bandwidth, TCP in this case, supposedly is supported via trickled daemon utility but after numerous hours I gave up on getting it to work.  Regardless, I abandoned it's use not only because I couldn't get it to work but also it's limitation to TCP and applying the daemon and client command required prepending 'trickle' to the command line.  This would disqualify applying the network bandwidth constraints to network services like sshd and such without modifying each service starting the process.

Seeking a system-wide bandwidth traffic shaper brought me back to Wondershaper once again.  My first experience with wondershaper I found it didn't always work, this round I tested the usage 1-10 Mbps and I quickly found that it limited the bandwidth like expected until reaching 10 Mbps where it jumped to realized bandwidth of 40 Mbps.  Head-scratcher; working fine for bandwidths under 10Mbps but broke at >= 10Mbps.  Consulting Google again brought me to a fix proposed by 'buzzy'; https://github.com/magnific0/wondershaper/issues/2.  Modifying the wondershaper script as 'buzzy' indicated resolved the issue and I could consistently specify bandwidths 1-40 Mbps and observe realized bandwidths accordingly.


$ cat go

#!/bin/bash



for i in `seq 1 50`; do

  echo "$i Mbps"

  K=`expr $i \* 1024`

  sudo wondershaper wlan0 $K $K

  iperf -t 10 -c 192.168.1.132 2> /dev/null | grep "Mbits/sec"

  sleep 2

done

sudo wondershaper wlan0 clear



lipeltgm@river:~$ ./go 
1 Mbps
[  3]  0.0-11.2 sec  1.38 MBytes  1.03 Mbits/sec
2 Mbps
[  3]  0.0-10.7 sec  2.62 MBytes  2.06 Mbits/sec
3 Mbps
[  3]  0.0-10.4 sec  3.75 MBytes  3.02 Mbits/sec
4 Mbps
[  3]  0.0-10.4 sec  5.00 MBytes  4.04 Mbits/sec
5 Mbps
[  3]  0.0-10.5 sec  5.12 MBytes  4.11 Mbits/sec
6 Mbps
[  3]  0.0-10.3 sec  7.38 MBytes  6.00 Mbits/sec
7 Mbps
[  3]  0.0-10.3 sec  8.50 MBytes  6.95 Mbits/sec
8 Mbps
[  3]  0.0-10.3 sec  9.75 MBytes  7.97 Mbits/sec
9 Mbps
[  3]  0.0-10.2 sec  10.6 MBytes  8.76 Mbits/sec
10 Mbps
[  3]  0.0-10.1 sec  12.0 MBytes  9.94 Mbits/sec
11 Mbps
[  3]  0.0-10.1 sec  13.2 MBytes  11.0 Mbits/sec
12 Mbps
[  3]  0.0-10.2 sec  14.5 MBytes  12.0 Mbits/sec
13 Mbps
[  3]  0.0-10.2 sec  15.5 MBytes  12.8 Mbits/sec
14 Mbps
[  3]  0.0-10.3 sec  16.1 MBytes  13.2 Mbits/sec
15 Mbps
[  3]  0.0-10.1 sec  16.4 MBytes  13.6 Mbits/sec
16 Mbps
[  3]  0.0-10.1 sec  19.0 MBytes  15.8 Mbits/sec
17 Mbps
[  3]  0.0-10.1 sec  19.8 MBytes  16.4 Mbits/sec
18 Mbps
[  3]  0.0-10.1 sec  21.1 MBytes  17.6 Mbits/sec
19 Mbps
[  3]  0.0-10.1 sec  22.1 MBytes  18.3 Mbits/sec
20 Mbps
[  3]  0.0-10.1 sec  23.1 MBytes  19.3 Mbits/sec
...


While the use of WonderShaper requires superuser privileges, it limits the system network bandwidth in it's entirety. Enjoy.

12 September, 2015

Makefile Mystique

Originating in the work by Stuart Feldman at Bell Labs in 1976, the make utility has existed in a number of fashions since and is one of the most common build utilities for *nix based systems.  Despite that however, in my 16+ years of professional software development, authoring or maintaining makefiles takes on a classic game of 'not it!!' seemingly everywhere I work.

Few would argue that the utility lacks flexibility or power, the general complaint is the syntax/semantics are confusing and unmaintainable, one of the primary reasons that popular IDEs synthesize their own makefiles in an attempt to isolate the user from the pain and misery of doing it themselves.  The goal of this post isn't to complain about the utility, but instead to work through a few examples in an attempt to better understand it myself.  While authoring and maintaining a makefile may feel like a prostate exam, it's also likely as necessary as one.  In preparing for this post I referred the documentation here and I invite you to do the same.

Part of make's popularity and power is because of it's implicit rules.  Making use of these rules you'll find that like good liquor, a little goes a long way.  This is evident for example when your project utilizes C/C++.

With a simple source file and relying on implicit make rules the necessary makefile is simplistic;
$ cat main.c 
#include <stdio.h>

int main()
{
  printf("(%s:%d) main process initializing\n",__FILE__,__LINE__);
  printf("(%s:%d) main process terminating\n",__FILE__,__LINE__);
}

A single rule comprises the makefile and provides a simplistic, minimalistic build system.
$ cat Makefile 
main: main.o

Each makefile consists of 'rules' taking the form;
     target ... : prerequisites ...
     <tab> recipe
     <tab> ...

Examining the rule we find the target is defined as 'main' with a prerequisite of 'main.o'.  This simply means that in order to create 'main' the 'main.o' file must exist.  The absence of a recipe relies on the implicit rules.  This can be observed by looking at the output when running make as below;
$ make
cc    -c -o main.o main.c
cc   main.o   -o main

The existence of implicit rules comes with some disadvantages, namely it's easy to not understand what is being done for you.  Conceptually, the implicit rule that generates the object files takes the form of the prefix rule below;
$ cat Makefile 
main: main.o

.c.o:
${CC} ${CPPFLAGS} ${CFLAGS} -c $^ 

Understanding what is going on allows tailoring the behavior without explicitly defining a rule.  Note the usage of the CPPFLAGS and CFLAGS variables.  Tweaking the original makefile will allow us to add debugging info and specifying an optimization level 3 as below;

$ cat Makefile 
CFLAGS += -g -o3
main: main.o

This results in a slight difference when we run make;
$ make
cc -g -o3   -c -o main.o main.c
cc   main.o   -o main

The foundation of make is detecting changes to the prerequisites and determining when the targets need to be remade.  This can be observed by re-running make immediately after running make, the result is a notification that "'main' is up to date".  Affecting the main.c file timestamp by modifying the file or simply touching it will result  in the need for the rule to be applied once again.

$ make
cc -g -o3   -c -o main.o main.c
cc   main.o   -o main
user@kaylee:~/make.blog/C$ make
make: `main' is up to date.
user@kaylee:~/make.blog/C$ touch main.c 
user@kaylee:~/make.blog/C$ make
cc -g -o3   -c -o main.o main.c
cc   main.o   -o main

Likely, you've seen this all before, but stay with me I assure you there's more interesting things to come.

Often, it's preferred to have a target that cleans up the directory and allows building from scratch.  The convention is to name such a target clean.  Below is a modified makefile that defines a clean target that simply deletes the executable and the object files.

CFLAGS += -g -o3
main: main.o

clean:
        ${RM} main main.o

Executing 'make clean' will result in deleting main and main.o files.  Adding a file to your project can be accomplished by adding the object file to the prerequisites for main and recipe for the clean target or we can make use of pattern.  We'll do this by explicitly defining each of the C source files in a variable, then perform a list replacement substituting the *.c with *.o extensions to get our object file list.  The object file list can then be used in the target prerequisites and in the clean target recipe.  Adding a file to the SRCS variable rather than duplication in multiple locations.

$ cat Makefile 
CFLAGS += -g -o3
SRCS=main.c 
OBJS=$(subst .c,.o,${SRCS})
main: ${OBJS}

clean:
${RM} main ${OBJS}


Still however there is duplication, namely the multiple references of main, that can be addressed by a new variable definition.

$ cat Makefile 
CFLAGS += -g -o3
PROGS=main
SRCS=main.c 
OBJS=$(subst .c,.o,${SRCS})
${PROGS}: ${OBJS}

clean:
${RM} ${PROGS} ${OBJS}

Definitely on the right path, but the addition of a file requires modification to the makefile.  The wildcard expansion demonstrated in the following makefile.  The addition or removal of a file with the .c extension in the current directory will take effect in the wildcard expansion.

$ cat Makefile 
CFLAGS += -g -o3
PROGS=main
SRCS=${wildcard *.c}
OBJS=$(subst .c,.o,${SRCS})
${PROGS}: ${OBJS}

clean:
${RM} ${PROGS} ${OBJS}



Let's look at some less typical usages of make which gives us a bit more insight into the creation of targets, prerequisites, and recipes.  Imagemagick is a common utility that we'll be making use in the following examples.

We'll build up the makefile as we go, incorporating what we've learned above.  We'll be satisfying the same objectives using two forms of makefiles; one that makes use of suffix rules, one that makes use of pattern rules.

Let's begin by defining our objectives.  Suppose our project requires taking in a list of JPG files and converting each into a series of other image file formats, namely PNG, GIF, JP2 and XWD files.

Using the suffix rule syntax, the makefile can begin taking the following form;

$ cat Makefile.suffix 
.SUFFIXES:
.SUFFIXES: .jpg .png .gif .jp2 .xwd 

all: image.xwd 

.jpg.png:
${SH} convert $< $@

.png.gif:
${SH} convert $< $@

.gif.jp2:
${SH} convert $< $@

.jp2.xwd:
${SH} convert $< $@

clean:
${RM} *.gif *.jp2 *.xwd

The all target consists of the default target, the prerequisite of image.xwd.  In other words, make is complete when an up-to-date image.xwd file exists.  How it arrives at it is make magic, more precisely a series of suffix rules.  A series of prefix rules chaining is required to get to the final XWD file, each target we can kick off by explicitly specifying on the command line.  Specifying 'make -f Makefile.suffix image.png' results in firing of the .jpg.png suffix rule.  The suffix rules are chained as each must fire to arrive at the final XWD file.  Running 'make' performs this by stepping through a series of recipes; JPG => PNG => GIF => JP2 => XWD.
$ make -f Makefile.suffix
convert image.jpg image.png
convert image.png image.gif
convert image.gif image.jp2
convert image.jp2 image.xwd
rm image.jp2 image.gif image.png

Notice the final step removes intermediate files which can be preserved which can be prevented by adding ".PRECIOUS: %.jpg %.png %.gif %.jp2 %.xwd" line which tells make not to remove the intermediate files with the specified extensions.  The example is a bit fictional but done to demonstrate suffix rules and chaining.  Modifying the source file image.jpg followed by rerunning make will result in converting the new file to each of the alternative file formats.

As is, each prerequisite is generated via suffix rule chaining to completion before moving on to the next prerequisite.  In other words, if you specified image.xwd and image01.xwd the image.xwd would be generated to completion (ie. JPG => PNG => GIF => JP2 => XWD) before moving on to image01.xwd.

Meeting the same goals, let's utilize pattern rules rather than suffix rules which are somewhat dated in use.

$ cat Makefile.pattern 
.PRECIOUS: %.jpg %.png %.gif %.jp2 %.xwd

all: image.xwd

%.png:%.jpg
${SH} convert $< $@

%.gif:%.png
${SH} convert $< $@

%.jp2:%.gif
${SH} convert $< $@

%.xwd:%.jp2
${SH} convert $< $@
        
clean:
${RM} *.gif *.jp2 *.xwd

The most noteworthy difference between the target/prerequisites.  The prefix rules define a target, the pattern rule defines a target and prerequisite making the illusion of the rules being reversed.

What if you want to convert each input images to Jpgs before moving on to Gifs before moving on to Jp2s before the Xwds.  This can be done by specifying a wildcard expansion for the source files and using the substitution expression for each of the formats then specifying each of the formats in as prerequisites for the all target, as follows;
$ cat Makefile.pattern 
.PRECIOUS: %.jpg %.png %.gif %.jp2 %.xwd

SRCS=${wildcard *.jpg}
PNGS=$(subst .jpg,.png,${SRCS})
GIFS=$(subst .jpg,.gif,${SRCS})
JP2S=$(subst .jpg,.jp2,${SRCS})
XWDS=$(subst .jpg,.xwd,${SRCS})

all: ${PNGS} ${GIFS} ${JP2S} ${XWDS}

%.png:%.jpg
${SH} convert $< $@

%.gif:%.png
${SH} convert $< $@

%.jp2:%.gif
${SH} convert $< $@

%.xwd:%.jp2
${SH} convert $< $@
        
clean:
${RM} ${PNGS} ${GIFS} ${JP2S} ${XWDS}

This way, each format is fully satisfied before moving on to the next.  Perhaps less necessary for image files, more applicable for generating source files.  For example, the Protobuf message compiler allows generation of header/c++ files which also allows interdependencies between message files.  This requires all the message files to be converted to C/H files before firing the compilation, otherwise a source file may reference a header file that hasn't been created yet.


Hope you find this useful.  Good luck with your make projects!



01 February, 2015

Setting Up Android For the Nth Time

Since I've been authoring Android apps, I've gone through numerous occasions of installing/re-installing/re-re-installing of the SDK and more recently AndroidStudio.  I've been a bit out of the loop, a bit of a hiatus from development but recently reacquainting with the SDK.

Start by downloading and extracting the SDK;

$ wget http://dl.google.com/android/android-sdk_r24.0.2-linux.tgz

$ tar -zxvf android-sdk_r24.0.2-linux.tgz


Append the locations of the new utilities to your Bash profile;


$ echo "export PATH=\$PATH:~/android-sdk-linux/tools" >> ~/.bashrc

$ echo "export PATH=\$PATH:~/android-sdk-linux/platform-tools" >> ~/.bashrc

The default install generally installs the latest APIs, but you can install additional ones;

$ android

Likely, if you've recently updated or reinstalled the Android SDK, you'll have to update the project XML files.  

The 'update project' command takes a numeric target id, listing the targets and 
find the appropriate id.

$ android list targets | grep id:
id: 1 or "android-7"
id: 2 or "android-8"
id: 3 or "android-21"
id: 4 or "Google Inc.:Google APIs:7"
id: 5 or "Google Inc.:Google APIs:8"
id: 6 or "Google Inc.:Google APIs:21"
The current API version is stored in the project.properties file within the project directory.


$ cat project.properties
.
.
target=Google Inc.:Google APIs:8
.
.

Updating the project to continue to use API 8 would therefore be done by;


$ android update project -p . -t 5

Get the list of devices available by issuing the following command;


$ adb devices
List of devices attached 
01aa7bcb8c8c07be device

$ adb -s 01aa7bcb8c8c07be install -r ./bin/Test01-debug-unaligned.apk


Whole buncha interesting stuff is available by examining the APK;

$ aapt dump badging ./bin/Test01-debug-unaligned.apk
package: name='com.abc.test01' versionCode='3' versionName='1.2' platformBuildVersionName=''
application-label:'Test01'
application-icon-160:'res/drawable/icon.png'
application: label='Test01' icon='res/drawable/icon.png'
application-debuggable
launchable-activity: name='com.abc.test01.Test01'  label='Test01' icon=''
uses-permission: name='android.permission.INTERNET'
uses-permission: name='android.permission.READ_PHONE_STATE'
uses-permission: name='android.permission.ACCESS_NETWORK_STATE'
sdkVersion:'7'
targetSdkVersion:'7'
feature-group: label=''
  uses-feature: name='android.hardware.screen.portrait'
  uses-implied-feature: name='android.hardware.screen.portrait' reason='one or more activities have specified a portrait orientation'
  uses-feature: name='android.hardware.touchscreen'
  uses-implied-feature: name='android.hardware.touchscreen' reason='default feature for all apps'
main
other-activities
supports-screens: 'small' 'normal' 'large'
supports-any-density: 'true'
locales: '--_--'
densities: '160'
That's all for now.  Cheers.






31 January, 2015

Android -- Introduction to Fragments (Part 2)

Building off our last example, we'll spend some time demonstrating how to introduce multiple fragments into a single activity.  Along the way, we'll pick up a little more knowledge on how the activities and fragment interaction with one another.

Let's start by extending the res/layout/main.xml to have two layouts as follows;


$ cat res/layout/main.xml 
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/container"
        android:orientation="vertical"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        >
    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Hello World, FragTest01"
        />
    </LinearLayout>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/container2"
        android:orientation="vertical"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        >
    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Hello World, FragTest02"
        />
    </LinearLayout>
</LinearLayout>

Notice we've duplicated the original linear layout (id=container) and identified the copy as container2.  In addition, both of these layouts have been contained within a parent layout, the layout_height attributes were modified to keep the first layout from using the full screen.

As you may recall, the activity FragTest01.java specifies adding an object of the MyFragment class into the desired container;


.
.
            getFragmentManager().beginTransaction()
                     .add(R.id.container, MyFragment.newInstance())
                     .commit();
.
.


If we extend on this call as follows we're left with creating two copies of the MyFragment fragment and placing into two independent containers.


.
.
            getFragmentManager().beginTransaction()
                     .add(R.id.container, MyFragment.newInstance())
                     .add(R.id.container2, MyFragment.newInstance())
                     .commit();
.
.



Ehh, not terribly interesting, two copies of the same fragment with the same layout.

We can now create specialized fragments, one for each layout.  We'll leave MyFragment.java/myfrag.xml in the top layout and create new elements MyFragment02.java/myfrag2.xml for the lower frame.

Duplicating res/layout/myfrag.xml, we simply change the text to demonstrate the difference from the original.

$ cat res/layout/myfrag2.xml 
<?xml version="1.0" encoding="utf-8"?>
   <LinearLayout
   xmlns:android="http://schemas.android.com/apk/res/android"
   android:orientation="horizontal"
   android:layout_width="fill_parent"
   android:layout_height="fill_parent"
   android:background="#666666">
   <TextView
   android:layout_width="fill_parent"
   android:layout_height="wrap_content"
   android:text="My Fragment Example 02"
   android:textColor="#000000"
   android:textSize="20px" />
</LinearLayout>

Similarly, we'll duplicate MyFragment.java for a new class, inflating from the new layout file.


$ cat src/com/fsk/example/FragTest01/MyFragment02.java

package com.fsk.example.FragTest01;

import android.os.Bundle;
import android.app.Fragment;
import android.view.ViewGroup;
import android.view.View;
import android.view.LayoutInflater;

public class MyFragment02 extends Fragment {
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.myfrag2, container, false);
    }

   public static Fragment newInstance() {
        MyFragment02 fragment = new MyFragment02();
        fragment.setRetainInstance(true);
        return fragment;
    }

}


Finally, return to the activity and add unique fragments rather than adding two copies of the original.

             .

             .

            getFragmentManager().beginTransaction()

                     .add(R.id.container, MyFragment.newInstance())

                     .add(R.id.container2, MyFragment02.newInstance())

                     .commit();

             .

             .



We end with two specialized fragments within the same activity;

Nothing sexy, but a toy example that demonstrates tying and linking activities and fragments.

Cheers.

Android -- Introduction to Fragments (Part 1)

Life gets busy. As a result, I took a hiatus from Android development for a period of several months. What I returned to; the concept of fragments, support libraries, Android Studio and with it a new file structure, new IDE and numerous new technologies for Android development.

Surrounded by new concepts and tools, one must focus on ramping back up one area at a time. With the objective of increased productivity, tools such as Android Studio do much for the developer hiding subtleties from the developer by automating a good deal of the heavy lifting. While I fully recommend use of such tools, the course of this post will be working with the SDK, no IDE, to better understand the subtleties and reduce the complexity of the files and structures.

Let's start by creating a project;

$ android list
targets | grep id:
id: 1 or "android-7"
id: 2 or "android-8"
id: 3 or "android-21"
id: 4 or "Google Inc.:Google APIs:7"
id: 5 or "Google Inc.:Google APIs:8"
id: 6 or "Google Inc.:Google APIs:21"

Targeting Google API v21, we specify target 6.

$ android create project --name FragTest01 --path ./ws/FragTest01 --target 6 --package com.fsk.example.FragTest01 --activity FragTest01
Build it by executing the build via Ant;

$ cd ws/FragTest01
$ ant debug
$ adb devices
List of devices attached 
01aa7bcb8c8c07be device

With a connected device, start the logcat service, followed by installing and running the app;

$ xterm -e adb logcat &amp;
$ adb -s 01aa7bcb8c8c07be install -r ./bin/FragTest01-debug-unaligned.apk
$ adb -s 01aa7bcb8c8c07be shell am start -a android.intent.action.MAIN -n com.fsk.example.FragTest01/.FragTest01


We now have an initial project set up, we can continue to play.

First modification we'll make is to the res/layout/main.xml file that was generated as part of the project creation. We'll simply be adding an id to the layout, the usage will become apparent later.


$ cat res/layout/main.xml 
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/container"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
<TextView  
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="Hello World, FragTest01"
    />
</LinearLayout>


We'll move along next by creating our first fragment. Before we do so though, let's spend a bit of time discussing the concept of fragments.

The Android developers website does solid job describing the concept of fragments, I'd recommend spending some candle-lit quality time with it, but for now the Cliff Notes for fragments are:

  • Fragments represent behavior, or portion of user interface in an activity. Think of fragments as a new container to stuff behaviors previously localized in activities with the overall goal of better supporting evolving screen sizes and resolutions.
  • A fragments meaning of life is to be contained within an activity, the activity gives the fragment(s) a purpose in life.

Since a fragment represents a portion of the UI, let's create a layout file for it;

$ cat res/layout/myfrag.xml 
<?xml version="1.0" encoding="utf-8"?>
   <LinearLayout
   xmlns:android="http://schemas.android.com/apk/res/android"
   android:orientation="horizontal"
   android:layout_width="fill_parent"
   android:layout_height="fill_parent"
   android:background="#666666">
   <TextView
   android:layout_width="fill_parent"
   android:layout_height="wrap_content"
   android:text="My Fragment Example"
   android:textColor="#000000"
   android:textSize="20px" />
</LinearLayout>

Linear layout, text view with some static text.
Next, we'll create a fragment that uses this layout.


$ cat src/com/fsk/example/FragTest01/MyFragment.java

package com.fsk.example.FragTest01;

import android.os.Bundle;
import android.app.Fragment;
import android.view.ViewGroup;
import android.view.View;
import android.view.LayoutInflater;

public class MyFragment extends Fragment {
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.myfrag, container, false);
    }
   public static Fragment newInstance() {
        MyFragment fragment = new MyFragment();
        fragment.setRetainInstance(true);
        return fragment;
    }
}
The two key methods of interest; onCreateView() and newInstance().   
The onCreateView() method is part of the Fragment Lifecycle, it's purpose is to return a View that is the root of the fragment layout. This is done in this case by inflating the myfrag.xml layout file.


The newInstance() method returns a new instance of the fragment, used by the activity which is shown below;

$ cat src/com/fsk/example/FragTest01/FragTest01.java 
package com.fsk.example.FragTest01;

import android.app.Activity;
import android.os.Bundle;
import java.util.Timer;
import java.util.TimerTask;

public class FragTest01 extends Activity
{
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        init();
    }

    private void init()
    {
       Timer t=new Timer();
       t.schedule(new TimerTask() 
       {
           public void run()
           {
            getFragmentManager().beginTransaction()
                     .add(R.id.container, MyFragment.newInstance())
                     .commit();
           }
       },5000);
    }
}


The activity simply sets the content view, represented by main.xml, then schedules a timer to add (read that as create) the fragment after 5 seconds. Adding/removing/replacing of fragments is done in the form of 'transactions' which are executed on the UI thread some time after being committed.


About as simple of an example as there is. We'll expand on it in later posts.

Full source for this example can be retrieved here.

Cheers.