Skip to content

Commit

Permalink
Add Report Button for Android Redbox, enabled in Ads Manager, Groups …
Browse files Browse the repository at this point in the history
…and FB4A

Reviewed By: foghina

Differential Revision: D3542780

fbshipit-source-id: a0dfb8b8af7a5ae0ca696e84ec4b8795a293c26f
  • Loading branch information
Siqi Liu authored and Facebook Github Bot 6 committed Aug 1, 2016
1 parent 42fc2e8 commit 75e404b
Show file tree
Hide file tree
Showing 5 changed files with 186 additions and 14 deletions.
Expand Up @@ -252,6 +252,7 @@ public void run() {
// JS errors are reported here after source mapping. // JS errors are reported here after source mapping.
if (mRedBoxHandler != null) { if (mRedBoxHandler != null) {
mRedBoxHandler.handleRedbox(message, stack, RedBoxHandler.ErrorType.JS); mRedBoxHandler.handleRedbox(message, stack, RedBoxHandler.ErrorType.JS);
mRedBoxDialog.resetReporting(true);
} }
mRedBoxDialog.show(); mRedBoxDialog.show();
} }
Expand All @@ -276,7 +277,7 @@ private void showNewError(
@Override @Override
public void run() { public void run() {
if (mRedBoxDialog == null) { if (mRedBoxDialog == null) {
mRedBoxDialog = new RedBoxDialog(mApplicationContext, DevSupportManagerImpl.this); mRedBoxDialog = new RedBoxDialog(mApplicationContext, DevSupportManagerImpl.this, mRedBoxHandler);
mRedBoxDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); mRedBoxDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
} }
if (mRedBoxDialog.isShowing()) { if (mRedBoxDialog.isShowing()) {
Expand All @@ -290,6 +291,9 @@ public void run() {
// inside {@link #updateJSError} after source mapping. // inside {@link #updateJSError} after source mapping.
if (mRedBoxHandler != null && errorType == ErrorType.NATIVE) { if (mRedBoxHandler != null && errorType == ErrorType.NATIVE) {
mRedBoxHandler.handleRedbox(message, stack, RedBoxHandler.ErrorType.NATIVE); mRedBoxHandler.handleRedbox(message, stack, RedBoxHandler.ErrorType.NATIVE);
mRedBoxDialog.resetReporting(true);
} else {
mRedBoxDialog.resetReporting(false);
} }
mRedBoxDialog.show(); mRedBoxDialog.show();
} }
Expand Down
Expand Up @@ -9,10 +9,15 @@


package com.facebook.react.devsupport; package com.facebook.react.devsupport;


import javax.annotation.Nullable;

import android.app.Dialog; import android.app.Dialog;
import android.content.Context; import android.content.Context;
import android.graphics.Color;
import android.net.Uri; import android.net.Uri;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.text.SpannedString;
import android.text.method.LinkMovementMethod;
import android.view.KeyEvent; import android.view.KeyEvent;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
Expand All @@ -22,6 +27,7 @@
import android.widget.BaseAdapter; import android.widget.BaseAdapter;
import android.widget.Button; import android.widget.Button;
import android.widget.ListView; import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView; import android.widget.TextView;


import com.facebook.common.logging.FLog; import com.facebook.common.logging.FLog;
Expand All @@ -30,6 +36,7 @@
import com.facebook.react.common.MapBuilder; import com.facebook.react.common.MapBuilder;
import com.facebook.react.common.ReactConstants; import com.facebook.react.common.ReactConstants;
import com.facebook.react.devsupport.StackTraceHelper.StackFrame; import com.facebook.react.devsupport.StackTraceHelper.StackFrame;
import com.facebook.react.devsupport.RedBoxHandler.ReportCompletedListener;


import okhttp3.MediaType; import okhttp3.MediaType;
import okhttp3.OkHttpClient; import okhttp3.OkHttpClient;
Expand All @@ -44,11 +51,59 @@


private final DevSupportManager mDevSupportManager; private final DevSupportManager mDevSupportManager;
private final DoubleTapReloadRecognizer mDoubleTapReloadRecognizer; private final DoubleTapReloadRecognizer mDoubleTapReloadRecognizer;
private final @Nullable RedBoxHandler mRedBoxHandler;


private ListView mStackView; private ListView mStackView;
private Button mReloadJs; private Button mReloadJsButton;
private Button mDismiss; private Button mDismissButton;
private Button mCopyToClipboard; private Button mCopyToClipboardButton;
private @Nullable Button mReportButton;
private @Nullable TextView mReportTextView;
private @Nullable ProgressBar mLoadingIndicator;
private @Nullable View mLineSeparator;
private boolean isReporting = false;

private ReportCompletedListener mReportCompletedListener = new ReportCompletedListener() {
@Override
public void onReportSuccess(final SpannedString spannedString) {
isReporting = false;
Assertions.assertNotNull(mReportButton).setEnabled(true);
Assertions.assertNotNull(mLoadingIndicator).setVisibility(View.GONE);
Assertions.assertNotNull(mReportTextView).setText(spannedString);
}
@Override
public void onReportError(final SpannedString spannedString) {
isReporting = false;
Assertions.assertNotNull(mReportButton).setEnabled(true);
Assertions.assertNotNull(mLoadingIndicator).setVisibility(View.GONE);
Assertions.assertNotNull(mReportTextView).setText(spannedString);
}
};

private View.OnClickListener mReportButtonOnClickListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
if (mRedBoxHandler == null || !mRedBoxHandler.isReportEnabled() || isReporting) {
return;
}
isReporting = true;
Assertions.assertNotNull(mReportTextView).setText("Reporting...");
Assertions.assertNotNull(mReportTextView).setVisibility(View.VISIBLE);
Assertions.assertNotNull(mLoadingIndicator).setVisibility(View.VISIBLE);
Assertions.assertNotNull(mLineSeparator).setVisibility(View.VISIBLE);
Assertions.assertNotNull(mReportButton).setEnabled(false);

String title = Assertions.assertNotNull(mDevSupportManager.getLastErrorTitle());
StackFrame[] stack = Assertions.assertNotNull(mDevSupportManager.getLastErrorStack());
String sourceUrl = mDevSupportManager.getSourceUrl();

mRedBoxHandler.reportRedbox(
title,
stack,
sourceUrl,
Assertions.assertNotNull(mReportCompletedListener));
}
};


private static class StackAdapter extends BaseAdapter { private static class StackAdapter extends BaseAdapter {
private static final int VIEW_TYPE_COUNT = 2; private static final int VIEW_TYPE_COUNT = 2;
Expand Down Expand Up @@ -203,7 +258,10 @@ protected Void doInBackground(String... clipBoardString) {
} }
} }


protected RedBoxDialog(Context context, DevSupportManager devSupportManager) { protected RedBoxDialog(
Context context,
DevSupportManager devSupportManager,
@Nullable RedBoxHandler redBoxHandler) {
super(context, R.style.Theme_Catalyst_RedBox); super(context, R.style.Theme_Catalyst_RedBox);


requestWindowFeature(Window.FEATURE_NO_TITLE); requestWindowFeature(Window.FEATURE_NO_TITLE);
Expand All @@ -212,25 +270,27 @@ protected RedBoxDialog(Context context, DevSupportManager devSupportManager) {


mDevSupportManager = devSupportManager; mDevSupportManager = devSupportManager;
mDoubleTapReloadRecognizer = new DoubleTapReloadRecognizer(); mDoubleTapReloadRecognizer = new DoubleTapReloadRecognizer();
mRedBoxHandler = redBoxHandler;


mStackView = (ListView) findViewById(R.id.rn_redbox_stack); mStackView = (ListView) findViewById(R.id.rn_redbox_stack);
mStackView.setOnItemClickListener(this); mStackView.setOnItemClickListener(this);
mReloadJs = (Button) findViewById(R.id.rn_redbox_reload_button);
mReloadJs.setOnClickListener(new View.OnClickListener() { mReloadJsButton = (Button) findViewById(R.id.rn_redbox_reload_button);
mReloadJsButton.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
mDevSupportManager.handleReloadJS(); mDevSupportManager.handleReloadJS();
} }
}); });
mDismiss = (Button) findViewById(R.id.rn_redbox_dismiss_button); mDismissButton = (Button) findViewById(R.id.rn_redbox_dismiss_button);
mDismiss.setOnClickListener(new View.OnClickListener() { mDismissButton.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
dismiss(); dismiss();
} }
}); });
mCopyToClipboard = (Button) findViewById(R.id.rn_redbox_copy_button); mCopyToClipboardButton = (Button) findViewById(R.id.rn_redbox_copy_button);
mCopyToClipboard.setOnClickListener(new View.OnClickListener() { mCopyToClipboardButton.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
String title = mDevSupportManager.getLastErrorTitle(); String title = mDevSupportManager.getLastErrorTitle();
Expand All @@ -242,12 +302,38 @@ public void onClick(View v) {
StackTraceHelper.formatStackTrace(title, stack)); StackTraceHelper.formatStackTrace(title, stack));
} }
}); });

if (mRedBoxHandler != null && mRedBoxHandler.isReportEnabled()) {
mLoadingIndicator = (ProgressBar) findViewById(R.id.rn_redbox_loading_indicator);
mLineSeparator = (View) findViewById(R.id.rn_redbox_line_separator);
mReportTextView = (TextView) findViewById(R.id.rn_redbox_report_label);
mReportTextView.setMovementMethod(LinkMovementMethod.getInstance());
mReportTextView.setHighlightColor(Color.TRANSPARENT);
mReportButton = (Button) findViewById(R.id.rn_redbox_report_button);
mReportButton.setOnClickListener(mReportButtonOnClickListener);
}
} }


public void setExceptionDetails(String title, StackFrame[] stack) { public void setExceptionDetails(String title, StackFrame[] stack) {
mStackView.setAdapter(new StackAdapter(title, stack)); mStackView.setAdapter(new StackAdapter(title, stack));
} }


/**
* Show the report button, hide the report textview and the loading indicator.
*/
public void resetReporting(boolean enabled) {
if (mRedBoxHandler == null || !mRedBoxHandler.isReportEnabled()) {
return;
}
isReporting = false;
Assertions.assertNotNull(mReportTextView).setVisibility(View.GONE);
Assertions.assertNotNull(mLoadingIndicator).setVisibility(View.GONE);
Assertions.assertNotNull(mLineSeparator).setVisibility(View.GONE);
Assertions.assertNotNull(mReportButton).setVisibility(
enabled ? View.VISIBLE : View.GONE);
Assertions.assertNotNull(mReportButton).setEnabled(true);
}

@Override @Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) { public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
new OpenStackFrameTask(mDevSupportManager).executeOnExecutor( new OpenStackFrameTask(mDevSupportManager).executeOnExecutor(
Expand Down
Expand Up @@ -9,12 +9,14 @@


package com.facebook.react.devsupport; package com.facebook.react.devsupport;


import android.text.SpannedString;

import com.facebook.react.devsupport.StackTraceHelper.StackFrame; import com.facebook.react.devsupport.StackTraceHelper.StackFrame;


/** /**
* Interface used by {@link DevSupportManagerImpl} to allow interception on any redboxes * Interface used by {@link DevSupportManagerImpl} to allow interception on any redboxes
* during development and handling the information from the redbox. * during development and handling the information from the redbox.
* The implementation should be passed by {@link #setRedBoxHandler} in {@link ReactInstanceManager}. * The implementation should be passed by setRedBoxHandler in ReactInstanceManager.
*/ */
public interface RedBoxHandler { public interface RedBoxHandler {
enum ErrorType { enum ErrorType {
Expand All @@ -29,5 +31,31 @@ public String getName() {
return name; return name;
} }
} }

/**
* Callback interface for {@link #reportRedbox}.
*/
interface ReportCompletedListener {
void onReportSuccess(SpannedString spannedString);
void onReportError(SpannedString spannedString);
}

/**
* Handle the information from the redbox.
*/
void handleRedbox(String title, StackFrame[] stack, ErrorType errorType); void handleRedbox(String title, StackFrame[] stack, ErrorType errorType);

/**
* Whether the report feature is enabled.
*/
boolean isReportEnabled();

/**
* Report the information from the redbox and set up a callback listener.
*/
void reportRedbox(
String title,
StackFrame[] stack,
String sourceUrl,
ReportCompletedListener reportCompletedListener);
} }
53 changes: 53 additions & 0 deletions ReactAndroid/src/main/res/devsupport/layout/redbox_view.xml
Expand Up @@ -11,6 +11,42 @@
android:layout_height="0dp" android:layout_height="0dp"
android:layout_weight="1" android:layout_weight="1"
/> />
<View
android:id="@+id/rn_redbox_line_separator"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@android:color/darker_gray"
android:visibility="gone"
/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
<ProgressBar
android:id="@+id/rn_redbox_loading_indicator"
android:layout_width="wrap_content"
android:layout_height="match_parent"
style="@android:style/Widget.ProgressBar.Small"
android:indeterminateOnly="true"
android:visibility="gone"
android:paddingLeft="16dp"
/>
<TextView
android:id="@+id/rn_redbox_report_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@android:color/white"
android:textSize="14sp"
android:fontFamily="monospace"
android:visibility="gone"
android:paddingTop="16dp"
android:paddingBottom="16dp"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:lineSpacingExtra="4dp"
/>
</LinearLayout>
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
Expand All @@ -27,6 +63,7 @@
android:textSize="14sp" android:textSize="14sp"
android:alpha="0.5" android:alpha="0.5"
style="?android:attr/borderlessButtonStyle" style="?android:attr/borderlessButtonStyle"
android:gravity="center_horizontal|top"
/> />
<Button <Button
android:id="@+id/rn_redbox_reload_button" android:id="@+id/rn_redbox_reload_button"
Expand All @@ -39,6 +76,7 @@
android:textSize="14sp" android:textSize="14sp"
android:alpha="0.5" android:alpha="0.5"
style="?android:attr/borderlessButtonStyle" style="?android:attr/borderlessButtonStyle"
android:gravity="center_horizontal|top"
/> />
<Button <Button
android:id="@+id/rn_redbox_copy_button" android:id="@+id/rn_redbox_copy_button"
Expand All @@ -51,6 +89,21 @@
android:textSize="14sp" android:textSize="14sp"
android:alpha="0.5" android:alpha="0.5"
style="?android:attr/borderlessButtonStyle" style="?android:attr/borderlessButtonStyle"
android:gravity="center_horizontal|top"
/>
<Button
android:id="@+id/rn_redbox_report_button"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_margin="4dp"
android:text="@string/catalyst_report_button"
android:textColor="@android:color/white"
android:textSize="14sp"
android:alpha="0.5"
style="?android:attr/borderlessButtonStyle"
android:visibility="gone"
android:gravity="center_horizontal|top"
/> />
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>
5 changes: 3 additions & 2 deletions ReactAndroid/src/main/res/devsupport/values/strings.xml
Expand Up @@ -18,7 +18,8 @@
<string name="catalyst_remotedbg_error" project="catalyst" translatable="false">Unable to connect with remote debugger</string> <string name="catalyst_remotedbg_error" project="catalyst" translatable="false">Unable to connect with remote debugger</string>
<string name="catalyst_element_inspector" project="catalyst" translatable="false">Toggle Inspector</string> <string name="catalyst_element_inspector" project="catalyst" translatable="false">Toggle Inspector</string>
<string name="catalyst_heap_capture" project="catalyst" translatable="false">Capture Heap</string> <string name="catalyst_heap_capture" project="catalyst" translatable="false">Capture Heap</string>
<string name="catalyst_dismiss_button" project="catalyst" translatable="false">Dismiss (ESC)</string> <string name="catalyst_dismiss_button" project="catalyst" translatable="false">Dismiss\n(ESC)</string>
<string name="catalyst_reload_button" project="catalyst" translatable="false">Reload (R,\u00A0R)</string> <string name="catalyst_reload_button" project="catalyst" translatable="false">Reload\n(R,\u00A0R)</string>
<string name="catalyst_copy_button" project="catalyst" translatable="false">Copy</string> <string name="catalyst_copy_button" project="catalyst" translatable="false">Copy</string>
<string name="catalyst_report_button" project="catalyst" translatable="false">Report</string>
</resources> </resources>

0 comments on commit 75e404b

Please sign in to comment.