views:

1351

answers:

7

For my first and most awesomest Android project, I want to create a home screen widget which displays one of those Arc Clocks that all the kids are raving about these days.

Based on the limitations of RemoteViews, it looks to me that the appropriate way to get it actually drawn on the screen is to use an ImageView in the actual layout, then when it is updating, create a ShapeDrawable or two and draw them onto a newly created Bitmap. Then, set that Bitmap as the source of the ImageView.

There is Something about that process that I'm just not grokking, though. The following is the code I tried to use to update the widget. I get nothing drawn on the screen at all. The ImageView has a placeholder image just set by its src property. When I don't run the code to update it to my drawing, the placeholder image stays in place. So, I know this code is doing something, just obviously not the right thing.

RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget);
Bitmap bitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);

ShapeDrawable drawable = new ShapeDrawable(new ArcShape(0, 360));
drawable.getPaint().setColor(0xffff0000);
drawable.getPaint().setStrokeWidth(5.0f);
drawable.setIntrinsicWidth(100);
drawable.setIntrinsicHeight(100);
drawable.draw(canvas);

views.setImageViewBitmap(R.id.ImageView01, bitmap);     
appWidgetManager.updateAppWidget(appWidgetId, views);

I knew it couldn't be that easy. So, am I even heading in the right direction?


Update

Ok, maybe that was too much information. The question I'm really trying to ask is this:

If I want to draw shapes on a widget, should I use an ImageView and create a bitmap from my ShapeDrawable or is there more appropriate way to draw into a widget where it is constrained by RemoteViews?

A: 

Are you saying that the placeholder is still there when trying to draw something over it?

sandos
No, the placeholder image goes away. It ends up with nothing visual on the screen. I can, however, hold-click on the widget and remove it still.
MojoFilter
A: 

To create an custom component, I would extend View or any subclass of View and override the onDraw(Canvas canvas) method to do your drawing. On the the canvas object you can call methods such as drawLine(), drawArc(), drawPicture(), drawPoints(), drawText(), drawRect(), etc.....

Here's more details.

Here's the api for canvas.

I believe you can then add your custom view to a remote view for the purpose of making a widget.

Jay Askren
I'm pretty sure that's the whole problem. If I could just subclass a view, it would be really simple. However, a RemoteViews which you use to talk to a widget can only contain a very specific set of elements.
MojoFilter
+3  A: 

There is actually a widget called AnalogClock in the SDK that is very similar to what you are trying to do.

It is implemented as a class that extends View and is annotated with @RemoteView. It registers receivers on Intent.ACTION_TIME_TICK and Intent.ACTION_TIME_CHANGED and draws itself by overriding the onDraw method. Check out the source. The standard AlarmClock application exposes this view as a widget that can be added to the home screen.

I think that is a good (if not the best) way to implement what you described and obviously works well.

Josef
Oh, cool. I was under the impression that you could not extend a view and add it to a RemoteView because only very specific types were allowed in a RemoteView, even subclasses. If that's all it takes, then I guess I should be able to rock and roll. I'll give it a shot.
MojoFilter
This is the documentation which gave me that impression:http://developer.android.com/guide/topics/appwidgets/index.html#CreatingLayout
MojoFilter
I did try it out and unfortunately you cannot subclass view and add it to a layout used in a RemoteView, as far as I can tell. The only reason that it works for the AnalogClock view is that AnalogClock is one of those explicitly allowed components.
MojoFilter
A: 

Did anyone find a solution for this problem yet?

Franklin
None that anybody want to share, I guess.
MojoFilter
A: 

I would also like to know the answer to the original question... @MojoFilter: did you find a solution? Anybody?

CrazyChris
Not at all. This experiment was a major disappointment.
MojoFilter
found solution!see the answer starting with "this works great"
CrazyChris
A: 

This works great:

Paint p = new Paint(); 
p.setAntiAlias(true);
p.setStyle(Style.STROKE);
p.setStrokeWidth(8);
p.setColor(0xFFFF0000);

Bitmap bitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
canvas.drawArc(new RectF(10, 10, 90, 90), 0, 270, false, p);

RemoteViews views = new RemoteViews(updateService.getPackageName(), R.layout.main);
views.setImageViewBitmap(R.id.canvas, bitmap);

ComponentName componentName = new ComponentName(updateService, DashboardAppWidgetProvider.class);
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(updateService);
appWidgetManager.updateAppWidget(componentName, views);

I guess the problem with your original code was just the way of drawing the arc - that's why nothing showed up.

BTW: You can find a customizable "Arc Clock" with a very small memory footprint in the Market by searching for "arc clock"!

CrazyChris
A: 
> Paint p = new Paint(); 
> p.setAntiAlias(true);
> p.setStyle(Style.STROKE);
> p.setStrokeWidth(8);
> p.setColor(0xFFFF0000);
> 
> Bitmap bitmap =
> Bitmap.createBitmap(100, 100,
> Config.ARGB_8888); Canvas canvas = new
> Canvas(bitmap); canvas.drawArc(new
> RectF(10, 10, 90, 90), 0, 270, false,
> p);
> 
> RemoteViews views = new
> RemoteViews(updateService.getPackageName(),
> R.layout.main);
> views.setImageViewBitmap(R.id.canvas,
> bitmap);
> 
> ComponentName componentName = new
> ComponentName(updateService,
> DashboardAppWidgetProvider.class);
> AppWidgetManager appWidgetManager =
> AppWidgetManager.getInstance(updateService);
> appWidgetManager.updateAppWidget(componentName,
> views);

So how does this work? your create a bitmap, then you create a canvas using that bitmap... then you modify the canvas... then you create the remote view and set it to r.id.canvas - which i am taking is just a view? so where are you actually setting up using the canvas?

morty346