I have developed an application that makes use of a widget. The widget could be added in the homescreen and used as a button. I have recently downgraded the version to <uses-sdk android:minSdkVersion="7" /> and no errors were spotted. However, now when i reinstall the, the widget is not responsive. In addition when I try to install the app on another phone running android 4.0.3, widget is not available anywhere, so i cannot even add it to the homescreen. Here is my code for the widget:
public class MyWidget extends AppWidgetProvider {
#Override
public void onUpdate(Context c, AppWidgetManager appWidgetManager,int[] appWidgetIds) {
final int N = appWidgetIds.length;
//for each of the instances of the widget
for (int i=0; i<N; i++) {
int appWidgetId = appWidgetIds[i];
RemoteViews views = new RemoteViews(c.getPackageName(), R.layout.widget_layout);
Intent fireDialog = new Intent(c,Execute.class);
PendingIntent pendingIntent = PendingIntent.getActivity(c, 0, fireDialog, 0);
views.setOnClickPendingIntent(R.id.myButton, pendingIntent); //when the button is clicked, an activity is launched
appWidgetManager.updateAppWidget(appWidgetId, views);
}
}
#Override
public void onReceive(Context c, Intent intent)
{
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(c,new int[]{appWidgetId});
}
}else{
super.onReceive(c, intent);
}
}
}
Here is the manifest.xml:
<application>
<receiver android:name=".myButton"
android:icon="#drawable/icon"
android:label="myWidget">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data android:name="android.appwidget.provider"
android:resource="#xml/my_xml" />
</receiver>
</application>
Related
I have got the issue that is very popular on Stackoverflow and there are a lot of recipes how to fix it. But unfortunately, all of them don`t fit me.
I created appWidget with collection (StackView), added ConfigActivity for configuration and permanent update mechanism with assigned time interval. Widget is displayed in a proper way, update works fine but when I want to run Config Activity and click on widget - nothing happens!
Maybe, I've missed some important details and hope you'll suggest me. Here are some of code snippets:
Manifest
<uses-sdk android:minSdkVersion="11"
android:targetSdkVersion="22"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application
android:name=".FinApp"
android:allowBackup="true"
android:icon="#mipmap/ic_fin"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<receiver android:name=".widget.WidgetProvider" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="#xml/fin_app_widget_info" />
</receiver>
<activity android:name=".ConfigActivity"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
</intent-filter>
</activity>
<service
android:name=".widget.WidgetService"
android:permission="android.permission.BIND_REMOTEVIEWS"/>
</application>
AppWidgetProvider
public class WidgetProvider extends AppWidgetProvider {
private static final String TAG = WidgetProvider.class.getSimpleName();
#Override
public void onReceive(Context context, Intent intent) {
Log.i(TAG, "onReceive");
super.onReceive(context, intent);
}
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
Log.w(TAG, "onUpdate: appWidgetIds - " + Arrays.toString(appWidgetIds));
for (int id : appWidgetIds) {
updateAppWidgetInstance(context, appWidgetManager, id);
}
}
public static void updateWidgetsOnDataSetChanged (Context context) {
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
int[] appWidgetIds = appWidgetManager.getAppWidgetIds(
new ComponentName(context.getPackageName(), WidgetProvider.class.getName()));
appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetIds, R.id.widget_list);
}
private static void addWidgetListener(Context context, int appWidgetId, RemoteViews widget) {
Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_CONFIGURE);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));
PendingIntent runConfigActivity = PendingIntent.getActivity(context, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
widget.setOnClickPendingIntent(R.id.widget_container, runConfigActivity);
}
private static void setupWidgetService(Context context, int appWidgetId, RemoteViews widget) {
Intent adapterIntent = new Intent(context, WidgetService.class);
adapterIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
adapterIntent.setData(Uri.fromParts("content", String.valueOf(appWidgetId), null));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
widget.setRemoteAdapter(R.id.widget_list, adapterIntent);
} else {
//noinspection deprecation
widget.setRemoteAdapter(appWidgetId, R.id.widget_list, adapterIntent);
}
}
private static void updateAppWidgetInstance(Context context, AppWidgetManager appWidgetManager,
int appWidgetId) {
Log.e(TAG, "updateAppWidgetInstance");
RemoteViews widget = new RemoteViews(context.getPackageName(), R.layout.widget_collection_layout);
setupWidgetService(context, appWidgetId, widget);
addWidgetListener(context, appWidgetId, widget);
appWidgetManager.updateAppWidget(appWidgetId, widget);
}
}
widget_collection_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/widget_container"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<StackView
android:id="#+id/widget_list"
android:loopViews="true"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
As I understand the point is in the method addWidgetListener
private static void addWidgetListener(Context context, int appWidgetId, RemoteViews widget) {
Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_CONFIGURE);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));
PendingIntent runConfigActivity = PendingIntent.getActivity(context, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
widget.setOnClickPendingIntent(R.id.widget_container, runConfigActivity);
}
but I have no idea what's wrong...
After some investigation I came to a conclusion that if I use collection in appWidget and want to open Config Activity tapping on whole widget container that the best practice is using setPendingIntentTemplate method, even if you dont't want to handle item click but the whole list instead (list container).
private static void addWidgetListener(Context context, int appWidgetId, RemoteViews widget) {
Intent intent = new Intent(context, ConfigActivity.class);
intent.setAction(AppWidgetManager.ACTION_APPWIDGET_CONFIGURE);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));
PendingIntent runConfigActivity = PendingIntent.getActivity(context, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
widget.setPendingIntentTemplate(R.id.widget_list, runConfigActivity);
}
and add 2 lines in WidgetFactory in method getViewAt(int position)
Intent intent = new Intent();
views.setOnClickFillInIntent(R.id.widget_item_container, intent);
I've created a simple widget have only a button and textView. When I add my widget first time to the homescreen a FC message coming and widget will added. And button click toast message won't work. Only i need to have a toast message when clicking the widget button. I've gone through lots of tutorials but couldn't figure out whats the problem. Any genius who'd like to help..really appriciate the help..Thanks..
widgetProvider.java
public class widgetProvider extends AppWidgetProvider{
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
final int N = appWidgetIds.length;
for (int i=0; i<N; i++) {
int appWidgetId = appWidgetIds[i];
Intent intent = new Intent(context, widgetProvider.class);
intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widgetlayout);
views.setOnClickPendingIntent(R.id.button1, pendingIntent);
appWidgetManager.updateAppWidget(appWidgetId, views);
}
}
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(AppWidgetManager.ACTION_APPWIDGET_UPDATE)) {
Toast.makeText(context, "Button Clicked", Toast.LENGTH_SHORT).show();
}
}
}
AndroidManifest.xml
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<receiver android:name=".widgetProvider" 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/widgetprovider" />
</receiver>
</application>
your onUpdate is never called since you overriden the onReceive method.
I tried a lot to change my widget view's image when i click on it but it doesn't work. It's my code:
public class myAppWidgetProvider extends AppWidgetProvider {
public static String ACTION_WIDGET_REFRESH = "ActionReceiverRefresh";
//...
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
final int N = appWidgetIds.length;
// Perform this loop procedure for each App Widget that belongs to this provider
for (int i=0; i<N; i++) {
int appWidgetId = appWidgetIds[i];
Intent intent = new Intent(context, myAppWidgetProvider.class);
intent.setAction(ACTION_WIDGET_REFRESH);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
RemoteViews rv = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
rv.setOnClickPendingIntent(R.id.imageView, pendingIntent);
appWidgetManager.updateAppWidget(appWidgetId, rv);
}
And in onReceive i want to receive it when i click widget's view, but it doesn't work:
#Override
public void onReceive(Context context, Intent intent) {
super.onReceive(context, intent);
final String action = intent.getAction();
if (AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)) {
RemoteViews rmv = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
//and this change doesn't work :(( \/
rmv.setImageViewResource(R.id.imageView, R.drawable.button_power_on_small);
}
}
It's my android manifest receiver:
<receiver android:name="myAppWidgetProvider" android:exported="false" android:icon="#drawable/button_power_off">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="com.xxx.xxx.myAppWidgetProvider.ACTION_WIDGET_REFRESH"/>
<action android:name="android.appwidget.action.APPWIDGET_DELETED"/>
<action android:name="android.media.RINGER_MODE_CHANGED"/>
</intent-filter>
<meta-data android:name="android.appwidget.provider"
android:resource="#xml/widget_info_provider" />
</receiver>
I will be grateful if someone suggest me some solution.
Change
<action android:name="com.xxx.xxx.myAppWidgetProvider.ACTION_WIDGET_REFRESH"/>
to
<action android:name="ActionReceiverRefresh"/>
Your BroadcastReceiver is looking for the wrong action string. Remember that AndroidManifest is an XML file. You have to put the actual value of the String; pointing to a Java constant doesn't work.
I have few widgets in my application with different sizes. And for each widget I need set receiver android:name to different values (otherwise Android show only one first widget). So I need to create separate class with identical code for each widget. That is uneasily. How I can avoid this? May be I can create one parent class and inherit it for other widget classes?
My code:
Manifest:
<meta-data
android:name="android.appwidget.provider"
android:resource="#xml/widget_1x1" />
</receiver>
<receiver android:exported="false"
android:name=".WidgetHandler_4x4"
android:label="Widget 4x4" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="#xml/widget_4x4" />
</receiver>
And WidgetHandler_1x1 / WidgetHandler_4x4:
public class WidgetHandler_4x4 extends AppWidgetProvider {
public static String ACTION_WIDGET_EDIT = "ActionWidgetEdit";
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget);
Intent editIntent = new Intent(context, this.getClass());
editIntent.setAction(ACTION_WIDGET_EDIT);
PendingIntent editPendingIntent = PendingIntent.getBroadcast(context, 0, editIntent, 0);
remoteViews.setOnClickPendingIntent(R.id.edit_button, editPendingIntent);
appWidgetManager.updateAppWidget(appWidgetIds, remoteViews);
}
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(ACTION_WIDGET_EDIT)) {
Toast.makeText(context, "edit", Toast.LENGTH_SHORT).show();
}
super.onReceive(context, intent);
}
}
I'm creating a widget for my app but it refuses to work.
This widget launching an configuration activity when it's being created, and when you click it, it should start a IntentService I've created.
But when I click it, it doesn't start the service! I tried to change this pending intent to an intent that would launch Google and it works.
Some code:
AppWidgetProvider XML
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:configure="com.eladaharon.android.lary.widget.LaryWidgetConfigurationActivity"
android:initialLayout="#layout/widget_1x1"
android:minHeight="72dp"
android:minWidth="72dp"
android:updatePeriodMillis="86400000" >
</appwidget-provider>
Manifest declaration
<activity
android:name=".widget.LaryWidgetConfigurationActivity"
android:configChanges="orientation|keyboard" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
</intent-filter>
</activity>
<service android:icon="#drawable/icon" android:enabled="true" android:name="widget.LaryWidgetCheckService" />
<!-- Broadcast Receiver that will process AppWidget updates -->
<receiver android:name=".widget.LaryWidgetProvider" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="android.appwidget.action.APPWIDGET_DELETED" />
<action android:name="android.appwidget.action.APPWIDGET_ENABLED" />
<action android:name="android.appwidget.action.APPWIDGET_DISABLED" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="#xml/widget_provider" />
</receiver>
AppWidgetProvider class
public class LaryWidgetProvider extends AppWidgetProvider {
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
final int N = appWidgetIds.length;
// Perform this loop procedure for each App Widget that belongs to this provider
for (int i=0; i<N; i++) {
int appWidgetId = appWidgetIds[i];
// Create an Intent to launch service
Intent intent = new Intent(context, LaryWidgetCheckService.class);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
PendingIntent pendingIntent = PendingIntent.getService(context, 0, intent, 0);
// Get the layout for the App Widget and attach an on-click listener
// to the button
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_1x1);
views.setOnClickPendingIntent(R.id.widget_check_button, pendingIntent);
// Tell the AppWidgetManager to perform an update on the current app widget
appWidgetManager.updateAppWidget(appWidgetId, views);
}
}
public void onEnabled(Context context) {
PackageManager pm = context.getPackageManager();
pm.setComponentEnabledSetting(
new ComponentName("com.eladaharon.android.lary.widget",
".SalaryWidgetConfigurationActivity"),
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP);
}
public void onDisabled(Context context) {
PackageManager pm = context.getPackageManager();
pm.setComponentEnabledSetting(
new ComponentName("com.eladaharon.android.lary.widget",
".LaryWidgetConfigurationActivity"),
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);
}
public void onDeleted(Context context, int[] appWidgetIds)
{
Editor edit = context.getSharedPreferences(Constants.PREFERNCES_WIDGET_PREFERENCES, Context.MODE_PRIVATE).edit();
final int N = appWidgetIds.length;
for (int i=0; i<N; i++)
{
edit.remove(String.valueOf(appWidgetIds[i]));
}
edit.commit();
}
public static void updateAppWidget(Context context, AppWidgetManager appWidgetManager,
int appWidgetId) {
// Create an Intent to launch service
Intent intent = new Intent(context, LaryWidgetCheckService.class);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
PendingIntent pendingIntent = PendingIntent.getService(context, 0, intent, 0);
// Get the layout for the App Widget and attach an on-click listener
// to the button
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_1x1);
views.setOnClickPendingIntent(R.id.widget_check_button, pendingIntent);
// Tell the AppWidgetManager to perform an update on the current app widget
appWidgetManager.updateAppWidget(appWidgetId, views);
}
}
Handler that being called on the configuration activity end
private Handler mHandler = new Handler(){
#Override
public void handleMessage(Message msg){
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(LaryWidgetConfigurationActivity.this);
LaryWidgetProvider.updateAppWidget(LaryWidgetConfigurationActivity.this, appWidgetManager,
mAppWidgetId);
// Make sure we pass back the original appWidgetId
Intent resultValue = new Intent();
resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);
setResult(RESULT_OK, resultValue);
finish();
}
};
The service I want to run on click
public class LaryWidgetCheckService extends IntentService {
private int mAppWidgetId;
public LaryWidgetCheckService(String name) {
super("WorkplaceService");
}
#Override
protected void onHandleIntent(Intent intent) {
Bundle extras = intent.getExtras();
if (extras != null) {
mAppWidgetId = extras.getInt(
AppWidgetManager.EXTRA_APPWIDGET_ID,
AppWidgetManager.INVALID_APPWIDGET_ID);
}
// If they gave us an intent without the widget id, just bail.
if (mAppWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) {
return;
}
// Running some code
}
}
Thanks in advance!!
I hate this world!!!
If you'll look again in the manifest you can notice that I wrote widget.SERVICENAME instead of .widget.SERVICENAME!!!
I've Spent a whole day on this!
Thanks for everyone who tried to help!
Widget runs in another process, and you are sending an explicit intent that will works only inside your application. The reason of why the intent to launch google page in the web browser is because this is another type of intent that will involve broadcast receiver and it's propagated system wide to see if someone responds.
I think that you must declare a broadcast receiver in your service and fire that intent from your widget.