How to have your AppWidget handle double-clicks, triple-clicks, quadrouple-clicks, etc.
I see some other people had trouble with this and I did not see any good solutions anywhere. I came up with my own and recently added it to EmWeather. It works very well, it may not be the best way - it seemed awkward at first but actually it makes sense. I would love to hear if anyone else has any other solutions. The basic setup is as follows: - You set your widget/widget component so that when it is clicked it triggers an intent with a "click" action. - You allow your widget to receive two types of intent actions, a "click" action and a "clicktimeout" action. Both of these actions just fall through to the same Service. If you receive a "clicktimeout" you set a specific flag for the service to differentiate between which action called the service. - In the service, each time you receive a "click", you augment a global variable and you set up a "clicktimeout" intent that will be sent to your widget 200ms (or whatever you want the click-timeout to be) in the future. - In the service, when you receive a "clicktimeout", you see how many times the widget was clicked before the timeout happened, reset the counter, then process the single, double, triple, etc. click. What happens: - When the widget is clicked, the num_clicks variable is augmented and an alarm is set for 200ms in the future - If the widget is clicked BEFORE the alarm goes off, the click variable is augmented again, and the alarm is *reset* for 200ms in the future. - (Repeat) - If the alarm goes off, you know how many clicks were made! I find 200ms works really well, if you find that is too fast, try 250ms. Going much higher than that starts to add some noticeable lag. Below is the abbreviated code. Full source for my implementation is available on the EmWeather project page. Hope this helps! /* In AppWidget Code */ public void onReceive(Context context, Intent intent) { final String action = intent.getAction(); if ((intent.getAction().equals("com.EmWeather.EmWeather.EmWeatherWidget.click"))) { int appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1); Intent click_service_intent = new Intent(context, WidgetClickerService.class); click_service_intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId); click_service_intent.putExtra(WidgetClickerService.TIME_UP, false); context.startService(click_service_intent); } else if ((intent.getAction().equals("com.EmWeather.EmWeather.EmWeatherWidget.clicktimeout"))) { int appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1); Intent click_service_intent = new Intent(context, WidgetClickerService.class); click_service_intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId); click_service_intent.putExtra(WidgetClickerService.TIME_UP, true); context.startService(click_service_intent); } super.onReceive(context, intent); } /*..... * In Service Code */ public static String TIME_UP = "time_up"; public static int CLICK_TIMEOUT = 200; //max time between clicks for double or triple-click, in ms private int num_clicks; private int last_appWidgetId; @Override public void onCreate() { num_clicks = 0; last_appWidgetId = -1; } @Override public void onStart(Intent intent, int startId) { Context context = getApplicationContext(); int appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1); boolean time_up = intent.getBooleanExtra(WidgetClickerService.TIME_UP, false); if (time_up) { switch(num_clicks) { case 0: break; case 1: process_single_click(); break; case 2: process_double_click(); break; case 3: default: process_triple_click(); break; } num_clicks = 0; return; } if (last_appWidgetId != appWidgetId) { //This is a different appWidget then last time num_clicks = 0; last_appWidgetId = appWidgetId; } num_clicks++; //Set up the intent for the alarm timeout Intent click_clear_intent = new Intent("com.EmWeather.EmWeather.EmWeatherWidget.clicktimeout", Uri.withAppendedPath(Uri.parse(WIDGET_SCHEME + "://widget/id/"), String.valueOf(appWidgetId))); click_clear_intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId); PendingIntent click_clear_pending = PendingIntent.getBroadcast(context, 0, click_clear_intent, PendingIntent.FLAG_CANCEL_CURRENT); AlarmManager alarms = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); //Set this to the last number of clicks you want to receive - ie. if we don't care about quadruple-clicks, there's no point allowing //the user to do more. Cancel the alarm we have set. if (3 <= num_clicks) { alarms.cancel(click_clear_pending); process_triple_click(appWidgetId, schema, intent_action_prefix, widget_config_class); return; } alarms.set(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + CLICK_TIMEOUT, click_clear_pending); } -- You received this message because you are subscribed to the Google Groups "Android Developers" group. To post to this group, send email to android-developers@googlegroups.com To unsubscribe from this group, send email to android-developers+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/android-developers?hl=en