From ac0746b9b9f8102213fee36d0375dafc6e8e81d2 Mon Sep 17 00:00:00 2001 From: EddyVerbruggen Date: Fri, 15 Jan 2016 13:12:03 +0100 Subject: [PATCH] #65 Success callback not triggered when toast tapped in Android --- README.md | 2 + package.json | 2 +- plugin.xml | 2 +- src/android/nl/xservices/plugins/Toast.java | 110 ++++++++++++++++---- 4 files changed, 94 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 4aa5fe5..b28d3ef 100644 --- a/README.md +++ b/README.md @@ -217,6 +217,8 @@ The Android code was entirely created by me. For iOS most credits go to this excellent [Toast for iOS project by Charles Scalesse] (https://github.com/scalessec/Toast). ## 6. CHANGELOG +2.3.2: The click event introduced with 2.3.0 did not work with Android 5+. + 2.3.0: The plugin will now report back to JS if Toasts were tapped by the user. 2.0.1: iOS messages are hidden when another one is shown. [Thanks Richie Min!](https://github.com/EddyVerbruggen/Toast-PhoneGap-Plugin/pull/13) diff --git a/package.json b/package.json index 5a5d7b0..8e6cae3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cordova-plugin-x-toast", - "version": "2.3.1", + "version": "2.3.2", "description": "This plugin allows you to show a Toast. A Toast is a little non intrusive buttonless popup which automatically disappears.", "cordova": { "id": "cordova-plugin-x-toast", diff --git a/plugin.xml b/plugin.xml index a1fff4b..4ea80a7 100755 --- a/plugin.xml +++ b/plugin.xml @@ -2,7 +2,7 @@ + version="2.3.2"> Toast diff --git a/src/android/nl/xservices/plugins/Toast.java b/src/android/nl/xservices/plugins/Toast.java index ec5cdae..dc58576 100644 --- a/src/android/nl/xservices/plugins/Toast.java +++ b/src/android/nl/xservices/plugins/Toast.java @@ -4,6 +4,7 @@ import android.os.Build; import android.view.Gravity; import android.view.MotionEvent; import android.view.View; +import android.view.ViewGroup; import org.apache.cordova.CallbackContext; import org.apache.cordova.CordovaPlugin; @@ -27,7 +28,14 @@ public class Toast extends CordovaPlugin { private static final String ACTION_SHOW_EVENT = "show"; private static final String ACTION_HIDE_EVENT = "hide"; + private static final int GRAVITY_TOP = Gravity.TOP|Gravity.CENTER_HORIZONTAL; + private static final int GRAVITY_CENTER = Gravity.CENTER_VERTICAL|Gravity.CENTER_HORIZONTAL; + private static final int GRAVITY_BOTTOM = Gravity.BOTTOM|Gravity.CENTER_HORIZONTAL; + + private static final int BASE_TOP_BOTTOM_OFFSET = 20; + private android.widget.Toast mostRecentToast; + private ViewGroup viewGroup; private static final boolean IS_AT_LEAST_ANDROID5 = Build.VERSION.SDK_INT >= 21; @@ -39,6 +47,7 @@ public class Toast extends CordovaPlugin { if (ACTION_HIDE_EVENT.equals(action)) { if (mostRecentToast != null) { mostRecentToast.cancel(); + getViewGroup().setOnTouchListener(null); } callbackContext.success(); return true; @@ -59,7 +68,7 @@ public class Toast extends CordovaPlugin { cordova.getActivity().runOnUiThread(new Runnable() { public void run() { - android.widget.Toast toast = android.widget.Toast.makeText( + final android.widget.Toast toast = android.widget.Toast.makeText( IS_AT_LEAST_ANDROID5 ? cordova.getActivity().getWindow().getContext() : cordova.getActivity().getApplicationContext(), message, "short".equals(duration) ? android.widget.Toast.LENGTH_SHORT : android.widget.Toast.LENGTH_LONG); @@ -71,35 +80,74 @@ public class Toast extends CordovaPlugin { // } catch (Exception ignore) { // } if ("top".equals(position)) { - toast.setGravity(Gravity.TOP|Gravity.CENTER_HORIZONTAL, 0, 20 + addPixelsY); + toast.setGravity(GRAVITY_TOP, 0, BASE_TOP_BOTTOM_OFFSET + addPixelsY); } else if ("bottom".equals(position)) { - toast.setGravity(Gravity.BOTTOM|Gravity.CENTER_HORIZONTAL, 0, 20 - addPixelsY); + toast.setGravity(GRAVITY_BOTTOM, 0, BASE_TOP_BOTTOM_OFFSET - addPixelsY); } else if ("center".equals(position)) { - toast.setGravity(Gravity.CENTER_VERTICAL|Gravity.CENTER_HORIZONTAL, 0, addPixelsY); + toast.setGravity(GRAVITY_CENTER, 0, addPixelsY); } else { callbackContext.error("invalid position. valid options are 'top', 'center' and 'bottom'"); return; } - toast.getView().setOnTouchListener(new View.OnTouchListener() { - @Override - public boolean onTouch(View view, MotionEvent motionEvent) { - if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) { - JSONObject json = new JSONObject(); - try { - json.put("event", "touch"); - json.put("message", message); - json.put("data", data); - } catch (JSONException e) { - e.printStackTrace(); + // On Android >= 5 you can no longer rely on the 'toast.getView().setOnTouchListener', + // so created something funky that compares the Toast position to the tap coordinates. + if (IS_AT_LEAST_ANDROID5) { + getViewGroup().setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View view, MotionEvent motionEvent) { + if (motionEvent.getAction() != MotionEvent.ACTION_DOWN) { + return false; + } + if (mostRecentToast == null || !mostRecentToast.getView().isShown()) { + getViewGroup().setOnTouchListener(null); + return false; + } + + float w = mostRecentToast.getView().getWidth(); + float startX = (view.getWidth() / 2) - (w / 2); + float endX = (view.getWidth() / 2) + (w / 2); + + float startY; + float endY; + + float g = mostRecentToast.getGravity(); + float y = mostRecentToast.getYOffset(); + float h = mostRecentToast.getView().getHeight(); + + if (g == GRAVITY_BOTTOM) { + startY = view.getHeight() - y - h; + endY = view.getHeight() - y; + } else if (g == GRAVITY_CENTER) { + startY = (view.getHeight() / 2) + y - (h / 2); + endY = (view.getHeight() / 2) + y + (h / 2); + } else { + // top + startY = y; + endY = y + h; + } + + float tapX = motionEvent.getX(); + float tapY = motionEvent.getY(); + + final boolean tapped = tapX >= startX && tapX <= endX && + tapY >= startY && tapY <= endY; + + if (tapped) { + getViewGroup().setOnTouchListener(null); + return returnTapEvent(message, data, callbackContext); } - callbackContext.success(json); - return true; - } else { return false; } - } - }); + }); + } else { + toast.getView().setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View view, MotionEvent motionEvent) { + return motionEvent.getAction() == MotionEvent.ACTION_DOWN && returnTapEvent(message, data, callbackContext); + } + }); + } toast.show(); mostRecentToast = toast; @@ -117,10 +165,32 @@ public class Toast extends CordovaPlugin { } } + private boolean returnTapEvent(String message, JSONObject data, CallbackContext callbackContext) { + final JSONObject json = new JSONObject(); + try { + json.put("event", "touch"); + json.put("message", message); + json.put("data", data); + } catch (JSONException e) { + e.printStackTrace(); + } + callbackContext.success(json); + return true; + } + + // lazy init and caching + private ViewGroup getViewGroup() { + if (viewGroup == null) { + viewGroup = (ViewGroup) ((ViewGroup) cordova.getActivity().findViewById(android.R.id.content)).getChildAt(0); + } + return viewGroup; + } + @Override public void onPause(boolean multitasking) { if (mostRecentToast != null) { mostRecentToast.cancel(); + getViewGroup().setOnTouchListener(null); } this.isPaused = true; }