I have a button on a lockscreen widget, and I'd like the button to launch an activity when pressed. If the screen is locked, I want the activity to appear over the lockscreen, without the user having to enter the PIN or pattern or whatever, and the lockscreen should reappear when the user leaves the activity.
I know about WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED, and my activity does appear over the lockscreen if I launch it manually using am start from an ADB shell. The problem is, when I press the button in the widget, it makes me enter the unlock PIN before it creates the activity at all.
I have this code in my widget provider:
#Override
public void onUpdate(final Context context, final AppWidgetManager appWidgetManager, final int[] appWidgetIds) {
for (final int appWidgetId : appWidgetIds) {
// Get the RemoteViews for controlling this widget instance.
final RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.my_widget);
// Construct an intent to launch the activity.
final Intent intent = new Intent(context, MyActivity.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);
views.setOnClickPendingIntent(R.id.my_button, pendingIntent);
appWidgetManager.updateAppWidget(appWidgetId, views);
}
}
And here's the code in MyActivity:
public MyActivity() {
Log.d(TAG, "Activity instantiated");
}
#Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Allow this activity to appear over the lock screen.
final Window window = getWindow();
window.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
setContentView(R.layout.my_activity);
}
When I press the button in the widget, I'm prompted for the unlock PIN. The log message in the activity's constructor doesn't appear until after I enter the PIN, which means that Android is deciding to ask for the pin before the FLAG_SHOW_WHEN_LOCKED can have any effect.
Is there a way to tell Android that I want to launch the activity while the screen is still locked? Maybe a flag that I can set on my Intent or PendingIntent?
You can use a broadcast intent and listen to it in your widget provider, then on the onRecieve method, start the activity intent, that's will not unlock your device but will launch your activity on foreground without requesting user to unlock.
Intent broadcastIntent = new Intent("com.yourapp.yourbroadcast");
widget.setOnClickPendingIntent(R.id.yourButton,
PendingIntent.getBroadcast(ctxt, 0, broadcastIntent, PendingIntent.FLAG_UPDATE_CURRENT));
On your onRecieve(Context ctx, Intent intent) :
if (intent.getAction().equals("com.yourapp.yourbroadcast"))
{
final Intent intent = new Intent(context, MyActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
ctx.startActivity(intent) ;
}
In your Manifest:
<receiver
android:name=".YourWidget"
android:label="Your Widget description" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="com.yourpackage.widgetbroadcast" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="#xml/wisget_yourwidget" />
</receiver>
Your Widgetclass:
public class YourWidget extends AppWidgetProvider {
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
for (int i = 0; i < appWidgetIds.length; i++) {
int appWidgetId = appWidgetIds[i];
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
Intent intent = new Intent("com.yourpackage.widgetbroadcast");
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
views.setOnClickPendingIntent(R.id.widget_yourlayout, pendingIntent);
appWidgetManager.updateAppWidget(appWidgetId, views);
}
}
#Override
public void onReceive(Context context, Intent intent) {
super.onReceive(context, intent);
if (intent.getAction().equals("com.yourpackage.widgetbroadcast")) {
Intent intentStart = new Intent(context, MainActivity.class);
intentStart.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intentStart);
}
}
}
In your MainActivity:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Window w = getWindow();
w.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
//Your code...
}
Make sure you set the Widow-Flag in the activity to FLAG_SHOW_WHEN_LOCKED and not to FLAG_DISMISS_KEYGUARD to keep the screen locked.
This example will start the activity by clicking on the widget.
Related
I want to know how to link widget and activity in android so that by clicking the widget only call some functios to do work but Not launch the activity something like when we click bluetooth in notification bar it just open bluetooth or close bluetooth without entering to that bluetooth app......
Thanks in advance :)
UPDATED ::
Below is Main Activity Code.
imageFlashlight.setOnClickListener(new View.OnClickListener() {
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
#Override
public void onClick(View view) {
if (finalHasCameraFlash) {
if (flashLightStatus)
flashLightOff();
else
flashLightOn();
} else {
Toast.makeText(MainActivity.this, "No flash available on your device",
Toast.LENGTH_SHORT).show();
}
}
});
The Code below is my widget code...
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private void updateAppWidget(Context context, AppWidgetManager appWidgetManager,
int appWidgetId) {
// Construct the RemoteViews object
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.app_widget);
// Construct an Intent object includes web adresss.
Intent intent = new Intent(context, MainActivity.class);
// In widget we are not allowing to use intents as usually. We have to use PendingIntent instead of 'startActivity'
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
// Here the basic operations the remote view can do.
views.setOnClickPendingIntent(R.id.tvWidget, pendingIntent);
// Instruct the widget manager to update the widget
appWidgetManager.updateAppWidget(appWidgetId, views);
}
UPDATED : As you can see i want to handle two functions by clicking the widget Without Entering to the activity just by tapping..
You can try sending Broadcast as
Intent broadcastIntent=new Intent(this,BroadcastReceiver.class);
//use .getBroadcast instead of getActivity and start a service when u receive this
//broadcast
PendingIntent pendingBroadcastIntent = PendingIntent.getBroadcast(context, 7, broadcastIntent, 0)
//set this pendingIntent on widget
the PendingIntent.getBroadcast() method will do the trick.
Remember to start the service when you receive this broadcast you can also set action on the intent using broadcastIntent.setAction(YOUR_ACTION).
Regards,
Karya
I have an android widget which is actually a button to start an activity.The widget works fine using this code but there is a small bug :
When I add the widget to the home screen , clicking it first time doesn't do anything , second time it works. Then it works normally from 1st click. And the same thing happens when the phone is restarted.Can someone help me solve this problem ??
MyWidgetIntentReceiver.java
public class MyWidgetIntentReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals("Start")) {
onUpdate(context);
}
}
private void onUpdate(Context context) {
RemoteViews remoteViews = new RemoteViews(context.getPackageName(),
R.layout.widget_demo);
Intent configIntent = new Intent(context, WidgetFlash.class);
configIntent.putExtra("widget", 1);
configIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent configPendingIntent = PendingIntent.getActivity(context,
0, configIntent, 0);
remoteViews.setOnClickPendingIntent(R.id.widget_button,
configPendingIntent);
MyWidgetProvider.pushWidgetUpdate(context.getApplicationContext(),
remoteViews);
} }
MyWidgetProvider.java :
public class MyWidgetProvider extends AppWidgetProvider {
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget_demo);
remoteViews.setOnClickPendingIntent(R.id.widget_button, buildButtonPendingIntent(context));
pushWidgetUpdate(context, remoteViews);
}
public static PendingIntent buildButtonPendingIntent(Context context) {
Intent intent = new Intent();
intent.setAction("Start");
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
public static void pushWidgetUpdate(Context context, RemoteViews remoteViews) {
ComponentName myWidget = new ComponentName(context, MyWidgetProvider.class);
AppWidgetManager manager = AppWidgetManager.getInstance(context);
manager.updateAppWidget(myWidget, remoteViews);
}}
Widget in Manifest:
<receiver android:name="com.hybernect.flashlight.MyWidgetProvider" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="#xml/demo_widget_provider" />
</receiver>
<receiver
android:name="com.hybernect.flashlight.MyWidgetIntentReceiver"
android:label="widgetBroadcastReceiver" >
<intent-filter>
<action android:name="Start" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="#xml/demo_widget_provider" />
</receiver>
It looks to me like you might be very new to Android widgets, and are missing some of the basics that you need to know. My advice is to find some more tutorials other than the one you worked off, to compare different ways that widgets are handled.
I wrote a simple widget as a demo tutorial - it contains all the boilerplate code required for a widget, and very little else:
WiFi Widget Demo (github)
WiFi Widget (Play store)
I wrote it in such a way to make it easy for anyone to remove the "wifi" related code, and adapt it to their own widget requirements. It might be perfect for you to look at, and relatively simple to add a single button to it.
You are mixing up the different onUpdate() methods in your MyWidgetIntentReceiver and MyWidgetProvider. Below I will try to explain what is wrong with the code that you gave in your original question.
When you add the widget to the home screen, MyWidgetProvider.onUpdate() is called, which in turn calls buildPendingIntent():
public static PendingIntent buildButtonPendingIntent(Context context) {
Intent intent = new Intent();
intent.setAction("Start");
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
This creates a PendingIntent that will send a broadcast with action set to "Start", when the button is clicked.
And that is what happens. The button is clicked, you send a broadcast with "Start" in it, and this is received by your MyWidgetIntentReceiver.
I do not understand why you have chosen to do it this way, as you could rather just start the activity from this class.
When your MyWidgetIntentReceiver.onReceive() method runs, it calls its own onUpdate() method.
(Note: this is poor practice; try to do as little as possible within a BroadcastReceiver)
This new onUpdate() method sets the click action to launch the activity:
Intent configIntent = new Intent(context, WidgetFlash.class);
configIntent.putExtra("widget", 1);
configIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent configPendingIntent = PendingIntent.getActivity(context,
0, configIntent, 0);
remoteViews.setOnClickPendingIntent(R.id.widget_button,
configPendingIntent);
And so the second time you click the button, the WidgetFlash activity is launched.
To summarise:
your first update calls PendingIntent.getBroadcast(), which sends "Start" to the receiver
your second update calls PendingIntent.getActivity(), which starts the WidgetFlash
I do not understand the need for your MyWidgetIntentReceiver in this code.
I have the following code in my sample app. I'm starting a service from an app widget when a button is clicked. The service's job is to play a short audio clip that depends on which button was clicked.
The app widget contains two buttons (PREV and NEXT). On click events are handled in onUpdate().
From different guides that I've found online I can start the service in two ways:
by creating a broadcast in onUpdate() method and handle it later in onReceive() method of the extended AppWidgetProvider class (as in the sample code for PREV button).
or by calling startService() via a PendingIntent in onUpdate() (as NEXT button).
Which of both is better practice or more commonly used? Thank you
<!-- widget_player.xml -->
<LinearLayout
android:id="#+id/player_controls"
android:layout_width="match_parent"
android:layout_height="30dp"
android:orientation="horizontal" >
<ImageButton
android:id="#+id/btn_player_prev"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:src="#android:drawable/ic_media_previous" />
<ImageButton
android:id="#+id/btn_player_next"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:src="#android:drawable/ic_media_next" />
</LinearLayout>
WidgetPlayer class
public class WidgetPlayer extends AppWidgetProvider {
public static String ACTION_WIDGET_PREV = "action.WIDGET_PREV";
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
super.onUpdate(context, appWidgetManager, appWidgetIds);
final int nPlayerWidgets = appWidgetIds.length;
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget_player);
for (int i = 0; i < nPlayerWidgets; i++) {
int appWidgetId = appWidgetIds[i];
updateWidgetPlayer(context, appWidgetManager);
Intent intent;
PendingIntent actionPendingIntent;
// PREV button
intent = new Intent(context, WidgetPlayer.class);
intent.setAction(ACTION_WIDGET_PREV);
actionPendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
remoteViews.setOnClickPendingIntent(R.id.btn_player_prev, actionPendingIntent);
// NEXT button (not using a broadcast)
intent = new Intent(context, PlayerService.class);
intent.setAction(PlayerService.ACTION_NEXT);
actionPendingIntent = PendingIntent.getService(context, 0, intent, 0);
remoteViews.setOnClickPendingIntent(R.id.btn_player_next, actionPendingIntent);
appWidgetManager.updateAppWidget(appWidgetId, remoteViews);
}
}
#Override
public void onReceive(Context context, Intent intent) {
AppWidgetManager manager = AppWidgetManager.getInstance(context.getApplicationContext());
if (intent.getAction().equals(ACTION_WIDGET_PREV)) {
Intent iPrev = new Intent(PlayerService.ACTION_PREV);
iPrev.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, allWidgetMetaPlayerIds);
context.startService(iPrev);
updateWidgetPlayer(context, manager);
}
// handle more actions here
else {
super.onReceive(context, intent);
}
}
}
The NEXT button code looks more concise so it is better choice if it does what you want. With the PREVIOUS code you have the extra step of receiving the broadcast which appears unnecessary.
You can pass along the id's in the intent to the service if you need those.
I have a widget on screen, a button click on widget enables/disables a broadcast reciver ... But when i turn the phone a bit.. all values on widget get reset and gives wrong info to user... I tried most of things to prevent this as below :
added android:configChanges="orientation|screenSize" in manifest
added this method in mainavtivity
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
setContentView(R.layout.widget_layout);
}
I hace also see suggestion to use onSaveInstanceState and all, But I cant get textview data from my widget from remoteviews approach to save it .. any other way
---- HERE IS THE CODE ----------
In Manifest...
<receiver android:name="MyWidgetProvider" >
<intent-filter >
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="com.makelifesimple.autopickmobiletracker.MyWidgetProvider.ACTION_WIDGET_ACTIVATE"/>
<action android:name="com.makelifesimple.autopickmobiletracker.MyWidgetProvider.ACTION_WIDGET_DEACTIVATE"/>
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="#xml/widget_info" />
</receiver>
<activity
android:name="com.makelifesimple.autopickmobiletracker.MainActivity"
android:configChanges="orientation|screenSize"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
--- in MyWidgetProvider ---
public class MyWidgetProvider extends AppWidgetProvider {
public static String ACTION_WIDGET_ACTIVATE = "ActivatePickup";
public static String ACTION_WIDGET_DEACTIVATE = "DeactivatePickup";
RemoteViews remoteViews;
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,int[] appWidgetIds) {
Toast.makeText(context, "in onupdate", Toast.LENGTH_SHORT).show();
remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
Intent active = new Intent(context, MyWidgetProvider.class);
active.setAction(ACTION_WIDGET_ACTIVATE);
PendingIntent actionPendingIntent = PendingIntent.getBroadcast(context, 0, active, 0);
remoteViews.setOnClickPendingIntent(R.id.button1, actionPendingIntent);
active = new Intent(context, MyWidgetProvider.class);
active.setAction(ACTION_WIDGET_DEACTIVATE);
actionPendingIntent = PendingIntent.getBroadcast(context, 0, active, 0);
remoteViews.setOnClickPendingIntent(R.id.button2, actionPendingIntent);
appWidgetManager.updateAppWidget(appWidgetIds, remoteViews);
}
#Override
public void onEnabled(Context context){
Toast.makeText(context, "in enables", Toast.LENGTH_SHORT).show();
context.startService(new Intent(context, MyWidgetProvider.class));
}
#Override
public void onDisabled(Context context){
Toast.makeText(context, "in disable", Toast.LENGTH_SHORT).show();
context.stopService(new Intent(context, MyWidgetProvider.class));
}
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "in onRecive", Toast.LENGTH_SHORT).show();
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
if (intent.getAction().equals(ACTION_WIDGET_ACTIVATE)) {
ComponentName receiver = new ComponentName(context, PhoneCallReceiver.class);
PackageManager pm = context.getPackageManager();
pm.setComponentEnabledSetting(receiver,PackageManager.COMPONENT_ENABLED_STATE_ENABLED,PackageManager.DONT_KILL_APP);
//remoteViews.setTextViewText(R.id.button1,"ACTIVATED");
remoteViews.setTextViewText(R.id.textView2,"ACTIVE");
} else if (intent.getAction().equals(ACTION_WIDGET_DEACTIVATE)) {
ComponentName receiver = new ComponentName(context, PhoneCallReceiver.class);
PackageManager pm = context.getPackageManager();
pm.setComponentEnabledSetting(receiver,PackageManager.COMPONENT_ENABLED_STATE_DISABLED,PackageManager.DONT_KILL_APP);
remoteViews.setTextViewText(R.id.textView2,"INACTIVE");
Intent headSetUnPluggedintent = new Intent(Intent.ACTION_HEADSET_PLUG);
headSetUnPluggedintent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
headSetUnPluggedintent.putExtra("state", 0); // 0 = unplugged 1 = Headset with microphone 2 = Headset without microphone
headSetUnPluggedintent.putExtra("name", "Headset");
context.sendOrderedBroadcast(headSetUnPluggedintent, null);
}
Intent active = new Intent(context, MyWidgetProvider.class);
active.setAction(ACTION_WIDGET_ACTIVATE);
PendingIntent actionPendingIntent = PendingIntent.getBroadcast(context, 0, active, 0);
remoteViews.setOnClickPendingIntent(R.id.button1, actionPendingIntent);
active = new Intent(context, MyWidgetProvider.class);
active.setAction(ACTION_WIDGET_DEACTIVATE);
actionPendingIntent = PendingIntent.getBroadcast(context, 0, active, 0);
remoteViews.setOnClickPendingIntent(R.id.button2, actionPendingIntent);
ComponentName thisWidget = new ComponentName( context, MyWidgetProvider.class );
AppWidgetManager.getInstance( context ).updateAppWidget(thisWidget, remoteViews );
}
}
what am i missing here.......PLS PLSSSSSSSSSS HELP
It is pretty risky to rely on onUpdate in the widget provider to do more than catch the creation and deleting of the widgets. Everything else should be managed from elsewhere, typically a service, or a thread, started from onUpdate.
You then catch orientation change (through various method, whether from an activity or a Broadcast receiver that triggers the service or other thread) which will need to redo the code you have in onUpdate.
Other places to look:
A good tutorial is in: http://www.vogella.com/articles/AndroidWidgets/article.html, I would only quibble with one point in that tutorial: it's generally advised to not use updatePeriod.
There's a bit more detail in Who (and how) create an instance of AppWidgetProvider?.
Some thoughts on handling services, activities and widgets all in one app are in Service being re-Created by AlarmManager.
There are several errors in this code.
First, your onEnabled and onDisabled methods try to treat the AppWidgetProvider as a service. It isn't: it's a BroadcastReceiver, so these calls will fail, possibly terminating your app.
However, this won't happen. You've overridden onReceive without calling through to the super method, so none of the other methods will be called at all.
Fix these errors before you try to do anything else. Your onEnabled and onDisabled methods should be empty, and your onReceive should look like the following, without the duplicate widget-update code you have there now.
if (ACTION_WIDGET_ACTIVATE.equals(intent.getAction()) {
...
} else if (ACTION_WIDGET_DEACTIVATE.equals(intent.getAction()) {
...
} else {
super.onReceive(context, intent);
}
As posted here: After orientation change buttons on a widget are not responding you can avoid this by applying all widget changes on each update, including button click handlers.
For AppWidgets it is essential to implement onUpdate to redraw the widget's content.
I have a very simple widget application which consists of a LinearLayout with a background and an ImageButton.
In the AppWidgetProvider onUpdate() method, I register the click of the button to broadcast an intent. When the widget first loads, everything runs fine and the click is captured. The problem occurs when the screen is rotated, and the click is never captured again even if the screen is rotated back.
What do I have to do to re-register the click when the screen rotates?
below is some segments of code I am using.
AppWidgetProvider
#Override
public void onReceive(Context context, Intent intent)
{
super.onReceive(context, intent);
if(intent.getAction().equals("test.CLICK"))
{
CallTestMethod(context);
}
}
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
final int N = appWidgetIds.length;
// Perform this loop procedure for each App Widget that belongs to this provider
for (int i=0; i<N; i++) {
int appWidgetId = appWidgetIds[i];
RemoteViews views=new RemoteViews(context.getPackageName(), R.layout.widget);
Intent clickintent=new Intent("test.CLICK");
PendingIntent pendingIntentClick=PendingIntent.getBroadcast(context, 0, clickintent, PendingIntent.FLAG_UPDATE_CURRENT);
views.setOnClickPendingIntent(R.id.change_mode, pendingIntentClick);
SetInitialLayout(context);
appWidgetManager.updateAppWidget(appWidgetId, views);
}
super.onUpdate(context, appWidgetManager, appWidgetIds);
}
Manifest
<receiver android:name=".Widget" android:label="#string/widget_name">
<intent-filter>
<action android:name="android.appwidget.action.ACTION_APPWIDGET_CONFIGURE" />
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="test.CLICK" />
</intent-filter>
<meta-data android:name="android.appwidget.provider" android:resource="#xml/widget_mode_switcher" />
</receiver>
Layout
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/widget_layout"
android:layout_width="140dip"
android:layout_height="140dip"
android:scaleType="fitCenter"
android:orientation="vertical"
android:background="#drawable/background">
<ImageButton
android:id="#+id/change_mode"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:scaleType="fitCenter"
android:orientation="vertical"
android:src="#drawable/none_selected"
android:background="#null"
android:clickable="true" />
</LinearLayout>
Thank you anyone for your help!
This helped me: Android widget ImageButton loses image when screen is rotated
In short, you have to register the clicks (views.setOnClickPendingIntent) before EVERY call to awm.updateAppWidget
I used a solution which requires a service on the widgetapp because it can handle orientation changes to the widgetapp. Unfortunately onReceive or onUpdate doesn't get called by orientation changes, but the service's onConfigurationChanged does get called. You need to have your service constantly running to detect these orientations as well. When the service detects the orientation change, then you proceed to change the remote view.
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
context.startService(new Intent(context, MyUpdateService.class));
}
This is the service class that you need to implement. You can look at this if you need more information about the service. http://android-developers.blogspot.com/2009/04/introducing-home-screen-widgets-and.html
public static class MyUpdateService extends Service
{
#Override
public void onCreate() {
super.onCreate();
}
#Override
public void onDestroy() {
super.onDestroy();
}
#Override
public void onStart(Intent intent, int startId)
{
super.onStart(intent, startId);
// Update the widget
RemoteViews remoteView = buildRemoteView(this);
// Push update to homescreen
pushUpdate(remoteView);
}
public RemoteViews buildRemoteView(Context context)
{
int layoutID = R.layout.widget;
if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE){
layoutID = R.layout.widget_landscape;
}
//Here is where you set your onclick listeners again since the remote views need to be refreshed/recreated
RemoteViews updateView = new RemoteViews(context.getPackageName(),layoutID);
// Create an Intent to launch ExampleActivity
Intent intent = new Intent(this, yourAndroidActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
intent, 0);
updateView.setOnClickPendingIntent(R.id.yourClickableViewHere, pendingIntent);
return updateView;
}
#Override
public void onConfigurationChanged(Configuration newConfig)
{
RemoteViews remoteView = buildRemoteView(this);
// Push update to home screen
pushUpdate(remoteView);
}
private void pushUpdate(RemoteViews updateViews)
{
ComponentName myWidget = new ComponentName(this, YourAppWidget.class);
AppWidgetManager manager = AppWidgetManager.getInstance(this);
//This is where you can update your remoteViews
updateViews.setTextViewText(R.id.YOUR_TEXTVIEW_ON_WIDGET, "" + "TEXT THAT WILL SHOW UP");
manager.updateAppWidget(myWidget, updateViews);
}
}
}
As I understand it, Android actually kills and recreates your activity every time the screen is rotated. Yuck, I know.
So anyway, I suspect if you put log statements in all the various lifecycle callbacks, you'll find that update is only called the one time. You probably need to handle listening for clicks in another callback. I couldn't tell you which one without checking some reference material. I'll leave that as an exercise to the reader.
hay have you use
android:configChanges="keyboardHidden|orientation"
with your Activity in Androidmanifest file.
I am new to android, but I am fairly certain that this way of doing it will work.
#Override
public void onReceive(Context context, Intent intent)
{
super.onReceive(context, intent);
if(intent.getAction().equals("test.CLICK"))
{
getIntent().putExtra("Just received click", true);
CallTestMethod(context);
}
}
Then in the onCreate you can see if it should recreate the click event by checking getIntent().getBooleanExtra("Just received click", false) (false refers to the default value. If that code returns true, then the above code did it's job and you should recreate the click event)
This should work because the intent object (and it's extras) are saved, even if your app is temporarily killed. The intent will accept any Serializable extra.