Android Workspace Widget

 

I was looking for an android widget similar to the launcher workspace widget ( the one used in almost all launchers ), but a bit more customizable and with the possibility to use an Adapter as content provider. So at the end I mixed portion of code from the android launcher Workspace widget, the Gallery widget and the AbsListView widget.

Nothing particular tricky, just a combination of the 3 widgets in order to have the same sliding effect of the workspace ( using custom number of columns and rows ), but at the same time with an ArrayAdapter for creating views, and a little glow effect at start at the end of scrolling for creating the gingerbread style overscroll effect.

This is the source code: workspace

It’s just a first version, so it’s not really optimized…

The adapter used for creating this example looks like this:
[cc]
class WorkspaceAdapter extends ArrayAdapter {

int screenId;
PackageManager pm;
private LayoutInflater mInflater;
private int nCellsPerScreen = 4;

public WorkspaceAdapter( Context context, int textViewResourceId, List objects ) {
super( context, textViewResourceId, objects );
screenId = textViewResourceId;
pm = context.getPackageManager();
nCellsPerScreen = context.getResources().getInteger( R.integer.config_portraitCells ) * context.getResources().getInteger( R.integer.config_portraitRows );
mInflater = (LayoutInflater) context.getSystemService( LAYOUT_INFLATER_SERVICE );
}

@Override
public int getCount() {
return (int) Math.ceil( (double) super.getCount() / nCellsPerScreen );
}

public int getRealCount() {
return super.getCount();
}

@Override
public View getView( int position, View convertView, ViewGroup parent ) {

if ( convertView == null ) {
convertView = mInflater.inflate( screenId, mWorkspace, false );
((CellLayout)convertView).setNumCols( nCellsPerScreen );
}

CellLayout cell = (CellLayout) convertView;

int index = position * nCellsPerScreen;
int realCount = getRealCount();

for ( int i = 0; i < nCellsPerScreen; i++ ) { CellInfo cellInfo = cell.findVacantCell( 1, 1 ); TextView text; if ( cellInfo == null ) { text = (TextView) cell.getChildAt( i ); } else { text = (TextView) mInflater.inflate( R.layout.application_boxed, cell, false ); CellLayout.LayoutParams lp = new CellLayout.LayoutParams( cellInfo.cellX, cellInfo.cellY, cellInfo.spanH, cellInfo.spanV ); cell.addView( text, i, lp ); } if ( index + i < realCount ) { ApplicationInfo appInfo = getItem( index + i ); CharSequence label = appInfo.loadLabel( pm ); Drawable bm = appInfo.loadIcon( pm ); text.setCompoundDrawablesWithIntrinsicBounds( null, bm, null, null ); // new text.setText( label ); text.setClickable( true ); text.setFocusable( true ); text.setVisibility( View.VISIBLE ); } else { text.setVisibility( View.INVISIBLE ); } } return convertView; } } [/cc]  

Compile skia for android on Mac Lion

Some time ago I started to look at skia as possible solution for graphics 2D editing for a native android project I was developing.
Well, even if skia is part of the android system and it’s used everywhere by android itself, trying to include skia in my project was quite an hell..
Looking for resources I just found old examples and tips, and every try was just a failure.. but since android uses skia internally to do graphics operations I decided to look into the android project.

After downloading the skia module from the android git repository I just realized it couldn’t be compiled by itself because it has external dependencies. So next step was to download and compile the whole android source code. Easy task? not at all, at least if you’re on a mac running Lion!

At the end I managed to compile everything and build the skia module as static module, in this way now my project can link the skia library and include correctly the skia headers.

Ok, I don’t have the whole procedure step by step here, first of all because it depends on the android version you’re going to compiled, second and most important because I didn’t write down all the steps 🙂 So this is more a sort of list of notes about compiling android on Lion and a reminder for myself too. ( I was trying to compile android 2.2 using “generic-user” as lunch configuration )

Build Android: http://source.android.com/source/initializing.html

To get rid of clearsilver errors: http://code.google.com/p/android/issues/detail?id=993#c27

Java 1.5 version complaining: http://wiki.oneswarm.org/index.php/OS_X_10.6_Snow_Leopard

Well, the first time you’ll try to “make” everything probably you’ll get this error:

[cc]
./external/elfutils/config-compat-darwin.h:42: error: static declaration of ‘strnlen’ follows non-static declaration
[/cc]

modify ./external/elfutils/config-compat-darwin.h.
replace:
[cc lang=”c”]
static inline size_t strnlen (const char *__string, size_t __maxlen)
{
int len = 0;
while (__maxlen– && *__string++)
len++;
return len;
}
[/cc]

with:
[cc lang=”c”]
#if 0
static inline size_t strnlen (const char *__string, size_t __maxlen)
{
int len = 0;
while (__maxlen– && *__string++)
len++;
return len;
}
#endif
[/cc]

Well, at the end of the process I just edited the Android.mk makefile into external/skia adding a new entry for BUILD_STATIC_LIBRARY and the next command was simply:

[cc]mmm external/skia[/cc]

which produced the required libskia.a file to be linked in my project.

QuickActionView in Android

While I was searching for an custom implementation of the QuickContactBadge for Android, I went into this interesting post ( Lorenz’s Blog ), which had a custom widget called QuickAction.
While it’s a very nice widget, it didn’t fit my needs because I had the necessity of create different action layouts ( horizontal, vertical, grid.. ), so I made a very quick modification to the above code and I ended with this implementation.
Basically I removed from the original Class the ActionItem list and set a BaseAdapter as content source. In this way it’s more simple and easy to add more and different views to the widget.
Moreover I added the support for columns ( both fixed and automatic ).
Here you can see a snippet code of the QuickActionView creation:

[cc lang=”java”]
public void onButtonClick( View v ) {

// create the quick action view, passing the view anchor
QuickActionView qa = QuickActionView.Builder( v );

// set the adapter
qa.setAdapter( new CustomAdapter( this ) );

// set the number of columns ( setting -1 for auto )
qa.setNumColumns( (int) (2 + (Math.random() * 10)) );
qa.setOnClickListener( new DialogInterface.OnClickListener() {

@Override
public void onClick( DialogInterface dialog, int which ) {
dialog.dismiss();
Toast.makeText( getBaseContext(), “Selected item: ” + which, Toast.LENGTH_SHORT ).show();
}
} );

// finally show the view
qa.show();
}
[/cc]

Here some Screenshots:

And here you can find the source code: source code

FBTracer updated to Firefox 5

FBTracer in action

FBTracer aka Flash Tracer has been just updated to version 0.1.3 ( also thanks to Daniel D. Vanzin ) which is now compatible with the new Firefox 5.

If you already have the extension installed it’s just a matter of check updates from the addons firefox page, otherwise you can download the extension from this page: http://blog.sephiroth.it/firefox-extensions/flash-tracer-for-firebug/

Note. After a fresh install or update of the plugin, sometimes the fbtracer panel doesn’t refresh itself… in that case a firefox restart will fix the problem.

ImageView Zoom and Scroll

Update: the source code has moved to github, so it’s easier for anyone to fork it!

As long as Android doesn’t have a built-in ImageView widget with zoom and scroll capabilities I tries to create one by myself starting from the google repository.

The result is pretty nice so I’m posting here the source code, if anyone is interested, or simply doesn’t want to waste the time creating a new one.

Here’s a sample code on how to use it in an Activity:

package it.sephiroth.android.demo;

import it.sephiroth.android.library.imagezoom.ImageViewTouch;

import java.io.IOException;

import android.app.Activity;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore.Images;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Toast;

public class ImageZoomActivity extends Activity {

private ImageViewTouch mImageView;

@Override
protected void onCreate( Bundle savedInstanceState )
{
super.onCreate( savedInstanceState );

requestWindowFeature( Window.FEATURE_NO_TITLE );
setContentView( R.layout.main );
getWindow().addFlags( WindowManager.LayoutParams.FLAG_FULLSCREEN );
selectRandomImage();
}

@Override
public void onContentChanged()
{
super.onContentChanged();
mImageView = (ImageViewTouch)findViewById( R.id.imageView1 );
}

/**
* pick a random image from your library
* and display it
*/
public void selectRandomImage()
{
Cursor c = getContentResolver().query( Images.Media.EXTERNAL_CONTENT_URI, null, null, null, null );
if ( c != null ) {
int count = c.getCount();
int position = (int)( Math.random() * count );
if ( c.moveToPosition( position ) ) {
long id = c.getLong( c.getColumnIndex( Images.Media._ID ) );
int orientation = c.getInt( c.getColumnIndex( Images.Media.ORIENTATION ) );

Uri imageUri = Uri.parse( Images.Media.EXTERNAL_CONTENT_URI + "/" + id );
Bitmap bitmap;
try {
bitmap = ImageLoader.loadFromUri( this, imageUri.toString(), 1024, 1024 );
mImageView.setImageBitmapReset( bitmap, orientation, true );
}
catch ( IOException e ) {
Toast.makeText( this, e.toString(), Toast.LENGTH_LONG ).show();
}
}
c.close();
c = null;
return;
}
}
}

 

 

Anyway, if you want to download the source, here is the eclipse source project:
http://blog.sephiroth.it/wp-…/ImageZoom.zip
https://github.com/sephiroth74/ImageViewZoom

Widget: SlidingDrawer top to bottom

My android experiments continue…
In the last project I had to implement a SlidingDrawer which comes from top and left. The problem was that the default widget does not support all the directions, but only bottom to top and right to left.

That’s why I grabbed the SlidingDrawer source code and modified it in order to allow any direction ( defined as styleable in attrs.xml ). The only problem using custom styleable xml is that if you want to use this widget as library you need to include in the main project also the attrs.xml file as well.. a bit frustrating.

Anyway this is just the sample xml how to include the widget:







Btw If you’re interest, here you can find the full source code of the widget including a running application:

SlidingDrawer Demo 

* Updated the code thanks to Maciej Ciemięga.

Multipage TIF to PDF

Recently I’ve continued the porting of iText adding the support for a new image type: multipage tif.

The only problem with this update is that actually it’s really slow and probably with very complex image files it can hang the player for too long. Probably I should modify the ImageElement.getInstance method and make it asynchronous in order to prevent flash player to freeze…

Anyway, the current trunk version of purePDF can handle TIF image and here a simple code example:


package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.events.TimerEvent;
import flash.net.FileReference;
import flash.utils.ByteArray;
import flash.utils.Timer;
import flash.utils.getQualifiedClassName;

import org.purepdf.elements.RectangleElement;
import org.purepdf.elements.images.ImageElement;
import org.purepdf.io.RandomAccessFileOrArray;
import org.purepdf.pdf.PageSize;
import org.purepdf.pdf.PdfDocument;
import org.purepdf.pdf.PdfViewPreferences;
import org.purepdf.pdf.PdfWriter;
import org.purepdf.pdf.codec.TiffImage;

public class TestTIF extends Sprite
{
[Embed( source="assets/foxdog_multiplepages.tif", mimeType="application/octet-stream" )]
private var cls1: Class;

private var document: PdfDocument;
private var writer: PdfWriter;
private var buffer: ByteArray;
private var filename: String;
private var index: int;
private var pages: int;
private var stream: RandomAccessFileOrArray;

public function TestTIF()
{
super();
addEventListener( Event.ADDED_TO_STAGE, onAdded );
}

private function onAdded( event: Event ): void
{
stage.addEventListener( MouseEvent.CLICK, onClick );
}

private function createDocument( subject: String = null, rect: RectangleElement = null ): void
{
buffer = new ByteArray();

if ( rect == null )
rect = PageSize.A4;
writer = PdfWriter.create( buffer, rect );
document = writer.pdfDocument;
document.addTitle( getQualifiedClassName( this ) );

if ( subject )
document.addSubject( subject );
document.setViewerPreferences( PdfViewPreferences.FitWindow );
}

private function onClick( event: Event ): void
{
filename = getQualifiedClassName( this ).split( "::" ).pop() + ".pdf";
var byte: ByteArray = new cls1();
stream = new RandomAccessFileOrArray( byte );
var image: ImageElement = ImageElement.getInstance( byte );
createDocument( "Multi page TIFF Image Example", PageSize.A4 );
document.open();
// add the first page to the document
document.add( image );
// get the total number of pages
pages = TiffImage.getNumberOfPages( stream );
trace("number of pages: " + pages );
// next page index to add to document (first page is 1)
index = 2;
var timer: Timer = new Timer( 100, 1 );
timer.addEventListener( TimerEvent.TIMER, onTimerComplete );
timer.start();
}

private function onComplete(): void
{
stream.close();
document.close();
save();
}

private function onTimerComplete( event: TimerEvent ): void
{
if ( index > pages )
{
onComplete();
return;
}
document.add( TiffImage.getTiffImage( stream, index ) );
index++;
Timer( event.target ).reset();
Timer( event.target ).start();
}

private function save( e: * = null ): void
{
var f: FileReference = new FileReference();
f.save( buffer, filename );
}
}
}


Here you can see the result PDF file.
And here the input TIF image.