I have an Android widget that has a configure activity. I also have an ImageView "button" set up on the widget to launch the configure activity, in case the user wants to change his/her preferences after initializing them.
So, basic lifecycle:
User adds the widget
Configure activity pops up, user fills in fields and clicks "Submit"
Widget is added on screen
User taps the ImageView to launch the configure activity
Configure activity pops up, user edits fields
After either hitting "Submit" or backing out, the widget is updated
User can continue to go through steps 5 and 6 as needed.
My problem is at step 5. The very first and only the first time that the user taps the ImageView, it looks like two configure activities are launched. That is, when I back out of the first one, there's still another one "behind" it. On all subsequent launches of the configure activity, however, only one is launched and everything works great.
What could be the problem? I'll post relevant code below.
AndroidManifest.xml
<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=".Widget"
android:label="Widget" >
<intent-filter>
<action
android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<intent-filter>
<action
android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<data android:scheme="sample_widget" />
</intent-filter>
<intent-filter>
<action
android:name="com.this.that.WIDGET_CONTROL" />
<data
android:scheme="sample_widget" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="#xml/widget" />
</receiver>
AppWidget-Provider widget.xml
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider
xmlns:android="http://schemas.android.com/apk/res/android"
android:updatePeriodMillis="5000"
android:minWidth="294dp"
android:minHeight="220dp"
android:initialLayout="#layout/widgetlayout"
android:configure="com.this.that.ConfigActivity" >
</appwidget-provider>
ConfigActivity.java
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Get the data we were launched with
Intent launchIntent = getIntent();
Bundle extras = launchIntent.getExtras();
if (extras != null) {
appWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
Intent cancelResultValue = new Intent();
cancelResultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
setResult(RESULT_CANCELED, cancelResultValue);
} else {
// Only launch if it's for configuration
finish();
}
setContentView(R.layout.myconfig);
// Create Buttons/EditTexts
SubmitBTN = (Button) findViewById(R.id.BTNSubmit);
SampleET= (EditText) findViewById(R.id.ETSample);
SubmitBTN.setOnClickListener(submitListener);
loadPreferences(ConfigActivity.this, appWidgetId);
}
private OnClickListener submitListener = new OnClickListener() {
public void onClick(View v) {
final Context context = PriorityViewConfig.this;
// Save strings in our prefs
String sample = SampleET.getText().toString();
SharedPreferences.Editor prefs = context.getSharedPreferences(PREFS_NAME, 0).edit();
prefs.putString(PREF_PREFIX_KEY + appWidgetId + "sample", sample);
prefs.commit();
if (appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID) {
// Tell the AppWidgetManager that we're now configured
Intent resultValue = new Intent();
//resultValue.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
setResult(RESULT_OK, resultValue);
// Get an instance of the AppWidgetManager
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
// Update the App Widget with the layout
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widgetlayout);
Widget.updateDisplayState(context, appWidgetId);
}
// Activity is now done
finish();
}
};
private void loadPreferences(Context context, int appWidgetId) {
SharedPreferences prefs = context.getSharedPreferences(PREFS_NAME, 0);
String sample = prefs.getString(PREF_PREFIX_KEY + appWidgetId + "sample", null);
if (sample != null) {
SampleET.setText(sample);
} else {
// Nothing stored, don't need to do anything
}
}
Widget.java
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
Log.d(LOG_TAG, "OnReceive:Action: " + action);
if (ACTION_WIDGET_CONTROL.equals(action)) {
// Pass this on to the action handler where we'll figure out what to do and update the widget
final int appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
if (appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID) {
this.onHandleAction(context, appWidgetId, intent.getData());
}
}
super.onReceive(context, intent);
}
public static void updateDisplayState(Context context, int appWidgetId) {
Intent configIntent = new Intent(context, ConfigActivity.class);
configIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
// Make this unique for this appWidgetId
configIntent.setData(Uri.withAppendedPath(Uri.parse(Widget.URI_SCHEME + "://widget/id/"), String.valueOf(appWidgetId)));
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, configIntent, PendingIntent.FLAG_UPDATE_CURRENT);
views.setOnClickPendingIntent(R.id.IVConfig, pendingIntent);
AppWidgetManager.getInstance(context).updateAppWidget(appWidgetId, views);
}
private void onHandleAction(Context context, int appWidgetId, Uri data) {
String controlType = data.getFragment();
// Nothing here yet
updateDisplayState(context, appWidgetId);
}
I think these are the most relevant sections. The places I'm going to be looking further into are in ConfigActivity.java in the submitListener and in the updateDisplayState method in Widget.java
Any help would be awesome! Thanks!
When calling an explicit intent, you should consider using one of the intent flags like FLAG_ACTIVITY_CLEAR_TOP to keep the stack organized. For example:
configIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
You can spot the lack of this flag in some apps like the IMDB app where each click of the Home button adds another instance of the home activity on the stack, so you need to click the Back button as many times to pop through the stack and back out of the app. :)
add to the activity at manifest file android:noHistory="true" and android:excludeFromRecents="true"
it suppose to solve the problem
<activity
android:name=".ConfigActivity"
android:label="#string/app_name"
android:noHistory="true"
android:excludeFromRecents="true">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
</intent-filter>
</activity>
Related
I'm trying to create a Widget which update the text every time I press the save button and get the information from 2 editText. When I press the button to send by Intent the variables it throws
"android.content.ActivityNotFoundException: Unable to find explicit activity class"
in the logcat. Here my code:
Main.class
public class MainActivity extends AppCompatActivity {
Button save;
EditText Nom;
EditText Cognom;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
save = (Button) findViewById(R.id.save);
Nom = (EditText) findViewById(R.id.editTextNom);
Cognom = (EditText) findViewById(R.id.editTextCognom);
save.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent i;
i = new Intent(MainActivity.this, NewAppWidget.class);
i.putExtra("NOM",Nom.getText().toString());
i.putExtra("COGNOM",Cognom.getText().toString());
startActivity(i);
}
});
}
}
WidgetClass
public class NewAppWidget extends AppWidgetProvider {
static Intent intent = new Intent();
static String nom = intent.getExtras().getString("NOM");
static String cognom = intent.getExtras().getString("COGNOM");
static void updateAppWidget(Context context, AppWidgetManager appWidgetManager,
int appWidgetId) {
CharSequence widgetText = context.getString(R.string.appwidget_text);
// Construct the RemoteViews object
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.new_app_widget);
views.setTextViewText(R.id.TextViewNom, nom);
views.setTextViewText(R.id.TextViewCognom, cognom);
// Instruct the widget manager to update the widget
appWidgetManager.updateAppWidget(appWidgetId, views);
}
#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);
}
}
#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
}
}
Manifest:
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name=".NewAppWidget">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="#xml/new_app_widget_info" />
</receiver>
</application>
Error:
android.content.ActivityNotFoundException: Unable to find explicit activity class
Dude first thing is you can not start an widget provider like an activity.
If you want update widget widget from activity you can do like this.
Intent intent = new Intent(this, MyAppWidgetProvider.class);
intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
// Use an array and EXTRA_APPWIDGET_IDS instead of AppWidgetManager.EXTRA_APPWIDGET_ID,
// since it seems the onUpdate() is only fired on that:
int[] ids = AppWidgetManager.getInstance(getApplication())
.getAppWidgetIds(new ComponentName(getApplication(), MyAppWidgetProvider.class));
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, ids);
sendBroadcast(intent);
You can pass your parameter to this intent or better you save your values in Shared Preference and use it in your widget provider class in onUpdate method.
I read your widgetprovider class, you will get many errors when using this class. For understanding android widget, you can fork and understand this Github sample.
In this sample you will get how to update widget, how to have multiple widget controls and much more. So i strongly recommend you go through this sample.
AppWidgetProvider extends BroadcastReceiver NOT ACTIVITY
i = new Intent(MainActivity.this, NewAppWidget.class);
startActivity(i);
To use startActivity you need to provide Activity class's child object
NewAppWidget is not an Activity !!
In AndroidStudio i create a new android project an create a app widget and choose option for configuration activity. AndroidStudio generates now the provider-info xml, the declerations in manifest xml an the both java classes. One activity, one widget provider.
This should be runnable but i get error: Could not identify launch activity: Default Activity not found. Error while Launching activity. The launch field also shows a red cross.
I dont understand why because there is no default activity. The configuration activity should start when the widget provider start working. To do so there is a intent-filter for the activitiy with android.appwidget.action.APPWIDGET_CONFIGURE.
I add also categroy in intent-filter LAUNCHER and DEFAULT. In provider and in activity. But still get the error message.
If I choose "Nothing" in launch configuration and I run the app it brings only many error messages: Waiting for application to come online: com.example.desktop_win10.myapplication | com.example.desktop_win10.myapplication.test
But the widget isnt installed and doesnt run. What doing Im wrong? I try out Intellij and AndroidStudio.
Manifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.desktop_win10.myapplication" >
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme" >
<receiver android:name=".NewAppWidget" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="#xml/new_app_widget_info" />
</receiver>
<activity android:name=".NewAppWidgetConfigureActivity" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
</intent-filter>
</activity>
</application>
</manifest>
widget_info.xml:
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="40dp"
android:minHeight="40dp"
android:updatePeriodMillis="86400000"
android:previewImage="#drawable/example_appwidget_preview"
android:initialLayout="#layout/new_app_widget"
android:configure="com.example.desktop_win10.myapplication.NewAppWidgetConfigureActivity"
android:resizeMode="horizontal|vertical"
android:widgetCategory="home_screen"
android:initialKeyguardLayout="#layout/new_app_widget">
</appwidget-provider>
And there are the two Java classes.
EDIT1:
Now I add category LAUNCHER and action MAIN:
<activity android:name=".NewAppWidgetConfigureActivity" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
If I start the debugger sometimes the widget ist in the widget store and sometimes not.
I also see that in the generated java activity class is a finish method called:
// If this activity was started with an intent without an app widget ID, finish with an error.
if (mAppWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) {
finish();
return;
}
But it also doesnt work if I delete thid. I dont unterstand why a the default google example not work.
Here are the java classes:
Activity:
package com.example.desktop_win10.myapplication;
import android.app.Activity;
import android.appwidget.AppWidgetManager;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
/**
* The configuration screen for the {#link NewAppWidget NewAppWidget} AppWidget.
*/
public class NewAppWidgetConfigureActivity extends Activity {
int mAppWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;
EditText mAppWidgetText;
private static final String PREFS_NAME = "com.example.desktop_win10.myapplication.NewAppWidget";
private static final String PREF_PREFIX_KEY = "appwidget_";
public NewAppWidgetConfigureActivity() {
super();
}
#Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
// Set the result to CANCELED. This will cause the widget host to cancel
// out of the widget placement if the user presses the back button.
setResult(RESULT_CANCELED);
setContentView(R.layout.new_app_widget_configure);
mAppWidgetText = (EditText)findViewById(R.id.appwidget_text);
findViewById(R.id.add_button).setOnClickListener(mOnClickListener);
// Find the widget id from the intent.
Intent intent = getIntent();
Bundle extras = intent.getExtras();
if (extras != null) {
mAppWidgetId = extras.getInt(
AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
}
// If this activity was started with an intent without an app widget ID, finish with an error.
if (mAppWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) {
finish();
return;
}
mAppWidgetText.setText(loadTitlePref(NewAppWidgetConfigureActivity.this, mAppWidgetId));
}
View.OnClickListener mOnClickListener = new View.OnClickListener() {
public void onClick(View v) {
final Context context = NewAppWidgetConfigureActivity.this;
// When the button is clicked, store the string locally
String widgetText = mAppWidgetText.getText().toString();
saveTitlePref(context,mAppWidgetId,widgetText);
// It is the responsibility of the configuration activity to update the app widget
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
NewAppWidget.updateAppWidget(context, 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();
}
};
// Write the prefix to the SharedPreferences object for this widget
static void saveTitlePref(Context context, int appWidgetId, String text) {
SharedPreferences.Editor prefs = context.getSharedPreferences(PREFS_NAME, 0).edit();
prefs.putString(PREF_PREFIX_KEY + appWidgetId, text);
prefs.apply();
}
// Read the prefix from the SharedPreferences object for this widget.
// If there is no preference saved, get the default from a resource
static String loadTitlePref(Context context, int appWidgetId) {
SharedPreferences prefs = context.getSharedPreferences(PREFS_NAME, 0);
String titleValue = prefs.getString(PREF_PREFIX_KEY + appWidgetId, null);
if (titleValue != null) {
return titleValue;
} else {
return context.getString(R.string.appwidget_text);
}
}
static void deleteTitlePref(Context context, int appWidgetId) {
SharedPreferences.Editor prefs = context.getSharedPreferences(PREFS_NAME, 0).edit();
prefs.remove(PREF_PREFIX_KEY + appWidgetId);
prefs.apply();
}
}
And Provider:
package com.example.desktop_win10.myapplication;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.Context;
import android.widget.RemoteViews;
/**
* Implementation of App Widget functionality.
* App Widget Configuration implemented in {#link NewAppWidgetConfigureActivity NewAppWidgetConfigureActivity}
*/
public class NewAppWidget extends AppWidgetProvider {
#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);
}
}
#Override
public void onDeleted(Context context, int[] appWidgetIds) {
// When the user deletes the widget, delete the preference associated with it.
for (int appWidgetId : appWidgetIds) {
NewAppWidgetConfigureActivity.deleteTitlePref(context, appWidgetId);
}
}
#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
}
static void updateAppWidget(Context context, AppWidgetManager appWidgetManager,
int appWidgetId) {
CharSequence widgetText = NewAppWidgetConfigureActivity.loadTitlePref(context, appWidgetId);
// Construct the RemoteViews object
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.new_app_widget);
views.setTextViewText(R.id.appwidget_text, widgetText);
// Instruct the widget manager to update the widget
appWidgetManager.updateAppWidget(appWidgetId, views);
}
}
Did you add:
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER" />
?
As I know, without it android won't know which activity to launch as the main activity.
I am making an Android widget to display real time transportation information based on bus stop numbers. It displays the next 3 bus arrivals for the stop number and has a button where the user can refresh the data. That was working ok until I tried adding my widget configuration activity.
Now when you select the widget, a configuration screen is opened where you enter your bus stop number. Once you do that the widget is added to the home screen, but it will not execute the method to gather data and the refresh button will not work for that either. I have not been able to figure out why.
WidgetConfig
public class WidgetConfig extends Activity implements OnClickListener{
EditText info;
AppWidgetManager awm;
Context c;
int awID;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.widget_config);
Button b = (Button)findViewById(R.id.bWidgetConfig);
b.setOnClickListener(this);
c = WidgetConfig.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);
}
public void onClick(View v) {
// TODO Auto-generated method stub
info = (EditText)findViewById(R.id.etWidgetConfig);
String e = info.getText().toString();
RemoteViews views = new RemoteViews(c.getPackageName(), R.layout.widget_layout);
views.setTextViewText(R.id.tvStopNum, e);
Intent in = new Intent(c, WidgetConfig.class);
PendingIntent pi = PendingIntent.getActivity(c, 0, in, PendingIntent.FLAG_UPDATE_CURRENT);
views.setOnClickPendingIntent(R.id.tvStopNum, pi);
awm.updateAppWidget(awID, views);
Intent result = new Intent();
result.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, awID);
setResult(RESULT_OK, result);
finish();
}
AppWidgetProvider
public class MyWidgetProvider extends AppWidgetProvider {
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds){
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
// Create a new intent that will target this class
Intent intent = new Intent(context, MyWidgetProvider.class);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetIds[0]);
intent.setAction("update");
// Create a new PendingIntent which will be run whenever the refresh button is pressed
// This PendingIntent will run the intent we just created before this
PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
remoteViews.setOnClickPendingIntent(R.id.button1, pi);
// Manually run the AsyncTask to initially populate the 5 question fields
new RTPIinformation().execute(context);
appWidgetManager.updateAppWidget(appWidgetIds, remoteViews);
}
// This method is called when it receives an Intent. In particular, it will
// receive an intent whenever the refresh button is clicked
#Override
public void onReceive(Context context, Intent intent){
super.onReceive(context, intent);
if (intent.getAction().equals("update")){
new RTPIinformation().execute(context);
}
}
class RTPIinformation extends AsyncTask<Context, Void, List<RealtimeData>>{
.
.
.
}
Manifest
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.ruben.dublin.bus.widget"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="15" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<application
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name=".WidgetConfig"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
</intent-filter>
</activity>
<receiver
android:name=".MyWidgetProvider"
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_info" />
</receiver>
</application>
Any help would be greatly appreciated
In my application, I have a Fragment which is attached to the main activity. This Fragment displays data with the help of an adapter. In the adapter, I have inflated a layout which has a clickable text "Watch From Home". The adapter displays data from the server. I want to show the same data on the home screen and when I click on the "Watch From Home" text, a home screen widget should be created without any user interaction.
I made a receiver MyWidgetProvider.What should the method onClickText() for "Watch From Home" have so that it takes me to the widget? I must admit, I am new to android. Thanks
Android Manifest file
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.pack.android.receiver"
android:versionCode="1"
android:versionName="1.0" >
<application
android:icon="#drawable/icon"
android:label="#string/app_name" >
<receiver android:name="MyWidgetProvider" >
<intent-filter >
<action
android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="#xml/widget_info" />
</receiver>
</application>
<uses-sdk android:minSdkVersion="8" />
</manifest>
MyWidgetProvider.Java file
public class MyWidgetProvider extends AppWidgetProvider {
private TextView team1Name;
private TextView team2Name;
private TextView team1Score;
private TextView team2Score;
public static boolean widgetView=false;
private static final String LOG = "com.playup.android.receiver";
public MyWidgetProvider(TextView team1Name, TextView team2Name, TextView team1Score, TextView team2Score){
this.team1Name=team1Name;
this.team2Name=team2Name;
this.team1Score=team1Score;
this.team2Score=team2Score;
initializeViews();
}
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,int[] appWidgetIds) {
Log.w(LOG, "onUpdate method called");
// Get all ids
ComponentName thisWidget = new ComponentName(context,MyWidgetProvider.class);
int[] allWidgetIds = appWidgetManager.getAppWidgetIds(thisWidget);
// Build the intent to call the service
Intent intent = new Intent(context.getApplicationContext(), UpdateWidgetService.class);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, allWidgetIds);
// Update the widgets via the service
context.startService(intent);
}
public void initializeViews(){
// team1Name= (TextView)content_layout.findViewById(R.id.team1Name);
}
}
UpdateWidgetService
public class UpdateWidgetService extends Service {
private static final String LOG = "com.playup.android.receiver";
#Override
public void onStart(Intent intent, int startId) {
Log.i(LOG, "Called");
// Create some random data
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(this
.getApplicationContext());
int[] allWidgetIds = intent
.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS);
ComponentName thisWidget = new ComponentName(getApplicationContext(),
MyWidgetProvider.class);
int[] allWidgetIds2 = appWidgetManager.getAppWidgetIds(thisWidget);
Log.w(LOG, "From Intent" + String.valueOf(allWidgetIds.length));
Log.w(LOG, "Direct" + String.valueOf(allWidgetIds2.length));
for (int widgetId : allWidgetIds) {
// Create some random data
int number = (new Random().nextInt(100));
RemoteViews remoteViews = new RemoteViews(this
.getApplicationContext().getPackageName(),0x7f030061); //Since R could not be resolve, I used the generated ids
Log.w("Widget", String.valueOf(number));
// Set the text
remoteViews.setTextViewText(0x7f0a022a,"Random: " + String.valueOf(number));
// Register an onClickListener
Intent clickIntent = new Intent(this.getApplicationContext(),MyWidgetProvider.class);
clickIntent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
clickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS,
allWidgetIds);
PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, clickIntent,PendingIntent.FLAG_UPDATE_CURRENT);
remoteViews.setOnClickPendingIntent(0x7f0a022a, pendingIntent);
appWidgetManager.updateAppWidget(widgetId, remoteViews);
}
stopSelf();
super.onStart(intent, startId);
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
Simply saying, You can't create a home widget without any user interaction.
Update:
Your receiver tag should start like this:
<receiver
android:name=".MyWidgetProvider"
android:label="My widget label" >
<!-- The rest as is -->
</receiver>
Home Screen Widget can only add to Home Screen directly by user.Only user can add widget as guest to Home Screen or other applications.
Edit:
To see your widget in widgets list:
It is necessary that register your AppWidgetProvider in manifest.
Your App has to have Launcher/Main Activity,and App must be directly run by user,before it be visible in widgets list.This is necessary ,because no broadcastreceiver(and so no AppWidgetProvider),no service,... of your App could not register before your App run directly by user.If you look at your manifest,you will see that your App has no Launcher/Main Activity(it has only a receiver),so it can not run by user and your AppWidgetProvider(that is a broadcastreceiver) will not register and thereupon you can not see your widget in widget list.
This had me scratching my head for a while.
I had the meta-data tag as child of the intent-filter tag, which is wrong. The meta-data is to be child of the receiver tag.
Incorrect version
<receiver
android:name=".AppWidgetReceiver"
android:label="AppWidgetReceiver" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<meta-data
android:name="android.appwidget.provider"
android:resource="#xml/appwidget_info" />
</intent-filter>
</receiver>
Following is the correct version
<receiver android:name=".AppWidgetReceiver"
android:label="AppWidgetReceiver" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="#xml/appwidget_info" />
</receiver>
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.