Tuesday, 24 November 2009

Android transitions, Views and Activities

When I talk about transitions in Android I'm referring to the Animations that link Views or Activities together. So when a user navigates from one View or Activity to another, they may see the present widgets slide to the left and the new ones slide in from the right, or the old widgets might fade out while the new ones fade in. In a post I wrote a while back I outlined how to implement a slide in slide out animation with Views, using the android ViewFlipper component and a number of translate animations. At the time I mentioned that this transitions animation was for views only and that there was a global control in the settings menu for enabling transitions for activities. At the time there did not seem to be a way of control the transitions for activities on a per Activity basis. That was back in Android 1.5, but since then things have move on some. With Android 2.0 it is now possible to control the transition animations for activities. These transitions can be enabled or disable on a per activity basis and it is also possible to set the in and out animation for each activity.

The first thing you need to know to override the activity transition is that there is a new function call in the Activity class called overridePendingTransistion. This function takes two arguments, the resource ID of the enter, or in, animation and the resource id of the exit, or out, animation. Also there is a new flag in the Intent class called FLAG_ACTIVITY_NO_ANIMATION, which gives control over which Activities transition Animations are shown.

So by using the new flag and the new function call it is now possible to control the transitions of your Activities in the same way as your Views. 

Android renderscript, more info' and an example application

Here's a few more snippets of information I've managed to uncover on android renderscript:
  • Compiled on the device
  • Uses acc compiler
  • No architectural support issues.
  • No external libraries
  • You cannot #include
  • No allocation allowed
  • Safe predictable
I admit some of these statements don't give too much away, but there's not too much else to go on at the moment. It does seem to point to a language that is compiled and is C like, but maybe with not all the power of C as allocations are not allowed.


Trying to shed some more light on things I had another look in the source code and found a few simple example Android applications usingrenderscript One of these simple example applications was called Fountain , it seemed to be one of the simplest applications so i thought it would be a good place to start.


The Android Fountain renderscript example 
What does this application do? Well I'm not totally sure because i haven't run it myself, and to be honest there are not many comments in the code, so it really is a case of read the code and work it out. My best guess is that it produces a Fountain like animation that randomly animates points on a screen generally moving up and outwards in a fountain like way. These animations start when a users touches the screen and originate from that point. This is my best guess at the moment from what I can make out in the code example.


OK so what does the code look like?. First lets have a look at the files and how they are layed out, the structure is :
  • Android.mk
  • AndroidManifest.xml
  • res
    • drawable
      • gadgets_clock_mp3.png
    • raw
      • fountain.c
  • src
    • com
      • android
        • fountain
        • Fountain.java
        • FountainRS.java
        • FountainView.java
Most of what we see here is a standard looking Android application. We have the basic android files such as the AndroidManifest file. Then we have our src directory that contains our android application source files, also we have the res directory, not unsual as it contains the drawable and raw directories, but as you can see the raw directory contains one very interesting and rather unusual file, the fountain.c file. This, it seems, is where therenderscript code resides, and the name does indeed suggest that it is  C code file. So lets have a look at what is contained in this file:
// Fountain test script
#pragma version(1)

int newPart = 0;

int main(int launchID) {
    int ct;
    int count = Control->count;
    int rate = Control->rate;
    float height = getHeight();
    struct point_s * p = (struct point_s *)point;

    if (rate) {
        float rMax = ((float)rate) * 0.005f;
        int x = Control->x;
        int y = Control->y;
        char r = Control->r * 255.f;
        char g = Control->g * 255.f;
        char b = Control->b * 255.f;
        struct point_s * np = &p[newPart];

        while (rate--) {
            vec2Rand((float *)np, rMax);
            np->x = x;
            np->y = y;
            np->r = r;
            np->g = g;
            np->b = b;
            np->a = 0xf0;
            newPart++;
            np++;
            if (newPart >= count) {
                newPart = 0;
                np = &p[newPart];
            }
        }
    }

    for (ct=0; ct < count; ct++) {
        float dy = p->dy + 0.15f;
        float posy = p->y + dy;
        if ((posy > height) && (dy > 0)) {
            dy *= -0.3f;
        }
        p->dy = dy;
        p->x += p->dx;
        p->y = posy;
        p++;
    }

    uploadToBufferObject(NAMED_PartBuffer);
    drawSimpleMesh(NAMED_PartMesh);
    return 1;
}
Yes, it is very C like. We have structs, pointers and chars. Starting at the top of the file. We have a Control structure or class that gives use a rate and a count as well as x,y and r,g,b values. Where does this Control structure get instantiated? I'll come back to this. Another structure that is also used in this code is point_s. This structure has a x and y coordinates, r,g,b values, which are likely to be Red, blue green, and an "a" value which is the alpha value. Without more information I cannot be sure exactly what is happening in this code, but I think that generally an array of points is given and then array of new points is generated, to allow some kind of animation.


Looking at the src code directory we have three .java files. Fountain.java, FountainView.java and FountainRS.java. Fountain.java is just the basic Android activity class that has an onCreate method that sets the contentView to an instance of FountainView. The Code for the FountainView.java file looks like this:
/*
 * Copyright (C) 2008 The Android Open Source Project
 *
 * 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 com.android.fountain;

import java.io.Writer;
import java.util.ArrayList;
import java.util.concurrent.Semaphore;

import android.renderscript.RSSurfaceView;
import android.renderscript.RenderScript;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.KeyEvent;
import android.view.MotionEvent;

public class FountainView extends RSSurfaceView {

    public FountainView(Context context) {
        super(context);
        //setFocusable(true);
    }

    private RenderScript mRS;
    private FountainRS mRender;

    private void destroyRS() {
        if(mRS != null) {
            mRS = null;
            destroyRenderScript();
        }
        java.lang.System.gc();
    }

    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
        super.surfaceChanged(holder, format, w, h);
        destroyRS();
        mRS = createRenderScript(false, true);
        mRender = new FountainRS();
        mRender.init(mRS, getResources(), w, h);
    }

    public void surfaceDestroyed(SurfaceHolder holder) {
        // Surface will be destroyed when we return
        destroyRS();
    }



    @Override
    public boolean onTouchEvent(MotionEvent ev)
    {
        int act = ev.getAction();
        if (act == ev.ACTION_UP) {
            mRender.newTouchPosition(0, 0, 0);
            return false;
        }
        float rate = (ev.getPressure() * 50.f);
        rate *= rate;
        if(rate > 2000.f) {
            rate = 2000.f;
        }
        mRender.newTouchPosition((int)ev.getX(), (int)ev.getY(), (int)rate);
        return true;
    }
}
The FountainView class is an Android View. As you can see from the code, FountainView extends a new type of Android view RSSufraceView. It also has references to a new RenderScript class and our defined FountainRS class. When creating a new surface in the surfacedChanged method a new RenderScript class and a new FountainRS class are created. We also call the init method on the FountainRS class and pass in several arguments, including a reference to the RenderScript object. So lets have a look at the FountainRS.java file:
/*
 * Copyright (C) 2008 The Android Open Source Project
 *
 * 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 com.android.fountain;

import android.content.res.Resources;
import android.renderscript.*;
import android.util.Log;


public class FountainRS {
    public static final int PART_COUNT = 20000;

    static class SomeData {
        public int x;
        public int y;
        public int rate;
        public int count;
        public float r;
        public float g;
        public float b;
    }

    public FountainRS() {
    }

    public void init(RenderScript rs, Resources res, int width, int height) {
        mRS = rs;
        mRes = res;
        initRS();
    }

    public void newTouchPosition(int x, int y, int rate) {
        if (mSD.rate == 0) {
            mSD.r = ((x & 0x1) != 0) ? 0.f : 1.f;
            mSD.g = ((x & 0x2) != 0) ? 0.f : 1.f;
            mSD.b = ((x & 0x4) != 0) ? 0.f : 1.f;
            if ((mSD.r + mSD.g + mSD.b) < 0.9f) {
                mSD.r = 0.8f;
                mSD.g = 0.5f;
                mSD.b = 1.f;
            }
        }
        mSD.rate = rate;
        mSD.x = x;
        mSD.y = y;
        mIntAlloc.data(mSD);
    }


    /////////////////////////////////////////

    private Resources mRes;

    private RenderScript mRS;
    private Allocation mIntAlloc;
    private SimpleMesh mSM;
    private SomeData mSD;
    private Type mSDType;

    private void initRS() {
        mSD = new SomeData();
        mSDType = Type.createFromClass(mRS, SomeData.class, 1, "SomeData");
        mIntAlloc = Allocation.createTyped(mRS, mSDType);
        mSD.count = PART_COUNT;
        mIntAlloc.data(mSD);

        Element.Builder eb = new Element.Builder(mRS);
        eb.addFloat(Element.DataKind.USER, "dx");
        eb.addFloat(Element.DataKind.USER, "dy");
        eb.addFloatXY("");
        eb.addUNorm8RGBA("");
        Element primElement = eb.create();


        SimpleMesh.Builder smb = new SimpleMesh.Builder(mRS);
        int vtxSlot = smb.addVertexType(primElement, PART_COUNT);
        smb.setPrimitive(Primitive.POINT);
        mSM = smb.create();
        mSM.setName("PartMesh");

        Allocation partAlloc = mSM.createVertexAllocation(vtxSlot);
        partAlloc.setName("PartBuffer");
        mSM.bindVertexAllocation(partAlloc, 0);

        // All setup of named objects should be done by this point
        // because we are about to compile the script.
        ScriptC.Builder sb = new ScriptC.Builder(mRS);
        sb.setScript(mRes, R.raw.fountain);
        sb.setRoot(true);
        sb.setType(mSDType, "Control", 0);
        sb.setType(mSM.getVertexType(0), "point", 1);
        Script script = sb.create();
        script.setClearColor(0.0f, 0.0f, 0.0f, 1.0f);

        script.bindAllocation(mIntAlloc, 0);
        script.bindAllocation(partAlloc, 1);
        mRS.contextBindRootScript(script);
    }

}
I'm not going to try and go through every detail of this code, but it seems that the interesting areas are in the initRS function. Here we have element builders, Simple Mesh builders and last but not least a script builder. Here we get a script builder instance, set the script to the fountain.c file. Set up some types such as Control and point (remember, these were used in the fountain.c file) and then create the script.


So there we have it, this is a quick peek into how Renderscript might be used. There are still a lot of unanswered questions yet, and there is still a lot more to learn about how renderscript will, and can be use, but i hope these few code snippets will at least give people a starting point. As usual, if anyone else out there has any interesting insights or comments I'd be really interested to hear them.

Friday, 20 November 2009

Android and RenderScript

It seems that the new and exciting high performance graphics technology for Android is RenderScript. There's not much detail as how to use RenderScript, but it is said to be a C-like language for high performance graphics programming, which helps you easily write efficient visual effects and animations in your Android applications. Also RenderScript isn’t released yet, as it isn’t finished. After having a dig around in the source could I found the java Libs for RenderScript here. I'm sure there will be more information on this new and exciting addition to the Android graphics framework soon. When i find out more I'll post it here. Hopefully I'll also have a few tutorials on RenderScript soon.

Tuesday, 3 November 2009

Android UI and Animations, what's new?


Over the last few days I've been looking at what's new for User interfaces and animations in the latest two releases of Android. Of course there have been some big changes such as the addition of gesture recognition and multi-touch, but i wanted to take a look at some of changes that have been less well publicised, but are still well worth knowing about. Here's some of the things that I found:



Android 1.6
For Android 1.6 here are some of the UI and Animation updates.

Interpolators
In Android 1.6 we've had a whole new set of Interpolators. Remember, Interpolators control animations. Each animation has it's own interpolator. A linear Interpolator means that the animation would be displayed at a constant rate for the animation duration, while and Accelerate Interpolator would mean that the animation would accelerate (get faster) towards the end of its animation duration. The new Interpolators are can all be found in android.view.animation and they are:

  • AnticipateInterpolator: An interpolator where the change starts backward then flings forward.
  • AnticipateOvershootInterpolator: An interpolator where the change starts backward then flings forward and overshoots the target value and finally goes back to the final value.
  • BounceInterpolator: An interpolator where the change bounces at the end.
  • OvershootInterpolator: An interpolator where the change flings forward and overshoots the last value then comes back.

For me these are an interesting addition to the animations for the android frame work. Taken together they can be used to create animations with a springy, bouncy and elastic feel, which you'll be very familiar with if you've ever used an iphone. ;)

Here's an example of using the OvershootInterpolator when applied to the ViewFlipper slide animation shown in a previous post:









Notice the slight overshoot at the end of the animation...

On click listeners
Another interesting addition to the UI framework in Android 1.6 is the ability to define click listeners in you XML layout file like this:
<Button android:onClick="myClickHandler" />

Now all you need is a public myClickHandler function that takes a View as an argument:
class MyActivity extends Activity {
public void myClickHandler(View target)
{ // Do stuff }
}
This gives the programmer a much more concise way of declaring and implementing click listeners.

For more info' on the changes to the UI framework in Android 1.6 see the post here.

Android 2.0 UI changes
For Android 2.0 we have:

New system themes
New system themes in android.R.style to easily display activities on top of the current system wallpaper. The new themes available are:
Theme_Light_WallpaperSettings
Theme_Wallpaper
Theme_WallpaperSettings
Theme_Wallpaper_NoTitleBar
Theme_Wallpaper_NoTitleBar_Fullscreen

WallpaperManager API
New WallpaperManager API replaces and extends the wallpaper APIs that were previously in Context, to allow applications to request and set the system wallpaper. Here there a two new methods in Animation called setDetachWallpaper and getDetachWallpaper. By setting Detached wallpaper to true an animation will only be applied to the window, and the wallpaper behind it will remain static.

Key Event Dispatching
KeyEvent has new key dispatching APIs, to help implement action-on-up and long press behavior, as well a new mechanism to cancel key presses (for virtual keys).

One last interesting thing on UI and Animations for Android 2.0. I've heard rumours that there is a "new exciting graphics technology" that is being worked on. I couldn't see any real evidence of this on the current android 2.0 release, but I read on blogs that there is another minor update due before the end of the year. So who knows, maybe this new graphics technology will be part of that minor release. If I find anything I will of course write about it and let others know.