Basically, I'd like to subclass ClipData.Item so that I can send data other than CharSequence, Intent or URI along with a DragEvent. The docs seem to suggest this is possible (see the documentation alongside the toString() method, which specifically mentions subclasses of Item), however everything I've tried hasn't worked despite neither ClipData nor Item being declared final.
The basic setup that I've got is an inner class extending ClipData.Item like so:
TowerButton.java
package com.conundrum.toweroffensenative.app;
import android.content.ClipData;
import android.content.ClipDescription;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import java.util.List;
/**
* Created by Nums on 27/03/14.
*/
public class TowerButton extends View {
private Paint mBackgroundPaint, mTowerPaint, mShadowPaint, mLabelPaint, mDisabledPaint;
private List<Tower> mTowers;
private Path mTowerPath;
private DragShadowBuilder mDragShadowBuilder;
private Rect r;
public TowerButton(Context context, AttributeSet attrs, List<Tower> towers) {
super(context, attrs);
mTowers = towers;
init();
}
// If I need a tower type that starts with 0 stock, add constructor which takes Paint/Path as args
private void init() {
mBackgroundPaint = new Paint();
mBackgroundPaint.setStyle(Paint.Style.FILL);
mBackgroundPaint.setColor(Color.GRAY);
mTowerPaint = mTowers.get(0).getPaint();
mTowerPath = mTowers.get(0).getPath();
mShadowPaint = new Paint(mTowerPaint);
mShadowPaint.setAlpha(150);
mDisabledPaint = new Paint(mTowerPaint);
mDisabledPaint.setColor(Color.LTGRAY);
mDisabledPaint.setAlpha(150);
mLabelPaint = new Paint();
mLabelPaint.setTextSize(28);
mLabelPaint.setTextAlign(Paint.Align.CENTER);
mLabelPaint.setAntiAlias(true);
mLabelPaint.setColor(Color.WHITE);
mDragShadowBuilder = new DragShadowBuilder(this) {
#Override
public void onDrawShadow(Canvas canvas) {
canvas.drawPath(mTowerPath, mShadowPaint);
}
};
setTag(mTowers.get(0).getClass().getName() + "Button");
r = new Rect();
}
public String getQuantity() {
return String.valueOf(mTowers.size());
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
Matrix pathMatrix = new Matrix();
RectF pathBounds = new RectF();
mTowerPath.computeBounds(pathBounds, false);
pathMatrix.setScale(w / pathBounds.width(), h / pathBounds.height());
mTowerPath.transform(pathMatrix);
r.set(0, 0, w, h);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawRect(r, mBackgroundPaint);
if (mTowers.size() > 0) {
canvas.drawPath(mTowerPath, mTowerPaint);
canvas.drawText(getQuantity(), getX() + (getWidth() / 2), getY() + (getHeight() / 2), mLabelPaint);
} else {
canvas.drawPath(mTowerPath, mDisabledPaint);
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN && mTowers.size() > 0) {
Tower dragTower = mTowers.get(0);
TowerItem item = new TowerItem(dragTower);
ClipData dragData = new ClipData(dragTower.getBuildRow(),
new String[]{ ClipDescription.MIMETYPE_TEXT_PLAIN }, item);
startDrag(dragData, mDragShadowBuilder, null, 0);
return true;
}
return false;
}
public Tower giveTower() {
// TODO: need checking to ensure size > 0?
Tower tower = mTowers.remove(0);
invalidate();
return tower;
}
public void recycleTower(Tower tower) {
mTowers.add(tower);
invalidate();
}
public static class TowerItem extends ClipData.Item {
final Tower mTower;
public TowerItem(Tower tower) {
super("");
mTower = tower;
}
public Tower getTower() {
return mTower;
}
#Override
public CharSequence coerceToText(Context context) {
if (mTower != null) {
return mTower.getClass().getName();
}
return super.coerceToText(context);
}
}
}
Then, in the class which will accept the DropEvent:
TowerView.java
package com.conundrum.toweroffensenative.app;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.content.ClipData;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
import android.os.Build;
import android.util.AttributeSet;
import android.util.Log;
import android.view.DragEvent;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewPropertyAnimator;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
/**
* Created by Nums on 24/03/14.
*/
public class TowerView extends View {
private Paint mBasePaint, mHighlightPaint, mStunnedPaint, mSelectedPaint;
private Tower mTower;
private Path mTowerPath;
private Paint mTowerPaint;
private boolean highlighted;
private boolean stunned;
private boolean selected;
private int mIndex;
private List<TowerView> mNeighbours;
private Rect r;
private class mListener extends GestureDetector.SimpleOnGestureListener {
#Override
public boolean onDown(MotionEvent e) {
return true;
}
#Override
public boolean onSingleTapUp(MotionEvent e) {
for (TowerView tv : mNeighbours) {
tv.highlighted ^= true;
tv.invalidate();
}
return true;
}
#Override
public void onLongPress(MotionEvent e) {
List<TowerView> myRow = ((TowerGrid) getParent()).getRow(mIndex % TowerGrid.ROWS);
for (TowerView v : myRow) {
v.stunned ^= true;
v.invalidate();
}
}
}
GestureDetector mDetector = new GestureDetector(TowerView.this.getContext(), new mListener());
Callable<Void> mStartRecycleCallable = new Callable<Void>() {
#Override
public Void call() throws Exception {
startRecycle();
return null;
}
};
Callable<Void> mRecycleCallable = new Callable<Void>() {
#Override
public Void call() throws Exception {
recycle();
return null;
}
};
public TowerView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
mIndex = -1;
mNeighbours = new ArrayList<TowerView>();
highlighted = false;
stunned = false;
selected = false;
LinearGradient baseGradient = new LinearGradient(0, 0, 0, 25,
new int[] {Color.LTGRAY, Color.DKGRAY}, null, Shader.TileMode.MIRROR);
LinearGradient highlightGradient = new LinearGradient(0, 0, 0, 25,
new int[] {Color.YELLOW, Color.RED}, null, Shader.TileMode.MIRROR);
LinearGradient stunnedGradient = new LinearGradient(0, 0, 0, 25,
new int[] {Color.CYAN, Color.BLUE}, null, Shader.TileMode.MIRROR);
mBasePaint = new Paint();
mBasePaint.setShader(baseGradient);
mHighlightPaint = new Paint();
mHighlightPaint.setShader(highlightGradient);
mStunnedPaint = new Paint();
mStunnedPaint.setShader(stunnedGradient);
mSelectedPaint = new Paint();
mSelectedPaint.setStyle(Paint.Style.STROKE);
mSelectedPaint.setColor(Color.GREEN);
mSelectedPaint.setStrokeWidth(5);
r = new Rect();
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
r.set(0, 0, w, h);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// Draw the tower base in one of three styles
if (highlighted) {
canvas.drawRect(r, mHighlightPaint);
} else if (stunned) {
canvas.drawRect(r, mStunnedPaint);
} else {
canvas.drawRect(r, mBasePaint);
}
if (mTower != null) {
canvas.drawPath(mTowerPath, mTowerPaint);
}
if (selected) {
canvas.drawRect(r, mSelectedPaint);
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
boolean result = mDetector.onTouchEvent(event);
if (!result) {
// Custom gesture code
}
return result;
}
#Override
public boolean dispatchTouchEvent(MotionEvent event) {
boolean result = super.dispatchTouchEvent(event);
return result;
}
#Override
public boolean onDragEvent(DragEvent event) {
final int action = event.getAction();
switch(action) {
case DragEvent.ACTION_DRAG_STARTED:
// check if Tower can be built on this col - in case I allow that to differ per Tower
if (mIndex / TowerGrid.ROWS == Integer.parseInt(event.getClipDescription().getLabel().toString())) {
selected = true;
invalidate();
return true;
}
return false;
case DragEvent.ACTION_DRAG_ENTERED:
highlighted = true;
invalidate();
break;
case DragEvent.ACTION_DRAG_EXITED:
highlighted = false;
invalidate();
break;
case DragEvent.ACTION_DROP:
ClipData.Item item = event.getClipData().getItemAt(0);
if (item instanceof TowerButton.TowerItem) {
Log.d("towerview", "SUCCESS!");
}
// Always returns false
TowerButton.TowerItem tItem = (TowerButton.TowerItem) item; // exception
Tower dragTower = item.getTower();
setTower(dragTower);
return true;
case DragEvent.ACTION_DRAG_ENDED:
highlighted = false;
selected = false;
invalidate();
return true;
}
return false;
}
public void setTower(Tower tower) {
if (mTower != null) {
TowerButton button = (TowerButton) getRootView().findViewWithTag(mTower.getClass().getName() + "Button");
button.recycleTower(mTower);
}
mTower = tower;
mTowerPaint = tower.getPaint();
mTowerPath = tower.getPath();
Matrix pathMatrix = new Matrix();
RectF pathBounds = new RectF();
mTowerPath.computeBounds(pathBounds, false);
pathMatrix.setScale(getWidth() / pathBounds.width(), getHeight() / pathBounds.height());
mTowerPath.transform(pathMatrix);
invalidate();
}
public boolean advance(int distance) {
if (!stunned) {
// first account for the new view being added
setTranslationX(getTranslationX() - distance);
// then animate right over 1000 ms
ViewPropertyAnimator animator = animate().translationXBy(distance).setDuration(1000);
addCompatibilityAnimationCallback(animator, mStartRecycleCallable).start();
return true;
}
return false;
}
private void startRecycle() {
if (mIndex / TowerGrid.ROWS == TowerGrid.COLS - 1) {
ViewPropertyAnimator animator = animate().translationXBy(getWidth() / -2).scaleX(0).setDuration(1000);
addCompatibilityAnimationCallback(animator, mRecycleCallable).start();
}
}
private void recycle() {
if (mTower != null) {
TowerButton button = (TowerButton) getRootView().findViewWithTag(mTower.getClass().getName() + "Button");
button.recycleTower(mTower);
}
((ViewGroup) getParent()).removeView(this);
}
public void updateNeighbours() {
ViewGroup parent = (ViewGroup) getParent();
mIndex = parent.indexOfChild(this);
mNeighbours.clear();
if (mIndex >= TowerGrid.ROWS) {
mNeighbours.add((TowerView) parent.getChildAt(mIndex - TowerGrid.ROWS));
}
if (mIndex < TowerGrid.ROWS * (TowerGrid.COLS - 2)) {
mNeighbours.add((TowerView) parent.getChildAt(mIndex + TowerGrid.ROWS));
}
if (mIndex % TowerGrid.ROWS != 0) {
mNeighbours.add((TowerView) parent.getChildAt(mIndex - 1));
}
if (mIndex % TowerGrid.ROWS != TowerGrid.ROWS - 1) {
mNeighbours.add((TowerView) parent.getChildAt(mIndex + 1));
}
}
private ViewPropertyAnimator addCompatibilityAnimationCallback(ViewPropertyAnimator animator, final Callable<Void> callbackFunc) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
animator.setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
try {
callbackFunc.call();
} catch (Exception e) {
e.printStackTrace();
}
}
});
} else {
animator.withEndAction(new Runnable() {
#Override
public void run() {
try {
callbackFunc.call();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
return animator;
}
}
There are no compile-time errors. However, when attempting to perform the cast at runtime, I get the exception:
java.lang.ClassCastException: android.content.ClipData$Item cannot be cast to com.conundrum.toweroffensenative.app.TowerButton$TowerItem
Similarly, code like item instanceof TowerButton.TowerItem returns false, even though TowerItem is obviously extending ClipData.Item.
Is there something I'm missing that prevents these classes from being subclassed? Or am I doing something wrong? I know I could use a ContentProvider and URIs to transfer more complex information, but that seems like overkill when the data being transferred never has to be made available outside this application.
EDIT
I've also tried making a subclass of ClipData with it's own Item inner class, so that I can override getItem() to return a TowerItem - but then I need to cast a ClipData to a TowerClipData, which fails with the same error.
EDIT 3
Included the entirety of both relevant files.
TowerItem is descended from ClipData.Item, therefore a TowerItem is a ClipData.Item but the reverse is not always true. A ClipData.Item can be a TowerItem but it isn't necessarily.
You avoid the compiler error by explicitly casting ClipData.Item to TowerItem: (TowerItem)ClipData.Item. But you cannot avoid runtime error.
The right usage of instanceOf should be in this way:
if(event.getClipData().getItemAt(0) instanceOf TowerButton.TowerItem) {
TowerButton.TowerItem item = (TowerButton.TowerItem) event.getClipData().getItemAt(0);
}
Similar problem, and I've been going over the system code for this. Basically, the ClipData is a Parcelable, so I think a subclass of ClipData.Item which doesn't have a sensible subclass of ClipData that recognises your custom ClipData.Item is going to get converted to a Charsequence and then come back as a basic text ClipData.Item. Otherwise, you need to create a ContentProvider for the URI format, which, for this use case, a ui in a single app, is overkill and possibly wrong.
My hack for this was eventually to pass an identifying tag in the ClipData as text, and make the drag initiating view (passed in the event data via the state) responsible for turning this into an object. Not entirely clean but not totally ugly.
Related
I come up against the great problem.
I`m try to BebopVideoView to Mat.
(BebopVideoView is parrot drone source code)
But I was failed for several days.
Here is the code.
package com.hyeonjung.dronecontroll.view;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.media.MediaCodec;
import android.media.MediaFormat;
import android.os.Environment;
import android.util.AttributeSet;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import com.parrot.arsdk.arcontroller.ARCONTROLLER_STREAM_CODEC_TYPE_ENUM;
import com.parrot.arsdk.arcontroller.ARControllerCodec;
import com.parrot.arsdk.arcontroller.ARFrame;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class BebopVideoView extends SurfaceView implements SurfaceHolder.Callback {
private static final String TAG = "BebopVideoView";
private static final String VIDEO_MIME_TYPE = "video/avc";
private static final int VIDEO_DEQUEUE_TIMEOUT = 33000;
private MediaCodec mMediaCodec;
private Lock mReadyLock;
private boolean mIsCodecConfigured = false;
private ByteBuffer mSpsBuffer;
private ByteBuffer mPpsBuffer;
private ByteBuffer[] mBuffers;
private static final int VIDEO_WIDTH = 640;
private static final int VIDEO_HEIGHT = 368;
public byte[] a;
public Mat k;
public BebopVideoView(Context context) {
super(context);
customInit();
}
public BebopVideoView(Context context, AttributeSet attrs) {
super(context, attrs);
customInit();
}
public BebopVideoView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
customInit();
}
private void customInit() {
mReadyLock = new ReentrantLock();
getHolder().addCallback(this);
}
public void displayFrame(ARFrame frame) {
mReadyLock.lock();
if ((mMediaCodec != null)) {
if (mIsCodecConfigured) {
// Here we have either a good PFrame, or an IFrame
int index = -1;
try {
index = mMediaCodec.dequeueInputBuffer(VIDEO_DEQUEUE_TIMEOUT);
} catch (IllegalStateException e) {
Log.e(TAG, "Error while dequeue input buffer");
}
if (index >= 0) {
ByteBuffer b;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
b = mMediaCodec.getInputBuffer(index); // fill inputBuffer with valid data
}
else {
b = mBuffers[index]; // fill inputBuffer with valid data
b.clear();
}
if (b != null) {
b.put(frame.getByteData(), 0, frame.getDataSize()); //write to b.
getMat(frame);
saveMat(k);
}
try {
mMediaCodec.queueInputBuffer(index, 0, frame.getDataSize(), 0, 0); //end of stream
} catch (IllegalStateException e) {
Log.e(TAG, "Error while queue input buffer");
}
}
}
// Try to display previous frame
MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
int outIndex;
try {
outIndex = mMediaCodec.dequeueOutputBuffer(info, 0);
while (outIndex >= 0) {
mMediaCodec.releaseOutputBuffer(outIndex, true);
outIndex = mMediaCodec.dequeueOutputBuffer(info, 0);
}
} catch (IllegalStateException e) {
Log.e(TAG, "Error while dequeue input buffer (outIndex)");
}
}
mReadyLock.unlock();
}
public void configureDecoder(ARControllerCodec codec) {
mReadyLock.lock();
if (codec.getType() == ARCONTROLLER_STREAM_CODEC_TYPE_ENUM.ARCONTROLLER_STREAM_CODEC_TYPE_H264) {
ARControllerCodec.H264 codecH264 = codec.getAsH264();
mSpsBuffer = ByteBuffer.wrap(codecH264.getSps().getByteData());
mPpsBuffer = ByteBuffer.wrap(codecH264.getPps().getByteData());
}
if ((mMediaCodec != null) && (mSpsBuffer != null)) {
configureMediaCodec();
}
mReadyLock.unlock();
}
private void configureMediaCodec() {
MediaFormat format = MediaFormat.createVideoFormat(VIDEO_MIME_TYPE, VIDEO_WIDTH, VIDEO_HEIGHT);
format.setByteBuffer("csd-0", mSpsBuffer);
format.setByteBuffer("csd-1", mPpsBuffer);
mMediaCodec.configure(format, getHolder().getSurface(), null, 0);
mMediaCodec.start();
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.LOLLIPOP) {
mBuffers = mMediaCodec.getInputBuffers();
}
mIsCodecConfigured = true;
}
private void initMediaCodec(String type) {
try {
mMediaCodec = MediaCodec.createDecoderByType(type);
} catch (IOException e) {
Log.e(TAG, "Exception", e);
}
if ((mMediaCodec != null) && (mSpsBuffer != null)) {
configureMediaCodec();
}
}
private void releaseMediaCodec() {
if (mMediaCodec != null) {
if (mIsCodecConfigured) {
mMediaCodec.stop();
mMediaCodec.release();
}
mIsCodecConfigured = false;
mMediaCodec = null;
}
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
mReadyLock.lock();
initMediaCodec(VIDEO_MIME_TYPE);
mReadyLock.unlock();
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
mReadyLock.lock();
releaseMediaCodec();
mReadyLock.unlock();
}
public void getMat(ARFrame frame) {
k = new Mat();
k.get(150, 150, frame.getByteData());
k.put(150, 150, frame.getByteData());
//or
//byte[] a= new byte[b.remaining()];
//b.get(a);
//k.get(150, 150, a);
//k.put(150, 150, a);
}
public void saveMat (Mat mat) {
Mat mIntermediateMat = new Mat(150, 150, CvType.CV_8UC1);
Imgproc.cvtColor(mat, mIntermediateMat, Imgproc.COLOR_GRAY2BGR);
File path = new File(Environment.getExternalStorageDirectory() + "/data");
path.mkdirs();
File file = new File(path, "image.png");
String filename = file.toString();
Boolean bool = Imgcodecs.imwrite(filename, mIntermediateMat);
if (bool)
Log.i(TAG, "SUCCESS writing image to external storage");
else
Log.i(TAG, "Fail writing image to external storage");
}
}
I think I can get an image related data from ByteBuffer b or frame.get ByteData ().
I was confirmed ByteBuffer b and frame.getByteData().
There was char data type with a range of -128 to 127.
So I was confirmed the result of getMat, saveMat and the result was a NULL(Mat k).
What is wrong?
Please help me T.T
If you use a TextureView you can simply grab a bitmap of it and convert it to a Mat. You need to use the TextureView's provided surface rather than the typical SurfaceView holder. This will require some additional refactoring of the mediaCodec lifecycle, but is a fairly trivial change.
public class BebopVideoView extends TextureView implements TextureView.SurfaceTextureListener {
#Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
this.surface = new Surface(surface);
surfaceCreated = true;
}
...
}
And inside of configureMediaCodec use the class level surface captured in onSurfaceTextureAvailable instead....
mediaCodec.configure(format, surface, null, 0);
With a couple other minor tweaks you now have a lot more control over the view. You can do things like setTransform() and more importantly in your case getBitmap:
Mat mat = new Mat();
Utils.bitmapToMat(getBitmap(), mat);
I'm trying to create a textbox effect for my RPG game, but I keep getting nullpointers because my variables are null, but I'm setting them in a method. I also need to be able to update the variables in the method, which isn't working. That's why the NPE is occurring. Here is my code:
package me.loafayyy.gui;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.util.Timer;
import java.util.TimerTask;
import me.loafayyy.main.RPG;
import me.loafayyy.main.RPGPane;
import me.loafayyy.main.RPGState;
public class GuiManager {
public int opacity = 0;
public int step = 0;
public static boolean transitioning = false;
public static boolean dialogue = false;
public String textlines1;
public String textlines2;
public String textlines3;
public boolean rect = false;
public Timer timer = new Timer();
public void createTransition() {
transitioning = true;
rect = true;
}
public void setOpacity(int op) {
opacity = op;
}
public int getOpacity() {
return opacity;
}
public void createDialogue(String line1, String line2, String line3, int dur) { // my method which I'm setting the variables.
if (!dialogue) {
dialogue = true;
this.textlines1 = line1;
this.textlines2 = line2;
this.textlines3 = line3;
timer.schedule(new TimerTask() {
#Override
public void run() {
dialogue = false;
}
}, dur);
} else {
System.out
.println("ERROR: Could not create dialogue, one is already displaying!");
}
}
public void render(Graphics g) {
for (int i = 0; i < 4; i++) {
if (transitioning) {
rect = false;
if (step == 0) {
if (opacity < 255) {
setOpacity(getOpacity() + 1);
} else if (opacity == 255) {
step = 1;
}
} else if (step == 1) {
if (opacity < 256 && opacity != 0) {
setOpacity(getOpacity() - 1);
} else if (opacity == 0) {
transitioning = false;
step = 0;
}
}
}
}
Graphics2D g2 = (Graphics2D) g.create();
if (transitioning) {
if (RPG.state == RPGState.MAIN) {
RPGPane.main.render(g);
} else if (RPG.state == RPGState.PAUSED) {
RPGPane.paused.render(g);
} else if (RPG.state == RPGState.INGAME) {
RPGPane.ingame.render(g);
}
g2.setColor(new Color(0, 0, 0, getOpacity()));
g2.fillRect(0, 0, RPG.getWidth(), RPG.getHeight());
}
if (RPG.state == RPGState.INGAME) {
if (dialogue) {
g2.drawString(textlines1, 300, 300); // <--- null right here
// do other textlines
}
}
}
}
New code:
package me.loafayyy.gui;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.util.Timer;
import java.util.TimerTask;
import me.loafayyy.main.RPG;
import me.loafayyy.main.RPGPane;
import me.loafayyy.main.RPGState;
public class GuiManager {
public int opacity = 0;
public int step = 0;
public static boolean transitioning = false;
public static boolean dialogue = false;
public String textlines1;
public String textlines2;
public String textlines3;
public boolean rect = false;
public Timer timer = new Timer();
public GuiManager () {
textlines1 = "";
}
public void createTransition() {
transitioning = true;
rect = true;
}
public void setOpacity(int op) {
opacity = op;
}
public int getOpacity() {
return opacity;
}
public void render(Graphics g) {
for (int i = 0; i < 4; i++) {
if (transitioning) {
rect = false;
if (step == 0) {
if (opacity < 255) {
setOpacity(getOpacity() + 1);
} else if (opacity == 255) {
step = 1;
}
} else if (step == 1) {
if (opacity < 256 && opacity != 0) {
setOpacity(getOpacity() - 1);
} else if (opacity == 0) {
transitioning = false;
step = 0;
}
}
}
}
Graphics2D g2 = (Graphics2D) g.create();
if (transitioning) {
if (RPG.state == RPGState.MAIN) {
RPGPane.main.render(g);
} else if (RPG.state == RPGState.PAUSED) {
RPGPane.paused.render(g);
} else if (RPG.state == RPGState.INGAME) {
RPGPane.ingame.render(g);
}
g2.setColor(new Color(0, 0, 0, getOpacity()));
g2.fillRect(0, 0, RPG.getWidth(), RPG.getHeight());
}
if (RPG.state == RPGState.INGAME) {
if (dialogue) {
g2.drawString(textlines1, 300, 300);
// do other textlines
}
}
}
public void createDialogue(String line1, String line2, String line3, int dur) {
if (!dialogue) {
dialogue = true;
this.textlines1 = line1;
this.textlines2 = line2;
this.textlines3 = line3;
timer.schedule(new TimerTask() {
#Override
public void run() {
dialogue = false;
}
}, dur);
} else {
System.out
.println("ERROR: Could not create dialogue, one is already displaying!");
}
}
}
I'm calling this from another class using this:
mng.createDialogue("test1", "test2", "test3", 1000);
Stacktrace:
Exception in thread "Thread-10" java.lang.NullPointerException: String is null
at sun.java2d.SunGraphics2D.drawString(Unknown Source)
at me.loafayyy.gui.GuiManager.render(GuiManager.java:98)
at me.loafayyy.main.RPGPane.render(RPGPane.java:107)
at me.loafayyy.main.RPGPane.run(RPGPane.java:82)
at java.lang.Thread.run(Unknown Source)
RPGPane is my JPanel.
I think the problem is your render method can be called before your createDialogue method. As a result, textlines1 can be unassigned/null.
One way to solve this is to take #Takendarkk's advice and initialize the variable to "". Another way is to ask yourself, "Does it make sense for this class to exist without textlines1 being set? If not, perhaps set this in the GuiManager's constructor.
After running my SWT application it doesn’t have any error at the time of compilation.
But after running it will shows the output for few sec and then the eclipse instance will become not responsive.
Please help me to avoid exceptions
I try to increase heap size.anybody is here to help me.....plzzzzzzzzzzzzzzzzzzzz
here i will give my code. i think my logic also have a problem. but i dont know how to correct it. i just follow on book to do this.here it is a program for clock. and i did in each movement of second hand a new thread is created. i want to make it as one thread.
it shows unable to create new native threads
activator.java
package com.packtpub.e4.clock.ui;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Tray;
import org.eclipse.swt.widgets.TrayItem;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.osgi.framework.BundleContext;
/**
* The activator class controls the plug-in life cycle
*/
public class Activator extends AbstractUIPlugin {
// The plug-in ID
public static final String PLUGIN_ID = "com.packtpub.e4.clock.ui"; //$NON-NLS-1$
// The shared instance
private static Activator plugin;
private TrayItem trayItem;
private Image image;
private Shell shell;
/**
* The constructor
*/
public Activator() {
}
/*
* (non-Javadoc)
* #see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)
*/
public void start(BundleContext context) throws Exception {
super.start(context);
plugin = this;
final Display display = Display.getDefault();
display.asyncExec(new Runnable() {
public void run() {
image = new Image(display, Activator.class.getResourceAsStream("/icons/sample.gif"));
Tray tray = display.getSystemTray();
if (tray != null && image != null) {
trayItem = new TrayItem(tray, SWT.NONE);
trayItem.setToolTipText("Hello World");
trayItem.setVisible(true);
trayItem.setText("Hello World");
trayItem.setImage(new Image(trayItem.getDisplay(),
Activator.class.getResourceAsStream("/icons/sample.gif")));
}
trayItem.addSelectionListener(new SelectionListener() {
public void widgetSelected(SelectionEvent e) {
if (shell == null) {
shell = new Shell(trayItem.getDisplay());
shell.setLayout(new FillLayout());
new ClockWidget(shell, SWT.NONE, new RGB(255, 0, 255));
shell.pack();
}
shell.open();
}
#Override
public void widgetDefaultSelected(SelectionEvent e) {
// TODO Auto-generated method stub
}
});
}
});
}
/*
* (non-Javadoc)
* #see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext)
*/
public void stop(BundleContext context) throws Exception {
if (trayItem != null && !trayItem.isDisposed()) {
Display.getDefault().asyncExec(new Runnable() {
public void run() {
if (trayItem != null && !trayItem.isDisposed())
trayItem.dispose();
}
});
}
if (image != null && !image.isDisposed()) {
Display.getDefault().asyncExec(new Runnable() {
public void run() {
if (image != null && !image.isDisposed())
image.dispose();
}
});
}
if (shell != null && !shell.isDisposed()) {
Display.getDefault().asyncExec(new Runnable() {
public void run() {
if (shell != null && !shell.isDisposed())
shell.dispose();
}
});
}
}
/**
* Returns the shared instance
*
* #return the shared instance
*/
public static Activator getDefault() {
return plugin;
}
/**
* Returns an image descriptor for the image file at the given
* plug-in relative path
*
* #param path the path
* #return the image descriptor
*/
public static ImageDescriptor getImageDescriptor(String path) {
return imageDescriptorFromPlugin(PLUGIN_ID, path);
}
}
clockwidget.java
package com.packtpub.e4.clock.ui;
import java.util.Date;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
public class ClockWidget extends Canvas
{
private final Color color;
private int offset;
public void setOffset(int offset)
{
this.offset = offset;
}
public Color getColor()
{
return color;
}
public int getOffset()
{
return offset;
}
public ClockWidget(Composite parent, int style,RGB rgb)
{
super(parent, style);
this.color = new Color(parent.getDisplay(),rgb);
addDisposeListener(new DisposeListener()
{
public void widgetDisposed(DisposeEvent e)
{
if(color != null && !color.isDisposed())
color.dispose();
}
});
addPaintListener(new PaintListener()
{
public void paintControl(PaintEvent e)
{
ClockWidget.this.paintControl(e);
}
});
}
public void paintControl(PaintEvent e)
{
#SuppressWarnings("deprecation")
int seconds = new Date().getSeconds();
int arc = (15-seconds) * 6 % 360;
e.gc.setBackground(color);
e.gc.fillArc(e.x,e.y,e.width-1,e.height-1,arc-1,2);
e.gc.drawArc(e.x,e.y,e.width-1,e.height-1,0,360);
e.gc.setBackground(e.display.getSystemColor(SWT.COLOR_BLACK));
#SuppressWarnings("deprecation")
int hours = new Date().getHours() + offset;
arc = (3 - hours) * 30 % 360;
e.gc.fillArc(e.x, e.y, e.width-1, e.height-1, arc - 5, 10);
new Thread("TickTock")
{
public void run()
{
while (!ClockWidget.this.isDisposed())
{
ClockWidget.this.getDisplay().asyncExec(
new Runnable()
{
public void run()
{
if (!ClockWidget.this.isDisposed())
ClockWidget.this.redraw();
}
});
try
{
Thread.sleep(99999);
}
catch (InterruptedException e)
{
System.out.println("#clock"+e.toString());
return;
}
}
}
}.start();
}
public Point computeSize(int w,int h,boolean changed)
{
int size;
if(w == SWT.DEFAULT)
{
size = h;
}
else if (h == SWT.DEFAULT)
{
size = w;
}
else
{
size = Math.min(w,h);
}
if(size == SWT.DEFAULT)
size = 50;
return new Point(size,size);
}
}
SampleView.java
package com.packtpub.e4.clock.ui.views;
import java.util.TimeZone;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.part.*;
import org.eclipse.swt.SWT;
import com.packtpub.e4.clock.ui.ClockWidget;
public class SampleView extends ViewPart {
private Combo timezones;
public void createPartControl(Composite parent) {
try{
RowLayout layout = new RowLayout(SWT.HORIZONTAL);
parent.setLayout(layout);
Object[] oo=parent.getDisplay().getDeviceData().objects;
int c = 0;
for (int j = 0; j < oo.length; j++)
if (oo[j] instanceof Color)
c++;
System.err.println("There are " + c + " Color instances");
final ClockWidget clock1 =new ClockWidget(parent, SWT.NONE, new RGB(255,0,0));
//final ClockWidget clock2 =new ClockWidget(parent, SWT.NONE, new RGB(0,255,0));
//final ClockWidget clock3 =new ClockWidget(parent, SWT.NONE, new RGB(0,0,255));
//clock1.setLayoutData(new RowData(20,20));
//clock3.setLayoutData(new RowData(100,100));
String[] ids = TimeZone.getAvailableIDs();
timezones = new Combo(parent, SWT.SIMPLE);
timezones.setVisibleItemCount(5);
for (int i = 0; i < ids.length; i++) {
timezones.add(ids[i]);
timezones.addSelectionListener(new SelectionListener() {
public void widgetSelected(SelectionEvent e) {
String z = timezones.getText();
TimeZone tz = z == null ? null : TimeZone.getTimeZone(z);
TimeZone dt = TimeZone.getDefault();
int offset = tz == null ? 0 : (
tz.getOffset(System.currentTimeMillis()) -
dt.getOffset(System.currentTimeMillis())) / 3600000;
clock1.setOffset(offset);
clock1.redraw();
}
public void widgetDefaultSelected(SelectionEvent e) {
clock1.setOffset(0);
clock1.redraw();
}
});
}
}catch(Exception e){
System.out.println("# SampleView.java"+e.toString());
}
}
public void setFocus() {
timezones.setFocus();
}
}
i got the answer... here the thread call is happend in clockwidgets paintcontrol function cut it from there and paste it on clockwidget constructor.
then the code will work proper
package com.packtpub.e4.clock.ui;
import java.util.Date;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
public class ClockWidget extends Canvas
{
private final Color color;
private int offset;
public void setOffset(int offset)
{
this.offset = offset;
}
public Color getColor()
{
return color;
}
public int getOffset()
{
return offset;
}
public ClockWidget(Composite parent, int style,RGB rgb)
{
super(parent, style);
this.color = new Color(parent.getDisplay(),rgb);
addDisposeListener(new DisposeListener()
{
public void widgetDisposed(DisposeEvent e)
{
if(color != null && !color.isDisposed())
color.dispose();
}
});
new Thread("TickTock")
{
public void run()
{
while (!ClockWidget.this.isDisposed())
{
ClockWidget.this.getDisplay().asyncExec(
new Runnable()
{
public void run()
{
if (!ClockWidget.this.isDisposed())
ClockWidget.this.redraw();
}
});
try
{
Thread.sleep(1000);
}
catch (InterruptedException e)
{
return;
}
}
}
}.start();
addPaintListener(new PaintListener()
{
public void paintControl(PaintEvent e)
{
ClockWidget.this.paintControl(e);
}
});
}
public void paintControl(PaintEvent e)
{
#SuppressWarnings("deprecation")
int seconds = new Date().getSeconds();
int arc = (15-seconds) * 6 % 360;
e.gc.setBackground(color);
e.gc.fillArc(e.x,e.y,e.width-1,e.height-1,arc-1,2);
e.gc.drawArc(e.x,e.y,e.width-1,e.height-1,0,360);
e.gc.setBackground(e.display.getSystemColor(SWT.COLOR_BLACK));
#SuppressWarnings("deprecation")
int hours = new Date().getHours() + offset;
arc = (3 - hours) * 30 % 360;
e.gc.fillArc(e.x, e.y, e.width-1, e.height-1, arc - 5, 10);
}
public Point computeSize(int w,int h,boolean changed)
{
int size;
if(w == SWT.DEFAULT)
{
size = h;
}
else if (h == SWT.DEFAULT)
{
size = w;
}
else
{
size = Math.min(w,h);
}
if(size == SWT.DEFAULT)
size = 50;
return new Point(size,size);
}
}
Hi i have created and android application using an ipcamera,for that i have used mjpeg class
Main class
package com.example.mjpeg;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.Window;
import android.view.WindowManager;
import com.example.mjpeg.MjpegInputStream;
import com.example.mjpeg.MjpegView;
public class MainActivity extends Activity {
private MjpegView mv;
private static final int MENU_QUIT = 1;
/* Creates the menu items */
public boolean onCreateOptionsMenu(Menu menu) {
menu.add(0, MENU_QUIT, 0, "Quit");
return true;
}
/* Handles item selections */
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case MENU_QUIT:
finish();
return true;
}
return false;
}
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
//sample public cam
String URL = "http://192.168.2.1/?action=appletvstream";
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN, WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
mv = new MjpegView(this);
setContentView(mv);
mv.setSource(MjpegInputStream.read(URL));
mv.setDisplayMode(MjpegView.SIZE_BEST_FIT);
mv.showFps(false);
}
public void onPause() {
super.onPause();
mv.stopPlayback();
}
}
MjpegInputstream class
package com.example.mjpeg;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.util.Properties;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
public class MjpegInputStream extends DataInputStream {
private final byte[] SOI_MARKER = { (byte) 0xFF, (byte) 0xD8 };
private final byte[] EOF_MARKER = { (byte) 0xFF, (byte) 0xD9 };
private final String CONTENT_LENGTH = "Content-Length";
private final static int HEADER_MAX_LENGTH = 100;
private final static int FRAME_MAX_LENGTH = 40000 + HEADER_MAX_LENGTH;
private int mContentLength = -1;
public static MjpegInputStream read(String url) {
HttpResponse res;
DefaultHttpClient httpclient = new DefaultHttpClient();
try {
res = httpclient.execute(new HttpGet(URI.create(url)));
return new MjpegInputStream(res.getEntity().getContent());
} catch (ClientProtocolException e) {
} catch (IOException e) {}
return null;
}
public MjpegInputStream(InputStream in) { super(new BufferedInputStream(in, FRAME_MAX_LENGTH)); }
private int getEndOfSeqeunce(DataInputStream in, byte[] sequence) throws IOException {
int seqIndex = 0;
byte c;
for(int i=0; i < FRAME_MAX_LENGTH; i++) {
c = (byte) in.readUnsignedByte();
if(c == sequence[seqIndex]) {
seqIndex++;
if(seqIndex == sequence.length) return i + 1;
} else seqIndex = 0;
}
return -1;
}
private int getStartOfSequence(DataInputStream in, byte[] sequence) throws IOException {
int end = getEndOfSeqeunce(in, sequence);
return (end < 0) ? (-1) : (end - sequence.length);
}
private int parseContentLength(byte[] headerBytes) throws IOException, NumberFormatException {
ByteArrayInputStream headerIn = new ByteArrayInputStream(headerBytes);
Properties props = new Properties();
props.load(headerIn);
return Integer.parseInt(props.getProperty(CONTENT_LENGTH));
}
public Bitmap readMjpegFrame() throws IOException {
mark(FRAME_MAX_LENGTH);
int headerLen = getStartOfSequence(this, SOI_MARKER);
reset();
byte[] header = new byte[headerLen];
readFully(header);
try {
mContentLength = parseContentLength(header);
} catch (NumberFormatException nfe) {
mContentLength = getEndOfSeqeunce(this, EOF_MARKER);
}
reset();
byte[] frameData = new byte[mContentLength];
skipBytes(headerLen);
readFully(frameData);
return BitmapFactory.decodeStream(new ByteArrayInputStream(frameData));
}
}
Mjpeg View
package com.example.mjpeg;
import java.io.IOException;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class MjpegView extends SurfaceView implements SurfaceHolder.Callback {
public final static int POSITION_UPPER_LEFT = 9;
public final static int POSITION_UPPER_RIGHT = 3;
public final static int POSITION_LOWER_LEFT = 12;
public final static int POSITION_LOWER_RIGHT = 6;
public final static int SIZE_STANDARD = 1;
public final static int SIZE_BEST_FIT = 4;
public final static int SIZE_FULLSCREEN = 8;
private MjpegViewThread thread;
private MjpegInputStream mIn = null;
private boolean showFps = false;
private boolean mRun = false;
private boolean surfaceDone = false;
private Paint overlayPaint;
private int overlayTextColor;
private int overlayBackgroundColor;
private int ovlPos;
private int dispWidth;
private int dispHeight;
private int displayMode;
public class MjpegViewThread extends Thread {
private SurfaceHolder mSurfaceHolder;
private int frameCounter = 0;
private long start;
private Bitmap ovl;
public MjpegViewThread(SurfaceHolder surfaceHolder, Context context) { mSurfaceHolder = surfaceHolder; }
private Rect destRect(int bmw, int bmh) {
int tempx;
int tempy;
if (displayMode == MjpegView.SIZE_STANDARD) {
tempx = (dispWidth / 2) - (bmw / 2);
tempy = (dispHeight / 2) - (bmh / 2);
return new Rect(tempx, tempy, bmw + tempx, bmh + tempy);
}
if (displayMode == MjpegView.SIZE_BEST_FIT) {
float bmasp = (float) bmw / (float) bmh;
bmw = dispWidth;
bmh = (int) (dispWidth / bmasp);
if (bmh > dispHeight) {
bmh = dispHeight;
bmw = (int) (dispHeight * bmasp);
}
tempx = (dispWidth / 2) - (bmw / 2);
tempy = (dispHeight / 2) - (bmh / 2);
return new Rect(tempx, tempy, bmw + tempx, bmh + tempy);
}
if (displayMode == MjpegView.SIZE_FULLSCREEN) return new Rect(0, 0, dispWidth, dispHeight);
return null;
}
public void setSurfaceSize(int width, int height) {
synchronized(mSurfaceHolder) {
dispWidth = width;
dispHeight = height;
}
}
private Bitmap makeFpsOverlay(Paint p, String text) {
Rect b = new Rect();
p.getTextBounds(text, 0, text.length(), b);
int bwidth = b.width()+2;
int bheight = b.height()+2;
Bitmap bm = Bitmap.createBitmap(bwidth, bheight, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(bm);
p.setColor(overlayBackgroundColor);
c.drawRect(0, 0, bwidth, bheight, p);
p.setColor(overlayTextColor);
c.drawText(text, -b.left+1, (bheight/2)-((p.ascent()+p.descent())/2)+1, p);
return bm;
}
public void run() {
start = System.currentTimeMillis();
PorterDuffXfermode mode = new PorterDuffXfermode(PorterDuff.Mode.DST_OVER);
Bitmap bm;
int width;
int height;
Rect destRect;
Canvas c = null;
Paint p = new Paint();
String fps = "";
while (mRun) {
if(surfaceDone) {
try {
c = mSurfaceHolder.lockCanvas();
synchronized (mSurfaceHolder) {
try {
bm = mIn.readMjpegFrame();
destRect = destRect(bm.getWidth(),bm.getHeight());
c.drawColor(Color.BLACK);
c.drawBitmap(bm, null, destRect, p);
if(showFps) {
p.setXfermode(mode);
if(ovl != null) {
height = ((ovlPos & 1) == 1) ? destRect.top : destRect.bottom-ovl.getHeight();
width = ((ovlPos & 8) == 8) ? destRect.left : destRect.right -ovl.getWidth();
c.drawBitmap(ovl, width, height, null);
}
p.setXfermode(null);
frameCounter++;
if((System.currentTimeMillis() - start) >= 1000) {
fps = String.valueOf(frameCounter)+"fps";
frameCounter = 0;
start = System.currentTimeMillis();
ovl = makeFpsOverlay(overlayPaint, fps);
}
}
} catch (IOException e) {}
}
} finally { if (c != null) mSurfaceHolder.unlockCanvasAndPost(c); }
}
}
}
}
private void init(Context context) {
SurfaceHolder holder = getHolder();
holder.addCallback(this);
thread = new MjpegViewThread(holder, context);
setFocusable(true);
overlayPaint = new Paint();
overlayPaint.setTextAlign(Paint.Align.LEFT);
overlayPaint.setTextSize(12);
overlayPaint.setTypeface(Typeface.DEFAULT);
overlayTextColor = Color.WHITE;
overlayBackgroundColor = Color.BLACK;
ovlPos = MjpegView.POSITION_LOWER_RIGHT;
displayMode = MjpegView.SIZE_STANDARD;
dispWidth = getWidth();
dispHeight = getHeight();
}
public void startPlayback() {
if(mIn != null) {
mRun = true;
thread.start();
}
}
public void stopPlayback() {
mRun = false;
boolean retry = true;
while(retry) {
try {
thread.join();
retry = false;
} catch (InterruptedException e) {}
}
}
public MjpegView(Context context, AttributeSet attrs) { super(context, attrs); init(context); }
public void surfaceChanged(SurfaceHolder holder, int f, int w, int h) { thread.setSurfaceSize(w, h); }
public void surfaceDestroyed(SurfaceHolder holder) {
surfaceDone = false;
stopPlayback();
}
public MjpegView(Context context) {
super(context);
init(context);
}
public void surfaceCreated(SurfaceHolder holder) {
surfaceDone = true;
}
public void showFps(boolean b) {
showFps = b;
}
public void setSource(MjpegInputStream source) {
mIn = source;
startPlayback();
}
public void setOverlayPaint(Paint p) {
overlayPaint = p;
}
public void setOverlayTextColor(int c) {
overlayTextColor = c;
}
public void setOverlayBackgroundColor(int c) {
overlayBackgroundColor = c;
}
public void setOverlayPosition(int p) {
ovlPos = p;
}
public void setDisplayMode(int s) {
displayMode = s;
}
}
i got this code from a blog,now i want to take a picture when i click on a button and save it in sd card,can anyone help me please
currently i can only view the video from the ipcam,i need to add a button in this class and when i click on the button it should capture a image and save it in sdcard.
You have a public Bitmap readMjpegFrame() method right there in MjpegInputStream.
Take the bitmap from that method and save it on SD card after you click on the button.
I have a class that extends android.view.Animation:
package diffusi.on.com.fifteen_puzzle;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
public class CustomAnimation extends Animation {
private boolean _isLast = false;
private View _currentTarget = null;
public interface AnimationListener {
void onAnimationEnd(CustomAnimation animation);
void onAnimationRepeat(CustomAnimation animation);
void onAnimationStart(CustomAnimation animation);
}
public static void animateSetOfViews(
View[] viewsSet,
int animResId,
int[] startTimeOffsets,
Context context,
AnimationListener animationListener
) {
CustomAnimation animation;
int startTimeOffset;
boolean isLastAnim;
for (int intA = 0; intA < viewsSet.length; intA++) {
isLastAnim = intA == viewsSet.length - 1;
animation = (CustomAnimation) AnimationUtils.loadAnimation(context, animResId);
if (intA <= startTimeOffsets.length - 1) {
startTimeOffset = startTimeOffsets[intA];
} else startTimeOffset = 0;
animation.applyToView(viewsSet[intA], startTimeOffset, isLastAnim, animationListener);
}
}
public CustomAnimation() {
}
public CustomAnimation(Context context, AttributeSet attrs) {
super(context, attrs);
}
public boolean isLast() {
return this._isLast;
}
public View getCurrentTarget() {
return this._currentTarget;
}
private void applyToView(View view, int startTimeOffset, boolean isLast, AnimationListener listener) {
this._isLast = isLast;
this._currentTarget = view;
this.setStartOffset(startTimeOffset);
this.setAnimationListener((Animation.AnimationListener) listener);
this._currentTarget.startAnimation(this);
}
}
It compiles in IDE without errors. But in runtame, it throws an exception (ClassCastEcxeption) on line:
animation = (CustomAnimation) AnimationUtils.loadAnimation(context, animResId)
Why does I can't upcast Animation instance to my CustomAnimation, which extends Animation ?
It's not upcasting, it is downcasting. Upcasting would be of the form CustomAnimation to Animation.
Presumably AnimationUtils.loadAnimation returns a reference to an object which isn't actually a CustomAnimation - so you can't cast to it. You can only cast to a type when the actual type of the object at execution time is compatible with the type you're casting to. For example:
Object x = new Integer(10);
String y = (String) x; // Bang - invalid cast
Object a = "Foo";
String b = (String) a; // This is fine