ClipDrawable does not work when using widget layout as background

I'm trying to create a simple widget that displays the percentage of charge in both text and graphical way in widgets. The text part works without problems, but I have big difficulties with graphically updating the widget.

Graphically, I have a battery image that I shoot according to the percentage of battery. I am trying to use ClipDrawable for this.

battery_widget_layout.xml

 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/widgetLayout" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="horizontal" android:padding="@dimen/widget_padding" android:background="@drawable/battery_clip_layer" > <TextView android:id="@+id/batteryPercentageWidgetTextView" android:layout_width="fill_parent" android:layout_height="fill_parent" android:text="@string/battery_percentage_widget_default" android:gravity="center" /> </LinearLayout> 

battery_clip_layer.xml (i.e. ClipDrawable)

 <clip xmlns:android="http://schemas.android.com/apk/res/android" android:clipOrientation="vertical" android:gravity="bottom" android:drawable="@drawable/battery_shape" /> 

BatteryService.java - a service that receives battery events and updates the widget via RemoteViews

 public class BatteryService extends Service { private static final String LOG = BatteryService.class.getName(); private final AtomicInteger batteryPercentage = new AtomicInteger(100); private final BroadcastReceiver batteryUpdateReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { int level = intent.getIntExtra("level", 0); batteryPercentage.set(level); updateWidget(); } }; @Override public void onCreate() { super.onCreate(); registerReceiver(batteryUpdateReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); Log.i(LOG, "Created..."); } @Override public void onDestroy() { super.onDestroy(); unregisterReceiver(batteryUpdateReceiver); Log.i(LOG, "Destroyed..."); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.i(LOG, "Started..."); updateWidget(); return super.onStartCommand(intent, flags, startId); } @Override public IBinder onBind(Intent arg0) { return null; } private void updateWidget() { final int percentage = batteryPercentage.get(); log.i(LOG, "Updated... " + percentage); RemoteViews remoteViews = new RemoteViews(getPackageName(), R.layout.battery_widget_layout); remoteViews.setTextViewText(R.id.batteryPercentageWidgetTextView, percentage + "%"); //ATTEMPT 1 - no cigar remoteViews.setInt(R.drawable.battery_clip_layer, "setLevel", 5000); AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(this); appWidgetManager.updateAppWidget(new ComponentName(this, BatteryAppWidgetProvider.class), remoteViews); } private void updateWidgetAttempt2() { final int percentage = batteryPercentage.get(); Log.i(LOG, "Updated... " + percentage); //ATTEMPT 2 - still no cigar Drawable clipLayer = getApplicationContext().getResources().getDrawable(R.drawable.battery_clip_layer); if (clipLayer instanceof ClipDrawable) { ClipDrawable clipDrawable = (ClipDrawable) clipLayer; int level = clipDrawable.getLevel(); if (clipDrawable.setLevel(10000)) { clipDrawable.invalidateSelf(); } Log.i(LOG, "Updated clip amount..." + level + " -> " + ((ClipDrawable) clipLayer).getLevel()); } RemoteViews remoteViews = new RemoteViews(getPackageName(), R.layout.battery_widget_layout); remoteViews.setTextViewText(R.id.batteryPercentageWidgetTextView, percentage + "%"); AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(this); appWidgetManager.updateAppWidget(new ComponentName(this, BatteryAppWidgetProvider.class), remoteViews); } } 

In BatteryService check out two different attempts to update the widget ( updateWidget() and updateWidgetAttempt2() ). Not a single attempt failed.

I feel that I am doing something fundamentally wrong. I am very grateful for any help / advice! :)

+4
source share
2 answers

You are correct in that you need to set the level in the Drawable instance, but unfortunately you cannot get the Drawable because it is in a remote view.

However, ImageView has a method called setImageLevel , which you can call remotely. My suggestion would be to put Drawable in the ImageView instead of the background of the container, and then use setInt(R.id.image_view, "setImageLevel", level) .

Here's what the layout looks like:

 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/widgetLayout" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="@dimen/widget_padding" > <ImageView android:id="@+id/battery" android:layout_width="match_parent" android:layout_height="match_parent" android:src="@drawable/battery_clip_layer" /> <TextView android:id="@+id/batteryPercentageWidgetTextView" android:layout_width="match_parent" android:layout_height="match_parent" android:text="@string/battery_percentage_widget_default" android:gravity="center" /> </FrameLayout> 

And the updateWidget() method:

 private void updateWidget() { final int percentage = batteryPercentage.get(); log.i(LOG, "Updated... " + percentage); RemoteViews remoteViews = new RemoteViews(getPackageName(), R.layout.battery_widget_layout); remoteViews.setTextViewText(R.id.batteryPercentageWidgetTextView, percentage + "%"); remoteViews.setInt(R.id.battery, "setImageLevel", percentage * 100); AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(this); appWidgetManager.updateAppWidget(new ComponentName(this, BatteryAppWidgetProvider.class), remoteViews); } 
+4
source

Two attempts you made regarding using ClipDrawable in a widget are incorrect. In the first attempt, you use the setInt() method incorrectly, since this method expects the first int parameter to be the id from the View from the widget layout (and not the link link as you try), also there is not setLevel() on any View subclass from the Android SDK, this method is present in the Drawable class. Your second approach is also incorrect, since all you do is load Drawable , set its level and everything that you just created Drawable not related to the LinearLayout root widget.

To perform ClipDrawable work, you need to set its level to the desired value, while drawable is already set as the LinearLayout background or when you have the opportunity to set it as the background. Unfortunately, I do not see how this can be done when the layout is used in widgets.

You need to use a workaround (provided by Jschools).

0
source

All Articles