This exercise TRY to simulate the effect on Android. The code for motion aftereffect generation is modified from http://en.wikipedia.org/wiki/File:Illusion_movie.ogg (c source code), with my optimization. But the effect seem not good! I test it on Nexus 7 tablet.
To see the illusions: Run the app on Android Tablet, and stare to the center of the image. After around one minute, look away (for example look to a face or to your hands). For few seconds everything you see will appear to distort. Or touch the motion picture on screen, it will stop and change to another ImageView.
Motion AfterEffect (MAE) |
The main part is in MySurfaceView.java.
package com.example.androidsurfaceview;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class MySurfaceView extends SurfaceView {
private SurfaceHolder surfaceHolder;
private MyThread myThread;
MainActivity mainActivity;
int T;
static final float freq = 80;
public MySurfaceView(Context context) {
super(context);
init(context);
}
public MySurfaceView(Context context,
AttributeSet attrs) {
super(context, attrs);
init(context);
}
public MySurfaceView(Context context,
AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
private void init(Context c){
mainActivity = (MainActivity)c;
T = 0;
myThread = new MyThread(this);
surfaceHolder = getHolder();
surfaceHolder.addCallback(new SurfaceHolder.Callback(){
@Override
public void surfaceCreated(SurfaceHolder holder) {
myThread.setRunning(true);
myThread.start();
}
@Override
public void surfaceChanged(SurfaceHolder holder,
int format, int width, int height) {
// TODO Auto-generated method stub
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
myThread.setRunning(false);
while (retry) {
try {
myThread.join();
retry = false;
} catch (InterruptedException e) {
}
}
}});
}
protected void drawSomething(Canvas canvas) {
int sizex = getWidth();
int sizey = getHeight();
float divby_sizex_sq = 1.0f/((float)sizex * (float)sizex);
int[] data = new int[sizex * sizey];
int m;
T++;
if(T >= 1200){
T = 0;
}
float halfT = T * 0.5f;
for (int j=0;j<sizey;j++){
float y0 = j*2-sizey;
float y2_2 = y0 * y0 * divby_sizex_sq;
float absY = Math.abs(y0/(float)sizey);
float halfT_plus_absY = absY + halfT;
float halfT_neg_plus_absY = absY - halfT;
int j_multi_sizex = j*sizex;
for (int i=0;i<sizex;i++){
float x=(i*2-sizex)/(float)sizex;
//0.2 instead of 0.1 to have a bigger circle
if ((x*x + y2_2)<0.2){
m = (int) (Math.sin((halfT_plus_absY+Math.abs(x))*freq)*127.0+128) & 0xFF;
}else {
m = (int) (Math.sin((halfT_neg_plus_absY+Math.abs(x))*freq)*127.0+128) & 0xFF;
}
data[i+j_multi_sizex] = 0xFF000000
+ (m << 16)
+ (m << 8)
+ m;
}
}
Bitmap bm = Bitmap.createBitmap(data, sizex, sizey, Bitmap.Config.ARGB_8888);
canvas.drawBitmap(bm, 0, 0, null);
}
}
MyThread.java
package com.example.androidsurfaceview;
import android.graphics.Canvas;
public class MyThread extends Thread {
MySurfaceView myView;
private boolean running = false;
public MyThread(MySurfaceView view) {
myView = view;
}
public void setRunning(boolean run) {
running = run;
}
@Override
public void run() {
while(running){
Canvas canvas = myView.getHolder().lockCanvas();
if(canvas != null){
synchronized (myView.getHolder()) {
myView.drawSomething(canvas);
}
myView.getHolder().unlockCanvasAndPost(canvas);
}
/*
try {
sleep(30);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
*/
}
}
}
/res/layout/activity_main.xml, where @drawable/android_er is a 640x480 .png in /res/drawable/ folder.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="@android:color/background_dark"
tools:context="com.example.androidsurfaceview.MainActivity" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:autoLink="web"
android:text="http://android-er.blogspot.com/"
android:textStyle="bold" />
<FrameLayout
android:layout_width="640dp"
android:layout_height="480dp"
android:layout_gravity="center">
<com.example.androidsurfaceview.MySurfaceView
android:id="@+id/myview"
android:layout_width="640dp"
android:layout_height="480dp"
android:layout_gravity="center" />
<ImageView
android:id="@+id/imageicon"
android:layout_width="640dp"
android:layout_height="480dp"
android:layout_gravity="center"
android:src="@drawable/android_er"
android:visibility="invisible"/>
</FrameLayout>
</LinearLayout>
MainActivity.java. The Motion graph will run when the app start. When user touch on it, it will show the ImageView of "@drawable/android_er".
package com.example.androidsurfaceview;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageView;
public class MainActivity extends Activity {
ImageView imageIcon;
MySurfaceView mySurfaceView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mySurfaceView = (MySurfaceView)findViewById(R.id.myview);
imageIcon = (ImageView)findViewById(R.id.imageicon);
mySurfaceView.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
imageIcon.setVisibility(View.VISIBLE);
mySurfaceView.setVisibility(View.INVISIBLE);
}});
}
}
Modify AndroidManifest.xml to force the app run in landscape mode.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.androidsurfaceview"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="19" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.example.androidsurfaceview.MainActivity"
android:label="@string/app_name"
android:screenOrientation="landscape" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Download the files.
Download and try the APK.
No comments:
Post a Comment