Android - Appwidget with Remoteviews not updating after reboot - android

I saw similar questions here on SO, but nothing seems to work in my case...
I created an appwidget with an AdapterViewFlipper (Simple ViewAnimator that will animate between two or more views that have been added to it). The appwidget has a Next button that enables the user to navigate to the next view on the widget.
It all works fine when I first add the appwidget. But if the smartphone reboots, the Next button of the widget no longer works on my Samsung S4 (the method onReceive is called, but nothings happens, it doesn't navigate to the next view and is stuck at the first view). I have to delete the widget and add it again in order for it to work...
I suspect that it is a problem of Touchwiz since I tested it on another phone (Moto G) and it worked fine.
Here are some portions of my code :
AppWidgetProvider
public class AppWidgetProvider extends AppWidgetProvider {
public static final String NEXT_ACTION = VersionUtil.getPackageName() + ".action.NEXT";
private static final String TAG = DailyAppWidget.class.getSimpleName();
#Override
public void onEnabled(Context context) {
// Enter relevant functionality for when the first widget is created
}
#Override
public void onDisabled(Context context) {
// Enter relevant functionality for when the last widget is disabled
}
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
// There may be multiple widgets active, so update all of them
for (int appWidgetId : appWidgetIds) {
updateAppWidget(context, appWidgetManager, appWidgetId, colorValue);
}
super.onUpdate(context, appWidgetManager, appWidgetIds);
}
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
void updateAppWidget(Context context, AppWidgetManager appWidgetManager,
int appWidgetId, int primaryColor) {
Intent intent = new Intent(context, ViewFlipperWidgetService.class);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
// When intents are compared, the extras are ignored, so we need to embed the extras
// into the data so that the extras will not be ignored.
intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));
// Instantiate the RemoteViews object for the app widget layout.
RemoteViews rv = new RemoteViews(context.getPackageName(), R.layout.app_widget);
// open the activity from the widget
Intent intentApp = new Intent(context, MainActivity.class);
intentApp.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intentApp, 0);
rv.setOnClickPendingIntent(R.id.widget_title, pendingIntent);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
rv.setRemoteAdapter(R.id.adapter_flipper, intent);
} else {
rv.setRemoteAdapter(appWidgetId, R.id.adapter_flipper, intent);
}
// Bind the click intent for the next button on the widget
final Intent nextIntent = new Intent(context,
AppWidgetProvider.class);
nextIntent.setAction(AppWidgetProvider.NEXT_ACTION);
nextIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
final PendingIntent nextPendingIntent = PendingIntent
.getBroadcast(context, 0, nextIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
rv.setOnClickPendingIntent(R.id.widget_btn_next, nextPendingIntent);
appWidgetManager.updateAppWidget(appWidgetId, mRemoteViews);
}
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (action.equals(NEXT_ACTION)) {
RemoteViews rv = new RemoteViews(context.getPackageName(),
R.layout.daily_app_widget);
rv.showNext(R.id.adapter_flipper);
int appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
AppWidgetManager.INVALID_APPWIDGET_ID);
Log.e(TAG, "onReceive APPWIDGET ID " + appWidgetId);
AppWidgetManager.getInstance(context).partiallyUpdateAppWidget(
appWidgetId, rv);
}
super.onReceive(context, intent);
}
Service
public class FlipperRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory {
private Context mContext;
private int mAppWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;
private static final String TAG = "FILPPERWIDGET";
public FlipperRemoteViewsFactory(Context context, Intent intent) {
mContext = context;
mAppWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
AppWidgetManager.INVALID_APPWIDGET_ID);
//... get the data
}
#Override
public void onCreate() {
Log.e(TAG, "onCreate()");
}
#Override
public void onDataSetChanged() {
Log.i(TAG, "onDataSetChanged()");
}
#Override
public void onDestroy() {
}
#Override
public int getCount() {
//... return size of dataset
}
#Override
public RemoteViews getViewAt(int position) {
Log.i(TAG, "getViewAt()" + position);
RemoteViews page = new RemoteViews(mContext.getPackageName(), R.layout.app_widget_item);
//... set the data on the layout
return page;
}
#Override
public RemoteViews getLoadingView() {
Log.i(TAG, "getLoadingView()");
return new RemoteViews(mContext.getPackageName(), R.layout.appwidget_loading);
}
#Override
public int getViewTypeCount() {
Log.i(TAG, "getViewTypeCount()");
return 1;
}
#Override
public long getItemId(int position) {
Log.i(TAG, "getItemId()");
return position;
}
#Override
public boolean hasStableIds() {
Log.i(TAG, "hasStableIds()");
return true;
}
}
Manifest
<receiver android:name=".AppWidgetProvider"
android:label="#string/app_name"
android:enabled="#bool/is_at_least_12_api">
<meta-data android:name="android.appwidget.provider"
android:resource="#xml/app_widget_info" />
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
</receiver>
<!-- Service serving the RemoteViews to the collection widget -->
<service android:name=".ViewFlipperWidgetService"
android:permission="android.permission.BIND_REMOTEVIEWS"
android:exported="false" />
app wigdet info
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:initialKeyguardLayout="#layout/app_widget"
android:initialLayout="#layout/app_widget"
android:minHeight="110dp"
android:minWidth="250dp"
android:previewImage="#drawable/widget_preview"
android:resizeMode="horizontal|vertical"
android:updatePeriodMillis="14400000"
android:widgetCategory="home_screen" />
Any help would be appreciated !

Depends on the launcher, there is no guarantee that your AppWidget will be updated immediately after the device started. It may be refreshed immeidately, or wait till the updatePeriodMillis passed after system started.
To solve your problem, define a BroadcastReceiver that will trigger the update of AppWidget after the reboot.
In AndroidManifest.xml, define the BootReceiver to get the boot_complete message.
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<receiver android:name=".BootReceiver" android:enabled="true" android:exported="false" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
And define the BootReceiver.java to start your AppWidgetUpdateService
public class BootReceiver extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent){
//start appwidget update service
}
}

Related

Widget onclick not working with configuraion activity

When I click a button in a widget, a Toast appears. But when I use a configuration activit to set the button's caption and then I click the button, the Toast doesn't appear. Why?
public class MyWidget extends AppWidgetProvider {
public static String ACTION_WIDGET_CONFIGURE = "ConfigureWidget";
public static String ACTION_WIDGET_RECEIVER = "ActionReceiverWidget";
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
Intent intent = new Intent(context, MyWidget.class);
intent.setAction(ACTION_WIDGET_RECEIVER);
PendingIntent actionPendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
remoteViews.setOnClickPendingIntent(R.id.btn_widget, actionPendingIntent);
appWidgetManager.updateAppWidget(appWidgetIds, remoteViews); //update our widget
}
#Override
public void onDeleted(Context context, int[] appWidgetIds) {
super.onDeleted(context, appWidgetIds);
}
#Override
public void onDisabled(Context context) {
super.onDisabled(context);
}
#Override
public void onEnabled(Context context) {
super.onEnabled(context);
}
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(ACTION_WIDGET_RECEIVER))
{
Toast.makeText(context, "You have just clicked the button!", Toast.LENGTH_LONG).show();
}
super.onReceive(context, intent);
}
Appwidget-provider xml:
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider
xmlns:android="http://schemas.android.com/apk/res/android"
android:initialLayout="#layout/widget_layout"
android:minHeight="72dp"
android:minWidth="72dp"
android:configure="com.bfarago.tutorials.widget.ConfigActivity"
>
</appwidget-provider>
Manifest:
<activity
android:name=".ConfigActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
</intent-filter>
</activity>
<receiver android:name="MyWidget" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="com.bfarago.tutorials.widget.MyWidget.ACTION_WIDGET_RECEIVER"/>
</intent-filter>
<meta-data android:name="android.appwidget.provider" android:resource="#xml/widget_info"/>
</receiver>
Configuration Activity:
public class ConfigActivity extends Activity {
Button btn;
EditText et;
Context c;
AppWidgetManager awm;
int awID;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.config);
btn = (Button)findViewById(R.id.btn);
et = (EditText)findViewById(R.id.et);
c = ConfigActivity.this;
//Getting info about the widget that launched this Activity
Intent i = getIntent();
Bundle extras = i.getExtras();
if (extras != null)
{
awID = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
}
else
{
finish();
}
awm = AppWidgetManager.getInstance(c);
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String newcaption = et.getText().toString();
RemoteViews views = new RemoteViews(c.getPackageName(), R.layout.widget_layout);
views.setTextViewText(R.id.btn_widget, newcaption);
views.setTextColor(R.id.btn_widget, Color.RED);
awm.updateAppWidget(awID, views);
Intent result = new Intent();
result.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, awID);
setResult(RESULT_OK, result);
finish();
}
});
}
}
If I remove the line android:configure="com.bfarago.tutorials.widget.ConfigActivity" from the appwidgetprovider xml, I see the Toast.
Your configure Activity's onClick calls updateAppWidget without having called setOnClickPendingIntent on the RemoteViews it passes in, so once it has run, there will be no click event from your widget. Fix it to be the same as your onUpdate method, or better yet, refactor the code so there's only one function that creates the RemoteViews and calls updateAppWidget.

Lags on widget update

I'm interesting building a simple clock widget here. And I wonder what is the best practice to do it? Most of the time it works fine but some says my clock widget lags behind. Actual time is 10.00am then my widget shows perhaps 9.48am
I have this on my manifest
<receiver
android:name="my.package.name.MyClock"
android:label="#string/widget_name">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="#xml/my_clock" />
</receiver>
<service
android:name="MyClock$UpdateService"
android:label="UpdateService" >
<intent-filter>
<action android:name="my.package.name.UPDATE" />
</intent-filter>
</service>
And this is my main java class
public class MyClock extends AppWidgetProvider {
#Override
public void onDisabled(Context context) {
super.onDisabled(context);
context.stopService(new Intent(context, UpdateService.class));
}
#Override
public void onEnabled(Context context) {
super.onEnabled(context);
context.startService(new Intent(UpdateService.ACTION_UPDATE));
}
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
super.onUpdate(context, appWidgetManager, appWidgetIds);
context.startService(new Intent(UpdateService.ACTION_UPDATE));
}
public static final class UpdateService extends Service {
static final String ACTION_UPDATE = "my.package.name.UPDATE";
private final static IntentFilter sIntentFilter;
private String mMinuteFormat;
private String mHourFormat;
private Calendar mCalendar;
static {
sIntentFilter = new IntentFilter();
sIntentFilter.addAction(Intent.ACTION_TIME_TICK);
sIntentFilter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
sIntentFilter.addAction(Intent.ACTION_TIME_CHANGED);
}
#Override
public void onCreate() {
super.onCreate();
reinit();
registerReceiver(mTimeChangedReceiver, sIntentFilter);
}
#Override
public void onDestroy() {
super.onDestroy();
unregisterReceiver(mTimeChangedReceiver);
}
#Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
reinit();
update();
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
private void update() {
mCalendar.setTimeInMillis(System.currentTimeMillis());
final CharSequence minute = DateFormat.format(mMinuteFormat, mCalendar);
final CharSequence hour = DateFormat.format(mHourFormat, mCalendar);
RemoteViews views = null; views = new RemoteViews(getPackageName(), R.layout.main);
views.setTextViewText(R.id.HOUR, hour);
views.setTextViewText(R.id.MINUTE, minute);
//Refresh the widget
ComponentName widget = new ComponentName(this, MyClock.class);
AppWidgetManager manager = AppWidgetManager.getInstance(this);
manager.updateAppWidget(widget, views);
}
private void reinit() {
mHourFormat = "hh";
mMinuteFormat = "mm";
}
private final BroadcastReceiver mTimeChangedReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (action.equals(Intent.ACTION_TIME_CHANGED) ||
action.equals(Intent.ACTION_TIMEZONE_CHANGED))
{
reinit();
}
update();
}
};
} }
What am I missing? Why the widget lags behind?
Can you please help me spot the issue here?
And am I doing correct approach? Using Service not AlarmManager to have clock widget updates each minute?
Regards
Quite a lot of reason that may leads to this problem, but most probably, is the Service is killed by System. There's no way to prevent a background service being killed by System, only making it foreground service will be safe in most of the time, but the notification icon is very annoying to user.
I think using AlarmManager would be the best, I recently updated my clock widget using this technique too. Since AlarmManager makes broadcast, even your application is killed, it will recreate it before sending.

change icon when textview is clicked in widget

I have create a widget in android , whenever i click on Widget TextView one service get starts but at the same time i want to change the icon which is shown on the right side.
I can set a onclick over Widget TextView using
remoteViews.setOnClickPendingIntent(R.id.widgetTxt,pendingIntent);
but i don't know where i can change the icon when the TextView get clicks
image
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,int[] appWidgetIds) {
// Here i am trying to set a onclick over TextView
Intent intent = new Intent(context,MyService.class);
PendingIntent pendingIntent = PendingIntent.getService(context,0 ,
intent, 0);
remoteViews.setOnClickPendingIntent(R.id.MyWidgetTxt,pendingIntent);
}
When an icon itself gets clicked , it changes too and i have set its code in onReceive
try this :
In manifest.xml
<receiver android:name="TestwidgetProvider"
android:label="#string/widget_title" android:exported="false" android:icon="#drawable/test">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="com.imranandroid.demo.ACTION_ON_ImG_CLICK"/>
<action android:name="android.appwidget.action.APPWIDGET_DELETED"/>
</intent-filter>
<meta-data android:name="android.appwidget.provider"
android:resource="#xml/widget_info" />
</receiver>
In AppWidgetProvider.java :
public class TestwidgetProvider extends AppWidgetProvider {
public static final String TAG_IMAGE_CLICK = "com.imranandroid.demo.ACTION_ON_ImG_CLICK";
public static RemoteViews rview;
public static int ii=0;
#Override
public void onUpdate(Context paramContext, AppWidgetManager appWidgetManager,
int[] appWidgetIds){
//REMOVE YOUR CODE FROM HERE
updateWidgetState(paramContext, "");
}
#Override
public void onReceive(Context paramContext, Intent paramIntent)
{
String str = paramIntent.getAction();
if (paramIntent.getAction().equals(TAG_IMAGE_CLICK)) {
updateWidgetState(paramContext, str);
}
else
{
super.onReceive(paramContext, paramIntent);
}
}
static void updateWidgetState(Context paramContext, String paramString)
{
RemoteViews localRemoteViews = buildUpdate(paramContext, paramString); //CALL HERE
ComponentName localComponentName = new ComponentName(paramContext, TestwidgetProvider.class);
AppWidgetManager.getInstance(paramContext).updateAppWidget(localComponentName, localRemoteViews);
}
private static RemoteViews buildUpdate(Context paramContext, String paramString)
{
rview = new RemoteViews(paramContext.getPackageName(), R.layout.widget_layoutmain);
Intent active = new Intent(paramContext, TestwidgetProvider.class); //YOUR WIDGET NAME
active.setAction(TAG_IMAGE_CLICK);
PendingIntent actionPendingIntent = PendingIntent.getBroadcast(paramContext, 0, active, 0);
rview.setOnClickPendingIntent(R.id.MyWidgetTxt, actionPendingIntent);
if (paramString.equals(TAG_IMAGE_CLICK)) {
if(ii==0)
{
rview.setImageViewResource(R.id.ImageView01a, R.drawable.off);
ii=1;
}
else
{
rview.setImageViewResource(R.id.ImageView01a, R.drawable.on);
ii=0;
}
}
return rview;
}
}

cant pass widget id to configuration activity

I wrote an AppWidget that has a configuration activity(I used the same configuration activity of the app itself)
When adding the Widget to the home screen while on debug mode I pass the widget id(using put extra) to the intent. when clicking on the widget itself(to load the prefs' activity I break at the onCreate method, at the parts where I'm calling intent.getExtras or intent.getIntExtra - I get null.
I wanted to use the following code but couldn;t understand how:
passing-widget-id-to-activity:
The issue was that android does caching with PendingIntents. The solution was to add the FLAG_UPDATE_CURRENT flag which causes it to update the cached PendingIntent.
PendingIntent configPendingIntent = PendingIntent.getActivity(context, REQUEST_CODE_ONE, configIntent, PendingIntent.FLAG_UPDATE_CURRENT);
here is my code:
Manifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.test.dryrun" android:versionCode="3"
android:versionName="1.1" android:installLocation="auto">
<uses-sdk android:minSdkVersion="8" />
<application android:icon="#drawable/ic_launcher_test"
android:label="#string/app_name" android:theme="#android:style/Theme.NoTitleBar.Fullscreen"
android:debuggable="true"><!-- different< android:theme="#style/Theme.NoBackground" -->
<!-- Main Activity -->
<activity android:name=".MyActivity"
android:configChanges="orientation"> <!--android:screenOrientation="portrait" -->
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- Preferences -->
<activity android:name=".Preferences.EditPreferences"
android:configChanges="orientation">
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE"/>
</activity>
<!-- Widgets -->
<!-- Widget-->
<receiver android:name=".Widget.testWidget" android:label="#string/app_widget_">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<!--action
android:name="com.test.dryrun.Widget.testWidget.PREFENCES_WIDGET_CONFIGURE" /-->
</intent-filter>
<meta-data android:name="android.appwidget.provider"
android:resource="#xml/test_widget__provider" />
</receiver>
<service android:name=".Widget.testWidget$WidgetService" />
<uses-permission android:name="android.permission.BIND_REMOTEVIEWS"></uses-permission>
</application>
</manifest>
appwidget_provider xml
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="146dip"
android:minHeight="146dip"
android:updatePeriodMillis="0"
android:initialLayout="#layout/test_widget_"
/>
Widget Class
public class testWidget extends AppWidgetProvider {
public static String PREFENCES_WIDGET_CONFIGURE = "ActionConfigureWidget";
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)
{
Intent svcIntent = new Intent(context, WidgetService.class);
context.startService(svcIntent);
}
#Override
public void onReceive(Context context, Intent intent)
{
RemoteViews remoteViews = new RemoteViews(
context.getPackageName(), R.layout.test_widget);
// v1.5 fix that doesn't call onDelete Action
final String action = intent.getAction();
if (AppWidgetManager.ACTION_APPWIDGET_DELETED.equals(action))
{
final int appWidgetId = intent.getExtras().getInt(
AppWidgetManager.EXTRA_APPWIDGET_ID,
AppWidgetManager.INVALID_APPWIDGET_ID);
if (appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID)
{
this.onDeleted(context, new int[] { appWidgetId });
}
}
else
{
super.onReceive(context, intent);
}
}
//public void updateWidget()
/**
* #param context
* #param remoteViews
*/
public static void updateWidget(Context context, RemoteViews remoteViews)
{
String Prefix = context.getString(R.string._prefix);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
String ToShow = prefs.getString(context.getString(
R.string.Widget_string),
context.getString(R.string.default_string));
String pkgName = context.getPackageName();
int resID = context.getResources().getIdentifier(Prefix + ToShow, "drawable", pkgName);
WidgetController widgetController = WidgetController.getInstance();
widgetController.setRemoteViewImageViewSource(remoteViews, R.id.WidgetImage, resID);
}
public static class WidgetService extends Service
{
#Override
public void onStart(Intent intent, int startId)
{
super.onStart(intent, startId);
// Update the widget
RemoteViews remoteView = buildRemoteView(this);
// Push update to homescreen
WidgetController.getInstance().pushUpdate(
remoteView,
getApplicationContext(),
testWidget.class);
// No more updates so stop the service and free resources
stopSelf();
}
public RemoteViews buildRemoteView(Context context)
{
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.test_widget_);
Intent runConfigtest = new Intent(context, EditPreferences.class);
runConfigtest.setAction(testWidget.PREFENCES_WIDGET_CONFIGURE);
//old code-what you get in all the widget examples
PendingIntent runtestPendingIntent = PendingIntent.getActivity(context, 0, runConfigtest, 0);
//new code - this is how you should write it
PendingIntent runtestPendingIntent = PendingIntent.getActivity(context, 0, runConfigtest, PendingIntent.FLAG_UPDATE_CURRENT);
remoteViews.setOnClickPendingIntent(R.id.WidgetImage, runtestPendingIntent);
updateWidget(context, remoteViews);
return remoteViews;
}
#Override
public void onConfigurationChanged(Configuration newConfig)
{
int oldOrientation = this.getResources().getConfiguration().orientation;
if(newConfig.orientation != oldOrientation)
{
// Update the widget
RemoteViews remoteView = buildRemoteView(this);
// Push update to homescreen
WidgetController.getInstance().pushUpdate(
remoteView,
getApplicationContext(),
testWidget.class);
}
}
#Override
public IBinder onBind(Intent arg0)
{
// TODO Auto-generated method stub
return null;
}
}
}
Prefences class
public class EditPreferences extends PreferenceActivity implements OnSharedPreferenceChangeListener
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
Intent intent = getIntent();
m_extras = intent.getExtras();
mAppWidgetId = intent.getIntExtra("widget_id", defaultVal);
}
private Bundle m_extras;
#Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key)
{
if(key.equals(getString(R.string.rlvntString)))
{
Context ctx = getApplicationContext();
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(ctx);
setResult(RESULT_CANCELED);
if (m_extras != null)
{
mAppWidgetId = m_extras.getInt(
AppWidgetManager.EXTRA_APPWIDGET_ID,
AppWidgetManager.INVALID_APPWIDGET_ID);
RemoteViews views = new RemoteViews(ctx.getPackageName(),
R.layout.test_widget);
appWidgetManager.updateAppWidget(mAppWidgetId, views);
Intent resultValue = new Intent();
resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);
setResult(RESULT_OK, resultValue);
finish();
}
else
{
RemoteViews views = new RemoteViews(ctx.getPackageName(),
R.layout.test_widget);
appWidgetManager.updateAppWidget(mAppWidgetId, views);
Intent resultValue = new Intent();
resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);
setResult(RESULT_OK, resultValue);
finish();
}
}
}
I needed to change the next thing:
//old code-what you get in all the widget examples
PendingIntent runtestPendingIntent = PendingIntent.getActivity(context, 0, runConfigtest, 0);
//new code - this is how you should write it
PendingIntent runtestPendingIntent = PendingIntent.getActivity(context, 0, runConfigtest, PendingIntent.FLAG_UPDATE_CURRENT);
now it works

Android: Clickable imageview widget

I want to make a very simple widget:
It must consist from just one image view
1) on incoming sms it should change the image
2) on click it also should change the image
I tried to make it using ImageButton but failed: there were problems with changing the image on sms received event: new image had wrong scale.
Anyway now I want to make an ImageView without anything else.
The problem is that I can't handle onClick event:
I've got a running service which should handle all events: sms received and click:
widget provider:
public class MyWidgetProvider extends AppWidgetProvider {
#Override
public void onDisabled(Context context) {
context.stopService(new Intent(context, UpdateService.class));
super.onDisabled(context);
}
#Override
public void onEnabled(Context context) {
super.onEnabled(context);
Intent intent = new Intent(context, UpdateService.class);
context.startService(intent);
}
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
super.onUpdate(context, appWidgetManager, appWidgetIds);
for (int i = 0; i < appWidgetIds.length; i++) {
int appWidgetId = appWidgetIds[i];
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.main);
Intent widgetClickIntent = new Intent(context, UpdateService.class);
widgetClickIntent.setAction(UpdateService.ACTION_ON_CLICK);
PendingIntent pendingIntentViewClick = PendingIntent.getService(context, 0, widgetClickIntent, 0);
remoteViews.setOnClickPendingIntent(R.id.widget_imageview, pendingIntentViewClick);
appWidgetManager.updateAppWidget(appWidgetId, remoteViews);
}
}
}
service:
public class UpdateService extends Service {
static final String ACTION_SMS_RECEIVED = "android.provider.Telephony.SMS_RECEIVED";
static final String ACTION_ON_CLICK = "android.MyWidget.ACTION_ON_CLICK";
private final static IntentFilter intentFilter;
static {
intentFilter = new IntentFilter();
intentFilter.addAction(ACTION_SMS_RECEIVED);
intentFilter.addAction(ACTION_ON_CLICK);
}
public final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (action.equals(ACTION_SMS_RECEIVED)) {
reactOnSms(context);
}
if (action.equals(ACTION_ON_CLICK)) {
onCLick(context);
}
}
};
#Override
public void onCreate() {
super.onCreate();
registerReceiver(broadcastReceiver, intentFilter);
}
#Override
public void onDestroy() {
super.onDestroy();
unregisterReceiver(broadcastReceiver);
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
private void reactOnSms(Context context) {
// doSomething
}
public void onCLick(Context context) {
// doSomething
}
Manifest:
<receiver a:name="..."...>
<intent-filter>
<action a:name="android.provider.Telephony.SMS_RECEIVED"/>
<action a:name="android.MyWidget.ACTION_ON_CLICK"/>
</intent-filter>
<meta-data a:name="android.appwidget.provider"
a:resource="#xml/my_widget_provider_info"/>
</receiver>
<service a:name=".UpdateService"
a:label="UpdateService">
<intent-filter>
<action a:name="android.provider.Telephony.SMS_RECEIVED"/>
<action a:name="android.MyWidget.ACTION_ON_CLICK"/>
</intent-filter>
</service>
I tried this Clickable widgets in android
I found the solution.
Sorry for those of you who read the question. Too much code inside, I understand.
The problem was that UpdateService was not the real handler of the broadcast intent. Anonymous implementation of BroadcastReceiver made all the work.
So the problem was in this code (widgetProvider):
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
super.onUpdate(context, appWidgetManager, appWidgetIds);
for (int i = 0; i < appWidgetIds.length; i++) {
int appWidgetId = appWidgetIds[i];
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.main);
// wrong:
// Intent widgetClickIntent = new Intent(context, UpdateService.class);
// widgetClickIntent.setAction(UpdateService.ACTION_ON_CLICK);
// PendingIntent pendingIntentViewClick = PendingIntent.getService(context, 0, widgetClickIntent, 0);
// correct:
Intent widgetClickIntent = new Intent(UpdateService.ACTION_ON_CLICK);
PendingIntent pendingIntentViewClick = PendingIntent.getBroadcast(context, 0, widgetClickIntent, 0);
///////
remoteViews.setOnClickPendingIntent(R.id.widget_imageview, pendingIntentViewClick);
appWidgetManager.updateAppWidget(appWidgetId, remoteViews);
}
}

Categories

Resources