I'm following the Android Game Programming for Dummies by: Derek James. It looks outdated too me because in the book it doesn't include the fragment_main. So I just copied the fragment_main and replaced it in the activity_main and deleted the fragment_main (I followed the how to get rid of fragment_main tutorial on this forum).
I'm trying to make the whack a mole game in the book.
Anyways I get two errors when I followed the book and it said I can run the program now but I am unable to do that because of:
background cannot be resolved or is not a field
title cannot be resolved or is not a field
I have everything the same as the book but why do I get these errors, I checked all over Google to find an answer or something similar but I can't find the error, I would really appreciate if someone can help me out. Sorry for writing a whole paragraph but I should let you know what I did.
This is my WhackAMoleView.java
package com.whackamole;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class WhackAMoleView extends SurfaceView implements
SurfaceHolder.Callback {
private Context myContext;
private SurfaceHolder mySurfaceHolder;
private Bitmap backgroundImg;
private int screenW = 1;
private int screenH = 1;
private boolean running = false;
private boolean onTitle = true;
private WhackAMoleThread thread;
public WhackAMoleView(Context context, AttributeSet attrs) {
super(context, attrs);
SurfaceHolder holder = getHolder();
holder.addCallback(this);
thread = new WhackAMoleThread(holder, context, new Handler()
{
#Override
public void handleMessage(Message m) {
}
});
setFocusable(true);
}
public WhackAMoleThread getThread() {
return thread;
}
class WhackAMoleThread extends Thread {
public WhackAMoleThread(SurfaceHolder surfaceHolder, Context context,
Handler handler) {
mySurfaceHolder = surfaceHolder;
myContext = context;
backgroundImg = BitmapFactory.decodeResource(
context.getResources(), R.drawable.title);
}
#Override
public void run() {
while (running) {
Canvas c = null;
try {
c = mySurfaceHolder.lockCanvas(null);
synchronized (mySurfaceHolder) {
draw(c);
}
} finally {
if (c != null) {
mySurfaceHolderunlockCanvasAndPost(c);
}
}
}
}
private void mySurfaceHolderunlockCanvasAndPost(Canvas c) {
// TODO Auto-generated method stub
}
private void draw(Canvas canvas) {
try {
canvas.drawBitmap(backgroundImg, 0, 0, null);
} catch (Exception e) {
}
}
boolean doTouchEvent(MotionEvent event) {
synchronized (mySurfaceHolder) {
int eventaction = event.getAction();
int x = (int) event.getX();
int Y = (int) event.getY();
switch (eventaction) {
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
if (onTitle) {
backgroundImg = BitmapFactory
.decodeResource(myContext.getResources(),
R.drawable.background);
backgroundImg = Bitmap.createScaledBitmap(
backgroundImg, screenW, screenH, true);
onTitle = false;
}
break;
}
}
return true;
}
public void setSurfaceSize(int width, int height) {
synchronized (mySurfaceHolder) {
screenW = width;
screenH = height;
backgroundImg = Bitmap.createScaledBitmap(backgroundImg, width,
height, true);
}
}
public void setRunning(boolean b) {
running = b;
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
return thread.doTouchEvent(event);
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
thread.setSurfaceSize(width, height);
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
thread.setRunning(true);
if (thread.getState() == Thread.State.NEW) {
thread.start();
}
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
thread.setRunning(false);
}
}
This is my MainActivity.java
package com.whackamole;
import android.app.Activity;
import android.os.Bundle;
import android.view.Window;
import android.view.WindowManager;
public class MainActivity extends Activity {
private WhackAMoleView myWhackAMoleView;
/**Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags
(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.whackamole_layout);
myWhackAMoleView = (WhackAMoleView)
findViewById(R.id.mole);
myWhackAMoleView.setKeepScreenOn(true);
}
}
This is my AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.whackamole"
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">
<activity
android:name="com.whackamole.MainActivity"
android:screenOrientation="landscape"
android:configChanges="keyboardHidden|orientation"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
mySurfaceHolderunlockCanvasAndPost(c);
}
}
}
}
mySurfaceHolderunlockCanvasAndPost should be mySurfaceHolder.unlockCanvasAndPost
*private void mySurfaceHolderunlockCanvasAndPost(Canvas c) {
// TODO Auto-generated method stub
}* should not be here
Related
I'm new here. I'm trying to make a game with Android Studio and I've a problem: the Android Studio emulator load every Activity and the background loop of the game, my phone doesn't the background loop game.
This is my code.
BackGround Java class
package com.example.francesco.fraedogame;
import android.graphics.Bitmap;
import android.graphics.Canvas;
public class Background {
private Bitmap image;
private int x, y, dx;
public Background(Bitmap res){
image = res;
}
public void update(){
x+=dx;
if(x<-GamePanel.WIDTH){
x = 0;
}
}
public void draw(Canvas canvas){
canvas.drawBitmap(image, x, y, null);
if(x < 0){
canvas.drawBitmap(image, x+GamePanel.WIDTH, y, null);
}
}
public void setVector(int dx){
this.dx = dx;
}
}
MainThread Java class (for the loop game)
package com.example.francesco.fraedogame;
import android.graphics.Canvas;
import android.view.SurfaceHolder;
public class MainThread extends Thread {
private int FPS = 30;
private double averageFPS;
private SurfaceHolder surfaceHolder;
private GamePanel gamePanel;
private boolean running;
private static Canvas canvas;
public MainThread(SurfaceHolder surfaceHolder, GamePanel gamePanel){
super();
this.surfaceHolder = surfaceHolder;
this.gamePanel = gamePanel;
}
#Override
public void run(){
long startTime;
long timeMillis;
long waitTime;
long totalTime = 0;
int frameCount = 0;
long targetTime = 1000/FPS;
while(running){
startTime = System.nanoTime();
canvas = null;
//Lock Canvas
try{
canvas = this.surfaceHolder.lockCanvas();
synchronized (surfaceHolder){
this.gamePanel.update();
this.gamePanel.draw(canvas);
}
}
catch(Exception e){
}
finally {
if(canvas!=null){
try{
surfaceHolder.unlockCanvasAndPost(canvas);
}
catch(Exception e){
e.printStackTrace();
}
}
}
timeMillis = (System.nanoTime() - startTime)/1000000;
waitTime = targetTime - timeMillis;
try{
this.sleep(waitTime);
}
catch(Exception e){
}
totalTime += System.nanoTime() - startTime;
frameCount++;
if(frameCount == FPS){
averageFPS = 1000/((totalTime/frameCount)/1000000);
frameCount = 0;
totalTime = 0;
System.out.println(averageFPS);
}
}
}
public void setRunning(boolean b){
running = b;
}
}
The GamePanel Java class
package com.example.francesco.fraedogame;
import android.content.Context;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class GamePanel extends SurfaceView implements SurfaceHolder.Callback{
//Image Background dimension
public static final int WIDTH = 856;
public static final int HEIGHT = 480;
private MainThread thread;
private Background bg;
public GamePanel(Context context){
super(context);
//Add the callBack to the SurfaceHolder for intercept events
getHolder().addCallback(this);
thread = new MainThread(getHolder(), this);
//GamePanel focusable for handle events
setFocusable(true);
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height){
}
#Override
public void surfaceDestroyed(SurfaceHolder holder){
//End the loop
boolean retry = true;
while(retry){
try{
thread.setRunning(false);
thread.join();
}
catch(InterruptedException e){
e.printStackTrace();
}
retry = false;
}
}
#Override
public void surfaceCreated(SurfaceHolder holder){
//Set the Background
bg = new Background(BitmapFactory.decodeResource(getResources(), R.drawable.background));
bg.setVector(-5);
//Start the loop
thread.setRunning(true);
thread.start();
}
#Override
//Handle touch screen motion events
public boolean onTouchEvent(MotionEvent event){
return super.onTouchEvent(event);
}
public void update(){
bg.update();
}
#Override
public void draw(Canvas canvas) {
final float scaleFactoryX = getWidth()/WIDTH;
final float scaleFactoryY = getHeight()/HEIGHT;
if (canvas != null) {
final int savedState= canvas.save();
canvas.scale(scaleFactoryX, scaleFactoryY);
bg.draw(canvas);
canvas.restoreToCount(savedState);
}
}
}
The manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.francesco.fraedogame">
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".HomePage">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".SecondHome" />
<activity android:name=".game"
android:screenOrientation="landscape"/>
<activity android:name=".options" />
<activity android:name=".records"></activity>
</application>
</manifest>
My issue is that no matter what I do, no matter how many questions and answers I read through on the internet, I cant get a simple rectangle to draw on my android device screen. Let me rephrase that, it shows up on screen but it wont change. I cant get an animation to update. onDraw() never calls multiple times, just once on startup. why? Here is my view objects code:
package prospect_industries.es;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
public class TestView extends View {
//Variables
public static final int SIZE = 300;
public float TOP = 0.0f;
public float LEFT = 0.0f;
public float RIGHT = 100f;
public float BOTTOM = 100f;
private Paint rectanglePaint;
private RectF rect1;
//Constructors
public TestView(final Context context, final AttributeSet attrs, final int defStyle) {
super(context, attrs, defStyle);
init();
}
public TestView(final Context context, final AttributeSet attrs) {
super(context, attrs, 0);
init();
}
public TestView(final Context context) {
super(context, null, 0);
init();
}
//View methods
#Override
protected void onDraw(final Canvas canvas){
canvas.drawRect(rect1, rectanglePaint);
Log.i("test1", "in onDraw");
}
#Override
protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
final int chosenWidth = chooseDimension(widthMode, widthSize);
final int chosenHeight = chooseDimension(heightMode, heightSize);
setMeasuredDimension(chosenWidth, chosenHeight);
Log.i("test1", String.valueOf(chosenWidth));
Log.i("test1",String.valueOf(chosenHeight));
}
//Class Methods
private int chooseDimension(final int mode, final int size) {
switch (mode) {
case MeasureSpec.AT_MOST:
case MeasureSpec.EXACTLY:
return size;
case MeasureSpec.UNSPECIFIED:
default:
return getDefaultDimension();
}
}
private int getDefaultDimension() { return SIZE; }
private void init(){
requestFocus();
rectanglePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
rectanglePaint.setColor(-1);
rectanglePaint.setStyle(Paint.Style.FILL);
rect1 = new RectF(LEFT, TOP, RIGHT, BOTTOM);
}
public void update() {
RIGHT += 10;
BOTTOM += 10;
rect1 = new RectF(LEFT, TOP, RIGHT, BOTTOM);
invalidate();
Log.i("test1", "in update");
}
}
Here is my main class which has a few methods for other things Im working on as well as a timer which calls the update() method inside of my test view object.
package prospect_industries.es;
import android.app.Activity;
import android.content.Context;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import java.io.IOException;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
public class MainActivity extends Activity {
private boolean setup = false;
public int waitDelay = 1000; //Milliseconds - currently 1 second
private Timer checkTime;
private TimerTask listen;
private MediaRecorder mRecorder;
//Splashscreen
private Timer splashScreen;
private int waitTime = 3000; //3 seconds
private GaugeView mGaugeView;
private final Random RAND = new Random();
private TestView testview;
private SurfaceHolder surfaceHolder;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.content_main);
//mGaugeView = (GaugeView) findViewById(R.id.gauge_view);
testview = (TestView) findViewById(R.id.test_view);
}
#Override
public void onStart() {
super.onStart();
//Timers
//1 second wait tick
checkTime = new Timer();
checkTime.schedule(new TimerTask() {
public void run() {
MainActivity.this.runOnUiThread(new Runnable() {
public void run() {
//mGaugeView.setTargetValue(RAND.nextInt(101));
testview.update();
}
});
}
}, 0, waitDelay);
//Set splash screen wait timer
splashScreen = new Timer();
splashScreen.schedule(new TimerTask() {
public void run() {
MainActivity.this.runOnUiThread(new Runnable() {
public void run() {
setContentView(R.layout.content_main);
}
});
splashScreen.cancel();
}
}, waitTime);
//set welcome screen
setContentView(R.layout.activity_welcome);
}
#Override
public void onStop() {
super.onStop();
if(checkTime != null) {
checkTime.cancel();
stop();
}
}
public void stop() {
if (mRecorder != null) {
mRecorder.stop();
mRecorder.release();
mRecorder = null;
}
}
public double getAmplitude() {
if (mRecorder != null)
return mRecorder.getMaxAmplitude();
else
return 0;
}
public void checkSound(){
if (mRecorder == null) {
mRecorder = new MediaRecorder();
mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
mRecorder.setOutputFile("/dev/null");
try {
mRecorder.prepare();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
mRecorder.start();
}
}
private static class MainView extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder surfaceHolder;
public MainView(Context context) {
super(context);
surfaceHolder = getHolder();
surfaceHolder.addCallback(this);
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
// TODO Auto-generated method stub
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
}
}
}
Lastly, here is the xml layout file which loads in the test view object.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#103681"
tools:context="prospect_industries.es.MainActivity">
<prospect_industries.es.TestView
android:layout_width="200dp"
android:layout_height="200dp"
android:id="#+id/test_view"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true" />
</RelativeLayout>
I have been looking all over stackExchange for hours but I cant fix my problem, onDraw is only called once and never again no matter what I do. Right now the rectangle should be expanding out but it isnt being redrawn.
The problem is that you initialize the rectangle to be 1px wide and 1px tall and never resize it. You should be able to see 1 white pixel somewhere in the top left corner of your TestView.
Try changing the rect1 size to 0,0,100,100 and see if the problem persists.
public static final float TOP = 0.0f;
public static final float LEFT = 0.0f;
public static final float RIGHT = 100.0f;
public static final float BOTTOM = 100.0f;
I'm a trying to render a Google Cardboard app rendering droidar objects, but for now i'm trying to display a simple cardboardview using the official tutorial (https://developers.google.com/cardboard/android/get-started) but I have an exception :
Caused by: android.view.InflateException: Binary XML file line #21: Error inflating class com.google.vrtoolkit.cardboard.CardboardView
And i can't find a solution, it's starting to drive me crazy...
Could you help me, please? Here's my code :
My Manifest.xml :
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="lp.s3im.cardboarddemo"
android:versionCode="1"
android:versionName="1.0" >
<uses-permission android:name="android.permission.NFC" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-sdk
android:minSdkVersion="15"
android:targetSdkVersion="19" />
<uses-feature
android:glEsVersion="0x00020000"
android:required="true" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name=".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" />
<category android:name="com.google.intent.category.CARDBOARD" />
</intent-filter>
</activity>
</application>
</manifest>
MainActivity :
package lp.s3im.cardboarddemo;
import java.nio.FloatBuffer;
import javax.microedition.khronos.egl.EGLConfig;
import com.google.vrtoolkit.cardboard.CardboardActivity;
import com.google.vrtoolkit.cardboard.CardboardView;
import com.google.vrtoolkit.cardboard.Eye;
import com.google.vrtoolkit.cardboard.HeadTransform;
import com.google.vrtoolkit.cardboard.Viewport;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.os.Vibrator;
import android.view.Menu;
import android.view.MenuItem;
public class MainActivity extends CardboardActivity implements
CardboardView.StereoRenderer {
private static final String TAG = "MainActivity";
private static final float Z_NEAR = 0.1f;
private static final float Z_FAR = 100.0f;
private static final float CAMERA_Z = 0.01f;
private static final float TIME_DELTA = 0.3f;
private static final float YAW_LIMIT = 0.12f;
private static final float PITCH_LIMIT = 0.12f;
private static final int COORDS_PER_VERTEX = 3;
// We keep the light always position just above the user.
private static final float[] LIGHT_POS_IN_WORLD_SPACE = new float[] { 0.0f,
2.0f, 0.0f, 1.0f };
private final float[] lightPosInEyeSpace = new float[4];
private FloatBuffer floorVertices;
private FloatBuffer floorColors;
private FloatBuffer floorNormals;
private FloatBuffer cubeVertices;
private FloatBuffer cubeColors;
private FloatBuffer cubeFoundColors;
private FloatBuffer cubeNormals;
private int cubeProgram;
private int floorProgram;
private int cubePositionParam;
private int cubeNormalParam;
private int cubeColorParam;
private int cubeModelParam;
private int cubeModelViewParam;
private int cubeModelViewProjectionParam;
private int cubeLightPosParam;
private int floorPositionParam;
private int floorNormalParam;
private int floorColorParam;
private int floorModelParam;
private int floorModelViewParam;
private int floorModelViewProjectionParam;
private int floorLightPosParam;
private float[] modelCube;
private float[] camera;
private float[] view;
private float[] headView;
private float[] modelViewProjection;
private float[] modelView;
private float[] modelFloor;
private int score = 0;
private float objectDistance = 12f;
private float floorDepth = 20f;
private Vibrator vibrator;
// private CardboardOverlayView overlayView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
CardboardView cardboardView = (CardboardView) findViewById(R.id.cardboard_view);
// Associate a CardboardView.StereoRenderer with cardboardView.
cardboardView.setRenderer(this);
// Associate the cardboardView with this activity.
setCardboardView(cardboardView);
// Initialize other objects here.
modelCube = new float[16];
camera = new float[16];
view = new float[16];
modelViewProjection = new float[16];
modelView = new float[16];
modelFloor = new float[16];
headView = new float[16];
vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public void onDrawEye(Eye arg0) {
// TODO Auto-generated method stub
}
#Override
public void onFinishFrame(Viewport arg0) {
// TODO Auto-generated method stub
}
#Override
public void onNewFrame(HeadTransform arg0) {
// TODO Auto-generated method stub
arg0.getHeadView(headView, 0);
}
#Override
public void onRendererShutdown() {
// TODO Auto-generated method stub
}
#Override
public void onSurfaceChanged(int arg0, int arg1) {
// TODO Auto-generated method stub
}
#Override
public void onSurfaceCreated(EGLConfig arg0) {
// TODO Auto-generated method stub
}
}
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context="lp.s3im.cardboarddemo.MainActivity" >
<com.google.vrtoolkit.cardboard.CardboardView
android:id="#+id/cardboard_view"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
Edit : With the following code i can display the camera with the starpreview method, but i can't use the preview of the andAR library (https://code.google.com/p/andar/), which does a black screen. I don"t understand if it is because it's overloaded or not.
package edu.dhbw.andar.sample;
import java.io.IOException;
import java.util.List;
import android.content.Intent;
import android.hardware.Camera;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.WindowManager;
import edu.dhbw.andar.ARToolkit;
import edu.dhbw.andar.AndARActivity;
import edu.dhbw.andar.exceptions.AndARException;
/**
* Example of an application that makes use of the AndAR toolkit.
*
* #author Tobi
*
*/
public class CustomActivity extends AndARActivity implements SurfaceHolder.Callback {
CustomObject someObject;
ARToolkit artoolkit;
SurfaceView surfaceView;
SurfaceHolder surfaceHolder;
Camera camera;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
CustomRenderer renderer = new CustomRenderer();// optional, may be set
// to null
super.setNonARRenderer(renderer);// or might be omited
try {
// register a object for each marker type
artoolkit = super.getArtoolkit();
someObject = new CustomObject("test", "patt.hiro", 80.0,
new double[] { 0, 0 });
artoolkit.registerARObject(someObject);
someObject = new CustomObject("test", "android.patt", 80.0,
new double[] { 0, 0 });
artoolkit.registerARObject(someObject);
someObject = new CustomObject("test", "barcode.patt", 80.0,
new double[] { 0, 0 });
artoolkit.registerARObject(someObject);
} catch (AndARException ex) {
// handle the exception, that means: show the user what happened
System.out.println("");
}
surfaceView = (SurfaceView) findViewById(R.id.surfaceView);
surfaceHolder = surfaceView.getHolder();
surfaceHolder.addCallback(this);
surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
// TODO Auto-generated method stub
startCamera(holder, width, height);
}
#Override
public SurfaceView getSurfaceView() {
// TODO Auto-generated method stub
return super.getSurfaceView();
}
#Override
public void startPreview() {
// TODO Auto-generated method stub
super.startPreview();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
super.surfaceDestroyed(holder);
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
camera = Camera.open();
try {
camera.setPreviewDisplay(holder);
} catch (IOException e) {
}
}
/**
* Inform the user about exceptions that occurred in background threads.
* This exception is rather severe and can not be recovered from. TODO
* Inform the user and shut down the application.
*/
#Override
public void uncaughtException(Thread thread, Throwable ex) {
Log.e("AndAR EXCEPTION", ex.getMessage());
finish();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
// getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
switch (id) {
// case R.id.settings:
// break;
default:
break;
}
return super.onOptionsItemSelected(item);
}
private void startCamera(SurfaceHolder sh, int width, int height) {
Camera.Parameters parameters = camera.getParameters();
List<Camera.Size> sizes = parameters.getSupportedPreviewSizes();
Camera.Size cs = sizes.get(0);
parameters.setPreviewSize(cs.width, cs.height);
camera.setParameters(parameters);
try {
camera.setPreviewDisplay(sh);
} catch (Exception e) {
}
camera.startPreview();
}
private void stopCamera() {
//camera.removeCallback(this);
camera.stopPreview();
camera.release();
}
}
Include the libprotobuf-java-2.3-nano.jar file in your build path.
I am new to Android so I am making a coloring book app just to get myself acquainted to android programming. I have looked up my problem extensively and implemented the solutions but still no progress.
I have an activity 'ColoringActivity' which calls a class 'PaintView' which extends surfaceview. I am trying to update the canvas in a separate thread. I also have a button in the layout which takes the user to another activity for picking colors. The problem is that when the user returns after choosing the color, the canvas becomes empty and I cant draw on the canvas anymore. I think i somehow loose the thread in between activities and although the thread is running in the background, I have no access to it.
I read on this forum that I must implement pause() and resume() methods in the thread class and basically kill the thread when I go to another activity and restart it when I return. Also I read I have to override onPause() and onResume() method in activity class and construct the surfaceview in onResume() so that it is constructed every time user returns to this activity.
I am sorry if it doesnt make much sense because I am lost as well.
My 'ColoringActivity':
package com.ali.coloryourself;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Toast;
public class ColoringActivity extends Activity {
private static final int COLOR_REQUEST_CODE = 100;
public static String file;
public static Bitmap bitmap;
BitmapFactory.Options options;
PaintView paintView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_draw);
Intent intent = getIntent();
file = intent.getStringExtra("fileName");
// paintView = (PaintView) findViewById(R.id.drawingSurface);
}
#Override
protected void onResume() {
paintView = (PaintView) findViewById(R.id.drawingSurface);
paintView.getThread().resume();
super.onResume();
}
#Override
protected void onPause() {
paintView.getThread().pause();
super.onPause();
}
public void pickColor(View v) {
paintView.getThread().pause();
Intent colorIntent = new Intent(this, ColorPickerActivity.class);
startActivityForResult(colorIntent, COLOR_REQUEST_CODE);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode != RESULT_CANCELED) {
if (requestCode == COLOR_REQUEST_CODE) {
int color = data.getIntExtra("Color", -1);
// paintView.getPaint().setColor(color);
}
}
}
}
My 'PaintView' class:
package com.ali.coloryourself;
import android.R.color;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
class PaintView extends SurfaceView implements SurfaceHolder.Callback {
private Paint paint = new Paint();
private Canvas canvas;
private PaintThread thread;
private Path path = new Path();
private Bitmap bitmap;
public PaintView(Context context, AttributeSet attrs) {
super(context, attrs);
SurfaceHolder holder = getHolder();
holder.addCallback(this);
paint.setColor(Color.WHITE);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setStrokeWidth(3);
setThread(new PaintThread(holder));
}
class PaintThread extends Thread {
private boolean mRun;
private SurfaceHolder mSurfaceHolder;
private int mMode;
public static final int STATE_PAUSE = 2;
public static final int STATE_RUNNING = 4;
public PaintThread(SurfaceHolder surfaceHolder) {
mSurfaceHolder = surfaceHolder;
}
#Override
public void run() {
while (mRun) {
try {
canvas = mSurfaceHolder.lockCanvas(null);
if (mMode == STATE_RUNNING) {
if (bitmap == null) {
bitmap = Bitmap.createBitmap(1, 1,
Bitmap.Config.ARGB_8888);
}
}
doDraw(canvas);
canvas.drawBitmap(bitmap, 0, 0, null);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (canvas != null) {
mSurfaceHolder.unlockCanvasAndPost(canvas);
}
}
}
}
private void doDraw(Canvas canvas) {
canvas.drawPath(path, paint);
}
public void setRunning(boolean b) {
mRun = b;
}
public void pause() {
if (mMode == STATE_RUNNING)
setState(STATE_PAUSE);
}
public void resume() {
setState(STATE_RUNNING);
}
public void setState(int mode) {
synchronized (mSurfaceHolder) {
mMode = mode;
}
}
}
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
// Log.d("Touch", "I am touching");
float eventX = event.getX();
float eventY = event.getY();
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
path.moveTo(eventX, eventY);
return true;
case MotionEvent.ACTION_MOVE:
path.lineTo(eventX, eventY);
break;
case MotionEvent.ACTION_UP:
// nothing to do
break;
default:
return false;
}
return true;
}
public void surfaceCreated(SurfaceHolder holder) {
if (getThread().getState() == Thread.State.NEW) {
getThread().setRunning(true);
getThread().start();
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
getThread().setRunning(false);
getThread().resume();
while (retry) {
try {
getThread().join();
retry = false;
} catch (InterruptedException e) {
}
}
}
public Paint getPaint() {
return paint;
}
public void setPaint(int color) {
this.paint.setColor(color);
}
public PaintThread getThread() {
return thread;
}
public void setThread(PaintThread thread) {
this.thread = thread;
}
}
my 'activity_draw.xml'
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<Button
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="10dp"
android:onClick="pickColor"
android:text="Pick Color" />
<com.ali.coloryourself.PaintView
android:id="#+id/drawingSurface"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#+id/button1"
android:layout_marginTop="10dp"/>
</RelativeLayout>
I know I am missing some very basic thread concept. I need to allow the user to pick color and return and be able to continue drawing. I will be extremely grateful for your help.
I think I have found an answer although I am not sure if it is a good programming practice. I found out that my surface view and thread were created once 'ColoringActivity' was created and destroyed every time 'ColoringActivity' went to background. But once 'ColoringActivity' was restarted and resumed, surface view and thread were not recreated. So i moved the following line
setContentView(R.layout.activity_draw);
to onResume() method and now I can draw on the canvas every time. Now I just need to save the canvas and re load it when the activity comes back on to start off the coloring where the user left it.
What is wrong with my coding clicking settings will crash app.
I cant read default settings values from prefs.xml
image sequence working like i want and now it's
moving right to left while images continue change (like a video)
someone genious see any problems ? :)
AndroidManifest.xml
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.mywallpaper"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="7" android:targetSdkVersion="12" />
<uses-feature android:name="android.software.live_wallpaper" />
<uses-permission android:name="android.permission.SET_WALLPAPER" />
<uses-permission android:name="android.permission.BIND_WALLPAPER" />
<application
android:label="#string/app_name"
android:icon="#drawable/ic_launcher"
android:theme="#style/AppTheme">
<service
android:label="#string/app_name"
android:name=".MyWallpaperService"
android:enabled="true"
android:permission="android.permission.BIND_WALLPAPER">
<intent-filter android:priority="1">
<action
android:name="android.service.wallpaper.WallpaperService">
</action>
</intent-filter>
<meta-data
android:name="android.service.wallpaper"
android:resource="#xml/wallpaper" >
</meta-data>
</service>
<activity
android:label="myPrefs"
android:name="com.example.mywallpaper.Prefs"
android:permission="android.permission.BIND_WALLPAPER"
android:enabled="true"
android:exported="true">
<intent-filter>
<category android:name="android.intent.category.PREFERENCE" />
</intent-filter>
</activity>
</application>
</manifest>
wallpaper.xml
<wallpaper
xmlns:android="http://schemas.android.com/apk/res/android"
android:name="something"
android:thumbnail="#drawable/ic_launcher"
android:description="#string/app_name"
android:settingsActivity="com.example.mywallpaper.Prefs">
</wallpaper>
prefs.xml
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
android:title="Title Preference"
android:key="myPrefs">
<CheckBoxPreference
android:title="Touch"
android:key="touch"
android:summary="Touch enable"
android:defaultValue="true"
/>
<EditTextPreference
android:title="Speed"
android:key="speed"
android:summary="Animation speed"
android:defaultValue="500"
/>
</PreferenceScreen>
Prefs.java
package com.example.mywallpaper;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceActivity;
public class Prefs extends PreferenceActivity
implements
SharedPreferences.OnSharedPreferenceChangeListener {
#SuppressWarnings("deprecation")
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getPreferenceManager().setSharedPreferencesName(MyWallpaperService.SHARED_PREFS_NAME);
addPreferencesFromResource(R.xml.prefs);
getPreferenceManager().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
}
#Override
protected void onResume() {
super.onResume();
}
#SuppressWarnings("deprecation")
#Override
protected void onDestroy() {
getPreferenceManager().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this);
super.onDestroy();
}
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
String key) {
// TODO Auto-generated method stub
}
}
MyWallpaperService.java
package com.example.mywallpaper;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Handler;
import android.service.wallpaper.WallpaperService;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
public class MyWallpaperService extends WallpaperService {
public static final String SHARED_PREFS_NAME = "myPrefs";
//drawable image array
int[] myImageList = new int[]{
R.drawable.bg,
R.drawable.bg1,
R.drawable.bg2,
R.drawable.bg3,
R.drawable.bg4,
R.drawable.bg5,
R.drawable.bg6,
R.drawable.bg7,
R.drawable.bg8,
R.drawable.bg9,
R.drawable.bg10,
R.drawable.bg11,
R.drawable.bg12,
R.drawable.bg13,
R.drawable.bg14,
R.drawable.bg15,
R.drawable.bg16
};
public boolean runUp = true;
public boolean touchEnabled = true;
public int mSpeed = 100;
public int bgNumber = 0;
public int bgFrame = 0;
public int bgFrameMax = 20;
#Override
public Engine onCreateEngine() {
return new WallpaperEngine();
}
private class WallpaperEngine extends Engine
implements SharedPreferences.OnSharedPreferenceChangeListener {
private SharedPreferences mPrefs;
private boolean mVisible = false;
private Bitmap backgroundImage;
private final Handler mHandler = new Handler();
private final Runnable mUpdateDisplay = new Runnable() {
public void run() {
draw();
}
};
private void draw() {
SurfaceHolder holder = getSurfaceHolder();
Canvas c = null;
try {
c = holder.lockCanvas();
if (c != null) {
//paint black
Paint p = new Paint();
p.setColor(Color.BLACK);
c.drawRect(0, 0, c.getWidth(), c.getHeight(), p);
drawBG(c);
}
} finally {
if (c != null)
holder.unlockCanvasAndPost(c);
}
mHandler.removeCallbacks(mUpdateDisplay);
if (mVisible) {
mHandler.postDelayed(mUpdateDisplay, mSpeed);
}
}
WallpaperEngine() {
mPrefs = MyWallpaperService.this.getSharedPreferences(SHARED_PREFS_NAME, 0);
mPrefs.registerOnSharedPreferenceChangeListener(this);
onSharedPreferenceChanged(mPrefs, null);
}
#Override
public void onTouchEvent(MotionEvent event) {
//super.onTouchEvent(event);
if(touchEnabled){
bgNumber = 0;
}
}
public void drawBG(Canvas c){
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPurgeable = true;
Resources res = getResources();
backgroundImage = BitmapFactory.decodeResource(res,myImageList[bgNumber], options);
//move looping imagas (video) right to left
int CH = c.getHeight();
int CW = c.getWidth();
double BH = backgroundImage.getHeight();
double BW = backgroundImage.getWidth();
double hScale = (BH/BW);
int bgSlideX = (CW/bgFrameMax);
int wallPH = (int) (CW*hScale);
int wLeft = 0+(CW-(bgSlideX*bgFrame));
int wTop = (int) ((CH/2)-(BH/2));
int wRight = CW+(CW-(bgSlideX*bgFrame));
int wBottom = wTop+wallPH;
Rect dest = new Rect(wLeft, wTop, wRight, wBottom);
Paint paint = new Paint();
paint.setFilterBitmap(true);
c.drawBitmap(backgroundImage, null, dest, paint);
bgFrame+=1;
if (bgFrame == bgFrameMax*2){
bgFrame = 0;
}
//Loop images up and down
if (runUp = true){
bgNumber += 1;
if (bgNumber == myImageList.length){
bgNumber=0;
runUp = false;
}
}
else if(runUp = false){
bgNumber -= 1;
if (bgNumber == 0){
bgNumber+=1;
runUp = true;
}
}
backgroundImage.recycle();
}
#Override
public void onVisibilityChanged(boolean visible) {
mVisible = visible;
if (visible) {
draw();
}
else {
mHandler.removeCallbacks(mUpdateDisplay);
}
}
#Override
public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
draw();
}
#Override
public void onSurfaceDestroyed(SurfaceHolder holder) {
super.onSurfaceDestroyed(holder);
mVisible = false;
mHandler.removeCallbacks(mUpdateDisplay);
}
#Override
public void onDestroy() {
super.onDestroy();
mVisible = false;
mHandler.removeCallbacks(mUpdateDisplay);
}
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
mSpeed = Integer.valueOf(sharedPreferences.getString("speed", "5000"));
//sharedPreferences.getInt("speed", 100);
touchEnabled = sharedPreferences.getBoolean("touch", true);
//mHandler.post(mUpdateDisplay);
}
}
public void onPause(){
super.onDestroy();
}
}
Based on the code you posted I can already see that you never closed the tag in your prefs.xml. That would cause a problem. You need to add a at the end of your prefs.xml to close it.