Android simple widget that launches activity - android

Hi i've never worked with widgets before but what i'm looking to do is create a very simple widget i basically want to make a 1 by 1 widget that has just an icon, just an image set as the background no text nothing just a small icon and when the icon is pressed i want to open an activity. Basically i want to make a second icon like in the app drawer in a widget form that opens another activity rather than the main one.
Any help is greatly appreciated

My provider ended up looking like this after a lot of research and playing
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, ClassToLaunchHere.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget);
views.setOnClickPendingIntent(R.id.widget, pendingIntent);
appWidgetManager.updateAppWidget(appWidgetId, views);
}
}
}

Couple of app widget implementations that show the easiest way to do that are visible at https://github.com/commonsguy/cw-advandroid/tree/master/AppWidget.
Specifically, https://github.com/commonsguy/cw-advandroid/blob/master/AppWidget/PairOfDice/src/com/commonsware/android/appwidget/dice/AppWidget.java shows how to use a PendingIntent as the onClick target for a Button. You can make your PendingIntent start an Activity and you should be good to go.

Declare a Variable
public static String YOUR_AWESOME_ACTION = "YourAwesomeAction";
then add onUpdate and onReceive
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
ComponentName thisWidget = new ComponentName(context, DigitalClock.class);
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.digital_clock);
for (int widgetId : appWidgetManager.getAppWidgetIds(thisWidget)) {
remoteViews.setOnClickPendingIntent(R.id.imageView, getPendingSelfIntent(context, YOUR_AWESOME_ACTION));
appWidgetManager.updateAppWidget(thisWidget, remoteViews);
}
}
#Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
super.onReceive(context, intent);
if (YOUR_AWESOME_ACTION.equals(intent.getAction())) {
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.digital_clock);
ComponentName watchWidget = new ComponentName(context, DigitalClock.class);
appWidgetManager.updateAppWidget(watchWidget, remoteViews);
Intent ntent = new Intent(context, MainActivity.class);
ntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(ntent);
//Toast.makeText(context, YOUR_AWESOME_ACTION, Toast.LENGTH_SHORT).show();
}
}
protected PendingIntent getPendingSelfIntent(Context context, String action) {
Intent intent = new Intent(context, getClass());
intent.setAction(action);
return PendingIntent.getBroadcast(context, 0, intent, 0);
}
and add activity on Manifest
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
hope this will help

Related

Change an Android intent action from opening URI to displaying a toast?

I'm trying to have my widget use an onClick action to prompt a refresh. I found some demo code that works, but it opens a URI in browser. I'm having trouble replacing the URI action with something simpler, like displaying a toast. I've marked the line that I'm trying to change, but I don't know how to make Android set a different action other than Action.VIEW.
public class NewAppWidget extends AppWidgetProvider {
static void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId) {
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.new_app_widget);
//I AM TRYING TO CHANGE THIS INTENT
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://google.com/"));
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
views.setOnClickPendingIntent(R.id.refresh, pendingIntent);
appWidgetManager.updateAppWidget(appWidgetId, views);
}
#Override //Nothing changed here
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
for (int appWidgetId : appWidgetIds) {
updateAppWidget(context, appWidgetManager, appWidgetId);
}
}
}
The specific lines are
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://google.com/"));
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
I got this to work completely unexpectedly. I followed this post but left my intent declarations where they were. The resulting lines were:
Intent intent = new Intent(context, NewAppWidget.class);
intent.setAction(refresh);
intent.putExtra("appWidgetId", appWidgetId);
views.setOnClickPendingIntent(R.id.refresh, PendingIntent.getBroadcast(context,0,intent, PendingIntent.FLAG_UPDATE_CURRENT));
appWidgetManager.updateAppWidget(appWidgetId, views);
followed by onReceive:
#Override
public void onReceive(Context context, Intent intent) {
if(refresh.equals(intent.getAction())) {
Toast.makeText(context, "Clicked", Toast.LENGTH_LONG).show();
}
}
Edit for clarity: intent.getAction() needs to be a registered action within the receiver's intent filter.

How to launch an activity after clicking a widget?

I want to create a simple widget with an icon to launch my app.
I have the widget and its layout working properly, but I can't find the way to make it launcher the app when clicking it.
This is the widget class:
public class LauncherWidget extends AppWidgetProvider {
private static final String ACTION_CLICK = "ACTION_CLICK";
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager) {
Intent intent = new Intent(context, SplashActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// Attach the intent to the widget's button.
final PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
remoteViews.setOnClickPendingIntent(R.id.widget, pendingIntent);
}
}
I have never created a widget so I have no idea what to do here.
I have checked round here for more info but all I can find are widgets that update its content when clicking, but I tried to use their code but it isn't working.
Thanks in advance.
This is what worked for me...
The onUpdate method code should be:
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
for (int i = 0; i < appWidgetIds.length; i++) {
int appWidgetId = appWidgetIds[i];
try {
Intent intent = new Intent("android.intent.action.MAIN");
intent.addCategory("android.intent.category.LAUNCHER");
intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
intent.setComponent(new ComponentName(context.getPackageName(),
"Activity.class"));
PendingIntent pendingIntent = PendingIntent.getActivity(
context, 0, intent, 0);
RemoteViews views = new RemoteViews(context.getPackageName(),
R.layout.widget_layout);
views.setOnClickPendingIntent(R.id.widget, pendingIntent);
appWidgetManager.updateAppWidget(appWidgetId, views);
} catch (ActivityNotFoundException e) {
Toast.makeText(context.getApplicationContext(),
"There was a problem loading the application: ",
Toast.LENGTH_SHORT).show();
}
}
}
Use this snippet in onUpdate() method of your widget AppWidgetProvider class:
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widgetlayout);
Intent configIntent = new Intent(context, Activity.class);
PendingIntent configPendingIntent = PendingIntent.getActivity(context, 0, configIntent, 0);
remoteViews.setOnClickPendingIntent(R.id.widget, configPendingIntent);
appWidgetManager.updateAppWidget(appWidgetIds, remoteViews);
}

Android Provide Different Layout for AppWidget at Lock Screen

I want 2 separate layouts for homescreen and lockscreen.
I have read https://developer.android.com/guide/topics/appwidgets/index.html#lockscreen
But it is unclear where to implement this and how to change the layout at runtime for both homescreen and lockscreen?
I would be grateful if there is clear tutorial / example to do this.
Thanks
If you know home screen widget implementation, it's easy.
From the code below you can figure out how to use different layout for lock screen and home screen to display the current time every second.
Create different layout for different widgets
#layout/widget_keyguard //For lock screen widget
#layout/widget_home //For home screen widget
Note: Use one TextView with id time_view on both the layouts to display the time
xml/widget_info.xml
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:initialKeyguardLayout="#layout/widget_keyguard" // layout for lock screen
android:initialLayout="#layout/widget_home" // layout for lock screen (if not provided) & home screen
android:minHeight="100dp"
android:minWidth="300dp"
android:previewImage="#drawable/ic_launcher"
android:resizeMode="none"
android:updatePeriodMillis="180000"
android:widgetCategory="keyguard|home_screen" > //Enable widgets on both home screen and lock screen
</appwidget-provider>
AppWidgetProvider.java
public class TestAppWidgetProvider extends AppWidgetProvider {
#Override
public void onDeleted(Context context, int[] appWidgetIds) {
super.onDeleted(context, appWidgetIds);
}
#Override
public void onDisabled(Context context) {
Intent intent = new Intent(context, AlarmManagerBroadcastReceiver.class);
PendingIntent sender = PendingIntent
.getBroadcast(context, 0, intent, 0);
AlarmManager am = (AlarmManager) context
.getSystemService(Context.ALARM_SERVICE);
am.cancel(sender); //When all the widgets are disabled, do not forget to cancel the service
super.onDisabled(context);
}
#Override
public void onEnabled(Context context) {
super.onEnabled(context);
Toast.makeText(context, "Widget Enabled", Toast.LENGTH_SHORT).show();
//AlarmManager to update the widgets
Intent intent = new Intent(context, AlarmManagerBroadcastReceiver.class);
PendingIntent p_intent = PendingIntent.getBroadcast(context, 0, intent,
0);
AlarmManager am = (AlarmManager) context
.getSystemService(Context.ALARM_SERVICE);
// Here I am updating the widgets every second (1000 ms) , you can use however you want
am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(),
1000, p_intent);
}
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
Toast.makeText(context, "Widget Updated", Toast.LENGTH_SHORT).show();
ComponentName thisWidget = new ComponentName(context,
TestAppWidgetProvider.class);
for (int widgetId : appWidgetManager.getAppWidgetIds(thisWidget)) {
Bundle myOptions = appWidgetManager.getAppWidgetOptions(widgetId);
int category = myOptions.getInt(
AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY, -1);
RemoteViews remoteViews;
if (category == AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD) {
// Get the remote views
remoteViews = new RemoteViews(context.getPackageName(),
R.layout.widget_keyguard);
}
else {
remoteViews = new RemoteViews(context.getPackageName(),
R.layout.widget_home);
}
SimpleDateFormat dateFormat = new SimpleDateFormat(
"HH:mm:ss", Locale.US);
// use TextView with time_view id on both home screen & lock screen layouts
remoteViews.setTextViewText(R.id.time_view,
dateFormat.format(new Date(System.currentTimeMillis())));
appWidgetManager.updateAppWidget(widgetId, remoteViews);
}
}
#Override
public void onAppWidgetOptionsChanged(Context context,
AppWidgetManager appWidgetManager, int appWidgetId,
Bundle newOptions) {
}
}
AlarmManagerBroadcastReceiver class
public class AlarmManagerBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
ComponentName thiswidget = new ComponentName(context,
TestAppWidgetProvider.class);
AppWidgetManager appWidgetManager = AppWidgetManager
.getInstance(context);
for (int widgetId : appWidgetManager.getAppWidgetIds(thiswidget)) {
Bundle myOptions = appWidgetManager.getAppWidgetOptions(widgetId);
int category = myOptions.getInt(
AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY, -1);
RemoteViews remoteViews;
if (category == AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD) {
// Get the remote views
Log.d("Widget", "Lockscreen widget");
remoteViews = new RemoteViews(context.getPackageName(),
R.layout.widget_keyguard);
}
else {
Log.d("Widget", "Homescreen widget");
remoteViews = new RemoteViews(context.getPackageName(),
R.layout.widget_home);
}
SimpleDateFormat dateFormat = new SimpleDateFormat(
"HH:mm:ss", Locale.US);
// use TextView with time_view id on both home screen & lock screen layouts
remoteViews.setTextViewText(R.id.time_view,
dateFormat.format(new Date(System.currentTimeMillis())));
appWidgetManager.updateAppWidget(widgetId, remoteViews);
}
}
}
Finally, do not forget to update the manifest file
<application
...
<receiver android:name=".AlarmManagerBroadcastReceiver" />
<receiver android:name=".TestAppWidgetProvider" >
<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>
that's it.
I hope it'll help you to solve your problem

update textView in a widget

I've read a lot of Q&As but I couldn't find my answer.
May be something in my implementation is wrong.
The problem is that my TextView in the widget doesn't get updated.
The logic is this:
1.setOnClickPendingIntent on a specific button in the onUpdate()
2.clicking on this button will broadcast an intent with a declared action
3.at last i'll update the text of the textView in the onRecieve()
Widget2.class :
public class Widget2 extends AppWidgetProvider {
private static final String SCROLL_LEFT = "widget2.SCROLL_LEFT";
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
super.onUpdate(context, appWidgetManager, appWidgetIds);
for (int i = 0; i < appWidgetIds.length; i++) {
int appWidgetId = appWidgetIds[i];
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.small);
Intent scrollLeft = new Intent(Widget2.SCROLL_LEFT);
PendingIntent leftScrollPendingIntent = PendingIntent.getBroadcast(context,
appWidgetId, scrollLeft, appWidgetId);
remoteViews.setOnClickPendingIntent(R.id.left_scroller, leftScrollPendingIntent);
appWidgetManager.updateAppWidget(appWidgetId, remoteViews);
}
}
#Override
public void onReceive(Context context, Intent intent) {
Log.e(getClass().getSimpleName(), "onReceive()");
int appWidgetId = intent.getFlags();
if (intent.getAction().equals(SCROLL_LEFT)) {
updateCurrentWidget(context, appWidgetId);
Log.i("onReceive", SCROLL_LEFT + " appWidgetId = " + appWidgetId);
}
super.onReceive(context,intent);
}
private void updateCurrentWidget(Context context, int appWidgetId) {
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.small);
remoteViews.setString(R.id.name_of_the_app, "setText", "android os");
remoteViews.setTextViewText(R.id.description, "best ever");
Log.i("updateCurrentWidget", "the text have been set");
AppWidgetManager manager = AppWidgetManager.getInstance(context);
manager.updateAppWidget(appWidgetId, remoteViews);
}
manifest.xml :
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="4"
android:targetSdkVersion="14" />
<application
android:icon="#drawable/ic_launcher"
android:label="#string/app_name" >
<receiver android:name=".Widget2" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="widget2.SCROLL_LEFT" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="#xml/widget_small" />
</receiver>
</application>
</manifest>
and here is the simplified logcat logs:
onReceive()
"myPackageName".Widget2.SCROLL_LEFT
the text have been set
"myPackageName".Widget2.SCROLL_LEFT appWidgetId = 268435456
everything seems to be correct but the text is never changed!
The key in the widget is you have to set every View and every Intent before calling the updateAppWidget() method. Here You can call updateWidgetInstance(...) from your onReceive() method:
// action = the String that you get from your intent in the onRecive() method
// id = the id of the appWidget instance that you want to update
// you can get the id in the onReceive() method like this:
// int id = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
private static void updateWidgetInstance(Context context, AppWidgetManager manager, String action, int id) {
RemoteViews remoteViews = updateCurrentWidget(context, id);
remoteViews = setIntents(remoteViews, context, id);
manager.updateAppWidget(id, remoteViews);
}
updating the View: (Here you can also change the layout of this instance depending on your needs)
private static RemoteViews updateCurrentWidget(Context context, int appWidgetId) {
RemoteViews remoteViews;
remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget_small_layout);
remoteViews.setTextViewText(R.id.widget_name_of_the_app, "Android OS");
remoteViews.setTextViewText(R.id.widget_app_description, "best ever");
remoteViews.setImageViewUri(R.id.widget_icon_of_the_app, ...);
return remoteViews;
}
updating intents:
private static RemoteViews setIntents(RemoteViews rm, Context context, int appWidgetId) {
Intent click = new Intent(context, Widget.class);
click.setAction("[name of the action]");
click.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
PendingIntent pendingIntent =
PendingIntent.getBroadcast(context, appWidgetId, click, PendingIntent.FLAG_UPDATE_CURRENT);
rm.setOnClickPendingIntent(R.id.button1, pendingIntent);
return rm;
}
you are setting your appWidgetId in the PendingIntent flags. that's just wrong since PendingIntet flags have meanings, they are not meant to save some data.
You should use the extras for that.

Android Widget: OnClickPendingIntent won't Work

Why doesn't recieve get called when I click on Button wid??
Code:
public class Widget extends AppWidgetProvider {
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
for (int i = 0; i < appWidgetIds.length; i++) {
int appWidgetId = appWidgetIds[i];
Intent intent = new Intent(context, Widget.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget);
views.setOnClickPendingIntent(R.id.wid, pendingIntent);
appWidgetManager.updateAppWidget(appWidgetId, views);
}
}
#Override
public void onReceive(Context context, Intent intent) {
super.onReceive(context, intent);
Log.d("ARH","CLICKK");
}
Becuase I need a button to manual refresh the widget but it seems that Log.d("ARH","CLICKK"); only gets called when i add the Widget.
Thanks!
You using a PendingIntent to call an Activity but your Widget class is not an activity.
If you want to update to your widget, then you need to use getBroadcast that sends an APPWIDGET_UPDATE action.

Categories

Resources