Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Android] Remaster feedback widgets #412

Open
wants to merge 7 commits into
base: staging
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
## XX.XX.XX
* The feedback widgets now have transparent backgrounds for a cleaner look.

* Mitigated an issue where visibility could have been wrongly assigned if a view was closed while going to background. (Experimental!)

* Deprecated "presentFeedbackWidget(widgetInfo, context, closeButtonText, devCallback)", replaced with "presentFeedbackWidget(widgetInfo, context, devCallback)" in the feedbacks.

## 24.7.5
* ! Minor breaking change ! All active views will now automatically stop when consent for "views" is revoked.

Expand Down
91 changes: 52 additions & 39 deletions sdk/src/main/java/ly/count/android/sdk/ModuleFeedback.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Handler;
import android.os.Looper;
import android.webkit.WebSettings;
Expand Down Expand Up @@ -173,7 +172,7 @@ static List<CountlyFeedbackWidget> parseFeedbackList(JSONObject requestResponse)
return parsedRes;
}

void presentFeedbackWidgetInternal(@Nullable final CountlyFeedbackWidget widgetInfo, @Nullable final Context context, @Nullable final String closeButtonText, @Nullable final FeedbackCallback devCallback) {
void presentFeedbackWidgetInternal(@Nullable final CountlyFeedbackWidget widgetInfo, @Nullable final Context context, @Nullable final FeedbackCallback devCallback) {
if (widgetInfo == null) {
L.e("[ModuleFeedback] Can't present widget with null widget info");

Expand Down Expand Up @@ -245,6 +244,8 @@ void presentFeedbackWidgetInternal(@Nullable final CountlyFeedbackWidget widgetI
JSONObject customObjectToSendWithTheWidget = new JSONObject();
try {
customObjectToSendWithTheWidget.put("tc", 1);
customObjectToSendWithTheWidget.put("rw", 1);
customObjectToSendWithTheWidget.put("xb", 1);
} catch (JSONException e) {
throw new RuntimeException(e);
}
Expand All @@ -257,8 +258,6 @@ void presentFeedbackWidgetInternal(@Nullable final CountlyFeedbackWidget widgetI

//enable for chrome debugging
//WebView.setWebContentsDebuggingEnabled(true);

final boolean useAlertDialog = true;
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
public void run() {
Expand All @@ -267,27 +266,46 @@ public void run() {
try {

ModuleRatings.RatingDialogWebView webView = new ModuleRatings.RatingDialogWebView(context);

webView.getSettings().setJavaScriptEnabled(true);
webView.clearCache(true);
webView.clearHistory();
webView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);
webView.setWebViewClient(new ModuleRatings.FeedbackDialogWebViewClient());
ModuleRatings.FeedbackDialogWebViewClient webViewClient = new ModuleRatings.FeedbackDialogWebViewClient();
webView.setWebViewClient(webViewClient);
webView.loadUrl(preparedWidgetUrl);
webView.requestFocus();

AlertDialog.Builder builder = prepareAlertDialog(context, webView, closeButtonText, widgetInfo, devCallback);
AlertDialog alert = new AlertDialog.Builder(context).setView(webView).setCancelable(false).create();
alert.getWindow().setBackgroundDrawableResource(android.R.color.transparent);
alert.getWindow().setDimAmount(0f);

if (useAlertDialog) {
// use alert dialog to host the webView
L.d("[ModuleFeedback] Creating standalone Alert dialog");
builder.show();
} else {
// use dialog fragment to host the webView
L.d("[ModuleFeedback] Creating Alert dialog in dialogFragment");
webViewClient.listener = new WebViewUrlListener() {
@Override
public boolean onUrl(String url, WebView webView) {
if (!url.startsWith(Utils.COMM_URL)) {
return false;
}

//CountlyDialogFragment newFragment = CountlyDialogFragment.newInstance(builder);
//newFragment.show(fragmentManager, "CountlyFragmentDialog");
}
Map<String, String> params = Utils.splitIntoParams(url, L);
String widgetCommand = params.get("cly_widget_command");

if ("1".equals(widgetCommand)) {
String close = params.get("close");
if ("1".equals(close)) {
if (devCallback != null) {
devCallback.onFinished(null);
}
reportFeedbackWidgetCancelButton(widgetInfo, cachedAppVersion);
alert.cancel();
return true;
}
}

return false;
}
};
alert.show();

if (devCallback != null) {
devCallback.onFinished(null);
Expand All @@ -302,27 +320,6 @@ public void run() {
});
}

AlertDialog.Builder prepareAlertDialog(@NonNull final Context context, @NonNull WebView webView, @Nullable String closeButtonText, @NonNull final CountlyFeedbackWidget widgetInfo, @Nullable final FeedbackCallback devCallback) {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setView(webView);
builder.setCancelable(false);
String usedCloseButtonText = closeButtonText;
if (closeButtonText == null || closeButtonText.isEmpty()) {
usedCloseButtonText = "Close";
}
builder.setNeutralButton(usedCloseButtonText, new DialogInterface.OnClickListener() {
@Override public void onClick(DialogInterface dialogInterface, int i) {
L.d("[ModuleFeedback] Cancel button clicked for the feedback widget");
reportFeedbackWidgetCancelButton(widgetInfo, deviceInfo.mp.getAppVersion(context));

if (devCallback != null) {
devCallback.onClosed();
}
}
});
return builder;
}

void reportFeedbackWidgetCancelButton(@NonNull CountlyFeedbackWidget widgetInfo, @NonNull String appVersion) {
L.d("[reportFeedbackWidgetCancelButton] Cancel button event");
if (consentProvider.getConsent(Countly.CountlyFeatureNames.feedback)) {
Expand Down Expand Up @@ -643,7 +640,7 @@ private void presentFeedbackWidgetNameIDorTag(@NonNull Context context, @NonNull
return;
}

presentFeedbackWidgetInternal(selectedWidget, context, null, devCallback);
presentFeedbackWidgetInternal(selectedWidget, context, devCallback);
}
});
}
Expand Down Expand Up @@ -679,12 +676,28 @@ public void getAvailableFeedbackWidgets(@Nullable RetrieveFeedbackWidgets callba
* @param context
* @param closeButtonText if this is null, no "close" button will be shown
* @param devCallback
* @deprecated use {@link #presentFeedbackWidget(CountlyFeedbackWidget, Context, FeedbackCallback)} instead
*/
public void presentFeedbackWidget(@Nullable CountlyFeedbackWidget widgetInfo, @Nullable Context context, @Nullable String closeButtonText, @Nullable FeedbackCallback devCallback) {
synchronized (_cly) {
L.i("[Feedback] Trying to present feedback widget in an alert dialog");

presentFeedbackWidgetInternal(widgetInfo, context, closeButtonText, devCallback);
presentFeedbackWidget(widgetInfo, context, devCallback);
}
}

/**
* Present a chosen feedback widget in an alert dialog
*
* @param widgetInfo the widget to present
* @param context the context to use for displaying the feedback widget
* @param devCallback callback to be called when the feedback widget is closed
*/
public void presentFeedbackWidget(@Nullable CountlyFeedbackWidget widgetInfo, @Nullable Context context, @Nullable FeedbackCallback devCallback) {
synchronized (_cly) {
L.i("[Feedback] Trying to present feedback widget in an alert dialog");

presentFeedbackWidgetInternal(widgetInfo, context, devCallback);
}
}

Expand Down
9 changes: 9 additions & 0 deletions sdk/src/main/java/ly/count/android/sdk/ModuleRatings.java
Original file line number Diff line number Diff line change
Expand Up @@ -564,10 +564,19 @@ public boolean onCheckIsTextEditor() {
}

static class FeedbackDialogWebViewClient extends WebViewClient {

WebViewUrlListener listener;

@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
String url = request.getUrl().toString();

if (listener != null) {
if (listener.onUrl(url, view)) {
return true;
}
}

// Filter out outgoing calls
if (url.endsWith("cly_x_int=1")) {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ public class TransparentActivity extends Activity {
static final String CONFIGURATION_LANDSCAPE = "Landscape";
static final String CONFIGURATION_PORTRAIT = "Portrait";
static final String ORIENTATION = "orientation";
private static final String URL_START = "https://countly_action_event";
int currentOrientation = 0;
TransparentActivityConfig configLandscape = null;
TransparentActivityConfig configPortrait = null;
Expand Down Expand Up @@ -64,14 +63,14 @@ protected void onCreate(Bundle savedInstanceState) {
int height = config.height;

configLandscape.listeners.add((url, webView) -> {
if (url.startsWith(URL_START)) {
if (url.startsWith(Utils.COMM_URL)) {
return contentUrlAction(url, configLandscape, webView);
}
return false;
});

configPortrait.listeners.add((url, webView) -> {
if (url.startsWith(URL_START)) {
if (url.startsWith(Utils.COMM_URL)) {
return contentUrlAction(url, configPortrait, webView);
}
return false;
Expand Down
4 changes: 4 additions & 0 deletions sdk/src/main/java/ly/count/android/sdk/Utils.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@
import static android.content.Context.UI_MODE_SERVICE;

public class Utils {
/**
* This is a communication url between web views and the SDK
*/
protected static final String COMM_URL = "https://countly_action_event";
private static final ExecutorService bg = Executors.newSingleThreadExecutor();

public static Future<?> runInBackground(Runnable runnable) {
Expand Down
Loading