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.
Related
I have a widget with a button. In my app widget (TestWidget.java) I have a private static boolean variable (buttonClicked) initialized to false.
When I click on the button the boolean buttonClicked is set to true. I have an updatePeriodMillis set to the minimum 30min (1800000ms).
First onUpdate comes: buttonClicked value is true. As expected.
Then I stop my main app. The following onUpdates shows buttonClicked value as false.
launch --> 06-10 10:55:56.365 4186-4186/com.narb.testwidget I/TESTWID: update setButtonClicked false
1st onUpdate after button click --> 06-10 10:56:11.685 4186-4186/com.narb.testwidget I/TESTWID: setButtonClicked true
onUpdate after main app exit --> I/TESTWID: update setButtonClicked false
Why is that?
App widget - TestWidget
public class TestWidget extends AppWidgetProvider {
private static RemoteViews views;
private static boolean buttonClicked = false;
static void updateAppWidget(Context context, AppWidgetManager appWidgetManager,
int appWidgetId) {
appWidgetManager.updateAppWidget(appWidgetId, views);
}
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
// Get all ids
ComponentName thisWidget = new ComponentName(context,
TestWidget.class);
int[] allWidgetIds = appWidgetManager.getAppWidgetIds(thisWidget);
Log.i("TESTWID", "update setButtonClicked "+buttonClicked);
views = new RemoteViews(context.getPackageName(), R.layout.test_widget);
views.setOnClickPendingIntent(R.id.wid_btn_tst, setButton(context));
for (int appWidgetId : appWidgetIds) {
updateAppWidget(context, appWidgetManager, appWidgetId);
}
}
public static void setButtonClicked(boolean b){
buttonClicked = b;
Log.i("TESTWID", "setButtonClicked "+buttonClicked);
}
public static PendingIntent setButton(Context context) {
Intent intent = new Intent();
intent.setAction("TEST");
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
public static void pushWidgetUpdate(Context context, RemoteViews remoteViews) {
ComponentName myWidget = new ComponentName(context, TestWidget.class);
AppWidgetManager manager = AppWidgetManager.getInstance(context);
manager.updateAppWidget(myWidget, remoteViews);
}
}
Button code - TestWidgetReceiver
public class TestWidgetReceiver extends BroadcastReceiver{
private static boolean isButtonON = false;
#Override
public void onReceive(Context context, Intent intent) {
if(intent.getAction().equals("TEST")){
updateWidgetButton(context, 2);
}
}
private void updateWidgetButton(Context context, int index) {
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.test_widget);
if(index == 2) {
if(isButtonON) {
remoteViews.setTextViewText(R.id.wid_btn_tst, "Test Off");
isButtonON = false;
}
else{
remoteViews.setTextViewText(R.id.wid_btn_tst, "Test On");
isButtonON = true;
TestWidget.setButtonClicked(isButtonON);
}
//REMEMBER TO ALWAYS REFRESH YOUR BUTTON CLICK LISTENERS!!!
remoteViews.setOnClickPendingIntent(R.id.wid_btn_tst, TestWidget.setButton(context));
}
TestWidget.pushWidgetUpdate(context.getApplicationContext(), remoteViews);
}
}
Manifest
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="Test"
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=".TestWidget">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="#xml/test_widget_info" />
</receiver>
<receiver
android:name=".TestWidgetReceiver"
android:label="widgetBroadcastReceiver" >
<intent-filter>
<action android:name="TEST" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="#xml/test_widget_info" />
</receiver>
</application>
In my app widget (TestWidget.java) I have a private static boolean variable (buttonClicked) initialized to false
static variables are a cache, at best.
Then I stop my main app.
I do not know exactly what you mean by that. My guess is that you mean that you remove a task associated with your app from the overview screen.
The following onUpdates shows buttonClicked value as false. Why is that?
If by "stop my main app", you do something like I outlined, you will have terminated your process. At a later point, such as when you click your app widget's button, Android will start a fresh process for you, at which point your static field, at which point your static field will be its default value.
I would have thought that widgets have their own memory copy as they continue to run even if the main app has exited?
No. The views associated with your app widget will exist, in the home screen. That does not include your TestWidget code, which is not part of the home screen.
I'm considering dropping this approach to do an alarmManager with a low refresh time (10 secs).
First, that's not possible on Android 5.1 and above, as it substantially drains the battery. Second, it does not guarantee that your process will stay around.
static variables are a cache, at best. Any app, including those with an app widget, need to store important data somewhere else: SharedPreferences, SQLite database, some other sort of file, a server, etc.
If you force stop the app or the system decides to stop it due to low memory, all classes are dropped from the memory and all static variables are lost. In this case, you should either persist your data to the DB or SharedPreferences or similar or rethink the approach itself. Is it really necessary to do it the way you're doing here?
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 my simple example app i have 2 activity:
MainActivity.java
NewAppWidgetConfigureActivity.java
Also in my app i have class NewAppWidget.java who extends AppWidgetProvider
What i want to accomplish is this:
When i add home widget to screen, i want to open activity NewAppWidgetConfigureActivity.java first. It is ok till now, its working nice.
When i add home widget to screen, my widget has 2 buttons and one TextView.
What i want is this:
when i click first button, i want to open MainActivity.java
when i click second button, i want to open NewAppWidgetConfigureActivity.java.
However, its not working. By clicking buttons nothing happens. I try to implement solutions from other questions but i it does not working.
Here are codes:
Manifest file code:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.petar.mywidgetwitbuttons">
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
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>
<activity android:name=".NewAppWidgetConfigureActivity">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
</intent-filter>
</activity>
</application>
This is code for new_ap_widget_info.xml, where i add all necessary info for my widget, including line of code where i automatically open activity NewAppWidgetConfigureActivity.java when i add widget.
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:configure="com.example.petar.mywidgetwitbuttons.NewAppWidgetConfigureActivity"
android:initialKeyguardLayout="#layout/new_app_widget"
android:initialLayout="#layout/new_app_widget"
android:minHeight="110dp"
android:minWidth="180dp"
android:previewImage="#drawable/example_appwidget_preview"
android:resizeMode="horizontal|vertical"
android:updatePeriodMillis="86400000"
android:widgetCategory="home_screen" />
This is code for NewAppWidget.java class who extends AppWidgetProvider
package com.example.petar.mywidgetwitbuttons;
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.widget.RemoteViews;
/**
* Implementation of App Widget functionality.
* App Widget Configuration implemented in {#link NewAppWidgetConfigureActivity NewAppWidgetConfigureActivity}
*/
public class NewAppWidget extends AppWidgetProvider {
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);
Log.d("widget", "onUpdatePrvo: Widget testiramo");
// 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);
Intent intent = new Intent(context, MainActivity.class);
Intent intent2 = new Intent(context, NewAppWidgetConfigureActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
PendingIntent pendingIntent2 = PendingIntent.getActivity(context, 0, intent2, 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.new_app_widget);
views.setOnClickPendingIntent(R.id.buttonCLICK, pendingIntent);
views.setOnClickPendingIntent(R.id.buttonCLICK2, pendingIntent2);
appWidgetManager.updateAppWidget(appWidgetId, views);
}
}
#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
}
}
Also, when i remove this line of code from provider info, then i can open MainActivity.java on the first button click, and still can not open NewAppWidgetConfigureActivity.java by clicking second button.
android:configure="com.example.petar.mywidgetwitbuttons.NewAppWidgetConfigureActivity"
And here is full provider info code without android:configure=""
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:configure="com.example.petar.mywidgetwitbuttons.NewAppWidgetConfigureActivity"
android:initialKeyguardLayout="#layout/new_app_widget"
android:initialLayout="#layout/new_app_widget"
android:minHeight="110dp"
android:minWidth="180dp"
android:previewImage="#drawable/example_appwidget_preview"
android:resizeMode="horizontal|vertical"
android:updatePeriodMillis="86400000"
android:widgetCategory="home_screen" />
These easy steps could help you to resolve your problem.
App widget allows certain UI controls not everything. So check what are allowed and what are not.
https://developer.android.com/guide/topics/appwidgets/index.html#CreatingLayout
Do not extend or create a custom UI control class. Ex;- class CustomButton extends Button
I do see your Intents do not have extra parameters. That might confuse the PendingIntent compare logic internally. So add a custom Action or few extra parameters to the intent.
EX;-
Intent a = new Intent("MainActivity");
Intent b = new Intent("ConfigureActivity");
This works for me.
public class widget_wordss extends AppWidgetProvider {
private static final String ACTION_SIMPLEAPPWIDGET = "ACTION_BROADCASTWIDGETSAMPLE";
private static final String ACTION_SIMPLEAPPWIDGET1 = "ACTION_BROADCASTWIDGETSAMPLE1";
public boolean widg = false;
static void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int
appWidgetId) {
RemoteViews views = new RemoteViews(context.getPackageName(),
R.layout.widget_main_words);
Intent intent = new Intent(context, widget_wordss.class);
Intent intent1 = new Intent(context, widget_wordss.class);
intent.setAction(ACTION_SIMPLEAPPWIDGET);
intent1.setAction(ACTION_SIMPLEAPPWIDGET1);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
PendingIntent pendingIntent1 = PendingIntent.getBroadcast(context, 0, intent1,
PendingIntent.FLAG_UPDATE_CURRENT);
views.setOnClickPendingIntent(R.id.btnOpen, pendingIntent);
views.setOnClickPendingIntent(R.id.btnayar, pendingIntent1);
appWidgetManager.updateAppWidget(appWidgetId, views);
The question is simple as it seems.
The Android Widget works as a charm, everything is OK.
I just want the widget content to be updated when (in the right moment) the user turn on its device screen.
I can't find a hint for this in internet nor the documentation. This means that I'm clearly overlooking something easy and important.
UPDATE
Thanks for the answer of Murtaza, seems perfect, but for some reason isn't working.
My widget has already a receiver, so i added the suggested intent filter:
<receiver android:name=".MyWidget" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="android.intent.action.SCREEN_ON" />
<action android:name="android.intent.action.SCREEN_OFF" />
</intent-filter>
Inside the widget class i overriden the suggested function:
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
playNotification(context);
} else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
playNotification(context);
}
}
The playNotification() plays an alarm. It works properly inside the widget. But when I switch the screen ON and OFF, nothing happens.
UPDATE II - A working widget in Android
I post the whole code of the widget for who need it.
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.Context;
import android.content.Intent;
import android.media.Ringtone;
import android.media.RingtoneManager;
import android.net.Uri;
import android.widget.RemoteViews;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;
import java.io.IOException;
import java.util.Calendar;
/**
* Implementation of App Widget functionality.
*/
public class MyWidget extends AppWidgetProvider {
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
// There may be multiple widgets active, so update all of them
final int N = appWidgetIds.length;
for (int i = 0; i < N; i++) {
updateAppWidget(context, appWidgetManager, appWidgetIds[i]);
}
}
#Override
public void onReceive(Context context, Intent intent) {
super.onReceive(context, intent);
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
playNotification(context, true);
} else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
playNotification(context, true);
}
}
static void updateAppWidget(Context context, AppWidgetManager appWidgetManager,
int appWidgetId) {
String widgetText = "";
playNotification(context, true);
widgetText += " DATE:" + Calendar.getInstance().getTime().getHours() + ":" + Calendar.getInstance().getTime().getMinutes();
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.mywidget);
views.setTextViewText(R.id.appwidget_text, widgetText);
appWidgetManager.updateAppWidget(appWidgetId, views);
}
public static void playNotification(Context context, boolean alarm) {
try {
Uri notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
if (alarm) notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM);
Ringtone r = RingtoneManager.getRingtone(context, notification);
if (!r.isPlaying())
r.play();
} catch (Exception e) {
e.printStackTrace();
}
}
ANDROID MANIFEST
This is what you need to add to the manifest to have a working widget on Android. More, the filters I would like to make work.
<receiver android:name=".MYWidget" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="android.intent.action.SCREEN_ON" />
<action android:name="android.intent.action.SCREEN_OFF" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="#xml/mywidget_info" />
</receiver>
PLEASE NOTE THAT the code works. Everything except what concern my question: "Update an Android Widget when the screen is turned ON"
You need to create a Broadcast Receiver for that.
Add these permissions in your Manifest.xml
<receiver android:name=".MyBroadcastReceiver" android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.ACTION_SCREEN_ON"></action>
<action android:name="android.intent.action.ACTION_SCREEN_OFF"></action>
</intent-filter>
</receiver>
MyBroadcastReceiver.java
public class MyBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
} else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
//update your widget.
}
}
}
The question turns into a new one, so I want to show some example. Your question now is, how to update the widget from inside all other classes. As I suspect, Your playNotification(); method is inside the receiver of Your widget. What You have to do is, make an extra class with Your playNotification() method as public , so You can call it from every other class. Look this example, based on the answer from Murtaza and Your update:
create an extra class:
public class NotificationHelper{
private Context mContext;
//make a constructor and set Context or other objects/values if You need it
public NotificationHelper(Context ctx){
mContext = ctx;
}
public void playNotification(){
//do Your stuff here inside
}
}
With this public class, You can do Your stuff from anywhere else. For example inside Your AppWidget Receiver or Your BroadCastReceiver that will be fired if the screen goes on or off:
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
NotificationHelper mHelper = new NotificationHelper(context);
mHelper.playNotification();
} else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
NotificationHelper mHelper = new NotificationHelper(context);
mHelper.playNotification();
}
}
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>