Use same AppWidgetProvider for different variants - android

I'm supporting different variants of the same basic widget (dark scheme, light scheme, etc.) and find that I can't use the same provider class in more than one receiver declaration in the manifest, such as:
<receiver android:name=".otd.OtdWidgetProvider" android:label="#string/otd_widget_label">
<meta-data android:name="android.appwidget.provider" android:resource="#xml/otd_appwidget_provider"/>
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
</intent-filter>
</receiver>
<receiver android:name=".otd.OtdWidgetProvider" android:label="#string/otd_widget_label">
<meta-data android:name="android.appwidget.provider" android:resource="#xml/otd_appwidget_light_provider"/>
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
</intent-filter>
</receiver>
Note that each receiver does declare a different XML file, which is where the different layouts are specified. I have worked around this by creating identical provider classes with different names (e.g., "otd.OtdWidgetProviderLight", etc.) but it would be more efficient to use the same provider class (internally, the provider can easily differentiate the variants by looking up the widget info via AppWidgetManager). Is there some way that I've missed to get around this limitation?

Related

GCM receiver with Parse

Hi I know this question has been asked multiple times but my requirement is a little different so pls bear with me.
I use two different libraries in my android application. One is for parse push notification which has the following declarations:
<receiver
android:name="com.parse.GcmBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<action android:name="com.google.android.c2dm.intent.REGISTRATION"/>
<category android:name="com.airloyal.ladooo" />
</intent-filter>
</receiver>
and the declaration for the other receiver is:
<receiver
android:name="com.google.android.gcm.GCMBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<action android:name="com.google.android.c2dm.intent.REGISTRATION"/>
<category android:name="com.airloyal.ladooo" />
</intent-filter>
</receiver>
I definitely need both the libraries in my app so removing one is not an option. I use both the receivers for different purposes. But when I declare both the receivers there is a conflict and I am not able to receive any push notifications.
Can someone pls point me in the right direction?
P.S Both the libraries are jar files and I do not have control over the receivers of both. So forwarding is not an option.
Any help would be appreciated. Thanks
If the broadcast receivers are conflict with each other, you may try to set the priority of your receiver in the AndroidManifest.xml in <intent-filter>
Use this attribute only if you really need to impose a specific order in which the broadcasts are received, or want to force Android to prefer one activity over others.
The value must be an integer, such as "100". Higher numbers have a higher priority. The default value is 0. The value must be greater than -1000 and less than 1000.
sample code:
<intent-filter android:icon="drawable resource"
android:label="string resource"
android:priority="integer" >
. . .
</intent-filter>
Also, another way to solve, please refer to here.

Changing receiver namespace without breaking already placed widgets

When I change the namespace of my widget provider, the widget goes blank and doesn't work until I delete it and add it again.
How would one change the namespace and the receiver name for a widget without breaking already placed widgets.
Before rename:
<receiver android:name="com.creativitality.labs.timezoneswidget.WidgetProvider" android:label="#string/widget" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="#xml/widget_info_large" />
</receiver>
After moving and renaming provider:
<receiver android:name="com.creativitality.labs.timezoneswidget.widget.WidgetLarge" android:label="#string/widget_4x1" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="#xml/widget_info_large" />
</receiver>
For activities, you can create an <activity-alias> element in your manifest that points to the new name of the <activity>.
There is no solution for receivers. <receiver-alias> does not exist. Your receiver must keep its original name forever or it will break.

Can't use #string notation to define <intent-filter> in AndroidManifest.xml

My BroadcastReceiver never gets called when I use "#string/action_name" to define the intent filter action. If I copy/paste the corresponding string from strings.xml into AndroidManifest.xml, then it works perfectly!
Non working example from AndroidManifest.xml:
<receiver
android:name=".ServerUpdateReceiver" >
<intent-filter>
<action android:name="#string/ACTION_INFORM_USER_SERVER_UPDATE" />
</intent-filter>
</receiver>
Working example from AndroidManifest.xml:
<receiver
android:name=".ServerUpdateReceiver" >
<intent-filter>
<action android:name="com.franklinharper.intent.action.ACTION_INFORM_USER_SERVER_UPDATE" />
</intent-filter>
</receiver>
Just for completeness, strings.xml contains the following line:
<string name="ACTION_INFORM_USER_SERVER_UPDATE">com.franklinharper.intent.action.ACTION_INFORM_USER_SERVER_UPDATE</string>
From the spec, there is no way to configure an action with a resource identifier. It has to be a simple string, perhaps to avoid requiring the Android Intent dispatch system to open your APK to figure out what the filter is for.

Android WidgetProvider duplicating

I have made a simple widget with stretchable layout, and want to allow users to put widgets with different sizes using the same layout and the same widget provider class.
I have found, that I need to create 4 widget_provider_x_y.xml files (x and y are values 2,2 2,3 3,2 3,3) that is very similar except width and height.
Also I have found, that I need to create multiple copies of WidgetProvider classes that is exactly the same (except names). If I try to use single WidgetProvider class - I will see only one widget in widgets list.
I have a question:
- why do I need to copy java class? It is the same, because layout is the same, and I do not want to have 4 more files in projects that I need to update simultaneously.
Here is a part of my androidManifest.xml:
<receiver android:name=".SimpleNoteWidgetProvider_3_2" android:label="#string/app_widget_3_2">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
<action android:name="ACTION_WIDGET_UPDATE_FROM_ACTIVITY"/>
<action android:name="ACTION_WIDGET_UPDATE_FROM_WIDGET"/>
</intent-filter>
<meta-data android:name="android.appwidget.provider" android:resource="#xml/widget_provider_3_2"/>
</receiver>
<receiver android:name=".SimpleNoteWidgetProvider_3_3" android:label="#string/app_widget_3_3">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
<action android:name="ACTION_WIDGET_UPDATE_FROM_ACTIVITY"/>
<action android:name="ACTION_WIDGET_UPDATE_FROM_WIDGET"/>
</intent-filter>
<meta-data android:name="android.appwidget.provider" android:resource="#xml/widget_provider_3_3"/>
</receiver>
You don't have to copy your WidgetProvider class n times to get n widget sizes. Just inherit from the main WidgetProvider class like this:
public class SimpleNoteWidgetProvider_3_2 extends SimpleNoteWidgetProvider {
}
and
public class SimpleNoteWidgetProvider_3_3 extends SimpleNoteWidgetProvider {
}

How to add multiple widgets in the same app?

I've just finished my Android widget. Now I need to have different sizes of this widget for the user to choose from.
For example, I need a medium, small and large size widget, so when the user installs the app and hold the home screen then choose widget, in the widget menu I want him to see three widgets with the same app name but with the size. Something like this:
helloSmall
helloMedium
helloLarge
I have the medium one ready, but how can I add the small and the large in the same app? Knowing that all three sizes contain the same exact data and actions, just the size and the background are different.
You need a receiver definition for each type in your manifest file like:
<receiver android:name=".MyWidget" android:label="#string/medium_widget_name">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data android:name="android.appwidget.provider"
android:resource="#xml/medium_widget_provider" />
</receiver>
<receiver android:name=".MyWidget" android:label="#string/large_widget_name">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data android:name="android.appwidget.provider"
android:resource="#xml/large_widget_provider" />
</receiver>
This would allow you to have the same AppWidgetProvider class be used for multiple widgets, with different widget names and different sizes defined in the <appwidget-provider> XML.
Now if you need more differences in your widgets than what is in the <appwidget-provider> XML I would create a base widget class that implements all the common behavoir between the different types:
public abstract class MyBaseWidget extends AppWidgetProvider
And then each of your concrete implementations could extend MyBaseWidget. Then in your manifest file you would have a receiver definition for each of your concrete implementations like:
<receiver android:name=".MyMediumWidget" android:label="#string/medium_widget_name">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data android:name="android.appwidget.provider"
android:resource="#xml/medium_widget_provider" />
</receiver>
<receiver android:name=".MyLargeWidget" android:label="#string/large_widget_name">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data android:name="android.appwidget.provider"
android:resource="#xml/large_widget_provider" />
</receiver>
Actually, android:name for each widget have to be different. If you will do this as in example, only one widget will be visible in widgets list.
Guys, I had the same problem.
You need to actually add a second widget provider aswell;
<receiver android:name=**".MyWidget**" android:label="#string/medium_widget_name">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data android:name="android.appwidget.provider"
android:resource="#xml/medium_widget_provider" />
</receiver>
<receiver android:name=**".MyWidget2"** android:label="#string/large_widget_name">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data android:name="android.appwidget.provider"
android:resource="#xml/large_widget_provider" />
</receiver>
Enjoy
Ok so basically you will need:
layout file fore each widget. ex: main_small.xml, main_medium.xml ...
in the xml directory add a provider for each widget. ex: small_provider.xml, medium_provider.xml ... and so on (note if you don't have an xml directory add it under the drawable directory).
now what!
define a receiver in the manifest for each widget. (just like the example in the main answer)
you can use the same layout or deferent layout. basically this is up to you.
in your provider you should have something like this:
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="146dip"
android:minHeight="138dip"
android:updatePeriodMillis="10000"
android:initialLayout="#layout/main"
/>
make sure, for each provider to specify the target layout file you want to use. in this code I'm asking for the file main.xml in the layout directory. for my medium widget for example i'll have another provider with the same exact code but i'll change the last line
> android:initialLayout="#layout/medium".
I hope this helps if not let me know and I can upload a working example on my website and you can take a closer look at it. please let me know how it goes.
best of luck.
Some extra info to the other answers...
If you are duplicating the files mentioned, and if your widget uses a Service to provide some functionality, you might have to duplicate your service.
If you duplicate your Service, remember to update your manifest with the new service, otherwise the new service won't run...
This wasted some time for me.
If you use any BroadcastReceiver to send Intents to your duplicate Services... don't forget to update that code too:
you must now send intents to each of the services.

Categories

Resources