Live Wallpaper Tutorial - android

I am trying to do the following from a live wallpaper tutorial I found here.
/**
* Do the actual drawing stuff
*/
private void doDraw(Canvas canvas) {
Bitmap b = BitmapFactory.decodeResource(context.getResources(), IMAGES[current]);
canvas.drawColor(Color.BLACK);
canvas.drawBitmap(b, 0, 0, null);
Log.d(TAG, "Drawing finished.");
}
/**
* Update the animation, sprites or whatever.
* If there is nothing to animate set the wait
* attribute of the thread to true
*/
private void updatePhysics() {
// if nothing was updated :
// this.wait = true;
if(previousTime - System.currentTimeMillis() >= 41) { //24 FPS
current = current < IMAGES.length ? current++ : 0;
}
Log.d(TAG, "Updated physics.");
}
But it doesn't seem to work. What am I doing wrong. The "Drawing finished." and "Updated physics." messages are getting printed. But I see the first image only. I'm testing it on the emulator.
Any help would be appreciated. Thanks

I have worked out a simple sample live wallpaper where the color shift over time. Maybe you can use this as a starting point:
package com.cmwmobile.android.samples;
import android.graphics.Canvas;
import android.os.Handler;
import android.service.wallpaper.WallpaperService;
import android.view.SurfaceHolder;
/**
* The SampleLiveWallpaperService class is responsible for showing the
* animation and is an interface to android.
* #author Casper Wakkers - www.cmwmobile.com
*/
public class SampleLiveWallpaperService extends WallpaperService {
private Handler handler = null;
/**
* Inner class representing the actual implementation of the
* Live Wallpaper {#link Engine}.
*/
private class SampleLiveWallpaperEngine extends Engine {
private boolean visible = false;
private int[] colors = {0, 0, 0} ;
/**
* Runnable implementation for the actual work.
*/
private final Runnable runnableSomething = new Runnable() {
/**
* {#inheritDoc}
*/
public void run() {
drawSomething();
}
};
/**
* The drawSomething method is responsible for drawing the animation.
*/
private void drawSomething() {
final SurfaceHolder holder = getSurfaceHolder();
Canvas canvas = null;
try {
canvas = holder.lockCanvas();
if (canvas != null) {
canvas.drawARGB(200, colors[0], colors[1], colors[2]);
}
updateColors(colors);
}
finally {
if (canvas != null) {
holder.unlockCanvasAndPost(canvas);
}
}
// Reschedule the next redraw.
handler.removeCallbacks(runnableSomething);
if (visible) {
// Play around with the delay for an optimal result.
handler.postDelayed(runnableSomething, 25);
}
}
/**
* Method updateColors updates the colors by increasing the value
* per RGB. The values are reset to zero if the maximum value is
* reached.
* #param colors to be updated.
*/
private void updateColors(int[] colors) {
if (colors[0] < 255) {
colors[0]++;
}
else {
if (colors[1] < 255) {
colors[1]++;
}
else {
if (colors[2] < 255) {
colors[2]++;
}
else {
colors[0] = 0;
colors[1] = 0;
colors[2] = 0;
}
}
}
}
/**
* {#inheritDoc}
*/
public void onDestroy() {
super.onDestroy();
handler.removeCallbacks(runnableSomething);
}
/**
* {#inheritDoc}
*/
public void onVisibilityChanged(boolean visible) {
super.onVisibilityChanged(visible);
this.visible = visible;
if (visible) {
drawSomething();
}
else {
handler.removeCallbacks(runnableSomething);
}
}
}
/**
* Constructor. Creates the {#link Handler}.
*/
public SampleLiveWallpaperService() {
handler = new Handler();
}
/**
* {#inheritDoc}
*/
public Engine onCreateEngine() {
return new SampleLiveWallpaperEngine();
}
}

I created a quick tutorial on my employers blog about using SVG in a Live Wallpaper, check it out if you like.
Part 1 http://blog.infrared5.com/2012/03/android-live-wallpaper/
Part 2 http://blog.infrared5.com/2012/03/android-live-wallpaper-part-2/

Related

EditText setCompoundDrawablesWithIntrinsicBounds() not working after setError()

I have an custom widget which has an clear button set as the right drawable using setCompoundDrawablesWithIntrinsicBounds() method.
Now I need to add errors to the widget and I've tried to use the default functionality and rely on the setError() method.
The issue I'm having is that after I set the error, my right drawable won't be shown again, even if I set it again afterwards.
Does anyone encountered this issue and maybe found an solution to the problem?
Thank you.
LE:
I forgot to mention that if I use setError("My error hint text", null) instead of setError("Please choose an valid destination!") everything works fine, but as you can guess the error icon won't be shown.
LLE:
This is my custom class which handles the display of the clear icon and the action for it.
/**
* Class of {#link android.widget.AutoCompleteTextView} that includes a clear (dismiss / close) button with a
* OnClearListener to handle the event of clicking the button
* <br/>
* Created by ionut on 26.04.2016.
*/
public class ClearableAutoCompleteTextView extends AppCompatAutoCompleteTextView implements View.OnTouchListener {
/**
* The time(in milliseconds) used for transitioning between the supported states.
*/
private static final int TRANSITION_TIME = 500;
/**
* Flag for hide transition.
*/
private static final int TRANSITION_HIDE = 101;
/**
* Flag for show transition.
*/
private static final int TRANSITION_SHOW = 102;
/**
* Image representing the clear button. (will always be set to the right of the view).
*/
#DrawableRes
private static int mImgClearButtonRes = R.drawable.ic_clear_dark;
/**
* Task with the role of showing the clear action button.
*/
private final Runnable showClearButtonRunnable = new Runnable() {
#Override
public void run() {
Message msg = transitionHandler.obtainMessage(TRANSITION_SHOW);
msg.sendToTarget();
}
};
/**
* Task with the role of hiding the clear action button.
*/
private final Runnable hideClearButtonRunnable = new Runnable() {
#Override
public void run() {
Message msg = transitionHandler.obtainMessage(TRANSITION_HIDE);
msg.sendToTarget();
}
};
/**
* Flag indicating if the default clear functionality should be disabled.
*/
private boolean mDisableDefaultFunc;
// The default clear listener which will clear the input of any text
private OnClearListener mDefaultClearListener = new OnClearListener() {
#Override
public void onClear() {
getEditableText().clear();
setText(null);
}
};
/**
* Touch listener which will receive any touch events that this view handles.
*/
private OnTouchListener mOnTouchListener;
/**
* Custom listener which will be notified when an clear event was made from the clear button.
*/
private OnClearListener onClearListener;
/**
* Transition drawable used when showing the clear action.
*/
private TransitionDrawable mTransitionClearButtonShow = null;
/**
* Transition drawable used when hiding the clear action.
*/
private TransitionDrawable mTransitionClearButtonHide = null;
private AtomicBoolean isTransitionInProgress = new AtomicBoolean(false);
private final Handler transitionHandler = new Handler(Looper.getMainLooper()) {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case TRANSITION_HIDE:
setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
isTransitionInProgress.set(false);
break;
case TRANSITION_SHOW:
setCompoundDrawablesWithIntrinsicBounds(0, 0, mImgClearButtonRes, 0);
isTransitionInProgress.set(false);
break;
default:
super.handleMessage(msg);
}
}
};
/* Required methods, not used in this implementation */
public ClearableAutoCompleteTextView(Context context) {
super(context);
init();
}
/* Required methods, not used in this implementation */
public ClearableAutoCompleteTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
/* Required methods, not used in this implementation */
public ClearableAutoCompleteTextView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
#Override
public boolean onTouch(View v, MotionEvent event) {
if (getCompoundDrawables()[2] == null) {
// Pass the touch event to other listeners, if none, the normal flow is resumed
return null != mOnTouchListener && mOnTouchListener.onTouch(v, event);
}
// React only when the UP event is detected
if (event.getAction() != MotionEvent.ACTION_UP) {
return false;
}
// Detect the clear button area of touch
int x = (int) event.getX();
int y = (int) event.getY();
int left = getWidth() - getPaddingRight() - getCompoundDrawables()[2].getIntrinsicWidth();
int right = getWidth();
boolean tappedX = x >= left && x <= right && y >= 0 && y <= (getBottom() - getTop());
if (tappedX) {
// Allow clear events only when the transition is not in progress
if (!isTransitionInProgress.get()) {
if (!mDisableDefaultFunc) {
// Call the default functionality only if it wasn't disabled
mDefaultClearListener.onClear();
}
if (null != onClearListener) {
// Call the custom clear listener so that any member listening is notified of the clear event
onClearListener.onClear();
}
}
}
// Pass the touch event to other listeners, if none, the normal flow is resumed
return null != mOnTouchListener && mOnTouchListener.onTouch(v, event);
}
#Override
public void setOnTouchListener(OnTouchListener l) {
// Instead of using the super, we manually handle the touch event (only one listener can exist normally at a
// time)
mOnTouchListener = l;
}
private void init() {
// Set the bounds of the button
setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
if (getCompoundDrawablePadding() == 0) {
// We want to have some default padding, in case no one is specified in the xml
setCompoundDrawablePadding(Dimensions.dpToPx(getContext(), 5f));
}
enableTransitionClearButton();
// if the clear button is pressed, fire up the handler. Otherwise do nothing
super.setOnTouchListener(this);
}
#Override
public void onRestoreInstanceState(Parcelable state) {
super.onRestoreInstanceState(state);
updateClearButton();
}
#Override
protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {
super.onTextChanged(text, start, lengthBefore, lengthAfter);
updateClearButton();
}
/**
* When hiding/showing the clear button an transition drawable will be used instead of the default drawable res.
*/
public void enableTransitionClearButton() {
mTransitionClearButtonShow =
(TransitionDrawable) ContextCompat.getDrawable(getContext(), R.drawable.ic_clear_fade_in);
mTransitionClearButtonHide =
(TransitionDrawable) ContextCompat.getDrawable(getContext(), R.drawable.ic_clear_fade_out);
mTransitionClearButtonShow.setCrossFadeEnabled(true);
mTransitionClearButtonHide.setCrossFadeEnabled(true);
}
/**
* When hiding/showing the clear button the default drawable res will be used instead of the transition drawable.
*/
#SuppressWarnings("unused")
public void disableTransitionClearButton() {
mTransitionClearButtonShow = null;
isTransitionInProgress.set(false);
transitionHandler.removeCallbacks(hideClearButtonRunnable);
transitionHandler.removeCallbacks(showClearButtonRunnable);
}
/**
* Set an custom listener which will get notified when an clear event was triggered from the clear button.
*
* #param clearListener
* The listener
* #param disableDefaultFunc
* {#code true} to disable the default clear functionality, usually meaning it will be
* handled by the
* calling member. {#code false} allow the default functionality of clearing the input.
*
* #see #setOnClearListener(OnClearListener)
*/
public void setOnClearListener(final OnClearListener clearListener, boolean disableDefaultFunc) {
this.onClearListener = clearListener;
this.mDisableDefaultFunc = disableDefaultFunc;
}
/**
* Set an custom listener which will get notified when an clear event was triggered from the clear button.
*
* #param clearListener
* The listener
*
* #see #setOnClearListener(OnClearListener, boolean)
*/
public void setOnClearListener(final OnClearListener clearListener) {
setOnClearListener(clearListener, false);
}
/**
* Disable the default functionality of the clear event - calling this won't allow for the input to be
* automatically
* cleared (it will give the ability to make custom implementations and react to the event before the clear).
*/
#SuppressWarnings("unused")
public void disableDefaultClearFunctionality() {
mDisableDefaultFunc = true;
}
/**
* Enable the default functionality of the clear event. Will automatically clear the input when the clear button is
* clicked.
*/
#SuppressWarnings("unused")
public void enableDefaultClearFunctionality() {
mDisableDefaultFunc = false;
}
/**
* Automatically show/hide the clear button based on the current input detected.
* <br/>
* If there is no input the clear button will be hidden. If there is input detected the clear button will be shown.
*/
public void updateClearButton() {
if (isEmpty()) {
hideClearButton();
} else {
showClearButton();
}
}
private boolean isEmpty() {
if (null == getText()) {
// Invalid editable text
return true;
} else if (TextUtils.isEmpty(getText().toString())) {
// Empty
return true;
} else if (TextUtils.isEmpty(getText().toString().trim())) {
// White spaces only
return true;
}
return false;
}
/**
* Hide the clear button.
* <br/>
* If an transition drawable was provided, it will be used to create an fade out effect, otherwise the default
* drawable resource will be used.
*/
public void hideClearButton() {
if (getCompoundDrawables()[2] == null) {
// The clear button was already hidden - do nothing
return;
}
if (null == mTransitionClearButtonHide) {
setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
return;
}
mTransitionClearButtonHide.resetTransition();
isTransitionInProgress.set(true);
mTransitionClearButtonHide.startTransition(TRANSITION_TIME);
setCompoundDrawablesWithIntrinsicBounds(null, null, mTransitionClearButtonHide, null);
transitionHandler.removeCallbacks(showClearButtonRunnable);
transitionHandler.removeCallbacks(hideClearButtonRunnable);
transitionHandler.postDelayed(hideClearButtonRunnable, TRANSITION_TIME);
}
/**
* Show the clear button.
* <br/>
* If an transition drawable was provided, it will be used to create an fade in effect, otherwise the default
* drawable resource will be used.
*/
public void showClearButton() {
if (getCompoundDrawables()[2] != null) {
// The clear button was already set - do nothing
return;
}
if (null == mTransitionClearButtonShow) {
setCompoundDrawablesWithIntrinsicBounds(0, 0, mImgClearButtonRes, 0);
return;
}
isTransitionInProgress.set(true);
mTransitionClearButtonShow.startTransition(TRANSITION_TIME);
setCompoundDrawablesWithIntrinsicBounds(null, null, mTransitionClearButtonShow, null);
transitionHandler.removeCallbacks(hideClearButtonRunnable);
transitionHandler.removeCallbacks(showClearButtonRunnable);
transitionHandler.postDelayed(showClearButtonRunnable, TRANSITION_TIME);
}
/**
* Custom contract which is used to notify any listeners that an clear event was triggered.
*/
public interface OnClearListener {
/**
* Clear event from the clear button triggered.
*/
void onClear();
}
}
When I want to display the error I use the following command:
// Enable and show the error
mClearView.requestFocus(); // we need to request focus, otherwise the error won't be shown
mClearView.setError("Please choose an valid destination!", null);
If I use:
mClearView.setError("Please choose an valid destination!"), so that the error icon to be shown, the clear button won't be shown anymore after this.
Since the documentation of setCompoundDrawablesWithIntrinsicBounds() (not so) clearly states that subsequent calls should overwrite the previously set drawables, and the documentation of setError() says the following:
Sets the right-hand compound drawable of the TextView to the "error" icon and sets an error message that will be displayed in a
popup when the TextView has focus.
I assume this is a bug.
Calling setError(null) and setting the previously set drawables to null before setting your new drawable is a possible workaround:
void setError(String error) {
editText.setError(error);
}
void setCompoundDrawableRight(Drawable rightDrawable) {
editText.setError(null);
editText.setCompoundDrawables(null, null, null, null);
editText.setCompoundDrawablesWithIntrinsicBounds(null, null, rightDrawable, null);
}

Image(s) placement over a image in Android Saving memory

I'm placing ImageView's in a RelativeLayout. I'm setting them with LayoutParams and using setMargins() to set the location of each picture. The max number of Images that will be placed on top of the first one will only reach 8. Their are 5 diffident Images and 8 positions on the screen where they can be placed. I would like to create the Images as their corresponding buttons are pressed and to be able to set that Image into the RelativeLayout and display the change. I would like a way to clear all the Images off the screen except for the main/ background ImageView. I don't like to populate 8 X 5 = 40 Images and then hide them all then change their view to Visible when i need them to show. I need something that will populate as need be but able to destory or remove when I clear it out.
Thanks,
Zelda
aButton.setOnClickListener(new OnClickListener(){
public void onClick(View v)
{
noteNumber++;
if(noteNumber <= 8){
note n = new note(getBaseContext());
n.setNoteNumber(noteNumber);
n.setHeight(85);
images.add(n); //ArrayList()
}
populate();
}
});
}
public void populate(){
//if(noteNumber < 9){
for(note a : images){
//note a = images.get(noteNumber-1); //images is of type ArrayList<ImageView>()
if(a != null && a.getMasterImage() != null){
int number = a.getNoteNumber();
imageParams.setMargins(25+45*number, a.getHeight(), 20, 360);
frame.addView(a.getMasterImage(),imageParams);
}
}
}
}
public class note {
private int noteNumber;
private int height;
private ImageView masterImage;
public note(Context c){
masterImage = new ImageView(c);
masterImage.setImageResource(R.raw.zelda);
this.noteNumber = 1;
height = 0;
}
/**
* #return the masterImage
*/
public ImageView getMasterImage() {
return masterImage;
}
/**
* #param masterImage the masterImage to set
*/
public void setMasterImage(ImageView masterImage) {
this.masterImage = masterImage;
}
/**
* #return the noteNumber
*/
public int getNoteNumber() {
return noteNumber;
}
/**
* #param noteNumber the noteNumber to set
*/
public void setNoteNumber(int noteNumber) {
this.noteNumber = noteNumber;
}
/**
* #return the height
*/
public int getHeight() {
return height;
}
/**
* #param height the height to set
*/
public void setHeight(int height) {
this.height = height;
}
}

android action_up not working

what im trying to do is when someone hold there finger down on the screen forward equals true but when they take it off it equals false
so i tryed using the get_actions() methods
but only the action_down gets called
heres my code
public class zombView extends SurfaceView{
private Bitmap bmp, grass, joystick;
private SurfaceHolder holder;
Timer t = new Timer();
float x = 0, y = 0;
boolean forward;
public zombView(Context context) {
super(context);
holder = getHolder();
holder.addCallback(new SurfaceHolder.Callback() {
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
#Override
public void surfaceCreated(final SurfaceHolder holder) {
t.scheduleAtFixedRate(new TimerTask(){
public void run(){
Canvas c = holder.lockCanvas(null);
onDraw(c);
holder.unlockCanvasAndPost(c);
if(forward){
x = x + 5;
}
onTouchEvent(null);
}
},200,100);
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format,
int width, int height) {
}
});
bmp = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
grass = BitmapFactory.decodeResource(getResources(), R.drawable.grassland);
joystick = BitmapFactory.decodeResource(getResources(), R.drawable.joystic);
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.BLACK);
canvas.drawBitmap(grass, getWidth() - getWidth(), getHeight() - getHeight(), null);
canvas.drawBitmap(joystick, getWidth() - getWidth(),joystick.getHeight(), null);
canvas.drawBitmap(bmp, x, y, null);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
/*switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN: forward = true;
case MotionEvent.ACTION_POINTER_DOWN: forward = true;
case MotionEvent.ACTION_UP: forward = false;
case MotionEvent.ACTION_POINTER_UP:forward = false;
case MotionEvent.ACTION_MOVE: forward = true;
}*/
if(event.getAction()== MotionEvent.ACTION_DOWN){
forward = true;
}if(event.getAction()== MotionEvent.ACTION_UP){
forward = false;
}
return super.onTouchEvent(event);
}
}
The layout containing this SurfaceView is not passing event to this SurfaceView. What you need to do is override ontouch menthod and return false in that. I hope this would be helpful.
use this
case MotionEvent.ACTION_DOWN:
touch_start(x, y);
invalidate();
break;
case MotionEvent.ACTION_MOVE:
touch_move(x, y);
invalidate();
break;
case MotionEvent.ACTION_UP:
touch_up();
invalidate();
break;
}
Timer in UI is unsafe. I could propose a class of my own purposed to keep some times and dates, showing themselves in some views.
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import android.os.Handler;
import android.widget.TextView;
/**
* The class for creating and refreshing many different fields on different layouts,
* that can hold actual time and/or date in different formats
* The formats should be as in http://developer.android.com/reference/java/text/SimpleDateFormat.html.
* Only present and visible fields are being actualized, so there is no need to clean the clock list after closing an activity
*
* Examples of use:
*
* Clock.registerClock((TextView) findViewById(R.id.TimeField), "HH:mm");
* Clock.registerClock((TextView) findViewById(R.id.DateField), "d.M.yyyy EEE");
* Clock.start(10000L);
*
* #author Petr Gangnus
*/
public final class Clock {
/**
* the handler that works instead of timer and supports UI
*/
static private Handler handler = new Handler();
/**
* the interval of the time refreshing
*/
static private long refreshStep;
/**
* pairs TextView timer+time/date format
*/
private TextView clockFace;
private String format;
private Clock(TextView clockFace, String format){
this.clockFace=clockFace;
this.format=format;
}
// here is the list of views containing the visual timers that should be held actual
static private ArrayList<Clock> clocks=new ArrayList<Clock>();
/**
* fills all timer fields by actual time value, according to their formats.
*/
static private Runnable mUpdateTimeTask = new Runnable() {
public void run() {
for(Clock clock:clocks){
showActualTimeDate(clock);
}
handler.postDelayed(this,refreshStep);
}
};
//============================================ public members ====================================================================
/**
* add a clock to the list of updating clocks
* #param clockFace - the place where the time or date will be shown
* #param format - the format of the time/date
* #return
*/
public static boolean registerClock(TextView clockFace, String format){
if (clockFace==null) return false;
if(clocks.contains(clockFace)){
// old clockFace
clocks.get(clocks.indexOf(clockFace)).format=format;
} else {
// new clockFace
clocks.add(new Clock(clockFace, format));
}
return true;
}
/**
* remove a clock from the updating list
* #param clockFace
* #return
*/
public static boolean unRegisterClock(TextView clockFace){
if (clockFace==null) return false;
if(clocks.contains(clockFace)){
// found clockFace
clocks.remove(clocks.indexOf(clockFace));
} else {
// not found clockFace
return false;
}
return true;
}
/**
* put in the "place" the actual date/time in the appropriate "format"
* #param place
* #param format
*/
public static void showActualTimeDate(Clock clock){
if (clock.clockFace==null) return;
if (clock.clockFace.getVisibility()!=TextView.VISIBLE) return;
Date thisDate=new Date();
SimpleDateFormat df=new SimpleDateFormat(clock.format);
clock.clockFace.setText(df.format(thisDate));
}
/**
* start the ticking for all clocks
* #param step the tick interval
*/
public static void start(long step) {
refreshStep=step;
handler.removeCallbacks(mUpdateTimeTask);
handler.postDelayed(mUpdateTimeTask, 0);
}
/**
* Stopping ticking all clocks (not removing them)
* the calling could be put somewhere in onStop
*/
public static void stop() {
handler.removeCallbacks(mUpdateTimeTask);
}
}

Animation in Live Wallpaper Android?

I am fairly new developer and trying to make a live wallpaper app. Among many animations, my first target is to show a rotating Bitmap which is actually a Black Hole.
public class Painting extends Thread {
/** Reference to the View and the context */
private SurfaceHolder surfaceHolder;
private Context context;
/** State */
private boolean wait;
private boolean run;
/** Dimensions */
private int width;
private int height;
/** Time tracking */
private long previousTime;
boolean first = true;
Bitmap hole;
int degree;
public Painting(Context con , SurfaceHolder surf)
{
context = con;
surfaceHolder = surf;
this.wait = true;
Log.i("Live Test","UnInitialized");
Drawable d = (con.getResources().getDrawable(R.drawable.vlack));
hole = ((BitmapDrawable)d).getBitmap();
hole.prepareToDraw();
if(hole != null)
Log.i("Live Test","Initialized");
run = true;wait = false;
degree = 0;
}
#Override
public void run()
{
while (run) {
this.run = true;
Canvas c = null;
Log.i("Live Test","Draw Color");
while (run) {
try {
c = this.surfaceHolder.lockCanvas();
synchronized (this.surfaceHolder) {
doDraw(c);
}
} finally {
if (c != null) {
this.surfaceHolder.unlockCanvasAndPost(c);
Log.i("Live Test","Unlocked And Posted");
}
}
// pause if no need to animate
synchronized (this) {
if (wait) {
try {
wait();
} catch (Exception e) {
Log.i("Live Test","Error wait");
}
}
}
}
}
}
public void setSurfaceSize(int width, int height) {
this.width = width;
this.height = height;
synchronized(this) {
this.notify();
}
}
/**
* Pauses the livewallpaper animation
*/
public void pausePainting() {
this.wait = true;
synchronized(this) {
this.notify();
}
}
/**
* Resume the livewallpaper animation
*/
public void resumePainting() {
this.wait = false;
synchronized(this) {
this.notify();
}
}
/**
* Stop the livewallpaper animation
*/
public void stopPainting() {
this.run = false;
synchronized(this) {
this.notify();
}
}
private void doDraw(Canvas canvas) {
if(first)
{
canvas.save();
canvas.drawColor(0x60444444);
canvas.drawBitmap(hole, 80,80,null);
canvas.restore();
first = false;
}
else
{
long currentTime = System.currentTimeMillis();
long elapsed = currentTime - previousTime;
if (elapsed > 20) {
canvas.save();
degree+= 5;
if(degree>359)degree = degree -358;
canvas.rotate((float) degree);
canvas.restore();
Log.i("Live Test","rotated");
}
previousTime = currentTime;
}
}
}
So I am trying to rotate the bitmap and show it again so it looks like its sucking stars and all.
Also I have removed Basic onPause onResume Functions so that you guys can understand the code easily. I know there is something basic I am missing, but What?
Hmmm. It would take more time than I have right now to puzzle this out, but I do have one suggestion: code your wallpaper using a simpler approach. Scrap the thread and do something more along the lines of the Cube example, that is to say make a runnable which schedules calls to itself using postDelayed. Hope this helps. George.

Android: Change activity state when receiving a phone call

A problem came up in my latest android programming project.
The problem is I would like to change Activity that launches when the phone receives a call.
Is it possible to add some text after the contact name when a call is received.
I have search the web for something that could do that, and been looking in the API for hours and I cannot find anything, is it possible with reflection of something like that?
I have made a class that listens to when the phone_state is receiving a call, and I can get the incomming number, but I would like to change the appearance on the screen.
// Thanks in advance
you can,t edit InCallScreen interface. but you can display some Text or whatever above it using toast,
class MyToast ............
package i4nc4mp.myLock.phone;
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import android.app.INotificationManager;
import android.app.ITransientNotification;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.PixelFormat;
import android.os.Handler;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
import android.view.WindowManagerImpl;
import android.widget.TextView;
/**
* A toast is a view containing a quick little message for the user. The toast class
* helps you create and show those.
* {#more}
*
* <p>
* When the view is shown to the user, appears as a floating view over the
* application. It will never receive focus. The user will probably be in the
* middle of typing something else. The idea is to be as unobtrusive as
* possible, while still showing the user the information you want them to see.
* Two examples are the volume control, and the brief message saying that your
* settings have been saved.
* <p>
* The easiest way to use this class is to call one of the static methods that constructs
* everything you need and returns a new Toast object.
*/
public class MyToast {
static final String TAG = "Toast";
static final boolean localLOGV = false;
/**
* Show the view or text notification for a short period of time. This time
* could be user-definable. This is the default.
* #see #setDuration
*/
public static final int LENGTH_SHORT = 0;
/**
* Show the view or text notification for a long period of time. This time
* could be user-definable.
* #see #setDuration
*/
public static final int LENGTH_LONG = 1;
final Handler mHandler = new Handler();
final Context mContext;
final TN mTN;
int mDuration;
int mGravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
int mX, mY;
float mHorizontalMargin;
float mVerticalMargin;
View mView;
View mNextView;
/**
* Construct an empty Toast object. You must call {#link #setView} before you
* can call {#link #show}.
*
* #param context The context to use. Usually your {#link android.app.Application}
* or {#link android.app.Activity} object.
*/
public MyToast(Context context) {
mContext = context;
mTN = new TN();
mY = context.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.toast_y_offset);
}
/**
* Show the view for the specified duration.
*/
public void show() {
if (mNextView == null) {
throw new RuntimeException("setView must have been called");
}
INotificationManager service = getService();
String pkg = mContext.getPackageName();
TN tn = mTN;
try {
service.enqueueToast(pkg, tn, mDuration);
} catch (RemoteException e) {
// Empty
}
}
/**
* Close the view if it's showing, or don't show it if it isn't showing yet.
* You do not normally have to call this. Normally view will disappear on its own
* after the appropriate duration.
*/
public void cancel() {
mTN.myHide();
// TODO this still needs to cancel the inflight notification if any
}
/**
* Set the view to show.
* #see #getView
*/
public void setView(View view) {
mNextView = view;
}
/**
* Return the view.
* #see #setView
*/
public View getView() {
return mNextView;
}
/**
* Set how long to show the view for.
* #see #LENGTH_SHORT
* #see #LENGTH_LONG
*/
public void setDuration(int duration) {
mDuration = duration;
}
/**
* Return the duration.
* #see #setDuration
*/
public int getDuration() {
return mDuration;
}
/**
* Set the margins of the view.
*
* #param horizontalMargin The horizontal margin, in percentage of the
* container width, between the container's edges and the
* notification
* #param verticalMargin The vertical margin, in percentage of the
* container height, between the container's edges and the
* notification
*/
public void setMargin(float horizontalMargin, float verticalMargin) {
mHorizontalMargin = horizontalMargin;
mVerticalMargin = verticalMargin;
}
/**
* Return the horizontal margin.
*/
public float getHorizontalMargin() {
return mHorizontalMargin;
}
/**
* Return the vertical margin.
*/
public float getVerticalMargin() {
return mVerticalMargin;
}
/**
* Set the location at which the notification should appear on the screen.
* #see android.view.Gravity
* #see #getGravity
*/
public void setGravity(int gravity, int xOffset, int yOffset) {
mGravity = gravity;
mX = xOffset;
mY = yOffset;
}
/**
* Get the location at which the notification should appear on the screen.
* #see android.view.Gravity
* #see #getGravity
*/
public int getGravity() {
return mGravity;
}
/**
* Return the X offset in pixels to apply to the gravity's location.
*/
public int getXOffset() {
return mX;
}
/**
* Return the Y offset in pixels to apply to the gravity's location.
*/
public int getYOffset() {
return mY;
}
/**
* Make a standard toast that just contains a text view.
*
* #param context The context to use. Usually your {#link android.app.Application}
* or {#link android.app.Activity} object.
* #param text The text to show. Can be formatted text.
* #param duration How long to display the message. Either {#link #LENGTH_SHORT} or
* {#link #LENGTH_LONG}
*
*/
public static MyToast makeText(Context context, CharSequence text, int duration) {
MyToast result = new MyToast(context);
LayoutInflater inflate = (LayoutInflater)
context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View v = inflate.inflate(com.android.internal.R.layout.transient_notification, null);
TextView tv = (TextView)v.findViewById(com.android.internal.R.id.message);
tv.setText(text);
result.mNextView = v;
result.mDuration = duration;
return result;
}
/**
* Make a standard toast that just contains a text view with the text from a resource.
*
* #param context The context to use. Usually your {#link android.app.Application}
* or {#link android.app.Activity} object.
* #param resId The resource id of the string resource to use. Can be formatted text.
* #param duration How long to display the message. Either {#link #LENGTH_SHORT} or
* {#link #LENGTH_LONG}
*
* #throws Resources.NotFoundException if the resource can't be found.
*/
public static MyToast makeText(Context context, int resId, int duration)
throws Resources.NotFoundException {
return makeText(context, context.getResources().getText(resId), duration);
}
/**
* Update the text in a Toast that was previously created using one of the makeText() methods.
* #param resId The new text for the Toast.
*/
public void setText(int resId) {
setText(mContext.getText(resId));
}
/**
* Update the text in a Toast that was previously created using one of the makeText() methods.
* #param s The new text for the Toast.
*/
public void setText(CharSequence s) {
if (mNextView == null) {
throw new RuntimeException("This Toast was not created with Toast.makeText()");
}
TextView tv = (TextView) mNextView.findViewById(com.android.internal.R.id.message);
if (tv == null) {
throw new RuntimeException("This Toast was not created with Toast.makeText()");
}
tv.setText(s);
}
// =======================================================================================
// All the gunk below is the interaction with the Notification Service, which handles
// the proper ordering of these system-wide.
// =======================================================================================
private static INotificationManager sService;
static private INotificationManager getService() {
if (sService != null) {
return sService;
}
sService = INotificationManager.Stub.asInterface(ServiceManager.getService("notification"));
return sService;
}
private class TN extends ITransientNotification.Stub {
final Runnable mShow = new Runnable() {
public void run() {
handleShow();
}
};
final Runnable mHide = new Runnable() {
public void run() {
handleHide();
}
};
private final WindowManager.LayoutParams mParams = new WindowManager.LayoutParams();
WindowManagerImpl mWM;
TN() {
// XXX This should be changed to use a Dialog, with a Theme.Toast
// defined that sets up the layout params appropriately.
final WindowManager.LayoutParams params = mParams;
params.height = WindowManager.LayoutParams.WRAP_CONTENT;
params.width = WindowManager.LayoutParams.WRAP_CONTENT;
params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
params.format = PixelFormat.TRANSLUCENT;
params.windowAnimations = com.android.internal.R.style.Theme_Dialog_Alert;
params.type = WindowManager.LayoutParams.TYPE_TOAST;
params.setTitle("Toast");
}
/**
* schedule handleShow into the right thread
*/
public void show() {
if (localLOGV) Log.v(TAG, "SHOW: " + this);
mHandler.post(mShow);
}
/**
* schedule handleHide into the right thread
*/
public void hide() {
System.out.println("hide called");
if (localLOGV) Log.v(TAG, "HIDE: " + this);
// mHandler.post(mHide);
}
public void myHide(){
System.out.println("my hide called");
if (localLOGV) Log.v(TAG, "HIDE: " + this);
mHandler.post(mHide);
}
public void handleShow() {
if (localLOGV) Log.v(TAG, "HANDLE SHOW: " + this + " mView=" + mView
+ " mNextView=" + mNextView);
if (mView != mNextView) {
// remove the old view if necessary
handleHide();
mView = mNextView;
mWM = WindowManagerImpl.getDefault();
final int gravity = mGravity;
mParams.gravity = gravity;
if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.FILL_HORIZONTAL) {
mParams.horizontalWeight = 1.0f;
}
if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == Gravity.FILL_VERTICAL) {
mParams.verticalWeight = 1.0f;
}
mParams.x = mX;
mParams.y = mY;
mParams.verticalMargin = mVerticalMargin;
mParams.horizontalMargin = mHorizontalMargin;
if (mView.getParent() != null) {
if (localLOGV) Log.v(
TAG, "REMOVE! " + mView + " in " + this);
mWM.removeView(mView);
}
if (localLOGV) Log.v(TAG, "ADD! " + mView + " in " + this);
mWM.addView(mView, mParams);
}
}
public void handleHide() {
//System.out.println("handle hid ecalles");
if (localLOGV) Log.v(TAG, "HANDLE HIDE: " + this + " mView=" + mView);
if (mView != null) {
// note: checking parent() just to make sure the view has
// been added... i have seen cases where we get here when
// the view isn't yet added, so let's try not to crash.
if (mView.getParent() != null) {
if (localLOGV) Log.v(
TAG, "REMOVE! " + mView + " in " + this);
mWM.removeView(mView);
}
mView = null;
}
}
}
}
// in broadcaste receiver ..........
String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE)
if (state.equals(TelephonyManager.EXTRA_STATE_RINGING)) {
toast = new MyToast(context);
toast.setGravity(Gravity.BOTTOM|Gravity.CENTER_HORIZONTAL, 0, 0);
toast.setDuration(Toast.LENGTH_SHORT);
toast.setView(view);
toast.show();
}
else if (state.equals(TelephonyManager.EXTRA_STATE_OFFHOOK)) {
toast.cancel();
}
else if (state.equals(TelephonyManager.EXTRA_STATE_IDLE)) {
toast.cancel();
}
}

Categories

Resources