How to add multiple widgets in the same app? - android

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.

Related

Use same AppWidgetProvider for different variants

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?

What is the purpose of a receiver for APPWIDGET_UPDATE

I'm working on an Android app written by someone no longer with the company, and not understanding what the purpose is of creating a receiver for AppWidget updates. The manifest has the main activity which runs when the app is launched. As far as I can tell, the appwidget is never used and its code is separate from the rest of the app. I can't tell if this is a left-over and can be removed or if it is still in use. All of the tutorials and examples I find explain how to implement this, but not really why one would, especially in this case.
Code from the manifest file:
<application
android:debuggable="true"
android:icon="#drawable/icon"
android:label="#string/app_name"
android:theme="#style/ConnectTheme" >
<activity
android:name="com.globalcrossing.connect.ConferenceListView"
android:label="#string/listTitle" >
<intent-filter android:label="#string/app_name" >
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="com.globalcrossing.connect.Preferences"
android:label="#string/set_preferences" >
</activity>
<!-- Broadcast Receiver that will process AppWidget updates -->
<receiver
android:name="com.globalcrossing.connect.ConferenceWidget"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="#xml/widget_provider" />
</receiver>
... more activities I understand, deleted for brevity
</application>
as in Doc:
ACTION_APPWIDGET_UPDATE :
Sent when it is time to update your AppWidget.
means ACTION_APPWIDGET_UPDATE Action faire when:
1. an new instance of Your AppWidget added to Home Screen from AppWidget Chooser( from AppWidget provider),
2. when requested update interval having lapsed which you have provided in AppWidget meta-data file using android:updatePeriodMillis attribute , and
3. when device reboot
If the application has a corresponding home screen widget, which can be found under the widgets section in the all programs list, then you will need APPWIDGET_UPDATE. Otherwise it will be unnecessary noise to your application with no purpose.

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 {
}

Android Activity order

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="muazam.multiplication.one"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="3" />
<application android:icon="#drawable/icon" android:label="#string/app_name">
<activity android:label="#string/app_name" android:name=".multiplication">
<intent-filter android:priority="1">
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:label="#string/app_name" android:name=".splash">
<intent-filter android:priority="3">
<action android:name="android.intent.action.CLEARSCREEN" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity android:label="#string/app_name" android:name=".Menu">
<intent-filter android:priority="2">
<action android:name="muazam.multiplication.one.Play" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
</application>
</manifest>
I want it to start with the .splash class first, and then .Menu class.
As you see I have put android:priority on them, but it seem to do nothing.
Anyone know how to solve this problem? Thanks.
I want it to start with the .splash class first
That has no meaning in Android.
If you meant to say "I want the .splash class to be what launches when the icon in the home screen launcher is clicked", then you need to get rid of the .splash class' current <intent-filter> (which is simply wrong) and move your MAIN/LAUNCHER <intent-filter> from the .multiplication class to the .splash class.
While you are at it, please get rid of the android:priority attributes (which are not used here) and your Play/DEFAULT <intent-filter> (which you really should not need, unless you plan on third-party apps starting up that activity directly).
and then .Menu class
You do this in Java code with startActivity().
As you see I have put android:priority on them, but it seem to do nothing.
Of course. There is no android:priority attribute for the <activity> element, as you can see in the documentation.
Activities aren't run automatically like a 'slide show' (although you could write your own code that way if you really wanted to).
The android:priority attribute is used for an entirely different purpose (from the docs for <intent-filter>...
It provides information about how able
an activity is to respond to an intent
that matches the filter, relative to
other activities that could also
respond to the intent. When an intent
could be handled by multiple
activities with different priorities,
Android will consider only those with
higher priority values as potential
targets for the intent.
In other word, if you have two activities each having an intent filter with the same action and category, then any Intent sent (from a 3rd party app) with those action/category details, will be passed first to the Activity whose intent filter has the highest priority.
This has nothing to do with how an app (and its activities) behave internally at runtime.

Categories

Resources