Android: Clickable imageview widget - android

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);
}
}

Related

Widget calls Broadcast only one time

I have an app widget that sends a broadcast, then a broadcast receiver will start a service, the problem is when clicking the widget it would only work at the first time, then I have to open the app to stop the service.
this the widget code:
public class Widget extends AppWidgetProvider {
int appWidgetId;
RemoteViews views;
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
super.onUpdate(context, appWidgetManager, appWidgetIds);
for (int i = 0; i < appWidgetIds.length; i++) {
appWidgetId = appWidgetIds[i];
views = new RemoteViews(context.getPackageName(), R.layout.widget);
Intent bIntent = new Intent(context,BroadCast.class);
PendingIntent pIntent = PendingIntent.getBroadcast(context, 0, bIntent,0);
views.setOnClickPendingIntent(R.id.widgetbtn, pIntent);
appWidgetManager.updateAppWidget(appWidgetId, views);
}
}
}
The broadcast:
public class BroadCast extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
Intent serviceIntent=new Intent(context,Service.class);
if (!isServiceOn) {
context.startService(serviceIntent);
} else {
context.stopService(serviceIntent);
}
}
}
But it works fine when I send the broadcast from the main activity.

Android - Appwidget with Remoteviews not updating after reboot

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

Automatically update widget in the home screen when i make modification in my application

How can we updating the View of a Home Screen Widget on the onReceive method of AppWidgetProvider?.I am trying to update the listview of my Home screen widget but it seems that I cant access the listview of my AppWidgetProvider on onReceive method.My problem is when i changes in my application and come back to the home screen that the widget has no modification.Here is a sample code of my onReceive
public class WidgetTaskSchedular extends AppWidgetProvider {
private final String TAG = "CalendarViewSample:"
+ this.getClass().getName();
static int ID;
int[] sameid=new int[1];
#Override
public void onReceive(Context context, Intent intent) {
super.onReceive(context, intent);
if(intent.getAction().equals("update_widget"))
{
Log.i(TAG,"AppWidgetIds:"+ID);
for(int i=0;i<1;i++)
{
sameid[i]=ID;
Log.i(TAG,"SameId:"+sameid[i]);
onUpdate(context, AppWidgetManager.getInstance(context),sameid);
}
}
}
public static String EXTRA_WORD=
"com.capsone.testing.calendar.WORD";
#SuppressWarnings("deprecation")
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
super.onUpdate(context, appWidgetManager, appWidgetIds);
for (int i=0; i<appWidgetIds.length; i++) {
ID=appWidgetIds[i];
Log.i(TAG,"LengthofWidget:"+appWidgetIds.length);
Log.i(TAG,"TestAppWidget:"+appWidgetIds[i]);
Intent intentWidgetService=new Intent(context, WidgetService.class);
intentWidgetService.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetIds[i]);
intentWidgetService.setData(Uri.parse(intentWidgetService.toUri(Intent.URI_INTENT_SCHEME)));
RemoteViews remoteView=new RemoteViews(context.getPackageName(),
R.layout.widgetlayout);
remoteView.setRemoteAdapter(appWidgetIds[i], R.id.listWidget,
intentWidgetService);
Intent clickIntent=new Intent(context, ActionBarActivity.class);
PendingIntent clickPendingIntent=PendingIntent
.getActivity(context, 0,
clickIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
remoteView.setPendingIntentTemplate(R.id.listWidget, clickPendingIntent);
ComponentName component=new ComponentName(context,WidgetTaskSchedular.class);
appWidgetManager.updateAppWidget(component, remoteView);
}
}
}
MainActivity class:
In this main class i change some modification and broadcast this to widget class using on pause method:
#Override
public void onPause() {
super.onPause();
Intent updateWidget = new Intent(getActivity(), WidgetTaskSchedular.class);
updateWidget.setAction("update_widget");
PendingIntent pending = PendingIntent.getBroadcast(getActivity(), 0, updateWidget, PendingIntent.FLAG_CANCEL_CURRENT);
try {
pending.send();
} catch (CanceledException e) {
e.printStackTrace();
}
}

Cant change ImageView resource on RemoteView Android

I'm trying yo make a simple widget with clickable image that will change when its clicked.
I don't understand why it doesn't work
public class AppWidget extends AppWidgetProvider {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction()==null) {
context.startService(new Intent(context,
ToggleService.class));
} else {
super.onReceive(context, intent);
}
}
#Override
public void onUpdate(Context context, AppWidgetManager
appWidgetManager, int[] appWidgetIds) {
context.startService(new Intent(context,
ToggleService.class));
}
public static class ToggleService extends IntentService {
public ToggleService() {
super("AppWidget$ToggleService");
}
#Override
protected void onHandleIntent(Intent intent) {
ComponentName me=new ComponentName(this, AppWidget.class);
AppWidgetManager mgr=AppWidgetManager.getInstance(this);
mgr.updateAppWidget(me, buildUpdate(this));
}
private RemoteViews buildUpdate(Context context) {
RemoteViews updateViews=new
RemoteViews(context.getPackageName(),R.layout.widget);
int a = 1;
if(a ==
1) {
updateViews.setImageViewResource(R.id.phoneState,
R.drawable.dual_off);
} else {
updateViews.setImageViewResource(R.id.phoneState,
R.drawable.dual_on);
}
Intent i=new Intent(this, AppWidget.class);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, i,0);
updateViews.setOnClickPendingIntent(R.id.phoneState,pi);
return updateViews;
}
}
}
I have tried all sort of things in for loop but it just won't change image.
I have done this from a book about android development, am new to java and android.
You would to update your widget by AppWidgetManager, after changing remoteview's source.In this snippet code I try to change layout of widget that it's AppWidgetProvider name is DictionWidgetProvider :
private void hideWidgetInstances() {
hideViews = new RemoteViews(App.getContext().getPackageName(),
R.layout.hide);
AppWidgetManager mManager = AppWidgetManager.getInstance(App
.getContext());
ComponentName cn = new ComponentName(App.getContext(),
DictionWidgetProvider.class);
mManager.updateAppWidget(cn, hideViews);
}
Here App is a class that extends Application.You can use Application Context to reach ComponentName.

How do I start an Activity when my Widget is clicked?

I have this widget that toggles sound on off but instead of that I want to call another activity (MYxz.class) please tell me what should I change here...
public class AppWidget extends AppWidgetProvider {
#Override
public void onReceive(Context ctxt, Intent intent)
{
if(intent.getAction()==null)
{
ctxt.startService(new Intent(ctxt,ToggleService.class));
}
else
{
super.onReceive(ctxt, intent);
}
}
#Override
public void onUpdate(Context context,AppWidgetManager appWidgetManager, int [] appWidgetIds)
{
context.startService(new Intent(context,ToggleService.class));
//RemoteViews buildUpdate(context);
}
public static class ToggleService extends IntentService
{
public ToggleService() {
super("AppWidget$ToggleService");
}
#Override
protected void onHandleIntent(Intent intent)
{
ComponentName me = new ComponentName(this,AppWidget.class);
AppWidgetManager mgr= AppWidgetManager.getInstance(this);
mgr.updateAppWidget(me,buildUpdate(this));
}
private RemoteViews buildUpdate(Context context)
{
RemoteViews updateViews=new RemoteViews(context.getPackageName(),R.layout.widget);
AudioManager audioManager=(AudioManager)context.getSystemService(Activity.AUDIO_SERVICE);
if(audioManager.getRingerMode()==AudioManager.RINGER_MODE_SILENT)
{
updateViews.setImageViewResource(R.id.phoneState,R.drawable.silent);
audioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
}
else {
updateViews.setImageViewResource(R.id.phoneState,R.drawable.phone123);
audioManager.setRingerMode(AudioManager.RINGER_MODE_SILENT);
}
Intent i=new Intent(this, AppWidget.class);
PendingIntent pi= PendingIntent.getBroadcast(context,0, i,0);
updateViews.setOnClickPendingIntent(R.id.phoneState,pi);
return updateViews;
}
}
}
Yes possible see example:
Upadte your manifest.xml
<receiver android:name=".AppWidget"
android:label="Caller"
android:icon="#drawable/ic_launcher" >
<intent-filter >
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="com.app.example.MyWidget.ACTION_WIDGET_CLICK_RECEIVER"/>
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="#xml/widget_provider"
/>
</receiver>
<service android:name=".AppWidget$ToggleService" />
and Update your AppWidgetProvider:
public class MyWidget extends AppWidgetProvider {
public static String ACTION_WIDGET_CLICK_RECEIVER = "ActionReceiverWidget";
public static int appid[];
public static RemoteViews rview;
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds){
updateWidgetState(context, "");
}
#Override
public void onReceive(Context paramContext, Intent paramIntent)
{
String str = paramIntent.getAction();
if (paramIntent.getAction().equals(ACTION_WIDGET_CLICK_RECEIVER)) {
updateWidgetState(paramContext, str);
}
else
{
if ("android.appwidget.action.APPWIDGET_DELETED".equals(str))
{
int i = paramIntent.getExtras().getInt("appWidgetId", 0);
if (i == 0)
{
}
else
{
int[] arrayOfInt = new int[1];
arrayOfInt[0] = i;
onDeleted(paramContext, arrayOfInt);
}
}
super.onReceive(paramContext, paramIntent);
}
}
static void updateWidgetState(Context paramContext, String paramString)
{
RemoteViews localRemoteViews = buildUpdate(paramContext, paramString);
ComponentName localComponentName = new ComponentName(paramContext, MyWidget.class);
AppWidgetManager.getInstance(paramContext).updateAppWidget(localComponentName, localRemoteViews);
}
private static RemoteViews buildUpdate(Context paramContext, String paramString)
{
// Toast.makeText(paramContext, "buildUpdate() ::"+paramString, Toast.LENGTH_SHORT).show();
rview = new RemoteViews(paramContext.getPackageName(), R.layout.widget_layout);
Intent active = new Intent(paramContext, MyWidget.class);
active.setAction(ACTION_WIDGET_RECEIVER);
PendingIntent configPendingIntent = PendingIntent.getActivity(paramContext, 0, active, 0);
// upadte this R.id.buttonus1 with your layout or image id on which click you want to start Activity
Intent configIntent = new Intent(paramContext, Caller2.class);
configIntent.setAction((ACTION_WIDGET_CLICK_RECEIVER);
PendingIntent configPendingIntent = PendingIntent.getActivity(paramContext, 0, configIntent, 0);
rview.setOnClickPendingIntent(R.id.Phonestatexx, configPendingIntent);
if(parmString.equals(ACTION_WIDGET_CLICK_RECEIVER))
{
//open Activity here..
//your code for update and what you want on button click
//
}
return rview;
}
#Override
public void onEnabled(Context context){
super.onEnabled(context);
// Toast.makeText(context, "onEnabled() ", Toast.LENGTH_SHORT).show();
}
// Called each time an instance of the App Widget is removed from the host
#Override
public void onDeleted(Context context, int [] appWidgetId){
super.onDeleted(context, appWidgetId);
// Toast.makeText(context, "onDeleted() ", Toast.LENGTH_SHORT).show();
}
// Called when last instance of App Widget is deleted from the App Widget host.
#Override
public void onDisabled(Context context) {
super.onDisabled(context);
// Toast.makeText(context, "onDisabled() ", Toast.LENGTH_SHORT).show();
}
}
Instead of:
Intent active = new Intent(paramContext, AppWidget.class);
You use:
Intent active = new Intent(paramContext, YOURCLASS.class);
before you create the pending intent, #imran khan helped me but there are some tweaks you should do 2...this should fire up the Activity you need.
With using pendingIntents you can call an intent (to your activity or sth else) when a widget item clicked. this may help:
http://www.vogella.de/articles/AndroidWidgets/article.html

Categories

Resources