Android: roatating images in a loop - java

I am trying with no success to modify the code example from:
http://www.inter-fuser.com/2009/08/android-animations-3d-flip.html
so it will rotate the images in a loop, when clicking on the image once. (second click should pause).
I tried using Handler and threading but cannot update the view since only the main thread can update UI.
Exception I get from the code below:
android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
[in 'image1.startAnimation(rotation);' ('applyRotation(0, 90);' from the main thread)]
package com.example.flip3d;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.animation.AccelerateInterpolator;
import android.widget.ImageView;
public class Flip3d extends Activity {
private ImageView image1;
private ImageView image2;
private boolean isFirstImage = true;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
image1 = (ImageView) findViewById(R.id.image01);
image2 = (ImageView) findViewById(R.id.image02);
image2.setVisibility(View.GONE);
image1.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
if (isFirstImage) {
applyRotation(0, 90);
isFirstImage = !isFirstImage;
} else {
applyRotation(0, -90);
isFirstImage = !isFirstImage;
}
}
});
}
private void applyRotation(float start, float end) {
// Find the center of image
final float centerX = image1.getWidth() / 2.0f;
final float centerY = image1.getHeight() / 2.0f;
// Create a new 3D rotation with the supplied parameter
// The animation listener is used to trigger the next animation
final Flip3dAnimation rotation =
new Flip3dAnimation(start, end, centerX, centerY);
rotation.setDuration(500);
rotation.setFillAfter(true);
rotation.setInterpolator(new AccelerateInterpolator());
rotation.setAnimationListener(new DisplayNextView(isFirstImage, image1, image2));
if (isFirstImage)
{
image1.startAnimation(rotation);
} else {
image2.startAnimation(rotation);
}
}
}
How can I manage to update the UI and control the rotation within onClick listener?
Thank you,
Oakist

Try wrapping the UI code in runOnUIThread()

Related

Displaying Images Dynamically

I am using the following code to display images from drawable folder.
But now i want to display pictures dynamically.Every time a new image is added to the drawable folder i don't want go again in the code and add it in the array it should automatically increment and get displayed.
Any Idea how should I go about this.Just started working on Android.
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.Menu;
import android.widget.ImageView;
import android.app.Service;
import android.os.Handler;
public class MainActivity extends AppCompatActivity {
private static ImageView imgView;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imgView = (ImageView) findViewById(R.id.imageView);
final int[] images=images{R.drawable.ic_launcher,
R.drawable.ic_launcher1,R.drawable.ic_launcher2,etc..};
final Handler handler = new Handler();
Runnable runnable = new Runnable() {
int i=0;
public void run() {
imgView.setImageResource(images[i]);
i++;
if(i>images.length-1)
{
i=0;
}
handler.postDelayed(this,5000); //for interval...
}
};
handler.postDelayed(runnable, 5000); //for initial delay..
}
if you want to add the image Dynamically you can Naming the image File like this : Image1.png; Image2.png; and so on.
And then you dont need to call all of them in the array, instead you can using lopp to get the name of the image in resource.
and then get the id using the code below :
public int getID(String resourceName,Context context){
Resources resources = context.getResources();
final int resourceId = resources.getIdentifier(resourceName, "drawable",
context.getPackageName());
return resourceId;
}
Note : after adding the image don't forget to increament the loop. hope it helps.
please keep variable i as static
i.e static int i=0;
final Handler handler = new Handler();
Runnable runnable = new Runnable() {
public void run() {
imgView.setImageResource(images[i]);
i++;
if(i>images.length-1)
{
i=0;
}
handler.postDelayed(this,5000); //for interval...
}
};
handler.postDelayed(runnable, 5000); //for initial delay..
change the handle code as follow
final Handler handler = new Handler();
Runnable runnable = new Runnable() {
public void run() {
imgView.setImageResource(images[i]);
if(i>images.length-1)
{
i=0;
}
else
{
i++;
}
handler.postDelayed(this,5000); //for interval...
}
};
handler.postDelayed(runnable, 5000); //for initial delay..

Display ImagesViews with animation issue

I want to display ImageViews in GridView using animation. I can display them and apply animation correctly.
But issue is that, if I apply animation on ImageView1 and then to ImageView2 (before animation on ImageView1 is ended) then animation on ImageView1 gets interrupted and ImageView1 is directly set to final state.
Note that I download image using ThreadPoolExecutor with 2 threads. Whenever an image is done downloading, I call addImage(image) method of below ImageAdapter which in turn adds image in GridView and GridView is refreshed to display latest set of images. And Here, while rendering, new image is displayed with animation and this animation(I guess) interrupts animation of currently animating images.
ImageAdapter :
public class ImageAdapter extends BaseAdapter {
private Context mContext;
private List<Bitmap> images;
private ArrayList<Integer> colors;
private boolean[] alreadyLoadedIndexes;
Animation animation;
AnimatorSet animator;
public void addImage(Bitmap img) {
images.add(img);
notifyDataSetChanged();
}
public void setAnimation(Animation animation) {
this.animator = null;
this.animation = animation;
}
public void setAnimator(AnimatorSet animation) {
this.animation = null;
this.animator = animation;
}
public void resetImages() {
images.clear();
notifyDataSetChanged();
alreadyLoadedIndexes = null;
alreadyLoadedIndexes = new boolean[20];
}
// Constructor
public ImageAdapter(Context c) {
mContext = c;
images = new ArrayList<Bitmap>();
colors = new ArrayList<Integer>();
colors.add(Color.CYAN);
colors.add(Color.BLUE);
colors.add(Color.GRAY);
colors.add(Color.YELLOW);
colors.add(Color.MAGENTA);
alreadyLoadedIndexes = new boolean[20];
}
#Override
public int getCount() {
return 20;
}
#Override
public Object getItem(int position) {
return 20;
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageView = new ImageView(mContext);
imageView
.setBackgroundColor(colors.get((int) ((Math.sqrt(position) + 2 * position) % 5)));
// If image at index 'position' is available
if (images.size() > position) {
// If loading this image first time then only apply animation
if (!alreadyLoadedIndexes[position]) {
// If animation is specified
if (this.animation != null) {
imageView.setImageBitmap(images.get(position));
imageView.startAnimation(animation);
}
// If animator set is specified
else if (this.animator != null) {
imageView.setImageBitmap(null);
imageView.setBackgroundColor(colors.get((int) ((Math
.sqrt(position) + 2 * position) % 5)));
animator.setTarget(imageView);
animator.start();
Log.e("", "setting image after " + animator.getDuration()
/ 2);
new Handler().postDelayed(
new runnable(imageView, images.get(position)), 500);
} else {
// Use default animation if nothing is specified.
imageView.setImageBitmap(images.get(position));
animation = AnimationUtils.loadAnimation(mContext,
R.anim.fade_in);
imageView.startAnimation(animation);
}
} else {
imageView.setImageBitmap(images.get(position));
}
alreadyLoadedIndexes[position] = true;
}
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setLayoutParams(new GridView.LayoutParams(150, 150));
return imageView;
}
class runnable implements Runnable {
ImageView image;
Bitmap bitmap;
public runnable(ImageView img, Bitmap bitmap) {
this.image = img;
this.bitmap = bitmap;
}
#Override
public void run() {
Log.e("", "setting image.");
image.setImageBitmap(bitmap);
}
}
}
try layout animation controlor for GridView, it will animate the views item by item with respect to time duration. check this link ,
Have you tried to apply the animation outside adapter getView method like:
mGridView.getChildAt(childIndexNeededToAnimate).startAnimation(animation);
These child views are independent and not being recycled anymore since they are already drawn.
You have some alternative.
First you can use Animation in your adapter class if you don't want to change your code.
For that check this.
In your adapter class inside the getView you have to call animation like this ,
Animation animation = null;
animation = AnimationUtils.loadAnimation(context, R.anim.push_left_in);
animation.setDuration(500);
convertView.startAnimation(animation);
return convertView;
Second you should use GridLayoutAnimationController in which A layout animation controller is used to animated a grid layout's children.
Sample 1
Sample 2
Just a guess. I'm neither sure if it will help nor if I read your code right. I suppose the problem is harder than I guess.
However, you are using the same animation object for every item. Maybe you should create a new animation for each item. This could be the reason why your animation stops when you launch a new one because the new call just reuse and restarts it.
Good luck.
You problem is notifyDataSetChanged(); it interrupt the animation. Try calling it when the animation is finished.

How to tell if an X and Y coordinate are inside my button?

I have managed, with great difficulty, to make a bitmap overlay the screen. I can also get touch input, however it gets touch input for EVERYWHERE on the screen.
I want to know how I would be able to check if the touch was on my bitmap, which is visible on the screen.
The service and view class is below. I have thought and thought, but I couldn't think of a way to do it :(
package <package>;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.os.IBinder;
import android.support.v4.app.NotificationCompat;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.Toast;
public class MyService extends Service {
ButtonView mView;
Bitmap bit;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
bit = BitmapFactory.decodeResource(getResources(), R.drawable.button);
NotificationCompat.Builder builder = new NotificationCompat.Builder(
this);
builder.setContentTitle("Ingress Tools Running");
builder.setContentText("Click to stop Ingress Tools");
builder.setSmallIcon(R.drawable.ic_launcher);
builder.setContentIntent(PendingIntent.getActivity(this, 0, new Intent(
this, StopActivity.class), 0));
NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
manager.notify(1, builder.build());
mView = new ButtonView(this, bit);
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.FILL_PARENT,
WindowManager.LayoutParams.FILL_PARENT,
WindowManager.LayoutParams.TYPE_PHONE,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
PixelFormat.TRANSLUCENT);
params.gravity = Gravity.RIGHT;
params.setTitle("Load Average");
WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
wm.addView(mView, params);
}
#Override
public void onDestroy() {
super.onDestroy();
Toast.makeText(getBaseContext(), "onDestroy", Toast.LENGTH_LONG).show();
if (mView != null) {
((WindowManager) getSystemService(WINDOW_SERVICE))
.removeView(mView);
mView = null;
}
}
}
class ButtonView extends ViewGroup {
private Paint mLoadPaint;
private Rect r;
private Bitmap bit;
public ButtonView(Context context, Bitmap bit) {
super(context);
Toast.makeText(context, "HUDView", Toast.LENGTH_LONG).show();
mLoadPaint = new Paint();
mLoadPaint.setAntiAlias(true);
mLoadPaint.setTextSize(10);
mLoadPaint.setARGB(255, 255, 0, 0);
r = new Rect();
r.set(380, 134, 468, 213);
this.bit = bit;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//canvas.drawColor(Color.BLACK);
canvas.drawBitmap(bit, 100, 100, null);
}
#Override
protected void onLayout(boolean arg0, int arg1, int arg2, int arg3, int arg4) {
}
#Override
public boolean onTouchEvent(MotionEvent event) {
int area = bit.getWidth() * bit.getHeight();
//if (event.getY() <= maxY && event.getX() <= maxX) {
Toast.makeText(getContext(), "Open tools: ", Toast.LENGTH_LONG)
.show();
//}
return true;
}
}
this works for any view
#Override
public boolean dispatchTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP) {
if (inViewInBounds(myButtonView, (int) event.getRawX(), (int) event.getRawY())) {
// User moved outside bounds
Log.e("dispatchTouchEvent", "you touched inside button");
} else {
Log.e("dispatchTouchEvent", "you touched outside button");
}
}
return super.dispatchTouchEvent(event);
}
Rect outRect = new Rect();
int[] location = new int[2];
private boolean inViewInBounds(View view, int x, int y) {
view.getDrawingRect(outRect);
view.getLocationOnScreen(location);
outRect.offset(location[0], location[1]);
return outRect.contains(x, y);
}
Consider using FrameLayout (or any other subclass of ViewGroup) instead of ViewGroup directly. Because your current implementation of onLayout method is not correct, which will lead you to problems with displaying of child views.
Now, closer to your question. You should ininitialize Rect and just store left, top, right and bottom position of your Bitmap. As I can see, currently you're initialized r variable, but not using it anywhere.
So, you can initialize it like this:
r = new Rect(100, 100, 100 + bit.getWidth(), 100 + bit.getHeight());
Now in onTouchEvent you can just check:
r.contains((int) event.getX(), (int) event.getY());
Rect rect = new Rect();
getHitRect(rect);
if (rect.contains((int) event.getX(), (int) event.getY())) {}
you can use getHitRect(Rect). it returns the Hit rectangle in parent's coordinates. Here the documentation
Use if statement with method if(r.contains(x, y)) on that button which you want to check. This method will return true, when x and y point is inside rectangle r. You can also make public method within that class, so you can access it outside ButtonView class with button object reference.
// We assume MotionEvent is from the direct View parent so we are in the same co-ordindate space
fun View.isWithinBounds(event: MotionEvent): Boolean {
val rect = Rect(x.roundToInt(), y.roundToInt(), (x + width).roundToInt(), (y + height).roundToInt())
return rect.contains(event.x.roundToInt(), event.y.roundToInt())
}
When the "touch event" happens, it's going through all view's tree.
F.e. if you have Linear layout and ImageView on it and user touchs the screen on ImageView, then touch event intercepts and firstly it'll be handled at LinearLayour and then at the ImageView.
If you want to block event f.e. on the bitmap, then you should override onTouchEvent for Bitmap and return true value. This will mean that you handled this event and it won't be available for LinearLayout.
image.setOnTouchListener( new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
return true; // attentively read documentation for onTouc interface
}
});

How do i handle touch events properly in android?

Scope of the project
When a user touches the Android screen with two fingers, draw a "Frame" at each touch location with a "cursor" for each frame. Each frame is a custom slider that the cursor will move up and down. All the way up will be 100%, middle will be 0% and all the way down will be -100%. This will be used to control small motors, similar to tank turning, each touch controls a separate motor (sending signals over bluetooth). After a two touch and everything is drawn, I want to be able to lift off either finger, BUT keep the cursor at what ever location it was last at, while the other finger is free to move its cursor. When the last finger is lifted off, everything "hides" and resets to 0%.
Functionality Wanted
On two finger touch, draw separate .pngs under the touch location
After the frames and cursors are drawn, keep track of where they are relative to the frame to determine the percentage.
If a finger is lifted off, keep that fingers cursor at last known location, but the other finger can move it's cursor. Also if the finger is put back down it should be able to move its cursor again.
If both fingers are lifted off of the screen, hide everything and reset percentages to 0%
Functionality Obtained
I can draw the frames and cursors on multitouch
Positions and percentages work fine
Cursors do move properly
What doesn't work
I am unsure if I should have one custom class that handles both touch event or if i should have 2 instances of the custom class each handling their own touch events (I have tried both, the only way i get any "real" functionality is with 1 custom class handling both touch events, the other way doesn't work as intended)
When I only have 1 custom class, It works great, but I have it "hide" everything if both fingers are not on the screen, and sometimes android registers that I have lifted a finger off the screen and this causes me a lot of issues when the frames hide then re appear in a different location
When I use 2 custom classes I touch each custom class would have its own touch event, and i wouldn't have to worry about multitouch if i split the classes evenly between the screen. This was not the case, still need to deal with multitouch
Can someone explain to me how android handles their touch events. from what I have done, it seems if i lay down finger 1, the finger 2, the first finger will register a "ACTION_DOWN" and the second will register a "ACTION_POINTER_2_DOWN", BUT if i life off my first finger, my second finger is "demoted" and now all of the events my second finger registers does not related to "ACTION_POINTER_2" and instead will be "ACTION_DOWN, ACTION_UP, etc". Is this correct?
TouchUI.java
package com.robota.android;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.ImageView;
public class TouchUI extends ImageView {
public static final String LEFT_TOUCHUI = "com.robota.android:id/leftTouchUI";
public static final String RIGHT_TOUCHUI = "com.robota.android:id/rightTouchUI";
private String whoAmI = new String();
private MyPoints framePts = new MyPoints();
private MyPoints cursorPts = new MyPoints();
private Bitmap frame;
private Bitmap cursor;
private int frameWidth;
private int frameHeight;
private int cursorHeight;
private boolean pointerDown = false;
private int dy;
public TouchUI(final Context context, final AttributeSet as){
super(context, as);
Log.d("TouchUI", getResources().getResourceName(this.getId()));
whoAmI = new String(getResources().getResourceName(this.getId()));
if(whoAmI.equals(LEFT_TOUCHUI)){
frame = BitmapFactory.decodeResource(getResources(), R.drawable.tank_left);
}else if(whoAmI.equals(RIGHT_TOUCHUI)){
frame = BitmapFactory.decodeResource(getResources(), R.drawable.tank_right);
}
cursor = BitmapFactory.decodeResource(getResources(), R.drawable.cursor);
frameWidth = frame.getWidth();
frameHeight = frame.getHeight();
cursorHeight = cursor.getHeight();
}
public void determinePointers(int x, int y){
framePts.setOrigin(x-frameWidth/2, y-frameHeight/2);
cursorPts.setOrigin(x-frameWidth/2, y-frameHeight/2);
}
#Override
public boolean onTouchEvent(MotionEvent e){
int x = 0;
int y = 0;
Log.d("TouchUI", ">>>>> " + whoAmI);
if(e.getAction() == MotionEvent.ACTION_DOWN){
determinePointers(x,y);
pointerDown = true;
}else if(e.getAction() == MotionEvent.ACTION_UP){
pointerDown = false;
}else if(e.getAction() == MotionEvent.ACTION_MOVE){
dy = (int)e.getY()-framePts.getY();
if(dy <= 0){
dy=0;
}else if(dy+cursorHeight/2 >= frameHeight){
dy=frameHeight;
}
sendMotorSpeed(dy);
}
return true;
}
public void sendMotorSpeed(int dy){
float motor = dy;
motor-=frameHeight;
motor*=-1;
motor = (motor/frameHeight)*255;
PacketController.updateMotorSpeeds(whoAmI, (int)motor);
}
public void onDraw(Canvas canvas){
if(pointerDown){//twoDown){
canvas.drawBitmap(frame, framePts.getX(), framePts.getY(), null);
canvas.drawBitmap(cursor, cursorPts.getX(), (cursorPts.getY()+dy), null);
}
invalidate();
}
private class MyPoints{
private int x = -100;
private int y = -100;
private int deltaY = 0;;
public MyPoints(){
this.x = 0;
this.y = 0;
}
public int getX(){
return this.x;
}
public int getY(){
return this.y;
}
public void setOrigin(int x, int y){
this.x = x;
this.y = y;
}
public int getDeltaY(){
return deltaY;
}
public void setDeltaY(int newY){
deltaY = (newY-y);
Log.d("TouchUI", "DY: " + deltaY);
}
}
}
Main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/parentLayout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<LinearLayout android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.robota.android.TouchUI xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/leftTouchUI"
android:background="#0000"
android:layout_height="match_parent"
android:layout_width="wrap_content"
android:layout_weight="1">
</com.robota.android.TouchUI>
<com.robota.android.TouchUI xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/rightTouchUI"
android:background="#0000"
android:layout_height="match_parent"
android:layout_width="wrap_content"
android:layout_weight="1">
</com.robota.android.TouchUI>
</LinearLayout>
RobotController.java (Main Activity Class)
package com.robota.android;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.Window;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;
public class RobotController extends Activity {
// Tag used to keep track of class in the Log
private static final String TAG = "robotController_new";
// Boolean to debugging
private static final boolean D = true;
// Intent request codes
private static final int DISCONNECT_DEVICE = 1;
private static final int CONNECT_DEVICE = 2;
private static final int REQUEST_ENABLE_BT = 3;
// Handler Codes
public static final int MESSAGE_READ = 1;
public static final int MESSAGE_WRITE = 2;
// Local Bluetooth Adapter
private BluetoothAdapter bluetoothAdapter = null;
// Bluetooth Discovery and Datahandler
private BluetoothComm btComm = null;
// Debug's TextView, this is where strings will be written to display
private TextView tv;
private ScrollView sv;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
if(D) Log.d(TAG, "++ON CREATE++");
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.main);
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if(bluetoothAdapter == null){
if(D) Log.d(TAG, "NO BLUETOOTH DEVICE");
Toast.makeText(this, "Bluetooth is not available", Toast.LENGTH_SHORT).show();
finish();
return;
}
PacketController.controller = this;
}
public void onStart(){
super.onStart();
if(D) Log.d(TAG, "++ON START++");
if(!bluetoothAdapter.isEnabled()){
Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
}else{
// Start BluetoothComm
if(btComm == null){
setupComm();
}
}
}
/**
* Creates new Bluetooth Communication
*/
private void setupComm(){
if(D) Log.d(TAG, "+++setupComm+++");
btComm = new BluetoothComm(this, handler);
}
private void connectDevice(Intent data){
if(D) Log.d(TAG, "+++connectDevice+++");
String addr = data.getExtras()
.getString(DeviceListActivity.EXTRA_DEVICE_ADDRESS);
BluetoothDevice device = bluetoothAdapter.getRemoteDevice(addr);
if(D) Log.d(TAG,"REMOTE ADDR: "+ addr);
btComm.connect(device);
}
private void disconnectDevice(){
if(D) Log.d(TAG, "---disconnectDevice---");
if(btComm.getState() == btComm.STATE_CONNECTED){
btComm.disconnect();
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu)
{
//super.onCreateOptionsMenu(menu);
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
Intent serverIntent = null;
switch(item.getItemId()){
case R.id.insecure_connect_scan:
// Launch the DeviceListActivity to see devices and do scan
serverIntent = new Intent(this, DeviceListActivity.class);
try{
startActivityForResult(serverIntent, CONNECT_DEVICE);
}catch(ActivityNotFoundException activityNotFound){
Log.e(TAG, "Could not start DeviceListActivity(Insecure)");
}
return true;
}
return false;
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data){
switch(requestCode){
case CONNECT_DEVICE:
if(resultCode == Activity.RESULT_OK){
connectDevice(data);
}
break;
case DISCONNECT_DEVICE:
if(resultCode == Activity.RESULT_OK){
disconnectDevice();
}
break;
}
}
public Handler getHandler(){
return this.handler;
}
public BluetoothComm getBtComm(){
return this.btComm;
}
// The Handler that gets information back from the BluetoothChatService
private final Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
if(D) Log.d(TAG, "check message");
switch (msg.what) {
case MESSAGE_READ:
if(D) Log.d(TAG, "trying to read message");
byte[] readBuf = (byte[]) msg.obj;
// construct a string from the valid bytes in the buffer
String readMessage = new String(readBuf, 0, msg.arg1);
if(D) Log.d(TAG, "bytes: " + readBuf + " arg1: " + msg.arg1 + " Message: " + readMessage);
tv.append(readMessage);
break;
case MESSAGE_WRITE:
if(D) Log.d(TAG, "trying to send message");
String sendMessage = new String(String.valueOf(msg.obj));
}
}
};
}
Any other classes not listed I didn't believe needed to be, but if they are needed please let me know.
Any help is much appreciated
You're going to need to save the pointerId's of each point and compare them to the new Id's given with each MotionEvent. It's slightly tricky to explain, so I'll point you to this ADB Post that explains it much better than I could. Long story short? Multitouch can be tricksy, but it's not as bad as it looks at first glance.

Android Button Doesn't Respond After Animation

I have a basic animation of a button after it is pressed currently in my application. After the button finishes animating, I can no longer click on it. It doesn't even press with an orange highlight.
Any help?
Here's my code:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
animation = new AnimationSet(true);
animation.setFillAfter(true);
Animation translate = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 5.0f);
translate.setDuration(500);
animation.addAnimation(translate);
LayoutAnimationController controller = new LayoutAnimationController(animation, 0.25f);
generate = (Button)findViewById(R.id.Button01);
generate.setOnClickListener(new View.OnClickListener(){
public void onClick(View v){
keyFromTop();
}
});
}
public void keyFromTop(){
generate.setAnimation(animation);
}
Animations affect only the drawing of widgets, which means after the animation is done, your button is still at its previous location. You need to manually update the layout parameters of your button if you want to move it to the new location. Also, your AnimationSet and your AnimationController are useless.
If you want to be able to click the button after the animation is complete, you have to manually move the component.
Here's an example of a translate animation applied to a button:
public class Test2XAnimation extends Activity {
private RelativeLayout buttonContainer;
private Button button;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button = (Button) this.findViewById(R.id.button1);
buttonContainer = (RelativeLayout) button.getParent();
}
public void startTapped(View view) {
animateButton(200, 100);
}
public void buttonTapped(View view) {
Toast.makeText(this, "tap", Toast.LENGTH_SHORT).show();
}
private RelativeLayout.LayoutParams params;
private CharSequence title;
private void animateButton(final int translateX, final int translateY) {
TranslateAnimation translate = new TranslateAnimation(0, translateX, 0,
translateY);
translate.setDuration(1500);
translate.setAnimationListener(new AnimationListener() {
public void onAnimationEnd(Animation animation) {
buttonContainer.removeView(button);
button = new Button(Test2XAnimation.this);
button.setText(title);
button.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
buttonTapped(button);
}
});
params.leftMargin = translateX + params.leftMargin;
params.topMargin = translateY + params.topMargin;
params.rightMargin = 0 + params.rightMargin;
params.bottomMargin = 0 + params.bottomMargin;
button.setLayoutParams(params);
buttonContainer.addView(button);
}
public void onAnimationRepeat(Animation animation) {
}
public void onAnimationStart(Animation animation) {
params = (RelativeLayout.LayoutParams) button.getLayoutParams();
title = button.getText();
}
});
button.startAnimation(translate);
}
}
The method startTapped() is triggered when a user clicks a button in the UI. The other button moves by (200,100). At the end, I remove the old one and create a new one, thenaI add it to the parent view. You can see that buttonTapped() is called after the animation.
A suggestion: you can use NineOldAndroids project if you want to support both the new and the old way of animating a component, then you can check the OS version and run this code only on Gingerbread and lower versions.
I really struggled with shuffling layout params to make the "real" button match up to its animated location. I finally succeeded by using this approach. I extended ImageButton and overrode getHitRect:
#Override
public void getHitRect(Rect outRect) {
Rect curr = new Rect();
super.getHitRect(curr);
outRect.bottom = curr.bottom + 75;
outRect.top = curr.top + 75;
outRect.left = curr.left;
outRect.right = curr.right;
}
Then, I could use this button in the troublesome view:
<com.sample.YPlus75ImageButton a:id="#+id/....
It's worth noting that all of this changes for 3.0.

Categories

Resources