Visual defects when I use drawBitmap() - android

It looks like this both in the emulator and on the phone. It's always a random square that is broken.
And here is the code from the SurfaceView class, the most relevant part is in prepareBackground() :
Code begins:
public class MenuBackgroundView extends SurfaceView implements SurfaceHolder.Callback
{
private Paint mPaint;
private Bitmap blocks12x12;
private boolean draw = false;
private Context ctx;
//private int begOffX;
private int offX;
private int offY;
private int mWidth = 1;
private int mHeight = 1;
private ViewThread mThread;
private int calcSizeXY;
public MenuBackgroundView(Context context, AttributeSet attrs) {
super(context, attrs);
getHolder().addCallback(this);
mThread = new ViewThread(this);
mPaint = new Paint();
mPaint.setColor(Color.RED);
ctx = context;
}
public void doDraw(long elapsed, Canvas canvas) {
canvas.drawColor(Color.BLUE);
if(draw)
{
canvas.drawBitmap(blocks12x12, offX, offY, mPaint);
}
canvas.drawText("FPS: " + Math.round(1000f / elapsed) + " Elements: ", 10, 10, mPaint);
}
public void animate(long elapsed)
{
/*
//elapsed = elapsed/10;
offX = (offX+2);
if(offX >= 0)
{
offX -= 2*calcSizeXY;
}
offY = (offY+3);
if(offY >= 0)
{
offY -= 2*calcSizeXY;
}
//offY = (offY + (int)(elapsed/10f)) % calcSizeXY*2;//
*
*///
}
public void prepareBackground()
{
if(mWidth <= 1 || mHeight <= 1 )
return;
Log.d("Menu", "prepareBackground");
if(mHeight > mWidth)
{
calcSizeXY = mHeight/10;
}
else
{
calcSizeXY = mWidth/10;
}
offX = -2*calcSizeXY;
Bitmap block = BitmapFactory.decodeResource(ctx.getResources(), R.drawable.block);
block = Bitmap.createScaledBitmap(block, calcSizeXY, calcSizeXY, false);
// Group together
int sizeX = 12*calcSizeXY;
int sizeY = 12*calcSizeXY;
blocks12x12 = Bitmap.createBitmap(sizeX, sizeY, Bitmap.Config.ARGB_8888);
Canvas blocks12x12Canvas = new Canvas(blocks12x12);
for(int i = 0; i < 14; i+=2)
{
for(int j = 0; j < 14; j+=2)
{
blocks12x12Canvas.drawBitmap(block, (j*calcSizeXY), (i*calcSizeXY), mPaint);
}
}
// "Memory leak"
block.recycle();
draw = true;
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
mWidth = width;
mHeight = height;
prepareBackground();
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
prepareBackground();
if (!mThread.isAlive()) {
mThread = new ViewThread(this);
mThread.setRunning(true);
mThread.start();
}
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
if (mThread.isAlive()) {
mThread.setRunning(false);
freeMem();
}
}
public void freeMem() {
// TODO Auto-generated method stub
draw = false;
blocks12x12.recycle(); // "Memory leak"
}
}

Ok I figured it out, simply make the thread sleep for 1ms:
blocks12x12 = Bitmap.createBitmap(sizeX, sizeY, Bitmap.Config.ARGB_8888);
Canvas blocks12x12Canvas = new Canvas(blocks12x12);
for(int i = 0; i < 14; i+=2)
{
for(int j = 0; j < 14; j+=2)
{
try {
Thread.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
blocks12x12Canvas.drawBitmap(block, (j*calcSizeXY), (i*calcSizeXY), mPaint);
}
}

Related

How to fill the color gradually on drawn view canvas Android

I am having a WaveFormView on which I want to change the color of it while playing Audio file and as the Audio is paused it should be stopped coloring at that certain point and when resumed it should continue forward with coloring. I am not getting how to do it in my code..
This is the screen shot of my generated waveform. Now when I will click on Play button it should change the color of waveform gradually with red color (from start to end slowly).
Here is my code to draw waveform view.
WaveFormView.class
public class WaveformView extends View {
public interface WaveformListener {
public void waveformFling(float x);
public void waveformDraw();
}
;
// Colors
private Paint mGridPaint;
private Paint mSelectedLinePaint;
private Paint mUnselectedLinePaint;
private Paint mUnselectedBkgndLinePaint;
private Paint mBorderLinePaint;
private Paint mPlaybackLinePaint;
private Paint mTimecodePaint;
private SoundFile mSoundFile;
private int[] mLenByZoomLevel;
private double[][] mValuesByZoomLevel;
private double[] mZoomFactorByZoomLevel;
private int[] mHeightsAtThisZoomLevel;
private int mZoomLevel;
private int mNumZoomLevels;
private int mSampleRate;
private int mSamplesPerFrame;
private int mOffset;
private int mSelectionStart;
private int mSelectionEnd;
private int mPlaybackPos;
private float mDensity;
private float mInitialScaleSpan;
private WaveformListener mListener;
private GestureDetector mGestureDetector;
private ScaleGestureDetector mScaleGestureDetector;
private boolean mInitialized;
Color color;
public WaveformView(Context context, AttributeSet attrs) {
super(context, attrs);
// We don't want keys, the markers get these
setFocusable(false);
mGridPaint = new Paint();
mGridPaint.setAntiAlias(false);
mGridPaint.setColor(
getResources().getColor(R.color.grid_line));
mSelectedLinePaint = new Paint();
mSelectedLinePaint.setAntiAlias(false);
mSelectedLinePaint.setColor(
getResources().getColor(R.color.waveform_selected));
mUnselectedLinePaint = new Paint();
mUnselectedLinePaint.setAntiAlias(false);
mUnselectedLinePaint.setColor(
getResources().getColor(R.color.waveform_unselected));
mUnselectedBkgndLinePaint = new Paint();
mUnselectedBkgndLinePaint.setAntiAlias(false);
mUnselectedBkgndLinePaint.setColor(
getResources().getColor(
R.color.selection_border));
mBorderLinePaint = new Paint();
mBorderLinePaint.setAntiAlias(true);
mBorderLinePaint.setStrokeWidth(1.5f);
mBorderLinePaint.setPathEffect(
new DashPathEffect(new float[]{3.0f, 2.0f}, 0.0f));
mBorderLinePaint.setColor(
getResources().getColor(R.color.selection_border));
mPlaybackLinePaint = new Paint();
mPlaybackLinePaint.setAntiAlias(false);
mPlaybackLinePaint.setColor(
getResources().getColor(R.color.playback_indicator));
mTimecodePaint = new Paint();
mTimecodePaint.setTextSize(12);
mTimecodePaint.setAntiAlias(true);
mTimecodePaint.setColor(
getResources().getColor(R.color.timecode));
mTimecodePaint.setShadowLayer(
2, 1, 1,
getResources().getColor(R.color.timecode_shadow));
mGestureDetector = new GestureDetector(
context,
new GestureDetector.SimpleOnGestureListener() {
public boolean onFling(
MotionEvent e1, MotionEvent e2, float vx, float vy) {
mListener.waveformFling(vx);
return true;
}
});
mSoundFile = null;
mLenByZoomLevel = null;
mValuesByZoomLevel = null;
mHeightsAtThisZoomLevel = null;
mOffset = 0;
mPlaybackPos = -1;
mSelectionStart = 0;
mSelectionEnd = 0;
mDensity = 1.0f;
mInitialized = false;
}
public boolean hasSoundFile() {
return mSoundFile != null;
}
public void setSoundFile(SoundFile soundFile) {
mSoundFile = soundFile;
mSampleRate = mSoundFile.getSampleRate();
mSamplesPerFrame = mSoundFile.getSamplesPerFrame();
computeDoublesForAllZoomLevels();
mHeightsAtThisZoomLevel = null;
}
/**
* Called once when a new sound file is added
*/
private void computeDoublesForAllZoomLevels() {
int numFrames = mSoundFile.getNumFrames();
int[] frameGains = mSoundFile.getFrameGains();
double[] smoothedGains = new double[numFrames];
if (numFrames == 1) {
smoothedGains[0] = frameGains[0];
} else if (numFrames == 2) {
smoothedGains[0] = frameGains[0];
smoothedGains[1] = frameGains[1];
} else if (numFrames > 2) {
smoothedGains[0] = (double)(
(frameGains[0] / 2.0) +
(frameGains[1] / 2.0));
for (int i = 1; i < numFrames - 1; i++) {
smoothedGains[i] = (double)(
(frameGains[i - 1] / 3.0) +
(frameGains[i ] / 3.0) +
(frameGains[i + 1] / 3.0));
}
smoothedGains[numFrames - 1] = (double)(
(frameGains[numFrames - 2] / 2.0) +
(frameGains[numFrames - 1] / 2.0));
}
// Make sure the range is no more than 0 - 255
double maxGain = 1.0;
for (int i = 0; i < numFrames; i++) {
if (smoothedGains[i] > maxGain) {
maxGain = smoothedGains[i];
}
}
double scaleFactor = 1.0;
if (maxGain > 255.0) {
scaleFactor = 255 / maxGain;
}
// Build histogram of 256 bins and figure out the new scaled max
maxGain = 0;
int gainHist[] = new int[256];
for (int i = 0; i < numFrames; i++) {
int smoothedGain = (int)(smoothedGains[i] * scaleFactor);
if (smoothedGain < 0)
smoothedGain = 0;
if (smoothedGain > 255)
smoothedGain = 255;
if (smoothedGain > maxGain)
maxGain = smoothedGain;
gainHist[smoothedGain]++;
}
// Re-calibrate the min to be 5%
double minGain = 0;
int sum = 0;
while (minGain < 255 && sum < numFrames / 20) {
sum += gainHist[(int)minGain];
minGain++;
}
// Re-calibrate the max to be 99%
sum = 0;
while (maxGain > 2 && sum < numFrames / 100) {
sum += gainHist[(int)maxGain];
maxGain--;
}
// Compute the heights
double[] heights = new double[numFrames];
double range = maxGain - minGain;
for (int i = 0; i < numFrames; i++) {
double value = (smoothedGains[i] * scaleFactor - minGain) / range;
if (value < 0.0)
value = 0.0;
if (value > 1.0)
value = 1.0;
heights[i] = value * value;
}
mNumZoomLevels = 5;
mLenByZoomLevel = new int[5];
mZoomFactorByZoomLevel = new double[5];
mValuesByZoomLevel = new double[5][];
// Level 0 is doubled, with interpolated values
mLenByZoomLevel[0] = numFrames * 2;
mZoomFactorByZoomLevel[0] = 2.0;
mValuesByZoomLevel[0] = new double[mLenByZoomLevel[0]];
if (numFrames > 0) {
mValuesByZoomLevel[0][0] = 0.5 * heights[0];
mValuesByZoomLevel[0][1] = heights[0];
}
for (int i = 1; i < numFrames; i++) {
mValuesByZoomLevel[0][2 * i] = 0.5 * (heights[i - 1] + heights[i]);
mValuesByZoomLevel[0][2 * i + 1] = heights[i];
}
// Level 1 is normal
mLenByZoomLevel[1] = numFrames;
mValuesByZoomLevel[1] = new double[mLenByZoomLevel[1]];
mZoomFactorByZoomLevel[1] = 1.0;
for (int i = 0; i < mLenByZoomLevel[1]; i++) {
mValuesByZoomLevel[1][i] = heights[i];
}
// 3 more levels are each halved
for (int j = 2; j < 5; j++) {
mLenByZoomLevel[j] = mLenByZoomLevel[j - 1] / 2;
mValuesByZoomLevel[j] = new double[mLenByZoomLevel[j]];
mZoomFactorByZoomLevel[j] = mZoomFactorByZoomLevel[j - 1] / 2.0;
for (int i = 0; i < mLenByZoomLevel[j]; i++) {
mValuesByZoomLevel[j][i] =
0.5 * (mValuesByZoomLevel[j - 1][2 * i] +
mValuesByZoomLevel[j - 1][2 * i + 1]);
}
}
if (numFrames > 5000) {
mZoomLevel = 3;
} else if (numFrames > 1000) {
mZoomLevel = 2;
} else if (numFrames > 300) {
mZoomLevel = 1;
} else {
mZoomLevel = 0;
}
mInitialized = true;
}
public boolean canZoomIn() {
return (mZoomLevel > 0);
}
public void zoomIn() {
if (canZoomIn()) {
mZoomLevel--;
mSelectionStart *= 2;
mSelectionEnd *= 2;
mHeightsAtThisZoomLevel = null;
int offsetCenter = mOffset + getMeasuredWidth() / 2;
offsetCenter *= 2;
mOffset = offsetCenter - getMeasuredWidth() / 2;
if (mOffset < 0)
mOffset = 0;
invalidate();
}
}
public boolean canZoomOut() {
return (mZoomLevel < mNumZoomLevels - 1);
}
public void zoomOut() {
if (canZoomOut()) {
mZoomLevel++;
mSelectionStart /= 2;
mSelectionEnd /= 2;
int offsetCenter = mOffset + getMeasuredWidth() / 2;
offsetCenter /= 2;
mOffset = offsetCenter - getMeasuredWidth() / 2;
if (mOffset < 0)
mOffset = 0;
mHeightsAtThisZoomLevel = null;
invalidate();
}
}
public double pixelsToSeconds(int pixels) {
double z = mZoomFactorByZoomLevel[mZoomLevel];
return (pixels * (double)mSamplesPerFrame / (mSampleRate * z));
}
public void setListener(WaveformListener listener) {
mListener = listener;
}
public void recomputeHeights(float density) {
mHeightsAtThisZoomLevel = null;
mDensity = density;
mTimecodePaint.setTextSize((int)(12 * density));
invalidate();
}
protected void drawWaveformLine(Canvas canvas,
int x, int y0, int y1,
Paint paint) {
canvas.drawLine(x, y0, x, y1, paint);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (mSoundFile == null)
return;
if (mHeightsAtThisZoomLevel == null)
computeIntsForThisZoomLevel();
DisplayMetrics displaymetrics = getContext().getResources().getDisplayMetrics();
int height = displaymetrics.heightPixels;
int widths = displaymetrics.widthPixels;
// Draw waveform
int measuredWidth = getMeasuredWidth();
int measuredHeight = getMeasuredHeight();
int start = mOffset;
int width = mHeightsAtThisZoomLevel.length - start;
int ctr = measuredHeight / 2;
Log.e("wid",String.valueOf(width));
Log.e("widCal",String.valueOf(mHeightsAtThisZoomLevel.length));
Log.e("widstart",String.valueOf(start));
if (width > measuredWidth)
width = measuredWidth;
Log.e("measured",String.valueOf(measuredWidth));
// Draw grid
double onePixelInSecs = pixelsToSeconds(1);
boolean onlyEveryFiveSecs = (onePixelInSecs > 1.0 / 50.0);
double fractionalSecs = mOffset * onePixelInSecs;
int integerSecs = (int) fractionalSecs;
int i = 0;
while (i < width) {
i++;
fractionalSecs += onePixelInSecs;
int integerSecsNew = (int) fractionalSecs;
if (integerSecsNew != integerSecs) {
integerSecs = integerSecsNew;
if (!onlyEveryFiveSecs || 0 == (integerSecs % 5)) {
canvas.drawLine(i, 0, i, measuredHeight, mGridPaint);
}
}
}
// Draw waveform
for ( i = 0; i < width; i++) {
Paint paint;
if (i + start >= mSelectionStart &&
i + start < mSelectionEnd) {
paint = mSelectedLinePaint;
// paint.setColor(color);
} else {
drawWaveformLine(canvas, ((widths/width)*i), 0, measuredHeight,
mUnselectedBkgndLinePaint);
paint = mUnselectedLinePaint;
}
drawWaveformLine(
canvas, ((widths/width)*i),
ctr - mHeightsAtThisZoomLevel[start + i],
ctr + 1 + mHeightsAtThisZoomLevel[start + i],
paint);
if (i + start == mPlaybackPos) {
canvas.drawLine(i, 0, i, measuredHeight, mPlaybackLinePaint);
}
}
if (mListener != null) {
mListener.waveformDraw();
}
}
private void computeIntsForThisZoomLevel() {
int halfHeight = (getMeasuredHeight() / 2) - 1;
mHeightsAtThisZoomLevel = new int[mLenByZoomLevel[mZoomLevel]];
for (int i = 0; i < mLenByZoomLevel[mZoomLevel]; i++) {
mHeightsAtThisZoomLevel[i] =
(int)(mValuesByZoomLevel[mZoomLevel][i] * halfHeight);
}
}
}
MainActivity.class
public class MainActivity extends AppCompatActivity implements WaveformView.WaveformListener {
WaveformView mWaveformView;
SoundFile mSoundFile;
private float mDensity;
private File mFile;
private String mFilename;
private long mLoadingLastUpdateTime;
boolean mLoadingKeepGoing;
boolean mFinishActivity;
private ProgressDialog mProgressDialog;
String mTitle,mArtist;
private Thread mLoadSoundFileThread;
private Thread mRecordAudioThread;
private Thread mSaveSoundFileThread;
private boolean mIsPlaying;
private SamplePlayer mPlayer;
private String mInfoContent;
private int mWidth;
private int mMaxPos;
private int mStartPos;
private int mEndPos;
private boolean mStartVisible;
private boolean mEndVisible;
private int mLastDisplayedStartPos;
private int mLastDisplayedEndPos;
private int mOffset;
private int mOffsetGoal;
private int mFlingVelocity;
private int mPlayStartMsec;
private int mPlayEndMsec;
private Handler mHandler;
Button pla;
MediaPlayer mediaPlayer;
boolean ismIsPlaying;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
pla = (Button)findViewById(R.id.play);
mWaveformView = (WaveformView)findViewById(R.id.waveform);
mWaveformView.setListener(this);
mHandler = new Handler();
Uri uri = Uri.parse("/sdcard/audio_file.mp3");
mediaPlayer = new MediaPlayer();
mediaPlayer = MediaPlayer.create(getApplicationContext(),uri);
loadGui();
loadFromFile();
}
/**
* Called from both onCreate and onConfigurationChanged
* (if the user switched layouts)
*/
private void loadGui() {
// Inflate our UI from its XML layout description.
setContentView(R.layout.activity_main);
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
mDensity = metrics.density;
mWaveformView = (WaveformView)findViewById(R.id.waveform);
mWaveformView.setListener(this);
if (mSoundFile != null && !mWaveformView.hasSoundFile()) {
mWaveformView.setSoundFile(mSoundFile);
mWaveformView.recomputeHeights(mDensity);
}
}
private void loadFromFile() {
mFilename = "/sdcard/audio_file.mp3";
mFile = new File(mFilename);
SongMetadataReader metadataReader = new SongMetadataReader(
this, mFilename);
mTitle = metadataReader.mTitle;
mArtist = metadataReader.mArtist;
String titleLabel = mTitle;
if (mArtist != null && mArtist.length() > 0) {
titleLabel += " - " + mArtist;
}
setTitle(titleLabel);
mLoadingLastUpdateTime = getCurrentTime();
mLoadingKeepGoing = true;
mFinishActivity = false;
mProgressDialog = new ProgressDialog(MainActivity.this);
mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
mProgressDialog.setTitle("Loading...");
mProgressDialog.setCancelable(true);
mProgressDialog.setOnCancelListener(
new DialogInterface.OnCancelListener() {
public void onCancel(DialogInterface dialog) {
mLoadingKeepGoing = false;
mFinishActivity = true;
}
});
mProgressDialog.show();
final SoundFile.ProgressListener listener =
new SoundFile.ProgressListener() {
public boolean reportProgress(double fractionComplete) {
long now = getCurrentTime();
if (now - mLoadingLastUpdateTime > 100) {
mProgressDialog.setProgress(
(int) (mProgressDialog.getMax() * fractionComplete));
mLoadingLastUpdateTime = now;
}
return mLoadingKeepGoing;
}
};
// Load the sound file in a background thread
mLoadSoundFileThread = new Thread() {
public void run() {
try {
mSoundFile = SoundFile.create(mFile.getAbsolutePath(), listener);
if (mSoundFile == null) {
mProgressDialog.dismiss();
String name = mFile.getName().toLowerCase();
String[] components = name.split("\\.");
String err;
if (components.length < 2) {
err = getResources().getString(
R.string.no_extension_error);
} else {
err = getResources().getString(
R.string.bad_extension_error) + " " +
components[components.length - 1];
}
final String finalErr = err;
Runnable runnable = new Runnable() {
public void run() {
showFinalAlert(new Exception(), finalErr);
}
};
mHandler.post(runnable);
return;
}
mPlayer = new SamplePlayer(mSoundFile);
} catch (final Exception e) {
mProgressDialog.dismiss();
e.printStackTrace();
mInfoContent = e.toString();
runOnUiThread(new Runnable() {
public void run() {
}
});
Runnable runnable = new Runnable() {
public void run() {
showFinalAlert(e, getResources().getText(R.string.read_error));
}
};
mHandler.post(runnable);
return;
}
mProgressDialog.dismiss();
if (mLoadingKeepGoing) {
Runnable runnable = new Runnable() {
public void run() {
finishOpeningSoundFile();
}
};
mHandler.post(runnable);
} else if (mFinishActivity){
MainActivity.this.finish();
}
}
};
mLoadSoundFileThread.start();
}
private void finishOpeningSoundFile() {
mWaveformView.setSoundFile(mSoundFile);
mWaveformView.recomputeHeights(mDensity);
Log.e("sound file",mFilename);
Log.e("sound", String.valueOf(mSoundFile));
}
/**
* Show a "final" alert dialog that will exit the activity
* after the user clicks on the OK button. If an exception
* is passed, it's assumed to be an error condition, and the
* dialog is presented as an error, and the stack trace is
* logged. If there's no exception, it's a success message.
*/
private void showFinalAlert(Exception e, CharSequence message) {
CharSequence title;
if (e != null) {
Log.e("Ringdroid", "Error: " + message);
Log.e("Ringdroid", getStackTrace(e));
title = getResources().getText(R.string.alert_title_failure);
setResult(RESULT_CANCELED, new Intent());
} else {
Log.v("Ringdroid", "Success: " + message);
title = getResources().getText(R.string.alert_title_success);
}
new AlertDialog.Builder(MainActivity.this)
.setTitle(title)
.setMessage(message)
.setPositiveButton(
R.string.alert_ok_button,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,
int whichButton) {
finish();
}
})
.setCancelable(false)
.show();
}
private void showFinalAlert(Exception e, int messageResourceId) {
showFinalAlert(e, getResources().getText(messageResourceId));
}
#Override
public void waveformTouchStart(float x) {
}
#Override
public void waveformTouchMove(float x) {
}
#Override
public void waveformTouchEnd() {
}
#Override
public void waveformFling(float x) {
}
#Override
public void waveformDraw() {
mWidth = mWaveformView.getMeasuredWidth();
if (mOffsetGoal != mOffset) {
// updateDisplay();
}
else if (mIsPlaying) {
// updateDisplay();
} else if (mFlingVelocity != 0) {
// updateDisplay();
}
}
private long getCurrentTime() {
return System.nanoTime() / 1000000;
}
private String getStackTrace(Exception e) {
StringWriter writer = new StringWriter();
e.printStackTrace(new PrintWriter(writer));
return writer.toString();
}
public void buttonClick(View view) {
Toast.makeText(MainActivity.this, "test", Toast.LENGTH_SHORT).show();
mediaPlayer.start();
ismIsPlaying = true;
}
}
In your onDraw(Canvas canvas) add the following lines
if (i + start <= mPlaybackPos) {
Paint mPaint = new Paint(paint);
mPaint.setColor(Color.RED);
drawWaveformLine(
canvas, ((widths/width)*i),
ctr - mHeightsAtThisZoomLevel[start + i],
ctr + 1 + mHeightsAtThisZoomLevel[start + i],
mPaint);
}
add them above the line:
if (i + start == mPlaybackPos) {
And if this works, consider to allocate the Paint-object outside the onDraw() method.

When line is draw after filling color using flood fill algorithm then filling color is gone

I have canvas drawing app. I successfully done integrating floodfill algorithm for filling color for finger drawing circle and rectangle area by finger drawing shapes. My problem is after filling color for created shapes by finger, filled color is gone when drawing line on canvas.
public class DrawingView extends View {
private final Paint mDefaultPaint;
private final Paint mFloodPaint = new Paint();
Bitmap mBitmap;
float x, y;
ProgressDialog pd;
LinearLayout drawing_layout;
private Canvas mLayerCanvas = new Canvas();
private Bitmap mLayerBitmap;
final Point p1 = new Point();
private Stack<DrawOp> mDrawOps = new Stack<>();
private Stack<DrawOp> mUndoOps = new Stack<>();
boolean isFill;/* = false;*/
private SparseArray<DrawOp> mCurrentOps = new SparseArray<>(0);
public DrawingView(Context context) {
this(context, null, 0);
}
public DrawingView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public DrawingView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mDefaultPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mDefaultPaint.setStyle(Paint.Style.STROKE);
mDefaultPaint.setStrokeJoin(Paint.Join.ROUND);
mDefaultPaint.setStrokeCap(Paint.Cap.ROUND);
mDefaultPaint.setStrokeWidth(40);
mDefaultPaint.setColor(Color.GREEN);
/*mFloodPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mFloodPaint.setStyle(Paint.Style.STROKE);
mFloodPaint.setStrokeJoin(Paint.Join.ROUND);
mFloodPaint.setStrokeCap(Paint.Cap.ROUND);
mFloodPaint.setStrokeWidth(40);
mFloodPaint.setColor(Color.GREEN);*/
setFocusable(true);
setFocusableInTouchMode(true);
setBackgroundColor(Color.WHITE);
setLayerType(LAYER_TYPE_SOFTWARE, null);
setSaveEnabled(true);
}
#Override
public boolean onTouchEvent(#NonNull MotionEvent event) {
final int pointerCount = MotionEventCompat.getPointerCount(event);
switch (MotionEventCompat.getActionMasked(event)) {
case MotionEvent.ACTION_DOWN: {
if (isFill == true) {
int xx = (int) event.getX();
int yy = (int) event.getY();
Point pp = new Point(xx, yy);
/*Point pp = new Point();
pp.x = (int) event.getX();
pp.y = (int) event.getY();*/
final int sourceColor = mLayerBitmap.getPixel(xx, yy);
final int targetColor = mDefaultPaint.getColor();
// final int targetColor = mFloodPaint.getColor();
new TheTask(mLayerBitmap, pp, sourceColor, targetColor)
.execute();
// JniBitmap.floodFill(mLayerBitmap, xx, yy, sourceColor,targetColor);
/* FloodFill f = new FloodFill();
f.floodFill(mLayerBitmap, pp, sourceColor, targetColor);*/
}
else if(isFill == false){
for (int p = 0; p < pointerCount; p++) {
final int id = MotionEventCompat.getPointerId(event, p);
DrawOp current = new DrawOp(mDefaultPaint);
current.getPath().moveTo(event.getX(), event.getY());
mCurrentOps.put(id, current);
}
}
}
break;
case MotionEvent.ACTION_MOVE: {
if (isFill == false) {
final int id = MotionEventCompat.getPointerId(event, 0);
DrawOp current = mCurrentOps.get(id);
final int historySize = event.getHistorySize();
for (int h = 0; h < historySize; h++) {
x = event.getHistoricalX(h);
y = event.getHistoricalY(h);
current.getPath().lineTo(x, y);
}
x = MotionEventCompat.getX(event, 0);
y = MotionEventCompat.getY(event, 0);
current.getPath().lineTo(x, y);
}
}
break;
case MotionEvent.ACTION_UP: {
if(isFill == false){
// mLayerCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
for (int p = 0; p < pointerCount; p++) {
final int id = MotionEventCompat.getPointerId(event, p);
mDrawOps.push(mCurrentOps.get(id));
mCurrentOps.remove(id);
}
updateLayer();
}
}
/* else{
for (int p = 0; p < pointerCount; p++) {
final int id = MotionEventCompat.getPointerId(event, p);
mDrawOps.push(mCurrentOps.get(id));
mCurrentOps.remove(id);
}
}*/
// }
break;
case MotionEvent.ACTION_CANCEL: {
if(isFill == false){
for (int p = 0; p < pointerCount; p++) {
mCurrentOps.remove(MotionEventCompat.getPointerId(event, p));
}
updateLayer();
}
}
break;
default:
return false;
}
invalidate();
return true;
}
class TheTask extends AsyncTask<Void, Integer, Void> {
Bitmap bmp;
Point pt;
int replacementColor, targetColor;
public TheTask(Bitmap bm, Point p, int sc, int tc) {
// this.bmp = bm;
mLayerBitmap = bm;
pd = new ProgressDialog(getContext());
this.pt = p;
this.replacementColor = tc;
this.targetColor = sc;
pd.setMessage("Filling....");
pd.show();
}
#Override
protected void onPreExecute() {
}
#Override
protected void onProgressUpdate(Integer... values) {
}
#Override
protected Void doInBackground(Void... params) {
FloodFill f = new FloodFill();
// mLayerBitmap = f.floodFill(bmp, pt, targetColor, replacementColor);
f.floodFill(mLayerBitmap, pt, targetColor, replacementColor);
// New Commented Algorithm
// f.FloodFill(mLayerBitmap, pt, targetColor, replacementColor);
return null;
}
#Override
protected void onPostExecute(Void result) {
pd.dismiss();
invalidate();
isFill = false;
}
}
public void fillShapeColor(Bitmap mBitmap2) {
isFill = true;
}
/*public void fillShapeColor() {
isFill = true;
}*/
public void setDrawing() {
isFill = false;
}
#Override
protected void onSizeChanged(int w, int h, int oldW, int oldH) {
super.onSizeChanged(w, h, oldW, oldH);
mLayerBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
mLayerCanvas.setBitmap(mLayerBitmap);
updateLayer();
}
/* private void updateDLayer(){
mLayerCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
for (DrawOp drawOp : mDrawOps) {
if (drawOp != null) {
// drawOp.draw(new Canvas(mLayerBitmap));
drawOp.draw(mLayerCanvas);
}
}
invalidate();
}*/
private void updateLayer() {
/* isFill=false;
if(isFill==false){
mLayerCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
}
else{
System.out.println("Not using mLayerCanvas.drawColor()");
}*/
// mLayerCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
// this.getPaintStrokeWidth();
// this.getPaintMaskFilter();
/* if(isFill == false){
// this.getPaintOpacity();
mLayerCanvas.save();
// mLayerCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
mLayerCanvas.restore();
}*/
/*mDefaultPaint.setXfermode(new PorterDuffXfermode(Mode.CLEAR));
mLayerCanvas.drawPaint(mDefaultPaint);
mDefaultPaint.setXfermode(new PorterDuffXfermode(Mode.SRC));
mLayerCanvas.drawPaint(mDefaultPaint);*/
/* if(isFill==false){
mLayerCanvas.save();
mLayerCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
mLayerCanvas.restore();
invalidate();
}
else{
mLayerCanvas.save();
for (DrawOp drawOp : mDrawOps) {
if (drawOp != null) {
// drawOp.draw(new Canvas(mLayerBitmap));
drawOp.draw(mLayerCanvas);
}
}
mLayerCanvas.restore();
}*/
/*DrawOp dr = new DrawOp(mDefaultPaint);
if(dr.getPath().isEmpty()){
// isFill = true;
isFill = false;
}
else{
isFill=true;
mLayerCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
}*/
if(isFill == false){
mLayerCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
}
for (DrawOp drawOp : mDrawOps) {
if (drawOp != null) {
// drawOp.draw(new Canvas(mLayerBitmap));
drawOp.draw(mLayerCanvas);
}
}
invalidate();
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (isInEditMode()) {
return;
}
/*int w = canvas.getWidth();
int h = canvas.getHeight();
canvas.drawRect(0,0,w,h, mDefaultPaint);*/
canvas.drawBitmap(mLayerBitmap, 0, 0, null);
for (int i = 0; i < mCurrentOps.size(); i++) {
DrawOp current = mCurrentOps.valueAt(i);
if (current != null) {
current.draw(canvas);
}
}
}
public void operationClear() {
mDrawOps.clear();
mUndoOps.clear();
mCurrentOps.clear();
// To Clear Whole Canvas
mLayerCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
updateLayer();
}
public void operationUndo() {
if (mDrawOps.size() > 0) {
mUndoOps.push(mDrawOps.pop());
updateLayer();
}
}
public void operationRedo() {
if (mUndoOps.size() > 0) {
mDrawOps.push(mUndoOps.pop());
updateLayer();
}
}
public void setPaintStrokeWidth(float widthPx) {
mDefaultPaint.setStrokeWidth(widthPx);
// mFloodPaint.setStrokeWidth(widthPx);
}
/*public float getPaintStrokeWidth(){
return mDefaultPaint.getStrokeWidth();
}*/
public void setPaintOpacity(int percent) {
int alphaValue = (int) Math.round(percent * (255.0 / 100.0));
mDefaultPaint.setColor(combineAlpha(mDefaultPaint.getColor(),
alphaValue));
// mFloodPaint.setColor(combineAlpha(mFloodPaint.getColor(),
// alphaValue));
}
/*public int getPaintOpacity(){
this.setPaintOpacity(50);
return mDefaultPaint.getColor();
}*/
public void setPaintColor(String color) {
mDefaultPaint.setXfermode(null);
mDefaultPaint.setColor(combineAlpha(Color.parseColor(color),
mDefaultPaint.getAlpha()));
// mDefaultPaint.setColor(mDefaultPaint.getAlpha());
mFloodPaint.setXfermode(null);
mFloodPaint.setColor(combineAlpha(Color.parseColor(color),
mFloodPaint.getAlpha()));
}
public void setPaintColor(int color) {
mDefaultPaint.setXfermode(null);
mDefaultPaint.setColor(combineAlpha(color, mDefaultPaint.getAlpha()));
mFloodPaint.setXfermode(null);
mFloodPaint.setColor(combineAlpha(color, mFloodPaint.getAlpha()));
}
// New Created
public void setEraser(int color){
// mDefaultPaint.setAlpha(0xFF);
mDefaultPaint.setColor(color);
mDefaultPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
}
public void setPaintMaskFilter(MaskFilter filter) {
mDefaultPaint.setMaskFilter(filter);
// mFloodPaint.setMaskFilter(filter);
}
/*public MaskFilter getPaintMaskFilter(){
return mDefaultPaint.getMaskFilter();
}*/
public void setPaintShader(BitmapShader shader) {
mDefaultPaint.setShader(shader);
// mFloodPaint.setShader(shader);
}
public void setPaintColorFilter(ColorFilter colorFilter) {
mDefaultPaint.setColorFilter(colorFilter);
// mFloodPaint.setColorFilter(colorFilter);
}
private static int combineAlpha(int color, int alpha) {
return (color & 0x00FFFFFF) | ((alpha & 0xFF) << 24);
}
private static class DrawOp {
private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private final Path mPath = new Path();
public DrawOp(Paint paint) {
reset(paint);
}
void reset(Paint paint) {
mPath.reset();
update(paint);
}
void update(Paint paint) {
mPaint.set(paint);
}
void draw(Canvas canvas) {
canvas.drawPath(mPath, mPaint);
}
public Path getPath() {
return mPath;
}
}
public void setFillColor(boolean flag){
this.isFill = flag;
}
}
update your updateLayer() method like below:
private void updateLayer() {
/*if(isFill == false){
mCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
}*/
for (DrawOp drawOp : mDrawOps) {
if (drawOp != null) {
drawOp.draw(mCanvas);
}
}
invalidate();
}

Canvas finger drawing opacity is increase after using FloodFill in android

I have canvas drawing app. I successfully done integrating floodfill algorithm for filling color for finger drawing circle and rectangle area. My problem is after filling color on finger drawing circle when i used blur mask brush effect and drawing using finger by blur mask brush then whole blur mask brush drawing is repaint again and again. Here is my code:
public class DrawingView extends View {
private final Paint mDefaultPaint;
Bitmap mBitmap;
float x, y;
ProgressDialog pd;
LinearLayout drawing_layout;
private Canvas mLayerCanvas = new Canvas();
private Bitmap mLayerBitmap;
final Point p1 = new Point();
private Stack<DrawOp> mDrawOps = new Stack<>();
private Stack<DrawOp> mUndoOps = new Stack<>();
boolean isFill = false;
private SparseArray<DrawOp> mCurrentOps = new SparseArray<>(0);
public DrawingView(Context context) {
this(context, null, 0);
}
public DrawingView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public DrawingView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mDefaultPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mDefaultPaint.setStyle(Paint.Style.STROKE);
mDefaultPaint.setStrokeJoin(Paint.Join.ROUND);
mDefaultPaint.setStrokeCap(Paint.Cap.ROUND);
mDefaultPaint.setStrokeWidth(40);
mDefaultPaint.setColor(Color.GREEN);
setFocusable(true);
setFocusableInTouchMode(true);
setBackgroundColor(Color.WHITE);
setLayerType(LAYER_TYPE_SOFTWARE, null);
setSaveEnabled(true);
}
#Override
public boolean onTouchEvent(#NonNull MotionEvent event) {
final int pointerCount = MotionEventCompat.getPointerCount(event);
switch (MotionEventCompat.getActionMasked(event)) {
case MotionEvent.ACTION_DOWN: {
if (isFill == true) {
int xx = (int) event.getX();
int yy = (int) event.getY();
Point pp = new Point(xx, yy);
/*Point pp = new Point();
pp.x = (int) event.getX();
pp.y = (int) event.getY();*/
final int sourceColor = mLayerBitmap.getPixel(xx, yy);
final int targetColor = mDefaultPaint.getColor();
new TheTask(mLayerBitmap, pp, sourceColor, targetColor)
.execute();
// JniBitmap.floodFill(mLayerBitmap, xx, yy, sourceColor,targetColor);
/* FloodFill f = new FloodFill();
f.floodFill(mLayerBitmap, pp, sourceColor, targetColor);*/
}
for (int p = 0; p < pointerCount; p++) {
final int id = MotionEventCompat.getPointerId(event, p);
DrawOp current = new DrawOp(mDefaultPaint);
current.getPath().moveTo(event.getX(), event.getY());
mCurrentOps.put(id, current);
}
}
break;
case MotionEvent.ACTION_MOVE: {
if (isFill == false) {
final int id = MotionEventCompat.getPointerId(event, 0);
DrawOp current = mCurrentOps.get(id);
final int historySize = event.getHistorySize();
for (int h = 0; h < historySize; h++) {
x = event.getHistoricalX(h);
y = event.getHistoricalY(h);
current.getPath().lineTo(x, y);
}
x = MotionEventCompat.getX(event, 0);
y = MotionEventCompat.getY(event, 0);
current.getPath().lineTo(x, y);
}
}
break;
case MotionEvent.ACTION_UP: {
for (int p = 0; p < pointerCount; p++) {
final int id = MotionEventCompat.getPointerId(event, p);
mDrawOps.push(mCurrentOps.get(id));
mCurrentOps.remove(id);
}
updateLayer();
}
break;
case MotionEvent.ACTION_CANCEL: {
for (int p = 0; p < pointerCount; p++) {
mCurrentOps.remove(MotionEventCompat.getPointerId(event, p));
}
updateLayer();
}
break;
default:
return false;
}
invalidate();
return true;
}
class TheTask extends AsyncTask<Void, Integer, Void> {
Bitmap bmp;
Point pt;
int replacementColor, targetColor;
public TheTask(Bitmap bm, Point p, int sc, int tc) {
// this.bmp = bm;
mLayerBitmap = bm;
pd = new ProgressDialog(getContext());
this.pt = p;
this.replacementColor = tc;
this.targetColor = sc;
pd.setMessage("Filling....");
pd.show();
}
#Override
protected void onPreExecute() {
}
#Override
protected void onProgressUpdate(Integer... values) {
}
#Override
protected Void doInBackground(Void... params) {
FloodFill f = new FloodFill();
// mLayerBitmap = f.floodFill(bmp, pt, targetColor, replacementColor);
f.floodFill(mLayerBitmap, pt, targetColor, replacementColor);
// New Commented Algorithm
// f.FloodFill(mLayerBitmap, pt, targetColor, replacementColor);
return null;
}
#Override
protected void onPostExecute(Void result) {
pd.dismiss();
invalidate();
isFill = false;
}
}
public void fillShapeColor(Bitmap mBitmap2) {
isFill = true;
}
public void setDrawing() {
isFill = false;
}
#Override
protected void onSizeChanged(int w, int h, int oldW, int oldH) {
super.onSizeChanged(w, h, oldW, oldH);
mLayerBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
mLayerCanvas.setBitmap(mLayerBitmap);
updateLayer();
}
private void updateLayer() {
for (DrawOp drawOp : mDrawOps) {
if (drawOp != null) {
// drawOp.draw(new Canvas(mLayerBitmap));
drawOp.draw(mLayerCanvas);
}
}
invalidate();
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (isInEditMode()) {
return;
}
canvas.drawBitmap(mLayerBitmap, 0, 0, null);
for (int i = 0; i < mCurrentOps.size(); i++) {
DrawOp current = mCurrentOps.valueAt(i);
if (current != null) {
current.draw(canvas);
}
}
}
public void operationClear() {
mDrawOps.clear();
mUndoOps.clear();
mCurrentOps.clear();
// To Clear Whole Canvas
mLayerCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
updateLayer();
}
public void operationUndo() {
if (mDrawOps.size() > 0) {
mUndoOps.push(mDrawOps.pop());
updateLayer();
}
}
public void operationRedo() {
if (mUndoOps.size() > 0) {
mDrawOps.push(mUndoOps.pop());
updateLayer();
}
}
public void setPaintStrokeWidth(float widthPx) {
mDefaultPaint.setStrokeWidth(widthPx);
}
/*public float getPaintStrokeWidth(){
return mDefaultPaint.getStrokeWidth();
}*/
public void setPaintOpacity(int percent) {
int alphaValue = (int) Math.round(percent * (255.0 / 100.0));
mDefaultPaint.setColor(combineAlpha(mDefaultPaint.getColor(),
alphaValue));
}
/*public int getPaintOpacity(){
this.setPaintOpacity(50);
return mDefaultPaint.getColor();
}*/
public void setPaintColor(String color) {
mDefaultPaint.setXfermode(null);
mDefaultPaint.setColor(combineAlpha(Color.parseColor(color),
mDefaultPaint.getAlpha()));
// mDefaultPaint.setColor(mDefaultPaint.getAlpha());
}
public void setPaintColor(int color) {
mDefaultPaint.setXfermode(null);
mDefaultPaint.setColor(combineAlpha(color, mDefaultPaint.getAlpha()));
}
// New Created
public void setEraser(int color){
// mDefaultPaint.setAlpha(0xFF);
mDefaultPaint.setColor(color);
mDefaultPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
}
public void setPaintMaskFilter(MaskFilter filter) {
mDefaultPaint.setMaskFilter(filter);
}
/*public MaskFilter getPaintMaskFilter(){
return mDefaultPaint.getMaskFilter();
}*/
public void setPaintShader(BitmapShader shader) {
mDefaultPaint.setShader(shader);
}
public void setPaintColorFilter(ColorFilter colorFilter) {
mDefaultPaint.setColorFilter(colorFilter);
}
private static int combineAlpha(int color, int alpha) {
return (color & 0x00FFFFFF) | ((alpha & 0xFF) << 24);
}
private static class DrawOp {
private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private final Path mPath = new Path();
public DrawOp(Paint paint) {
reset(paint);
}
void reset(Paint paint) {
mPath.reset();
update(paint);
}
void update(Paint paint) {
mPaint.set(paint);
}
void draw(Canvas canvas) {
canvas.drawPath(mPath, mPaint);
}
public Path getPath() {
return mPath;
}
}
}
After lots of research i fond my problem and getting correct it. Below is my code.
if (isFloodFill) {
if (mZoomMode) {
return false;
} else {
final Point p = new Point();
float[] mTmpPoint1 = new float[2];
mTmpPoint1[0] = event.getX() - mPanX;
mTmpPoint1[1] = event.getY() - mPanY;
mZoomMatrixInv.mapPoints(mTmpPoint1);
p.x = (int) (mTmpPoint1[0]);
p.y = (int) (mTmpPoint1[1]);
System.out.println("--plotX mTmpPoint0: touch:" + p.x);
System.out.println("--plotY mTmpPoint0: touch:" + p.y);
this.mBitmap = getBitmap();
if (this.mBitmap != null) {
if(p.x > mBitmap.getWidth() || p.y > mBitmap.getHeight())
{
return false;
}
else
{
if(p.x >= 0 && p.y >= 0)
{
this.color = this.mBitmap.getPixel(p.x, p.y);
}
else
{
return false;
}
}
}
try {
// isFilling = false;
new FloodFillAlgo().execute(p);
return false;
} catch (Exception e) {
e.printStackTrace();
}
}
}

Android Canvas error - error queuing buffer to SurfaceTexture

Does anyone have an idea what would cause the below error?
queueBuffer: error queuing buffer to SurfaceTexture, -32
I'm using SurfaceTexture in my app. The above error occurs when I try to set as
a livewallpaper
Below is the code:
public class ClockWallpaperService extends WallpaperService {
private WallpaperEngine myEngine;
public void onCreate() {
super.onCreate();
}
#Override
public Engine onCreateEngine() {
System.out.println("Service: onCreateEngine");
this.myEngine = new WallpaperEngine();
return myEngine;
}
public void onDestroy() {
this.myEngine = null;
super.onDestroy();
}
private class WallpaperEngine extends Engine implements OnGestureListener,
OnSharedPreferenceChangeListener {
public Bitmap image1, backgroundImage;
private ArrayList<Leaf> leafList;
private Bitmap bitmap1;
private Bitmap bitmap2;
private Bitmap bitmap3;
private Bitmap currentBackgroundBitmap;
private Paint paint;
private int count;
private int heightOfCanvas;
private int widthOfCanvas;
private float touchX;
private float touchY;
private int interval;
private int amount;
private boolean fallingDown;
private float bgX = 0;
private String colorFlag;
private String backgroundFlag;
private Random rand;
private GestureDetector detector;
private static final int DRAW_MSG = 0;
private static final int MAX_SIZE = 101;
private Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case DRAW_MSG:
drawPaper();
break;
}
}
};
/** hands colors for hour, min, sec */
private int[] colors = { 0xFFFF0000, 0xFF0000FF, 0xFFA2BC13 };
// private int bgColor;
private int width;
private int height;
private boolean visible = true;
private boolean displayHandSec;
private AnalogClock clock;
private SharedPreferences prefs;
WallpaperEngine() {
// get the fish and background image references
backgroundImage = BitmapFactory.decodeResource(getResources(),
R.drawable.bg1);
SharedPreferences sp = getSharedPreferences("back_position",
Activity.MODE_PRIVATE);
int position = sp.getInt("back_position", 1);
Global.backgroundDial = BitmapFactory.decodeResource(
getResources(), Global.BackgroundId[position]);
prefs = PreferenceManager
.getDefaultSharedPreferences(ClockWallpaperService.this);
prefs.registerOnSharedPreferenceChangeListener(this);
displayHandSec = prefs.getBoolean(
SettingsActivity.DISPLAY_HAND_SEC_KEY, true);
paint = new Paint();
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(5);
// bgColor = Color.parseColor("#C0C0C0");
clock = new AnalogClock(getApplicationContext());
}
#Override
public void onCreate(SurfaceHolder surfaceHolder) {
// TODO Auto-generated method stub
super.onCreate(surfaceHolder);
System.out.println("Engine: onCreate");
this.leafList = new ArrayList<Leaf>();
this.bitmap1 = BitmapFactory.decodeResource(getResources(),
R.drawable.flower1);
this.bitmap2 = BitmapFactory.decodeResource(getResources(),
R.drawable.flower2);
this.bitmap3 = BitmapFactory.decodeResource(getResources(),
R.drawable.flower3);
this.paint = new Paint();
this.paint.setAntiAlias(true);
this.count = -1;
this.rand = new Random();
this.detector = new GestureDetector(this);
this.touchX = -1.0f;
this.touchY = -1.0f;
SharedPreferences pref = PreferenceManager
.getDefaultSharedPreferences(ClockWallpaperService.this);
pref.registerOnSharedPreferenceChangeListener(this);
String speedStr = pref.getString("leaf_falling_speed", "20");
String amountStr = pref.getString("leaf_number", "50");
this.interval = Integer.parseInt(speedStr);
this.amount = Integer.parseInt(amountStr);
this.colorFlag = pref.getString("leaf_color", "0");
this.backgroundFlag = pref.getString("paper_background", "0");
String directionFlag = pref.getString("leaf_moving_direction", "0");
if (directionFlag.equals("0")) {
this.fallingDown = true;
} else {
this.fallingDown = false;
}
this.setTouchEventsEnabled(true);
}
#Override
public void onDestroy() {
// TODO Auto-generated method stub
System.out.println("Engine: onDestroy");
this.mHandler.removeMessages(DRAW_MSG);
PreferenceManager.getDefaultSharedPreferences(
ClockWallpaperService.this)
.unregisterOnSharedPreferenceChangeListener(this);
super.onDestroy();
}
#Override
public void onSurfaceChanged(SurfaceHolder holder, int format,
int width, int height) {
// TODO Auto-generated method stub
this.width = width;
this.height = height;
super.onSurfaceChanged(holder, format, width, height);
}
#Override
public void onSurfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
super.onSurfaceCreated(holder);
System.out.println("Engine: onSurfaceCreate");
Canvas canvas = holder.lockCanvas();
this.heightOfCanvas = canvas.getHeight();
this.widthOfCanvas = canvas.getWidth();
System.out.println("Width = " + widthOfCanvas + ", Height = "
+ heightOfCanvas);
holder.unlockCanvasAndPost(canvas);
this.mHandler.sendEmptyMessage(DRAW_MSG);
}
#Override
public void onSurfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
System.out.println("Engine: onSurfaceDestroyed");
this.mHandler.removeMessages(DRAW_MSG);
if (this.currentBackgroundBitmap != null) {
this.currentBackgroundBitmap.recycle();
this.currentBackgroundBitmap = null;
}
if (this.bitmap1 != null) {
this.bitmap1.recycle();
this.bitmap1 = null;
}
if (this.bitmap2 != null) {
this.bitmap2.recycle();
this.bitmap2 = null;
}
if (this.bitmap3 != null) {
this.bitmap3.recycle();
this.bitmap3 = null;
}
super.onSurfaceDestroyed(holder);
}
#Override
public void onOffsetsChanged(float xOffset, float yOffset,
float xOffsetStep, float yOffsetStep, int xPixelOffset,
int yPixelOffset) {
super.onOffsetsChanged(xOffset, yOffset, xOffsetStep, yOffsetStep,
xPixelOffset, yPixelOffset);
System.out.println("xPixelOffset: " + xPixelOffset
+ ", yPixelOffset: " + yPixelOffset);
this.bgX = xPixelOffset;
}
private void drawPaper() {
count++;
if (count >= 10000) {
count = 0;
}
if (count % 10 == 0) {
if (this.leafList.size() < MAX_SIZE) {
Leaf l = null;
Bitmap temp = bitmap1;
if (colorFlag.equals("0")) {
int index = rand.nextInt(3) + 1;
switch (index) {
case 1:
temp = bitmap1;
break;
case 2:
temp = bitmap2;
break;
case 3:
temp = bitmap3;
break;
default:
temp = bitmap1;
break;
}
} else if (colorFlag.equals("1")) {
temp = bitmap1;
} else if (colorFlag.equals("2")) {
temp = bitmap2;
} else if (colorFlag.equals("3")) {
temp = bitmap3;
}
l = new Leaf(temp, this.heightOfCanvas, this.widthOfCanvas);
this.leafList.add(l);
}
}
SurfaceHolder holder = this.getSurfaceHolder();
Canvas canvas = holder.lockCanvas();
drawBackground(canvas);
int size = Math.min(this.amount, this.leafList.size());
for (int i = 0; i < size; i++) {
Leaf l = this.leafList.get(i);
if (l.isTouched()) {
l.handleTouched(touchX, touchY);
} else {
l.handleFalling(this.fallingDown);
}
l.drawLeaf(canvas, paint);
}
holder.unlockCanvasAndPost(canvas);
this.mHandler.sendEmptyMessageDelayed(DRAW_MSG, this.interval);
}
private void drawBackground(Canvas c) {
c.drawBitmap(backgroundImage, 0, 0, null);
clock.config(width / 2, height / 2, (int) (width * 0.6f),
new Date(), paint, colors, displayHandSec);
clock.draw(c);
}
#Override
public void onTouchEvent(MotionEvent event) {
super.onTouchEvent(event);
this.detector.onTouchEvent(event);
}
public boolean onDown(MotionEvent e) {
touchX = e.getX();
touchY = e.getY();
int size = Math.min(this.amount, this.leafList.size());
for (int i = 0; i < size; i++) {
Leaf l = this.leafList.get(i);
float centerX = l.getX() + l.getBitmap().getWidth() / 2.0f;
float centerY = l.getY() + l.getBitmap().getHeight() / 2.0f;
if (!l.isTouched()) {
if (Math.abs(centerX - touchX) <= 80
&& Math.abs(centerY - touchY) <= 80
&& centerX != touchX) {
l.setTouched(true);
}
}
}
return true;
}
public void onShowPress(MotionEvent e) {
}
public boolean onSingleTapUp(MotionEvent e) {
return false;
}
public boolean onScroll(MotionEvent e1, MotionEvent e2,
float distanceX, float distanceY) {
return false;
}
public void onLongPress(MotionEvent e) {
}
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
return false;
}
public void onSharedPreferenceChanged(
SharedPreferences sharedPreferences, String key) {
if (key.equals("leaf_falling_speed")) {
String speedStr = sharedPreferences.getString(key, "20");
this.interval = Integer.parseInt(speedStr);
} else if (key.equals("leaf_number")) {
String amountStr = sharedPreferences.getString(key, "50");
this.amount = Integer.parseInt(amountStr);
} else if (key.equals("leaf_moving_direction")) {
String directionFlag = sharedPreferences.getString(key, "0");
if (directionFlag.equals("0")) {
this.fallingDown = true;
} else {
this.fallingDown = false;
}
} else if (key.equals("leaf_color")) {
this.colorFlag = sharedPreferences.getString(key, "0");
this.leafList.removeAll(leafList);
}
}
}
}

Android game in surfaceview lagg spikes

guys. I'm playing around with making my very first Android game, but stumbled into a problem. The framerate seems to have random lag spikes. If I comment the background(s) out the framerate gets much smoother. I've looked around SO and can't find anything to solve my problems. I have a feeling it has something to do with allocating a specific amount of time every time I draw, but I don't know how to properly implement such a feature. Any suggestions? Btw, tryed hardware ac, anti etc.
This is the class that starts the surfaceview :
package com.example.glassrunner;
Imports Here
public class Game extends Activity
{
MySurfaceView mySurfaceView;
public SoundPool spool;
private int soundID;
int length=0;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
this.setVolumeControlStream(AudioManager.STREAM_MUSIC);
mySurfaceView = new MySurfaceView(this);
setContentView(mySurfaceView);
}
#Override
protected void onResume()
{
// TODO Auto-generated method stub
super.onResume();
mySurfaceView.onResumeMySurfaceView();
}
#Override
protected void onPause()
{
// TODO Auto-generated method stub
super.onPause();
mySurfaceView.onPauseMySurfaceView();
}
#Override
protected void onDestroy()
{
super.onDestroy();
mySurfaceView = null;
}
}
This is the surfaceview class :
package com.example.glassrunner;
Imports here
public class MySurfaceView extends SurfaceView implements Runnable
{
public static boolean gameOver = false;
SurfaceHolder surfaceHolder;
Thread thread = null;
public Integer score=0;
public SoundPool spool;
private int soundID;
int length=0;
public static MediaPlayer mp;
volatile boolean running = false;
int Yposition = 450;
int Xposition = 50;
Paint textPaint;
long mLastTime;
Bitmap background;
Bitmap background2;
Bitmap lines;
Bitmap runSprite;
Bitmap box;
Paint bitmapPaint ;
Paint textPaint2;
Bitmap scaledBackground ;
Bitmap scaledBackground2 ;
Bitmap scaledLines ;
Bitmap scaledBox;
Canvas canvas;
Paint paint;
int SpX=0;
int SpY=0;
Bitmap[][] sprite;
/** Variables for the counter */
int frameSamplesCollected = 0;
int frameSampleTime = 0;
int fps = 0;
int speed = 5;
Toast GameOverToast;
Context context;
MediaPlayer mMediaPlayer;
public MySurfaceView(Context context)
{
super(context);
this.context = context;
// TODO Auto-generated constructor stub
surfaceHolder = getHolder();
surfaceHolder.setFormat(PixelFormat.RGB_565);
CharSequence text = "Game Over!";
int duration = Toast.LENGTH_SHORT;
GameOverToast = Toast.makeText(context, text, duration);
spool = new SoundPool(10, AudioManager.STREAM_MUSIC, 0);
soundID = spool.load(context, R.raw.jump, 1);
mp = MediaPlayer.create(context, R.raw.saturdaymorningfunk);
initialization();
}
public void initialization()
{
mp.setLooping(true);
mp.start();
Options options = new Options();
options.inSampleSize = 1/4;
options.inPreferredConfig = Bitmap.Config.RGB_565;
background=BitmapFactory.decodeResource(getResources(),R.drawable.background,options);
lines=BitmapFactory.decodeResource(getResources(),R.drawable.lines);// getting the png from drawable folder
background2=BitmapFactory.decodeResource(getResources(),R.drawable.background2,options);
runSprite=BitmapFactory.decodeResource(getResources(),R.drawable.runsprite);
box=BitmapFactory.decodeResource(getResources(),R.drawable.box);
bitmapPaint = new Paint(Paint.ANTI_ALIAS_FLAG); // tool for painting on the canvas
bitmapPaint.setAntiAlias(true);
bitmapPaint.setFilterBitmap(true);
textPaint = new Paint();
textPaint.setColor(Color.RED);
textPaint.setTextSize(32);
textPaint2 = new Paint();
textPaint2.setColor(Color.BLUE);
textPaint2.setTextSize(50);
scaledBackground = Bitmap.createScaledBitmap(background, 2560, 500, true);
scaledBackground2 = Bitmap.createScaledBitmap(background2, 2560, 400, true);
scaledLines = Bitmap.createScaledBitmap(lines, 2560, 30, true);
runSprite = Bitmap.createScaledBitmap(runSprite, 1400, 1000, true);
scaledBox = Bitmap.createScaledBitmap(box, 100, 100, true);
sprite = new Bitmap[4][7];
for(int row=0;row<=3;row++)
{
for(int col=0;col<=6;col++)
{
sprite[row][col] = Bitmap.createBitmap(runSprite, SpX, SpY, 200, 250);
SpX+=200;
}
SpX=0;
SpY+=250;
}
}
public void onResumeMySurfaceView()
{
mp.seekTo(length);
mp.start();
running = true;
thread = new Thread(this);
thread.start();
}
public void onPauseMySurfaceView()
{
mp.pause();
length=mp.getCurrentPosition();
boolean retry = true;
running = false;
while(retry){
try {
thread.join();
retry = false;
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public void onDestroyMySurfaceView()
{
mp.stop();
running = false;
thread = null;
thread.stop();
}
private void fps()
{
long now = System.currentTimeMillis();
if (mLastTime != 0)
{
//Time difference between now and last time we were here
int time = (int) (now - mLastTime);
frameSampleTime += time;
frameSamplesCollected++;
//After 10 frames
if (frameSamplesCollected == 10)
{
//Update the fps variable
fps = (int) (10000 / frameSampleTime);
//Reset the sampletime + frames collected
frameSampleTime = 0;
frameSamplesCollected = 0;
}
}
mLastTime = now;
}
public boolean pressDown = false;
public long pressTime;
public boolean onTouchEvent(MotionEvent event)
{
if (event != null)
{
if (event.getAction() == MotionEvent.ACTION_DOWN)
{ if(Yposition == orgPos)
{
spool.play(soundID, 15, 15, 1, 0, 1f);
pressDown = true;
pressTime = System.currentTimeMillis();
}
}else if (event.getAction() == MotionEvent.ACTION_UP)
{
pressDown = false;
}
}
return true;
}
int x=0;
int y=100;
int x2=0;
int y2=20;
int row=0;
int col=0;
int limit = 100;
int orgPos = 450;
int Xbox = 1280;
int Ybox = 580;
Random r = new Random();
int RBox;
public static String Fscore;
boolean onTop = false;
long now;
long start;
long stop;
long time ;
int spritePosition = 0 ;
int spriteSize;
#Override
public void run()
{
while(running)
{
canvas = null;
if(surfaceHolder.getSurface().isValid())
{
canvas = surfaceHolder.lockCanvas();
fps(); // fps
// Update screen parameters
update();
draw();
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
}
public void update()
{
if(score<500)
{
speed = 7;
}
else if(score%500 == 0)
{
speed = 7 + (score / 500);
}
if(col==6)
{
row++;
col=0;
}
if(row==4)
{
row=0;
}
score++;
Fscore = score.toString();
if(x>-1280)
{
x-=speed;
}else if(x<=-1280)
{
x=0;
}
if(x2>-1280)
{
x2-=5;
}else if(x2<=-1280)
{
x2=-0;
}
RBox = r.nextInt(999)+1280;
if(Xbox > -100)
{
Xbox-=speed;
}else if(Xbox<=-100)
{
Xbox=RBox;
}
if( (Xposition + 200 == Xbox +40 )&&(Yposition + 250 > Ybox+20)||( Xposition+200<=Xbox+70)&&( Xposition+200>=Xbox+20)&&(Yposition + 250 > Ybox+30) ) // collision
{
GameOverToast.show();
running = false;
spool.release();
mp.release();
Looper.prepare();
Intent database = new Intent(context, MainHighscore.class);
database.putExtra("score", Fscore);
context.startActivity(database);
onDestroyMySurfaceView();
}
now = System.currentTimeMillis();
if(( now - pressTime) <= 600)
{
if(Yposition > limit)
{
Yposition -= 10;
}
}
onTop = false;
if((now - pressTime) >= 600 && (now - pressTime) <= 1200)
{
if(!(Yposition == orgPos))
{
if(Yposition+250 >= Ybox && Xposition+200>=Xbox+70 && Xposition <= Xbox+40)
{
onTop=true;
Yposition = 340;
}else
{
Yposition += 10;
}
}
}
if((now - pressTime) >= 1200)
{
if(Yposition < 450) Yposition +=10;
else Yposition = 450;
}
}
public void draw()
{
canvas.drawColor(Color.WHITE);
//canvas.drawBitmap(scaledBackground, x2,y2, bitmapPaint);
canvas.drawBitmap(scaledBackground2, x,y, bitmapPaint);
canvas.drawBitmap(scaledLines, x,650, bitmapPaint);
canvas.drawText(Fscore, 1050, 50, textPaint2);
canvas.drawText(fps + " fps", getWidth() / 2, getHeight() / 2, textPaint);
canvas.drawBitmap(sprite[row][col],Xposition,Yposition,bitmapPaint );
canvas.drawBitmap(scaledBox,Xbox,Ybox,bitmapPaint);
col++;
}
}
I think your problem might be actually the moving part. Your just drawing too much stuff, and the surfaceView is not meant for that.

Categories

Resources