animation with cocos2d android - android

I doing animation with framework cocos2d android.I have series image same blow image, I want to crop a tivi in image use to cocos2d in android. Plz help me?
link image
public class MainActivity extends Activity {
private static final boolean DEBUG = true;
private CCGLSurfaceView mGLSurfaceView;
static Context context;
static Resources resources;
static AssetManager assetManager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
mGLSurfaceView = new CCGLSurfaceView(this);
setContentView(mGLSurfaceView);
assetManager = getAssets();
}
#Override
protected void onStart() {
super.onStart();
// attach the OpenGL view to a Window
Director.sharedDirector().attachInView(mGLSurfaceView);
// set landscape mode
// Director.sharedDirector().setLandscape(true);
// show FPS
Director.sharedDirector().setDisplayFPS(true);
// frames per second
Director.sharedDirector().setAnimationInterval(1.0f / 60);
Scene scene = Scene.node();
scene.addChild(nextAction());
// Make the scene active
Director.sharedDirector().runWithScene(scene);
}
static int sceneIdx = -1;
static Class transitions[] = { Animation1.class, };
static Layer nextAction() {
sceneIdx++;
sceneIdx = sceneIdx % transitions.length;
return restartAction();
}
static Layer restartAction() {
try {
Class c = transitions[sceneIdx];
return (Layer) c.newInstance();
} catch (Exception e) {
if (DEBUG)
e.printStackTrace();
return null;
}
}
#Override
protected void onPause() {
super.onPause();
Director.sharedDirector().pause();
}
#Override
protected void onResume() {
super.onResume();
Director.sharedDirector().resume();
}
#Override
protected void onDestroy() {
super.onDestroy();
TextureManager.sharedTextureManager().removeAllTextures();
}
static class Anima extends Layer {
Sprite tivi;
Sprite bg2;
InputStream is;
Resources resources;
AssetManager asset;
Bitmap bf, bitmap, bitmap2;
CCSize s = Director.sharedDirector().displaySize();
public Anima() {
Log.v("MP", "Width: " + s.width + " Height: " + s.height);
bg2 = Sprite.sprite("Scene02.png");
bg2.setScaleX(s.width / bg2.getTexture().getWidth());
bg2.setScaleY(s.height / bg2.getTexture().getHeight());
bg2.setPosition(s.width / 2, s.height / 2);
addChild(bg2, 1);
tivi = Sprite.sprite("TV0000.png");
tivi.setScaleX(s.width / bg2.getTexture().getWidth());
tivi.setScaleY(s.height / bg2.getTexture().getHeight());
//tivi.setPosition(0, 0);
tivi.setPosition(247 * s.width / bg2.getTexture().getWidth(), 480
* s.height / bg2.getTexture().getHeight());
addChild(tivi, 1);
}
protected void centerSprites() {
// tivi.setPosition(247 * s.width / bg2.getTexture().getWidth(), 480
// * s.height / bg2.getTexture().getHeight());
}
}
static class Animation1 extends Anima {
Animation tvAnimation;
IntervalAction tvAction;
CCSize s = Director.sharedDirector().displaySize();
boolean ck = true;
public Animation1() {
// centerSprites();
isTouchEnabled_ = true;
tvAnimation = initTVAnimation();
tvAction = Animate.action(tvAnimation);
}
private Animation initTVAnimation() {
Animation animation = new Animation("abc", 0.2f);
for (int i = 1; i < 40; i++) {
try {
is = assetManager.open(new CCFormatter().format(
"TV00%02d.png", i));
bf = BitmapFactory.decodeStream(is);
bitmap = Bitmap.createBitmap(bf, 0, 0, bf.getWidth(),
bf.getHeight());
bitmap2 = Bitmap
.createBitmap(bitmap, (int) (153 * (s.width / bg2
.getTexture().getWidth())),
(int) (261.5 * (s.height / bg2.getTexture()
.getHeight())),
(int) (87 * (s.width / bg2.getTexture()
.getWidth())),
(int) (97 * (s.height / bg2.getTexture()
.getHeight())));
animation.addFrame(bitmap2);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return animation;
}
#Override
public boolean ccTouchesBegan(MotionEvent event) {
CCSize s = Director.sharedDirector().displaySize();
CCPoint location = Director.sharedDirector().convertToGL(
event.getX(), event.getY());
if ((location.x >= 203.5 * s.width / bg2.getTexture().getWidth() && location.x <= 290
* s.width / bg2.getTexture().getWidth())
&& (location.y >= 433.5 * s.height
/ bg2.getTexture().getHeight() && location.y <= 526
* s.height / bg2.getTexture().getHeight())) {
if (tvAction.isDone() == true || ck == true) {
tivi.runAction(tvAction);
ck = false;
}
}
// addNew(location);
return TouchDispatcher.kEventHandled;
}
}
}

Animation animation = new Animation("abc", 0.2f);
for (int i = 1; i < 40; i++) {
try {
is = assetManager.open(new CCFormatter().format(
"TV00%02d.png", i));
bf = BitmapFactory.decodeStream(is);
bitmap = Bitmap.createBitmap(bf, 0, 0, bf.getWidth(),
bf.getHeight());
bitmap2 = Bitmap
.createBitmap(bitmap, (int) (153 * (s.width / bg2
.getTexture().getWidth())),
(int) (261.5 * (s.height / bg2.getTexture()
.getHeight())),
(int) (87 * (s.width / bg2.getTexture()
.getWidth())),
(int) (97 * (s.height / bg2.getTexture()
.getHeight())));
animation.addFrame(bitmap2);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return animation;
}
try to make simple of this code.... use the latest example series from the cocs2d-android 1 .. it have basic concept for handing the animation ..... you will get the answer from the example series

Hai i hope this will help you lot. I have used CCSprite. it scale to support all Screens with animation. scaling CCSprite in 480x800
public class MainMenuScreen extends CCColorLayer {
private CCSprite newGame1;
private CGSize size; // this is where we hold the size of current display
private float scaleX, scaleY;// these are the ratios that we need to compute
public static CCScene sence() {
CCScene ccScene = CCScene.node();
CCLayer layer = new MainMenuScreen(ccColor4B.ccc4(69, 3, 3, 255));
ccScene.addChild(layer);
return ccScene;
}
protected MainMenuScreen(ccColor4B color) {
super(color);
size = CCDirector.sharedDirector().winSize();
CCSprite backGround = CCSprite
.sprite(CandygrabberImage.MENU_BACKGROUND);
this.setIsTouchEnabled(true);
// backGround.setContentSize(winSize);
backGround.setTag(1);
backGround.setScale(.5f);
backGround.setPosition(CGPoint.ccp(size.width / 2.0f,
size.height / 2.0f));
backGround
.setScaleX(size.width / backGround.getTexture().getWidth());
backGround.setScaleY(size.height
/ backGround.getTexture().getHeight());
addChild(backGround);
scaleX = size.width / 480f;// assuming that all my assets are available
// for a 320X480(landscape) resolution;
scaleY = size.height / 800f;
newGame1 = CCSprite.sprite("newgame1.png");
CCAnimation buttonAnimation = CCAnimation.animation("", 1f);
buttonAnimation.addFrame("newgame1.png");
buttonAnimation.addFrame("newgame2.png");
buttonAnimation.addFrame("newgame3.png");
buttonAnimation.addFrame("newgame4.png");
buttonAnimation.addFrame("newgame5.png");
buttonAnimation.addFrame("newgame6.png");
buttonAnimation.addFrame("newgame7.png");
buttonAnimation.addFrame("newgame8.png");
CCIntervalAction buttonAction = CCAnimate.action(5, buttonAnimation,
false);
newGame1.runAction(CCRepeatForever.action(buttonAction));
newGame1.setScaleX(scaleX);
newGame1.setScaleY(scaleY);
newGame1.setScale(aspect_Scale(newGame1, scaleX, scaleY));
this.addChild(newGame1);
this.setIsTouchEnabled(true);
}
public float aspect_Scale(CCSprite sprite, float scaleX, float scaleY) {
float sourcewidth = sprite.getContentSize().width;
float sourceheight = sprite.getContentSize().height;
float targetwidth = sourcewidth * scaleX;
float targetheight = sourceheight * scaleY;
float scalex = (float) targetwidth / sourcewidth;
float scaley = (float) targetheight / sourceheight;
return Math.min(scalex, scaley);
}
}

Related

Custom canvas artifacts being shown despite using drawColor()

I've created a custom view that draws a dial gauge. If I set a static value for the angle of the needle, the gauge draws as expected (see first image below). If I attempt to set the angle of the needle through runOnUiThread, then I have weird needle artifacts (see second image).
I am calling canvas.drawColor(color.BLACK) each time onDraw() is called, so I am not sure how the artifacts are being carried over. My best guess is that I am not handling threading correctly in the method that calls runOnUiThread().
DialGaugeView class:
package net.dynu.kubie.redneksldhlr;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
public class DialGaugeView extends View {
private int height, width, min = 0;
private int numberFontSize, titleFontSize = 0;
private float dialEdgeStroke, dialEdgeRadius = 0;
private float dialFaceRadius = 0;
private float tickMajorStroke, tickSweep, tickAngleStart, tickAngleEnd, tickEdgeRadius, tickInnerMajorRadius, tickInnerMinorRadius = 0;
private int tickMajorCount = 0;
private float tickMinorStroke = 0;
private int tickMinorCount = 0;
private int tickTotalCount = 0;
private int numberMin, numberMax = 0;
private float numberRadius = 0;
private float arrowTipRadius, arrowRearRadius = 0;
private float arrowCenterRadius, arrowPinRadius = 0;
private float sensorInput = 0;
private float temp = 0;
private Paint paint;
private boolean isInit;
private float titleRadius = 0;
private Rect rect = new Rect();
private Path path = new Path();
private String titleStr = "";
//Variables common to drawing functions
private float center_x, center_y = 0;
private float x1, x2, x3, y1, y2, y3 = 0;
private float angle = 0;
private int number = 0;
private String str = "";
public DialGaugeView(Context context) {
super(context);
}
public DialGaugeView(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.getTheme().obtainStyledAttributes(
attrs,
R.styleable.DialGaugeView,
0, 0);
try {
tickMajorCount = a.getInteger(R.styleable.DialGaugeView_tickCountMajor, 5);
tickMinorCount = a.getInteger(R.styleable.DialGaugeView_tickCountMinor, 0);
tickSweep = a.getFloat(R.styleable.DialGaugeView_tickSweep, 270) / 2;
numberMin = a.getInteger(R.styleable.DialGaugeView_displayMin, 0);
numberMax = a.getInteger(R.styleable.DialGaugeView_displayMax, 1);
titleStr = a.getString(R.styleable.DialGaugeView_displayTitle);
} finally {
a.recycle();
}
}
public DialGaugeView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public int getTickMajorCount() {
return tickMajorCount;
}
public void setTickMajorCount(int i) {
tickMajorCount = i;
isInit = false;
invalidate();
requestLayout();
}
public int getTickMinorCount() {
return tickMinorCount;
}
public void setTickMinorCount(int i) {
tickMinorCount = i;
isInit = false;
invalidate();
requestLayout();
}
public float getTickSweep() {
return tickSweep;
}
public void setTickSweep(float i) {
tickSweep = i / 2;
isInit = false;
invalidate();
requestLayout();
}
public int getDisplayMin() {
return numberMin;
}
public void setDisplayMin(int i) {
numberMin = i;
isInit = false;
invalidate();
requestLayout();
}
public int getDisplayMax() {
return numberMax;
}
public void setDisplayMax(int i) {
numberMax = i;
isInit = false;
invalidate();
requestLayout();
}
public float getSensorInput() {
return sensorInput;
}
public void setSensorInput(float i) {
sensorInput = i;
isInit = false;
invalidate();
requestLayout();
}
public String getTitle() {
return titleStr;
}
public void setTitle(String i) {
titleStr = i;
invalidate();
requestLayout();
}
private void initGauge() {
//Common variables
height = getHeight();
width = getWidth();
min = Math.min(height, width);
center_x = width / 2;
center_y = height / 2;
paint = new Paint();
isInit = true;
//Dial face variables
dialEdgeStroke = min / 20;
dialEdgeRadius = min / 2 - dialEdgeStroke / 2;
dialFaceRadius = dialEdgeRadius - dialEdgeStroke / 2;
//Tick variables
//tickMajorCount = 7; //TODO - Class input needed
//tickMinorCount = 1; //TODO - Class input needed
//tickSweep = 270 / 2; //TODO - Class input needed //Degrees +/- from 90 degrees
tickEdgeRadius = dialFaceRadius - dialEdgeStroke / 2;
tickInnerMajorRadius = (float) (tickEdgeRadius - dialEdgeStroke * 1.5);
tickInnerMinorRadius = ((tickEdgeRadius + tickInnerMajorRadius) / 2);
tickMajorStroke = min / 75;
tickAngleStart = 90 + tickSweep;
tickAngleEnd = 90 - tickSweep;
tickMinorStroke = tickMajorStroke / 2;
tickTotalCount = tickMajorCount + (tickMajorCount - 1) * tickMinorCount;
//Numeral variables
//numberMin = 0; //TODO - Class input needed
//numberMax = 120; //TODO - Class input needed
numberRadius = (tickInnerMajorRadius); // - (tickEdgeRadius - tickInnerMajorRadius) * 1.25);
numberFontSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, min / 40,
getResources().getDisplayMetrics());
//Title variables
titleRadius = tickInnerMajorRadius;
titleFontSize = numberFontSize;
//Arrow variables
//sensorInput = (float) (numberMax * .4965); //TODO - Class input needed
arrowTipRadius = tickEdgeRadius;
arrowRearRadius = arrowTipRadius / 2;
arrowCenterRadius = (arrowTipRadius * 1 / 8);
arrowPinRadius = (arrowTipRadius * 1 / 24);
}
#Override
protected void onDraw(Canvas canvas) {
if (!isInit) {
initGauge();
}
canvas.drawColor(Color.BLACK);
drawDialFace(canvas);
drawTicks(canvas);
drawNumeral(canvas);
drawTitle(canvas);
drawArrow(canvas);
postInvalidateDelayed(500);
invalidate();
requestLayout();
}
private void drawDialFace(Canvas canvas) {
paint.reset();
paint.setColor(getResources().getColor(android.R.color.black));
paint.setStrokeWidth(dialEdgeStroke);
paint.setStyle(Paint.Style.STROKE);
paint.setAntiAlias(true);
canvas.drawCircle(center_x, center_y, dialEdgeRadius, paint);
paint.reset();
paint.setColor(getResources().getColor(android.R.color.white));
paint.setStyle(Paint.Style.FILL);
paint.setAntiAlias(true);
canvas.drawCircle(center_x, center_y, dialFaceRadius, paint);
}
private void drawTicks(Canvas canvas) {
paint.reset();
paint.setColor(getResources().getColor(android.R.color.black));
paint.setStyle(Paint.Style.STROKE);
paint.setAntiAlias(true);
for(int i = 0; i < tickTotalCount; i++) {
angle = (float) (((tickAngleEnd - tickAngleStart) * i / (tickTotalCount - 1) + tickAngleStart) / 180 * Math.PI);
x1 = (float) (center_x + Math.cos(angle) * tickEdgeRadius);
y1 = (float) (center_y - Math.sin(angle) * tickEdgeRadius);
if((i % (tickMinorCount + 1)) == 0) {
paint.setStrokeWidth(tickMajorStroke);
x2 = (float) (center_x + Math.cos(angle) * tickInnerMajorRadius);
y2 = (float) (center_y - Math.sin(angle) * tickInnerMajorRadius);
} else {
paint.setStrokeWidth(tickMinorStroke);
x2 = (float) (center_x + Math.cos(angle) * tickInnerMinorRadius);
y2 = (float) (center_y - Math.sin(angle) * tickInnerMinorRadius);
}
canvas.drawLine(x1, y1, x2, y2, paint);
}
}
private void drawNumeral(Canvas canvas) {
paint.reset();
paint.setTextSize(numberFontSize);
paint.setColor(getResources().getColor(android.R.color.black));
for(int i = 0; i < tickMajorCount; i++) {
angle = (float) (((tickAngleEnd - tickAngleStart) * i / (tickMajorCount - 1) + tickAngleStart) / 180 * Math.PI);
number = (numberMax - numberMin) * i / (tickMajorCount - 1) + numberMin;
str = String.valueOf(number);
paint.getTextBounds(str, 0, str.length(), rect);
double c = Math.cos(angle);
double s = Math.sin(angle);
if(rect.width() * Math.abs(s) < rect.height() * Math.abs(c)) {
x2 = (float) (Math.signum(c) * rect.width() / 2);
y2 = (float) (Math.tan(angle) * x2);
} else {
y2 = (float) (Math.signum(s) * rect.height() / 2);
x2 = (float) (1 / Math.tan(angle) * y2);//Math.cotg(angle) * y;
}
x1 = (float) (center_x + Math.cos(angle) * numberRadius - rect.width() / 2 - x2 * 1.25);
y1 = (float) (center_y - Math.sin(angle) * numberRadius + rect.height() / 2 + y2 * 1.25);
canvas.drawText(str, x1, y1, paint);
}
}
private void drawTitle(Canvas canvas) {
paint.reset();
paint.setTextSize(titleFontSize);
paint.setColor(getResources().getColor(android.R.color.black));
angle = (float) ((270.0 / 180) * Math.PI);
paint.getTextBounds(titleStr, 0, str.length(), rect);
x1 = (float) (center_x + Math.cos(angle) * titleRadius - rect.width() / 2);
y1 = (float) (center_y - Math.sin(angle) * titleRadius + rect.height() / 3);
canvas.drawText(titleStr, x1, y1, paint);
}
private void drawArrow(Canvas canvas) {
paint.reset();
paint.setColor(getResources().getColor(android.R.color.holo_red_dark));
paint.setStyle(Paint.Style.FILL);
paint.setAntiAlias(true);
//Calculate (x,y) coordinates for the arrow path.
temp = (tickAngleEnd - tickAngleStart) * sensorInput / numberMax + tickAngleStart;
angle = (float) (temp / 180 * Math.PI);
x1 = (float) (center_x + Math.cos(angle) * arrowTipRadius);
y1 = (float) (center_y - Math.sin(angle) * arrowTipRadius);
angle = (float) ((temp + 170) / 180 * Math.PI);
x2 = (float) (center_x + Math.cos(angle) * arrowRearRadius);
y2 = (float) (center_y - Math.sin(angle) * arrowRearRadius);
angle = (float) ((temp - 170) / 180 * Math.PI);
x3 = (float) (center_x + Math.cos(angle) * arrowRearRadius);
y3 = (float) (center_y - Math.sin(angle) * arrowRearRadius);
//Draw arrow path using calculated coordinates.
path.moveTo(x1, y1);
path.lineTo(x2, y2);
path.lineTo(x3, y3);
path.close();
canvas.drawPath(path, paint);
//Calculate (x,y) coordinates for dial center.
x1 = center_x;
y1 = center_y;
canvas.drawCircle(x1, y1, arrowCenterRadius, paint);
paint.setColor(getResources().getColor(android.R.color.darker_gray));
canvas.drawCircle(x1, y1, arrowPinRadius, paint);
}
}
My MainActivity:
package net.dynu.kubie.redneksldhlr;
import android.app.Activity;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import org.w3c.dom.Text;
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
hideSystemUI();
startGenerating();
}
#Override
protected void onResume() {
super.onResume();
hideSystemUI();
//demoData();
}
#Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (hasFocus) {
hideSystemUI();
//demoData();
}
}
private void hideSystemUI() {
// Enables regular immersive mode.
// For "lean back" mode, remove SYSTEM_UI_FLAG_IMMERSIVE.
// Or for "sticky immersive," replace it with SYSTEM_UI_FLAG_IMMERSIVE_STICKY
View decorView = getWindow().getDecorView();
decorView.setSystemUiVisibility(
View.SYSTEM_UI_FLAG_IMMERSIVE
// Set the content to appear under the system bars so that the
// content doesn't resize when the system bars hide and show.
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
// Hide the nav bar and status bar
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_FULLSCREEN);
}
private void startGenerating() {
DoSomethingThread randomWork = new DoSomethingThread();
randomWork.start();
}
public class DoSomethingThread extends Thread {
private static final String TAG = "DoSomethingThread";
private static final int DELAY = 15000; // 5 seconds
private static final int RANDOM_MULTIPLIER = 120;
#Override
public void run() {
//Log.v(TAG, "doing work in Random Number Thread");
while (true) {
float randNum = (float) (Math.random() * RANDOM_MULTIPLIER);
// need to publish the random number back on the UI at this point in the code through the publishProgress(randNum) call
publishProgress(randNum);
try {
Thread.sleep(DELAY);
} catch (InterruptedException e) {
// Log.v(TAG, "Interrupting and stopping the Random Number Thread");
return;
}
}
}
}
private void publishProgress(float randNum) {
//Log.v(TAG, "reporting back from the Random Number Thread");
//final String text = String.format(getString(R.string.service_msg), randNum);
//final String text = Integer.toString(randNum);
final float text = randNum;
runOnUiThread(new Runnable() {
#Override
public void run() {
updateResults(text);
}
});
}
public void updateResults(float results) {
//TextView myTextView = (TextView) findViewById(R.id.testTextView);
DialGaugeView myDial = findViewById(R.id.my_gauge);
myDial.setSensorInput(results);
}
}
I eventually realized that my issue wasn't artifacts at all. My arrow is being drawn as a series of paths. If I do not reset the path prior to adding coordinates for the new arrow, the previous arrow(s) just get dragged along. Adding path.reset(); prior to the addition of the first arrow coordinate solved my problem.
//Draw arrow path using calculated coordinates.
path.reset();
path.moveTo(x1, y1);
path.moveTo(x2, y2);
path.moveTo(x3, y3);
path.close();
canvas.drawPath(path, paint);

How to use custom created drawable images for Android watch Face

Its been a week I was trying to create a watch Face for Android wear. As a kick start I followed Google official documentation and found these Android official watch face app tutorial with source code
So my current issue is , In Google documentation they use canvas to create analogue watch faces . The watch hands are generated using paint
Here is the sample of code for creating dial hand
public class AnalogWatchFaceService extends CanvasWatchFaceService {
private static final String TAG = "AnalogWatchFaceService";
/**
* Update rate in milliseconds for interactive mode. We update once a second to advance the
* second hand.
*/
private static final long INTERACTIVE_UPDATE_RATE_MS = TimeUnit.SECONDS.toMillis(1);
#Override
public Engine onCreateEngine() {
return new Engine();
}
private class Engine extends CanvasWatchFaceService.Engine {
static final int MSG_UPDATE_TIME = 0;
static final float TWO_PI = (float) Math.PI * 2f;
Paint mHourPaint;
Paint mMinutePaint;
Paint mSecondPaint;
Paint mTickPaint;
boolean mMute;
Calendar mCalendar;
/** Handler to update the time once a second in interactive mode. */
final Handler mUpdateTimeHandler = new Handler() {
#Override
public void handleMessage(Message message) {
switch (message.what) {
case MSG_UPDATE_TIME:
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "updating time");
}
invalidate();
if (shouldTimerBeRunning()) {
long timeMs = System.currentTimeMillis();
long delayMs = INTERACTIVE_UPDATE_RATE_MS
- (timeMs % INTERACTIVE_UPDATE_RATE_MS);
mUpdateTimeHandler.sendEmptyMessageDelayed(MSG_UPDATE_TIME, delayMs);
}
break;
}
}
};
final BroadcastReceiver mTimeZoneReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
mCalendar.setTimeZone(TimeZone.getDefault());
invalidate();
}
};
boolean mRegisteredTimeZoneReceiver = false;
/**
* Whether the display supports fewer bits for each color in ambient mode. When true, we
* disable anti-aliasing in ambient mode.
*/
boolean mLowBitAmbient;
Bitmap mBackgroundBitmap;
Bitmap mBackgroundScaledBitmap;
#Override
public void onCreate(SurfaceHolder holder) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "onCreate");
}
super.onCreate(holder);
setWatchFaceStyle(new WatchFaceStyle.Builder(AnalogWatchFaceService.this)
.setCardPeekMode(WatchFaceStyle.PEEK_MODE_SHORT)
.setBackgroundVisibility(WatchFaceStyle.BACKGROUND_VISIBILITY_INTERRUPTIVE)
.setShowSystemUiTime(false)
.build());
Resources resources = AnalogWatchFaceService.this.getResources();
Drawable backgroundDrawable = resources.getDrawable(R.drawable.bg, null /* theme */);
mBackgroundBitmap = ((BitmapDrawable) backgroundDrawable).getBitmap();
mHourPaint = new Paint();
mHourPaint.setARGB(255, 200, 200, 200);
mHourPaint.setStrokeWidth(5.f);
mHourPaint.setAntiAlias(true);
mHourPaint.setStrokeCap(Paint.Cap.ROUND);
mMinutePaint = new Paint();
mMinutePaint.setARGB(255, 200, 200, 200);
mMinutePaint.setStrokeWidth(3.f);
mMinutePaint.setAntiAlias(true);
mMinutePaint.setStrokeCap(Paint.Cap.ROUND);
mSecondPaint = new Paint();
mSecondPaint.setARGB(255, 255, 0, 0);
mSecondPaint.setStrokeWidth(2.f);
mSecondPaint.setAntiAlias(true);
mSecondPaint.setStrokeCap(Paint.Cap.ROUND);
mTickPaint = new Paint();
mTickPaint.setARGB(100, 255, 255, 255);
mTickPaint.setStrokeWidth(2.f);
mTickPaint.setAntiAlias(true);
mCalendar = Calendar.getInstance();
}
#Override
public void onDestroy() {
mUpdateTimeHandler.removeMessages(MSG_UPDATE_TIME);
super.onDestroy();
}
#Override
public void onPropertiesChanged(Bundle properties) {
super.onPropertiesChanged(properties);
mLowBitAmbient = properties.getBoolean(PROPERTY_LOW_BIT_AMBIENT, false);
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "onPropertiesChanged: low-bit ambient = " + mLowBitAmbient);
}
}
#Override
public void onTimeTick() {
super.onTimeTick();
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "onTimeTick: ambient = " + isInAmbientMode());
}
invalidate();
}
#Override
public void onAmbientModeChanged(boolean inAmbientMode) {
super.onAmbientModeChanged(inAmbientMode);
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "onAmbientModeChanged: " + inAmbientMode);
}
if (mLowBitAmbient) {
boolean antiAlias = !inAmbientMode;
mHourPaint.setAntiAlias(antiAlias);
mMinutePaint.setAntiAlias(antiAlias);
mSecondPaint.setAntiAlias(antiAlias);
mTickPaint.setAntiAlias(antiAlias);
}
invalidate();
// Whether the timer should be running depends on whether we're in ambient mode (as well
// as whether we're visible), so we may need to start or stop the timer.
updateTimer();
}
#Override
public void onInterruptionFilterChanged(int interruptionFilter) {
super.onInterruptionFilterChanged(interruptionFilter);
boolean inMuteMode = (interruptionFilter == WatchFaceService.INTERRUPTION_FILTER_NONE);
if (mMute != inMuteMode) {
mMute = inMuteMode;
mHourPaint.setAlpha(inMuteMode ? 100 : 255);
mMinutePaint.setAlpha(inMuteMode ? 100 : 255);
mSecondPaint.setAlpha(inMuteMode ? 80 : 255);
invalidate();
}
}
#Override
public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
if (mBackgroundScaledBitmap == null
|| mBackgroundScaledBitmap.getWidth() != width
|| mBackgroundScaledBitmap.getHeight() != height) {
mBackgroundScaledBitmap = Bitmap.createScaledBitmap(mBackgroundBitmap,
width, height, true /* filter */);
}
super.onSurfaceChanged(holder, format, width, height);
}
#Override
public void onDraw(Canvas canvas, Rect bounds) {
mCalendar.setTimeInMillis(System.currentTimeMillis());
int width = bounds.width();
int height = bounds.height();
// Draw the background, scaled to fit.
canvas.drawBitmap(mBackgroundScaledBitmap, 0, 0, null);
// Find the center. Ignore the window insets so that, on round watches with a
// "chin", the watch face is centered on the entire screen, not just the usable
// portion.
float centerX = width / 2f;
float centerY = height / 2f;
// Draw the ticks.
float innerTickRadius = centerX - 10;
float outerTickRadius = centerX;
for (int tickIndex = 0; tickIndex < 12; tickIndex++) {
float tickRot = tickIndex * TWO_PI / 12;
float innerX = (float) Math.sin(tickRot) * innerTickRadius;
float innerY = (float) -Math.cos(tickRot) * innerTickRadius;
float outerX = (float) Math.sin(tickRot) * outerTickRadius;
float outerY = (float) -Math.cos(tickRot) * outerTickRadius;
canvas.drawLine(centerX + innerX, centerY + innerY,
centerX + outerX, centerY + outerY, mTickPaint);
}
float seconds =
mCalendar.get(Calendar.SECOND) + mCalendar.get(Calendar.MILLISECOND) / 1000f;
float secRot = seconds / 60f * TWO_PI;
float minutes = mCalendar.get(Calendar.MINUTE) + seconds / 60f;
float minRot = minutes / 60f * TWO_PI;
float hours = mCalendar.get(Calendar.HOUR) + minutes / 60f;
float hrRot = hours / 12f * TWO_PI;
float secLength = centerX - 20;
float minLength = centerX - 40;
float hrLength = centerX - 80;
if (!isInAmbientMode()) {
float secX = (float) Math.sin(secRot) * secLength;
float secY = (float) -Math.cos(secRot) * secLength;
canvas.drawLine(centerX, centerY, centerX + secX, centerY + secY, mSecondPaint);
}
float minX = (float) Math.sin(minRot) * minLength;
float minY = (float) -Math.cos(minRot) * minLength;
canvas.drawLine(centerX, centerY, centerX + minX, centerY + minY, mMinutePaint);
float hrX = (float) Math.sin(hrRot) * hrLength;
float hrY = (float) -Math.cos(hrRot) * hrLength;
canvas.drawLine(centerX, centerY, centerX + hrX, centerY + hrY, mHourPaint);
}
}
The entire code can be found inside the official sample app . Below you can find the screen shot of application which I made using Google official tutorial .
If anyone have any idea how to replace the clock hands with an drawable images ? . Any help would be appreciated .
Create a Bitmap of your drawable resource:
Bitmap hourHand = BitmapFactory.decodeResource(context.getResources(), R.drawable.hour_hand);
Do whatever transformations you need to your canvas and draw the bitmap:
canvas.save();
canvas.rotate(degrees, px, py);
canvas.translate(dx, dy);
canvas.drawBitmap(hourHand, centerX, centerY, null); // Or use a Paint if you need it
canvas.restore();
Use following method to rotate bitmap from canvas,
/**
* To rotate bitmap on canvas
*
* #param canvas : canvas on which you are drawing
* #param handBitmap : bitmap of hand
* #param centerPoint : center for rotation
* #param rotation : rotation angle in form of seconds
* #param offset : offset of bitmap from center point (If not needed then keep it 0)
*/
public void rotateBitmap(Canvas canvas, Bitmap handBitmap, PointF centerPoint, float rotation, float offset) {
canvas.save();
canvas.rotate(secondRotation - 90, centerPoint.x, centerPoint.y);
canvas.drawBitmap(handBitmap, centerPoint.x - offset, centerPoint.y - handBitmap.getHeight() / Constants.INTEGER_TWO, new Paint(Paint.FILTER_BITMAP_FLAG));
canvas.restore();
}
I am a little bit late with the answer, but maybe it can be helpful for others
canvas.save()
val antialias = Paint()
antialias.isAntiAlias = true
antialias.isFilterBitmap = true
antialias.isDither = true
canvas.rotate(secondsRotation - minutesRotation, centerX, centerY)
canvas.drawBitmap(
secondsHandBitmap,
centerX - 10,
centerY - 160,
antialias
)
canvas.restore()
Here is my public Git Repo you can check the source code

How to fit the Ringdroid waveform in full width according to width of mobile screen

I want to implement the Ringdroid waveform in my android app.But for some songs,the waveform created after choosing the song is larger than the screen size and for songs the waveform width is smaller than the mobile screen width .
Plz suggest me the change in code of Ringdroid ,so that every time the waveform of song totally covers the width of screen.
This is the link of Ringdroid project
https://github.com/google/ringdroid
After a whole lot of searching and surfing about it. I tried it myself and got the desired output with it
This is the WaveformView class of Ringdroid
package com.ringdroid;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import com.ringdroid.soundfile.SoundFile;
/**
* WaveformView is an Android view that displays a visual representation
* of an audio waveform. It retrieves the frame gains from a CheapSoundFile
* object and recomputes the shape contour at several zoom levels.
*
* This class doesn't handle selection or any of the touch interactions
* directly, so it exposes a listener interface. The class that embeds
* this view should add itself as a listener and make the view scroll
* and respond to other events appropriately.
*
* WaveformView doesn't actually handle selection, but it will just display
* the selected part of the waveform in a different color.
*/
public class WaveformView extends View {
public interface WaveformListener {
public void waveformTouchStart(float x);
public void waveformTouchMove(float x);
public void waveformTouchEnd();
public void waveformFling(float x);
public void waveformDraw();
public void waveformZoomIn();
public void waveformZoomOut();
};
// 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;
public WaveformView(Context context, AttributeSet attrs) {
super(context, attrs);
// We don't want keys, the markers get these
setFocusable(false);
Resources res = getResources();
mGridPaint = new Paint();
mGridPaint.setAntiAlias(false);
mGridPaint.setColor(res.getColor(R.color.grid_line));
mSelectedLinePaint = new Paint();
mSelectedLinePaint.setAntiAlias(false);
mSelectedLinePaint.setColor(res.getColor(R.color.waveform_selected));
mUnselectedLinePaint = new Paint();
mUnselectedLinePaint.setAntiAlias(false);
mUnselectedLinePaint.setColor(res.getColor(R.color.waveform_unselected));
mUnselectedBkgndLinePaint = new Paint();
mUnselectedBkgndLinePaint.setAntiAlias(false);
mUnselectedBkgndLinePaint.setColor(res.getColor(R.color.waveform_unselected_bkgnd_overlay));
mBorderLinePaint = new Paint();
mBorderLinePaint.setAntiAlias(true);
mBorderLinePaint.setStrokeWidth(1.5f);
mBorderLinePaint.setPathEffect(new DashPathEffect(new float[] { 3.0f, 2.0f }, 0.0f));
mBorderLinePaint.setColor(res.getColor(R.color.selection_border));
mPlaybackLinePaint = new Paint();
mPlaybackLinePaint.setAntiAlias(false);
mPlaybackLinePaint.setColor(res.getColor(R.color.playback_indicator));
mTimecodePaint = new Paint();
mTimecodePaint.setTextSize(12);
mTimecodePaint.setAntiAlias(true);
mTimecodePaint.setColor(res.getColor(R.color.timecode));
mTimecodePaint.setShadowLayer(2, 1, 1, res.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;
}
}
);
mScaleGestureDetector = new ScaleGestureDetector(
context,
new ScaleGestureDetector.SimpleOnScaleGestureListener() {
public boolean onScaleBegin(ScaleGestureDetector d) {
Log.v("Ringdroid", "ScaleBegin " + d.getCurrentSpanX());
mInitialScaleSpan = Math.abs(d.getCurrentSpanX());
return true;
}
public boolean onScale(ScaleGestureDetector d) {
float scale = Math.abs(d.getCurrentSpanX());
Log.v("Ringdroid", "Scale " + (scale - mInitialScaleSpan));
if (scale - mInitialScaleSpan > 40) {
mListener.waveformZoomIn();
mInitialScaleSpan = scale;
}
if (scale - mInitialScaleSpan < -40) {
mListener.waveformZoomOut();
mInitialScaleSpan = scale;
}
return true;
}
public void onScaleEnd(ScaleGestureDetector d) {
Log.v("Ringdroid", "ScaleEnd " + d.getCurrentSpanX());
}
}
);
mSoundFile = null;
mLenByZoomLevel = null;
mValuesByZoomLevel = null;
mHeightsAtThisZoomLevel = null;
mOffset = 0;
mPlaybackPos = -1;
mSelectionStart = 0;
mSelectionEnd = 0;
mDensity = 1.0f;
mInitialized = false;
}
#Override
public boolean onTouchEvent(MotionEvent event) {
mScaleGestureDetector.onTouchEvent(event);
if (mGestureDetector.onTouchEvent(event)) {
return true;
}
switch(event.getAction()) {
case MotionEvent.ACTION_DOWN:
mListener.waveformTouchStart(event.getX());
break;
case MotionEvent.ACTION_MOVE:
mListener.waveformTouchMove(event.getX());
break;
case MotionEvent.ACTION_UP:
mListener.waveformTouchEnd();
break;
}
return true;
}
public boolean hasSoundFile() {
return mSoundFile != null;
}
public void setSoundFile(SoundFile soundFile) {
mSoundFile = soundFile;
mSampleRate = mSoundFile.getSampleRate();
mSamplesPerFrame = mSoundFile.getSamplesPerFrame();
computeDoublesForAllZoomLevels();
mHeightsAtThisZoomLevel = null;
}
public boolean isInitialized() {
return mInitialized;
}
public int getZoomLevel() {
return mZoomLevel;
}
public void setZoomLevel(int zoomLevel) {
while (mZoomLevel > zoomLevel) {
zoomIn();
}
while (mZoomLevel < zoomLevel) {
zoomOut();
}
}
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 int maxPos() {
return mLenByZoomLevel[mZoomLevel];
}
public int secondsToFrames(double seconds) {
return (int)(1.0 * seconds * mSampleRate / mSamplesPerFrame + 0.5);
}
public int secondsToPixels(double seconds) {
double z = mZoomFactorByZoomLevel[mZoomLevel];
return (int)(z * seconds * mSampleRate / mSamplesPerFrame + 0.5);
}
public double pixelsToSeconds(int pixels) {
double z = mZoomFactorByZoomLevel[mZoomLevel];
return (pixels * (double)mSamplesPerFrame / (mSampleRate * z));
}
public int millisecsToPixels(int msecs) {
double z = mZoomFactorByZoomLevel[mZoomLevel];
return (int)((msecs * 1.0 * mSampleRate * z) /
(1000.0 * mSamplesPerFrame) + 0.5);
}
public int pixelsToMillisecs(int pixels) {
double z = mZoomFactorByZoomLevel[mZoomLevel];
return (int)(pixels * (1000.0 * mSamplesPerFrame) /
(mSampleRate * z) + 0.5);
}
public void setParameters(int start, int end, int offset) {
mSelectionStart = start;
mSelectionEnd = end;
mOffset = offset;
}
public int getStart() {
return mSelectionStart;
}
public int getEnd() {
return mSelectionEnd;
}
public int getOffset() {
return mOffset;
}
public void setPlayback(int pos) {
mPlaybackPos = pos;
}
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();
// Draw waveform
int measuredWidth = getMeasuredWidth();
int measuredHeight = getMeasuredHeight();
int start = mOffset;
int width = mHeightsAtThisZoomLevel.length - start;
int ctr = measuredHeight / 2;
if (width > measuredWidth)
width = 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;
} else {
drawWaveformLine(canvas, i, 0, measuredHeight,
mUnselectedBkgndLinePaint);
paint = mUnselectedLinePaint;
}
drawWaveformLine(
canvas, i,
ctr - mHeightsAtThisZoomLevel[start + i],
ctr + 1 + mHeightsAtThisZoomLevel[start + i],
paint);
if (i + start == mPlaybackPos) {
canvas.drawLine(i, 0, i, measuredHeight, mPlaybackLinePaint);
}
}
// If we can see the right edge of the waveform, draw the
// non-waveform area to the right as unselected
for (i = width; i < measuredWidth; i++) {
drawWaveformLine(canvas, i, 0, measuredHeight,
mUnselectedBkgndLinePaint);
}
// Draw borders
canvas.drawLine(
mSelectionStart - mOffset + 0.5f, 30,
mSelectionStart - mOffset + 0.5f, measuredHeight,
mBorderLinePaint);
canvas.drawLine(
mSelectionEnd - mOffset + 0.5f, 0,
mSelectionEnd - mOffset + 0.5f, measuredHeight - 30,
mBorderLinePaint);
// Draw timecode
double timecodeIntervalSecs = 1.0;
if (timecodeIntervalSecs / onePixelInSecs < 50) {
timecodeIntervalSecs = 5.0;
}
if (timecodeIntervalSecs / onePixelInSecs < 50) {
timecodeIntervalSecs = 15.0;
}
// Draw grid
fractionalSecs = mOffset * onePixelInSecs;
int integerTimecode = (int) (fractionalSecs / timecodeIntervalSecs);
i = 0;
while (i < width) {
i++;
fractionalSecs += onePixelInSecs;
integerSecs = (int) fractionalSecs;
int integerTimecodeNew = (int) (fractionalSecs /
timecodeIntervalSecs);
if (integerTimecodeNew != integerTimecode) {
integerTimecode = integerTimecodeNew;
// Turn, e.g. 67 seconds into "1:07"
String timecodeMinutes = "" + (integerSecs / 60);
String timecodeSeconds = "" + (integerSecs % 60);
if ((integerSecs % 60) < 10) {
timecodeSeconds = "0" + timecodeSeconds;
}
String timecodeStr = timecodeMinutes + ":" + timecodeSeconds;
float offset = (float) (
0.5 * mTimecodePaint.measureText(timecodeStr));
canvas.drawText(timecodeStr,
i - offset,
(int)(12 * mDensity),
mTimecodePaint);
}
}
if (mListener != null) {
mListener.waveformDraw();
}
}
/**
* 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;
}
/**
* Called the first time we need to draw when the zoom level has changed
* or the screen is resized
*/
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);
}
}
}
The change is here in this part of code
DisplayMetrics displaymetrics = getContext().getResources().getDisplayMetrics();
int ScreenWidth= displaymetrics.widthPixels;
// Draw waveform
for ( i = 0; i < width; i++) {
Paint paint;
if (i + start >= mSelectionStart &&
i + start < mSelectionEnd) {
paint = mSelectedLinePaint;
} else {
drawWaveformLine(canvas, ((ScreenWidth/width)*i), 0, measuredHeight,
mUnselectedBkgndLinePaint);
paint = mUnselectedLinePaint;
}
drawWaveformLine(
canvas, ((ScreenWidth/width)*i),
ctr - mHeightsAtThisZoomLevel[start + i],
ctr + 1 + mHeightsAtThisZoomLevel[start + i],
paint);
you have to change the x-axis of draw line method according to your screen size
import java.util.LinkedList;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.SurfaceView;
/**
* A view that displays audio data on the screen as a waveform.
*/
public class WaveformView extends SurfaceView {
// The number of buffer frames to keep around (for a nice fade-out
// visualization.
private static final int HISTORY_SIZE = 6;
// To make quieter sounds still show up well on the display, we use
// +/- 8192 as the amplitude that reaches the top/bottom of the view
// instead of +/- 32767. Any samples that have magnitude higher than this
// limit will simply be clipped during drawing.
private static final float MAX_AMPLITUDE_TO_DRAW = 8192.0f;
// The queue that will hold historical audio data.
private LinkedList<short[]> mAudioData;
private Paint mPaint;
public WaveformView(Context context) {
this(context, null, 0);
}
public WaveformView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public WaveformView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mAudioData = new LinkedList<short[]>();
mPaint = new Paint();
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setColor(Color.WHITE);
mPaint.setStrokeWidth(0);
mPaint.setAntiAlias(true);
}
/**
* Updates the waveform view with a new "frame" of samples and renders it.
* The new frame gets added to the front of the rendering queue, pushing the
* previous frames back, causing them to be faded out visually.
*
* #param buffer the most recent buffer of audio samples.
*/
public synchronized void updateAudioData(short[] buffer) {
short[] newBuffer;
// We want to keep a small amount of history in the view to provide a nice
// fading effect. We use a linked list that we treat as a queue for this.
if (mAudioData.size() == HISTORY_SIZE) {
newBuffer = mAudioData.removeFirst();
System.arraycopy(buffer, 0, newBuffer, 0, buffer.length);
} else {
newBuffer = buffer.clone();
}
mAudioData.addLast(newBuffer);
// Update the display.
Canvas canvas = getHolder().lockCanvas();
if (canvas != null) {
drawWaveform(canvas);
getHolder().unlockCanvasAndPost(canvas);
}
}
/**
* Repaints the view's surface.
*
* #param canvas the {#link Canvas} object on which to draw.
*/
private void drawWaveform(Canvas canvas) {
// Clear the screen each time because SurfaceView won't do this for us.
canvas.drawColor(Color.BLACK);
float width = getWidth();
float height = getHeight();
float centerY = height / 2;
// We draw the history from oldest to newest so that the older audio
// data is further back and darker than the most recent data.
int colorDelta = 255 / (HISTORY_SIZE + 1);
int brightness = colorDelta;
for (short[] buffer : mAudioData) {
mPaint.setColor(Color.argb(brightness, 128, 255, 192));
float lastX = -1;
float lastY = -1;
// For efficiency, we don't draw all of the samples in the buffer,
// but only the ones that align with pixel boundaries.
for (int x = 0; x < width; x++) {
int index = (int) ((x / width) * buffer.length);
short sample = buffer[index];
float y = (sample / MAX_AMPLITUDE_TO_DRAW) * centerY + centerY;
if (lastX != -1) {
canvas.drawLine(lastX, lastY, x, y, mPaint);
}
lastX = x;
lastY = y;
}
brightness += colorDelta;
}
}
}

moving an object in a fixed circular path in android

I want to move an object in a fixed circular path like the planets around the sun.
Here is the link as per my research:
how to make an object move in circular path?
However, it is not working.
Here is the updated code:
public class MainActivity extends Activity {
ourView v;
Bitmap tball;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
v = new ourView(this);
setContentView(v);
tball = (BitmapFactory.decodeResource(getResources(),
R.drawable.blueball));
}
protected void onPause() {
super.onPause();
v.pause();
}
protected void onResume() {
super.onResume();
v.resume();
}
public class ourView extends SurfaceView implements Runnable {
Thread t;
SurfaceHolder holder;
Boolean isitok = false;
public ourView(Context context) {
super(context);
// TODO Auto-generated constructor stub
holder = getHolder();
}
// float aX, aY;
#Override
public void run() {
// TODO Auto-generated method stub
while (isitok == true) {
// perform drawing
if (!holder.getSurface().isValid()) {
continue;
}
Canvas canvas = holder.lockCanvas();
canvas.drawARGB(255, 150, 150, 10);
// System.out.println("Canvas matrix -" + canvas.getm));
Paint p = new Paint();
// canvas.drawBitmap(tball, (x - tball.getWidth()) / 2,
// (y - tball.getHeight()) / 2, p);
p.setStyle(Paint.Style.STROKE);
p.setColor(Color.WHITE);
p.setColor(Color.parseColor("#0101DF"));
canvas.drawCircle(canvas.getWidth() / 2,
canvas.getHeight() / 2, 110, p);
canvas.drawCircle(canvas.getWidth() / 2,
canvas.getHeight() / 2, 210, p);
float x = (canvas.getWidth() / 2) - (tball.getWidth() / 2);
float y = (canvas.getHeight() / 2) - 210 + (210 - 110) / 2
- (tball.getHeight() / 2);
float MX = canvas.getWidth() / 2;
float MY = canvas.getHeight() / 2;
for (double i = 0; i < 12 ; i++) {
float R = 160;
x = (float) (MX + (R * Math.cos(i)));
y = (float) (MY + (R * Math.sin(i)));
//y = (float) (MY - (R * Math.sin( i )));
canvas.drawBitmap(tball, x, y, p);
i++;
}
// float movingpts[];
holder.unlockCanvasAndPost(canvas);
}
}
public void pause() {
isitok = false;
while (true) {
try {
t.join();
} catch (InterruptedException e) {
// TODO: handle exception
e.printStackTrace();
}
break;
}
t = null;
}
public void resume() {
isitok = true;
t = new Thread(this);
t.start();
}
}
}"
`
Take a look at NineOldAndroids. This is an animation library available on every android version back to 1.0. I don't know if its possible to achieve an fixed circular path animation but the library seems pretty powerful.
Here is the sample code for a path animation: link-to-sample

Android page curl with images streaming from web?

So, I am using https://github.com/harism/android_page_curl , this project to achieve the curl functionality to create a book. But I want to achieve the same while streaming images from web directly, obviously in an asynchronous manner.
But then I would require an OpenGL , progress bar for the same. But I don't have any knowledge in OPENGL, So how can I go about tweaking this code and achieve the functionality I want.
Also , have a look at this question for more clear view of what I want to achieve...
PageCurl(magazine) with Image from web
package fi.harism.curl;
public class CurlActivity extends Activity {
private CurlView mCurlView;
Button btn;
private AQuery aq;
Drawable d =null;
TextView mText;
List<String> data;
MediaPlayer mPlayer;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
int index = 0;
if (getLastNonConfigurationInstance() != null) {
index = (Integer) getLastNonConfigurationInstance();
}
mCurlView = (CurlView) findViewById(R.id.curl);
mCurlView.setPageProvider(new PageProvider());
mCurlView.setSizeChangedObserver(new SizeChangedObserver());
mCurlView.setCurrentIndex(index);
mCurlView.setBackgroundColor(Color.GREEN);
}
#Override
public void onPause() {
super.onPause();
mCurlView.onPause();
}
#Override
public void onResume() {
super.onResume();
mCurlView.onResume();
}
#Override
public Object onRetainNonConfigurationInstance() {
return mCurlView.getCurrentIndex();
}
/**
* Bitmap provider.
*/
private class PageProvider implements CurlView.PageProvider {
private String[] mBitmapStrings={"http://myserver.com/image/img%20p1.png",
"http://myserver.com/image/img%20p2.png",
"http://myserver.com/image/img%20p3.png",
"http://myserver.com/image/img%20p4.png"};
#Override
public int getPageCount() {
return mBitmapStrings.length;
}
private Bitmap loadBitmap(int width, int height, int index) throws MalformedURLException, IOException {
Bitmap b = Bitmap.createBitmap(width, height,
Bitmap.Config.ARGB_8888);
b.eraseColor(0xFFFFFFFF);
Canvas c = new Canvas(b);
if(index==mBitmapStrings.length)
{
index=0;
}
Drawable d = new BitmapDrawable(drawable_from_url(mBitmapStrings[index]));
int margin = 7;
int border = 3;
Rect r = new Rect(margin, margin, width - margin, height - margin);
int imageWidth = r.width() - (border * 2);
int imageHeight = imageWidth * d.getIntrinsicHeight()
/ d.getIntrinsicWidth();
if (imageHeight > r.height() - (border * 2)) {
imageHeight = r.height() - (border * 2);
imageWidth = imageHeight * d.getIntrinsicWidth()
/ d.getIntrinsicHeight();
}
r.left += ((r.width() - imageWidth) / 2) - border;
r.right = r.left + imageWidth + border + border;
r.top += ((r.height() - imageHeight) / 2) - border;
r.bottom = r.top + imageHeight + border + border;
Paint p = new Paint();
p.setColor(0xFFC0C0C0);
c.drawRect(r, p);
r.left += border;
r.right -= border;
r.top += border;
r.bottom -= border;
d.setBounds(r);
d.draw(c);
return b;
}
#Override
public void updatePage(CurlPage page, int width, int height, int index) {
Bitmap front;
try {
front = loadBitmap(width, height, index);
page.setTexture(front, CurlPage.SIDE_FRONT);
page.setColor(Color.rgb(180, 180, 180), CurlPage.SIDE_BACK);
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
/**
* CurlView size changed observer.
*/
private class SizeChangedObserver implements CurlView.SizeChangedObserver {
#Override
public void onSizeChanged(int w, int h) {
/*if (w > h) {
mCurlView.setViewMode(CurlView.SHOW_TWO_PAGES);
mCurlView.setMargins(.1f, .05f, .1f, .05f);
} else {*/
mCurlView.setViewMode(CurlView.SHOW_ONE_PAGE);
//mCurlView.setMargins(.1f, .1f, .1f, .1f);
mCurlView.setMargins(0,0,0,0);
//}
}
}
Bitmap drawable_from_url(String url) throws java.net.MalformedURLException, java.io.IOException {
Bitmap x;
HttpURLConnection connection = (HttpURLConnection)new URL(url) .openConnection();
connection.setRequestProperty("User-agent","Mozilla/4.0");
connection.connect();
InputStream input = connection.getInputStream();
x = BitmapFactory.decodeStream(input);
return x;
}
}
----Edit----
Also , I am using android-query library for asynchronous image/file
loading. Would it be feasible to use it with this project in case of
streaming images from web. How?
public class CurlActivity extends Activity {
private CurlView mCurlView;
Bitmap y;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
int index = 0;
if (getLastNonConfigurationInstance() != null) {
index = (Integer) getLastNonConfigurationInstance();
}
mCurlView = (CurlView) findViewById(R.id.curl);
mCurlView.setPageProvider(new PageProvider());
mCurlView.setSizeChangedObserver(new SizeChangedObserver());
mCurlView.setCurrentIndex(index);
mCurlView.setBackgroundColor(0xFF202830);
}
#Override
public void onPause() {
super.onPause();
mCurlView.onPause();
}
#Override
public void onResume() {
super.onResume();
mCurlView.onResume();
}
#Override
public Object onRetainNonConfigurationInstance() {
return mCurlView.getCurrentIndex();
}
/**
* Bitmap provider.
*/
private class PageProvider implements CurlView.PageProvider {
// Bitmap resources.
/*private int[] mBitmapIds = { R.drawable.obama, R.drawable.road_rage,
R.drawable.taipei_101, R.drawable.world };*/
private String[] mBitmapIds = {"your url","your url",
"your urlg", "your url" }; //your image url
#Override
public int getPageCount() {
return 5;
}
private Bitmap loadBitmap(int width, int height, int index) {
Bitmap b = Bitmap.createBitmap(width, height,
Bitmap.Config.ARGB_8888);
b.eraseColor(0xFFFFFFFF);
Canvas c = new Canvas(b);
//Uri url = Uri.parse("http://stackoverflow.com");
//Drawable d =getResources().getDrawable(url);
//Drawable d = getResources().getDrawable(mBitmapIds[index]);
try {
drawableFromUrl(mBitmapIds[index]);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Drawable d = new BitmapDrawable(getResources(),y);
//Drawable d = new BitmapDrawable(drawable_from_url(y));
int margin = 7;
int border = 3;
Rect r = new Rect(margin, margin, width - margin, height - margin);
int imageWidth = r.width() - (border * 2);
int imageHeight = imageWidth * d.getIntrinsicHeight()
/ d.getIntrinsicWidth();
if (imageHeight > r.height() - (border * 2)) {
imageHeight = r.height() - (border * 2);
imageWidth = imageHeight * d.getIntrinsicWidth()
/ d.getIntrinsicHeight();
}
r.left += ((r.width() - imageWidth) / 2) - border;
r.right = r.left + imageWidth + border + border;
r.top += ((r.height() - imageHeight) / 2) - border;
r.bottom = r.top + imageHeight + border + border;
Paint p = new Paint();
p.setColor(0xFFC0C0C0);
c.drawRect(r, p);
r.left += border;
r.right -= border;
r.top += border;
r.bottom -= border;
d.setBounds(r);
d.draw(c);
return b;
}
#Override
public void updatePage(CurlPage page, int width, int height, int index) {
switch (index) {
// First case is image on front side, solid colored back.
case 0: {
Bitmap front = loadBitmap(width, height, 0);
page.setTexture(front, CurlPage.SIDE_FRONT);
page.setColor(Color.rgb(180, 180, 180), CurlPage.SIDE_BACK);
break;
}
// Second case is image on back side, solid colored front.
case 1: {
Bitmap back = loadBitmap(width, height, 2);
page.setTexture(back, CurlPage.SIDE_BACK);
page.setColor(Color.rgb(127, 140, 180), CurlPage.SIDE_FRONT);
break;
}
// Third case is images on both sides.
case 2: {
Bitmap front = loadBitmap(width, height, 1);
Bitmap back = loadBitmap(width, height, 3);
page.setTexture(front, CurlPage.SIDE_FRONT);
page.setTexture(back, CurlPage.SIDE_BACK);
break;
}
// Fourth case is images on both sides - plus they are blend against
// separate colors.
case 3: {
Bitmap front = loadBitmap(width, height, 2);
Bitmap back = loadBitmap(width, height, 1);
page.setTexture(front, CurlPage.SIDE_FRONT);
page.setTexture(back, CurlPage.SIDE_BACK);
page.setColor(Color.argb(127, 170, 130, 255),
CurlPage.SIDE_FRONT);
page.setColor(Color.rgb(255, 190, 150), CurlPage.SIDE_BACK);
break;
}
// Fifth case is same image is assigned to front and back. In this
// scenario only one texture is used and shared for both sides.
case 4:
Bitmap front = loadBitmap(width, height, 0);
page.setTexture(front, CurlPage.SIDE_BOTH);
page.setColor(Color.argb(127, 255, 255, 255),
CurlPage.SIDE_BACK);
break;
}
}
}
/**
* CurlView size changed observer.
*/
private class SizeChangedObserver implements CurlView.SizeChangedObserver {
#Override
public void onSizeChanged(int w, int h) {
if (w > h) {
mCurlView.setViewMode(CurlView.SHOW_TWO_PAGES);
mCurlView.setMargins(.1f, .05f, .1f, .05f);
} else {
mCurlView.setViewMode(CurlView.SHOW_ONE_PAGE);
mCurlView.setMargins(.1f, .1f, .1f, .1f);
}
}
}
public void drawableFromUrl(String url) throws IOException {
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
connection.connect();
InputStream input = connection.getInputStream();
y = BitmapFactory.decodeStream(input);
}
}

Categories

Resources