From d8527a0f81da582e399abeaee303c1a52010fc32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ferreira?= Date: Mon, 25 Nov 2019 13:34:33 +0000 Subject: [PATCH 1/6] feat: listen to 2-finger long press and open ECT To avoid a breaking change, this feature will live side-by-side with the old code and only run on applications which were built on MABS 6 and above and thus only target SDK 29 and onwards, which provides the required version of the Broadcaster plugin. The breaking change would manifest due to the lack of proper release segmentation on this asset. Since this plugin always injected at the latest version of the respective O branch that means it is possible to have these changes running on an application built with MABS < 6. References https://outsystemsrd.atlassian.net/browse/RNMT-3515 --- src/android/OSAppFeedback.java | 108 ++++++++++++++++++++++----------- 1 file changed, 73 insertions(+), 35 deletions(-) diff --git a/src/android/OSAppFeedback.java b/src/android/OSAppFeedback.java index 6caa807..be1d5d1 100755 --- a/src/android/OSAppFeedback.java +++ b/src/android/OSAppFeedback.java @@ -1,12 +1,12 @@ package com.outsystems.plugins.appfeedback; -import android.app.Activity; -import android.preference.Preference; -import android.preference.PreferenceManager; -import android.support.v4.view.GestureDetectorCompat; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.Bundle; +import android.support.v4.content.LocalBroadcastManager; import android.support.v4.view.MotionEventCompat; -import android.util.Log; -import android.view.GestureDetector; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; @@ -14,18 +14,19 @@ import android.widget.LinearLayout; import android.widget.RelativeLayout; -import com.outsystems.android.mobileect.MobileECTController; import com.outsystems.android.mobileect.api.interfaces.OSECTProviderAPIHandler; +import com.outsystems.plugins.broadcaster.constants.Constants; +import com.outsystems.plugins.broadcaster.interfaces.Event; import org.apache.cordova.CallbackContext; import org.apache.cordova.CordovaActivity; import org.apache.cordova.CordovaPlugin; -import org.apache.cordova.CordovaPreferences; import org.apache.cordova.engine.SystemWebViewEngine; import org.json.JSONArray; import org.json.JSONException; import java.lang.ref.WeakReference; +import java.util.Map; import java.util.Timer; import java.util.TimerTask; @@ -242,39 +243,76 @@ public void execute(boolean result) { private void registerGestureHandler(){ final CordovaActivity cordovaActivity = (CordovaActivity) cordova.getActivity(); - webView.getView().setOnTouchListener(new View.OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - int action = MotionEventCompat.getActionMasked(event); - - if(event.getPointerCount() == 2) { - switch (action) { - case MotionEvent.ACTION_POINTER_DOWN: - mSecondFingerTimeDown = System.currentTimeMillis(); - mGestureRecognizerTimer = new Timer(); - mGestureRecognizerTimer.schedule(new GestureRecognizerTimedTask(cordovaActivity), INTERVAL_TO_SHOW_MENU); - break; - case MotionEvent.ACTION_POINTER_UP: - if ((System.currentTimeMillis() - mSecondFingerTimeDown) <= INTERVAL_TO_SHOW_MENU) { - mGestureRecognizerTimer.cancel(); - } - if ((System.currentTimeMillis() - mSecondFingerTimeDown) >= INTERVAL_TO_SHOW_MENU) { - mSecondFingerTimeDown = 0; + if(cordovaActivity.getApplicationInfo().targetSdkVersion >= 29) { + BroadcastReceiver broadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + Bundle extras = intent.getExtras(); + if(extras != null) { + Event gestureEvent = extras.getParcelable(Constants.GESTURE_EVENT); + if(gestureEvent != null) { + Map eventData = gestureEvent.getData(); + if(eventData != null) { + if(eventData.get(Constants.GESTURE_TYPE).equals(Constants.GESTURE_LONG_PRESS) && + eventData.get(Constants.GESTURE_NUMBER_FINGERS).equals(Constants.GESTURE_TWO_FINGERS)) { + cordovaActivity.runOnUiThread(new Runnable() { + @Override + public void run() { + appFeedbackListener.handleECTAvailable(new OSECTProviderAPIHandler() { + @Override + public void execute(boolean result) { + if(result) { + appFeedbackListener.handleOpenECT(null); + } + } + }); + } + }); + } } - break; + } } - } - else{ - if(mGestureRecognizerTimer != null){ - mGestureRecognizerTimer.cancel(); + }; + + LocalBroadcastManager.getInstance(this.cordova.getActivity().getApplicationContext()).registerReceiver(broadcastReceiver, new IntentFilter(Constants.GESTURE_EVENT)); + } + else { + webView.getView().setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + int action = MotionEventCompat.getActionMasked(event); + + if(event.getPointerCount() == 2) { + switch (action) { + case MotionEvent.ACTION_POINTER_DOWN: + mSecondFingerTimeDown = System.currentTimeMillis(); + mGestureRecognizerTimer = new Timer(); + mGestureRecognizerTimer.schedule(new GestureRecognizerTimedTask(cordovaActivity), INTERVAL_TO_SHOW_MENU); + break; + case MotionEvent.ACTION_POINTER_UP: + if ((System.currentTimeMillis() - mSecondFingerTimeDown) <= INTERVAL_TO_SHOW_MENU) { + mGestureRecognizerTimer.cancel(); + } + if ((System.currentTimeMillis() - mSecondFingerTimeDown) >= INTERVAL_TO_SHOW_MENU) { + mSecondFingerTimeDown = 0; + } + break; + } + + } + else{ + if(mGestureRecognizerTimer != null){ + mGestureRecognizerTimer.cancel(); + } + mSecondFingerTimeDown = 0; } - mSecondFingerTimeDown = 0; + + return webView.getView().onTouchEvent(event); } + }); + } - return webView.getView().onTouchEvent(event); - } - }); } } \ No newline at end of file From c004b26c47b7b4302a1766669a06a2158c06e198 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ferreira?= Date: Mon, 25 Nov 2019 13:52:39 +0000 Subject: [PATCH 2/6] docs: update CHANGELOG.md References https://outsystemsrd.atlassian.net/browse/RNMT-3515 --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 586aaf2..55c0773 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Additions +- Opens ECT through broadcast gestures when targeting Android 10 and above [RNMT-3515](https://outsystemsrd.atlassian.net/browse/RNMT-3515) ## [2.3.0] ### Additions From 0f00c07d453c89d2a07af3a66ea6dd9696ebb0d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ferreira?= Date: Mon, 25 Nov 2019 17:15:15 +0000 Subject: [PATCH 3/6] refactor: test equality on constant Avoids potential NPE. References https://outsystemsrd.atlassian.net/browse/RNMT-3515 --- src/android/OSAppFeedback.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/android/OSAppFeedback.java b/src/android/OSAppFeedback.java index be1d5d1..5bfbfed 100755 --- a/src/android/OSAppFeedback.java +++ b/src/android/OSAppFeedback.java @@ -253,8 +253,8 @@ public void onReceive(Context context, Intent intent) { if(gestureEvent != null) { Map eventData = gestureEvent.getData(); if(eventData != null) { - if(eventData.get(Constants.GESTURE_TYPE).equals(Constants.GESTURE_LONG_PRESS) && - eventData.get(Constants.GESTURE_NUMBER_FINGERS).equals(Constants.GESTURE_TWO_FINGERS)) { + if(Constants.GESTURE_LONG_PRESS.equals(eventData.get(Constants.GESTURE_TYPE)) && + Constants.GESTURE_TWO_FINGERS.equals(eventData.get(Constants.GESTURE_NUMBER_FINGERS))) { cordovaActivity.runOnUiThread(new Runnable() { @Override public void run() { From 71c03a953d29e944b6256144259b58a60f3bb231 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ferreira?= Date: Thu, 28 Nov 2019 17:02:06 +0000 Subject: [PATCH 4/6] fix: do not depend on Broadcaster constants This would cause a breaking change due to the way this plugin is (not) versioned. Bear in mind that these constants still mirror the ones in the Broadcaster plugin and should any of these be modified there such changes must be reflected here, lest this code start failing suddenly. References https://outsystemsrd.atlassian.net/browse/RNMT-3515 --- src/android/OSAppFeedback.java | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/android/OSAppFeedback.java b/src/android/OSAppFeedback.java index 5bfbfed..6a9cf28 100755 --- a/src/android/OSAppFeedback.java +++ b/src/android/OSAppFeedback.java @@ -15,7 +15,6 @@ import android.widget.RelativeLayout; import com.outsystems.android.mobileect.api.interfaces.OSECTProviderAPIHandler; -import com.outsystems.plugins.broadcaster.constants.Constants; import com.outsystems.plugins.broadcaster.interfaces.Event; import org.apache.cordova.CallbackContext; @@ -35,6 +34,18 @@ public class OSAppFeedback extends CordovaPlugin { private static final String DEFAULT_HOSTNAME = "DefaultHostname"; private static final String DEFAULT_HANDLER = "DefaultAppFeedbackHandler"; + // These constants match the ones defined in the Broadcaster plugin + // They are intended to use for MABS 6 only + // If any of these changes on Broadcaster plugin it should be reflected here + private static final String GESTURE_EVENT = "gestureEvent"; + private static final String GESTURE_TYPE = "gestureType"; + private static final String GESTURE_TAP = "gestureTap"; + private static final String GESTURE_LONG_PRESS = "gestureLongPress"; + private static final String GESTURE_NUMBER_FINGERS = "gestureNumberFingers"; + private static final String GESTURE_ONE_FINGER = "1"; + private static final String GESTURE_TWO_FINGERS = "2"; + private static final String GESTURE_THREE_FINGERS = "3"; + private OSAppFeedbackListener appFeedbackListener; private ViewGroup mainViewGroup; @@ -249,12 +260,12 @@ private void registerGestureHandler(){ public void onReceive(Context context, Intent intent) { Bundle extras = intent.getExtras(); if(extras != null) { - Event gestureEvent = extras.getParcelable(Constants.GESTURE_EVENT); + Event gestureEvent = extras.getParcelable(GESTURE_EVENT); if(gestureEvent != null) { Map eventData = gestureEvent.getData(); if(eventData != null) { - if(Constants.GESTURE_LONG_PRESS.equals(eventData.get(Constants.GESTURE_TYPE)) && - Constants.GESTURE_TWO_FINGERS.equals(eventData.get(Constants.GESTURE_NUMBER_FINGERS))) { + if(GESTURE_LONG_PRESS.equals(eventData.get(GESTURE_TYPE)) && + GESTURE_TWO_FINGERS.equals(eventData.get(GESTURE_NUMBER_FINGERS))) { cordovaActivity.runOnUiThread(new Runnable() { @Override public void run() { @@ -275,7 +286,7 @@ public void execute(boolean result) { } }; - LocalBroadcastManager.getInstance(this.cordova.getActivity().getApplicationContext()).registerReceiver(broadcastReceiver, new IntentFilter(Constants.GESTURE_EVENT)); + LocalBroadcastManager.getInstance(this.cordova.getActivity().getApplicationContext()).registerReceiver(broadcastReceiver, new IntentFilter(GESTURE_EVENT)); } else { webView.getView().setOnTouchListener(new View.OnTouchListener() { From e6a6d423634710b1d59e7904a782365bc66adbd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ferreira?= Date: Fri, 29 Nov 2019 14:29:29 +0000 Subject: [PATCH 5/6] fix: manage receiver in proper lifecycle callbacks This fix is twofold: 1) Unregisters the receiver which was not being done at all 2) Moves the register/unregister calls to the onStart and onStop lifecycle callbacks as per Android best practices References https://outsystemsrd.atlassian.net/browse/RNMT-3515 --- src/android/OSAppFeedback.java | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/src/android/OSAppFeedback.java b/src/android/OSAppFeedback.java index 6a9cf28..16799cb 100755 --- a/src/android/OSAppFeedback.java +++ b/src/android/OSAppFeedback.java @@ -1,5 +1,6 @@ package com.outsystems.plugins.appfeedback; +import android.app.Activity; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -50,6 +51,7 @@ public class OSAppFeedback extends CordovaPlugin { private ViewGroup mainViewGroup; private ViewGroup ectViewGroup; + private BroadcastReceiver broadcastReceiver; private boolean inBackground; private String defaultHostname; @@ -118,12 +120,30 @@ public void onResume(boolean multitasking) { inBackground = false; } + @Override + public void onStart() { + super.onStart(); + final Activity activity = this.cordova.getActivity(); + if(activity.getApplicationInfo().targetSdkVersion >= 29) { + LocalBroadcastManager.getInstance(activity.getApplicationContext()).registerReceiver(this.broadcastReceiver, new IntentFilter(GESTURE_EVENT)); + } + } + @Override public void onPause(boolean multitasking) { super.onPause(multitasking); inBackground = true; } + @Override + public void onStop() { + final Activity activity = this.cordova.getActivity(); + if(activity.getApplicationInfo().targetSdkVersion >= 29) { + LocalBroadcastManager.getInstance(activity.getApplicationContext()).unregisterReceiver(this.broadcastReceiver); + } + super.onStop(); + } + @Override public boolean execute(String action, JSONArray args, final CallbackContext callbackContext) throws JSONException { if (!inBackground) { @@ -255,7 +275,7 @@ private void registerGestureHandler(){ final CordovaActivity cordovaActivity = (CordovaActivity) cordova.getActivity(); if(cordovaActivity.getApplicationInfo().targetSdkVersion >= 29) { - BroadcastReceiver broadcastReceiver = new BroadcastReceiver() { + this.broadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { Bundle extras = intent.getExtras(); @@ -285,8 +305,6 @@ public void execute(boolean result) { } } }; - - LocalBroadcastManager.getInstance(this.cordova.getActivity().getApplicationContext()).registerReceiver(broadcastReceiver, new IntentFilter(GESTURE_EVENT)); } else { webView.getView().setOnTouchListener(new View.OnTouchListener() { From 20ef2ca7cef915494c338e404172b0f40440ea34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Ferreira?= Date: Fri, 29 Nov 2019 14:32:00 +0000 Subject: [PATCH 6/6] docs: update CHANGELOG.md References https://outsystemsrd.atlassian.net/browse/RNMT-3515 --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 55c0773..aac6da2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,9 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Fixes +- Register/unregister receiver in proper lifecycle callbacks [RNMT-3515](https://outsystemsrd.atlassian.net/browse/RNMT-3515) + ### Additions - Opens ECT through broadcast gestures when targeting Android 10 and above [RNMT-3515](https://outsystemsrd.atlassian.net/browse/RNMT-3515)