7

I have a flashlight app with a widget. The widget is used to turn the flashlight on and off and does not display main activity or anything. After a few hours, however, the widget does nothing. I mean if you click it, nothing happens. I have two classes to accomplish this a Provider and a Receiver.

Provider:

public class WidgetProvider extends AppWidgetProvider {

  @
  Override
  public void onUpdate(Context context, AppWidgetManager appWidgetManager,
    int[] appWidgetIds) {

    Intent receiver = new Intent(context, FlashlightWidgetReceiver.class);
    receiver.setAction("COM_FLASHLIGHT");
    receiver.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
    PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, receiver, 0);

    RemoteViews views = new RemoteViews(context.getPackageName(),
      R.layout.appwidget_layout);
    views.setOnClickPendingIntent(R.id.imageButton, pendingIntent);

    appWidgetManager.updateAppWidget(appWidgetIds, views);

  }
}

Receiver:

public class FlashlightWidgetReceiver extends BroadcastReceiver {
  private static boolean isLightOn = false;
  private static Camera camera;
  MediaPlayer mp;@
  Override
  public void onReceive(Context context, Intent intent) {
    RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.appwidget_layout);

    if (isLightOn) {
      views.setImageViewResource(R.id.imageButton, R.drawable.btn_switch_off);
      mp = MediaPlayer.create(context, R.raw.light_switch_off);
    } else {
      views.setImageViewResource(R.id.imageButton, R.drawable.btn_switch_on);
      mp = MediaPlayer.create(context, R.raw.light_switch_on);
    }
    mp.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {

      @
      Override
      public void onCompletion(MediaPlayer mp) {
        // TODO Auto-generated method stub
        mp.release();
      }
    });
    mp.start();
    AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
    appWidgetManager.updateAppWidget(new ComponentName(context, WidgetProvider.class),
      views);

    if (isLightOn) {
      if (camera != null) {
        camera.stopPreview();
        camera.release();
        camera = null;
        isLightOn = false;
      }

    } else {
      camera = Camera.open();

      if (camera == null) {
        Toast.makeText(context, "No Camera!", Toast.LENGTH_SHORT).show();
      } else {
        Camera.Parameters param = camera.getParameters();
        param.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
        try {
          camera.setParameters(param);
          camera.startPreview();
          isLightOn = true;
        } catch (Exception e) {
          Toast.makeText(context, "No Flash!", Toast.LENGTH_SHORT).show();
        }
      }
    }
  }
}

Setup:

<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:minWidth="40dp"
    android:minHeight="40dp"
    android:maxWidth="40dp"
    android:maxHeight="40dp"
    android:updatePeriodMillis="86400000"
    android:initialLayout="@layout/appwidget_layout"
    android:resizeMode="horizontal|vertical">
</appwidget-provider>

Update: Reducing the update interval makes the widget refresh more often so if it's stuck it works again after 30 min and then it might freeze again sometime.

Update 2: Changing the date instantly freezes the widget until it's refreshed.

Update 3: Changing the date somehow restarts the launcher and whenever the launcher is restarted the widget freezes for 30 mins.

Muhammad Ali
  • 3,478
  • 5
  • 19
  • 30
  • Possible duplicate of [Widget not updated on launcher restart](https://stackoverflow.com/questions/6650553/widget-not-updated-on-launcher-restart) – userA789 Mar 19 '18 at 12:52

2 Answers2

6

Look for this post, I think this problem is explained here the dark side of app widgets

curioushikhov
  • 2,461
  • 2
  • 30
  • 44
  • 1
    Thanks, but the post talks about some OS bugs, most of the freezes we experience come from the app itself and are avoidable. – Alireza May 28 '15 at 07:55
4

Alright guys, I finally got time to fix this problem once and for all :)

I created more methods for the provider instead of doing everything in onUpdate, one important method needed:

    public static PendingIntent buildButtonPendingIntent(Context context) {
      Intent intent = new Intent();
      intent.setAction("COM_FLASHLIGHT");
      return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
    }

And this method is called through the receiver when the widget is clicked using the code below:

private void turnFlash(Context context) {
    RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.appwidget_layout);
    views.setOnClickPendingIntent(R.id.imageButton,       WidgetProvider.buildButtonPendingIntent(context));
}

That is all, no more hiccups!

Muhammad Ali
  • 3,478
  • 5
  • 19
  • 30
  • 2
    Refreshes the listener for the widget. – Muhammad Ali May 28 '15 at 04:15
  • 1
    Hi Mohamed, I know that the post from 2 years, but if you can provide me the the code after changes, or at least tell me where you call turnFlash ? I will be grateful so much. I am trying to build app widget but I am still not fully understand how it working so I hope you help me – Tefa Feb 02 '18 at 12:45
  • 2
    @MuhammadAli I'm seeing the same issue that you reported in this post. Can you please help me with it, how did you solve it. I'm already using the same approach that you used in the accepted answer. Did you do anything else to fix it? – Muhammad Mehdi Raza Nov 06 '18 at 16:57
  • @Jim do you eyes or buttons instead? The solution is right there. It worked for me, obviously if I was an expert on this matter and could explain everything I wouldn't be posting the question. Brag about what? I was happy I found the solution lol? – Muhammad Ali Jun 01 '19 at 17:26