private void showNewError( final String message, final StackFrame[] stack, final int errorCookie) { UiThreadUtil.runOnUiThread( new Runnable() { @Override public void run() { if (mRedBoxDialog == null) { mRedBoxDialog = new RedBoxDialog(mApplicationContext, DevSupportManagerImpl.this); mRedBoxDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); } if (mRedBoxDialog.isShowing()) { // Sometimes errors cause multiple errors to be thrown in JS in quick succession. Only // show the first and most actionable one. return; } mRedBoxDialog.setExceptionDetails(message, stack); mRedBoxDialog.setErrorCookie(errorCookie); mRedBoxDialog.show(); } }); }
@Override public View getView(int position, View convertView, ViewGroup parent) { if (position == 0) { TextView title = convertView != null ? (TextView) convertView : (TextView) LayoutInflater.from(parent.getContext()) .inflate(R.layout.redbox_item_title, parent, false); title.setText(mTitle); return title; } else { if (convertView == null) { convertView = LayoutInflater.from(parent.getContext()) .inflate(R.layout.redbox_item_frame, parent, false); convertView.setTag(new FrameViewHolder(convertView)); } StackFrame frame = mStack[position - 1]; FrameViewHolder holder = (FrameViewHolder) convertView.getTag(); holder.mMethodView.setText(frame.getMethod()); holder.mFileView.setText(frame.getFileName() + ":" + frame.getLine()); return convertView; } }
@Override protected Void doInBackground(StackFrame... stackFrames) { try { String openStackFrameUrl = Uri.parse(mDevSupportManager.getSourceUrl()).buildUpon() .path("/open-stack-frame") .query(null) .build() .toString(); OkHttpClient client = new OkHttpClient(); for (StackFrame frame: stackFrames) { String payload = stackFrameToJson(frame).toString(); RequestBody body = RequestBody.create(JSON, payload); Request request = new Request.Builder().url(openStackFrameUrl).post(body).build(); client.newCall(request).execute(); } } catch (Exception e) { FLog.e(ReactConstants.TAG, "Could not open stack frame", e); } return null; }
@Override public View getView(int position, View convertView, ViewGroup parent) { if (position == 0) { TextView title = convertView != null ? (TextView) convertView : (TextView) LayoutInflater.from(parent.getContext()) .inflate(R.layout.redbox_item_title, parent, false); title.setText(mTitle); return title; } else { if (convertView == null) { convertView = LayoutInflater.from(parent.getContext()) .inflate(R.layout.redbox_item_frame, parent, false); convertView.setTag(new FrameViewHolder(convertView)); } StackFrame frame = mStack[position - 1]; FrameViewHolder holder = (FrameViewHolder) convertView.getTag(); holder.mMethodView.setText(frame.getMethod()); final int column = frame.getColumn(); final String columnString = column < 0 ? "" : ":" + column; holder.mFileView.setText(frame.getFileName() + ":" + frame.getLine() + columnString); return convertView; } }
@Override public void handleException(Exception e) { if (mIsDevSupportEnabled) { if (e instanceof JSException) { FLog.e(ReactConstants.TAG, "Exception in native call from JS", e); // TODO #11638796: convert the stack into something useful showNewError( e.getMessage() + "\n\n" + ((JSException) e).getStack(), new StackFrame[] {}, JSEXCEPTION_ERROR_COOKIE, ErrorType.JS); } else { showNewJavaError(e.getMessage(), e); } } else { mDefaultNativeModuleCallExceptionHandler.handleException(e); } }
@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)); }
@Override public View getView(int position, View convertView, ViewGroup parent) { if (position == 0) { TextView title = convertView != null ? (TextView) convertView : (TextView) LayoutInflater.from(parent.getContext()) .inflate(R.layout.redbox_item_title, parent, false); title.setText(mTitle); return title; } else { if (convertView == null) { convertView = LayoutInflater.from(parent.getContext()) .inflate(R.layout.redbox_item_frame, parent, false); convertView.setTag(new FrameViewHolder(convertView)); } StackFrame frame = mStack[position - 1]; FrameViewHolder holder = (FrameViewHolder) convertView.getTag(); holder.mMethodView.setText(frame.getMethod()); holder.mFileView.setText(StackTraceHelper.formatFrameSource(frame)); return convertView; } }
private static JSONObject stackFrameToJson(StackFrame frame) { return new JSONObject( MapBuilder.of( "file", frame.getFile(), "methodName", frame.getMethod(), "lineNumber", frame.getLine(), "column", frame.getColumn() )); }
@Override public void updateJSError( final String message, final ReadableArray details, final int errorCookie) { UiThreadUtil.runOnUiThread( new Runnable() { @Override public void run() { // Since we only show the first JS error in a succession of JS errors, make sure we only // update the error message for that error message. This assumes that updateJSError // belongs to the most recent showNewJSError if (mRedBoxDialog == null || !mRedBoxDialog.isShowing() || errorCookie != mLastErrorCookie) { return; } StackFrame[] stack = StackTraceHelper.convertJsStackTrace(details); mRedBoxDialog.setExceptionDetails(message, stack); updateLastErrorInfo(message, stack, errorCookie, ErrorType.JS); // JS errors are reported here after source mapping. if (mRedBoxHandler != null) { mRedBoxHandler.handleRedbox(message, stack, RedBoxHandler.ErrorType.JS); mRedBoxDialog.resetReporting(true); } mRedBoxDialog.show(); } }); }
private void showNewError( final String message, final StackFrame[] stack, final int errorCookie, final ErrorType errorType) { UiThreadUtil.runOnUiThread( new Runnable() { @Override public void run() { if (mRedBoxDialog == null) { mRedBoxDialog = new RedBoxDialog(mApplicationContext, DevSupportManagerImpl.this, mRedBoxHandler); mRedBoxDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); } if (mRedBoxDialog.isShowing()) { // Sometimes errors cause multiple errors to be thrown in JS in quick succession. Only // show the first and most actionable one. return; } mRedBoxDialog.setExceptionDetails(message, stack); updateLastErrorInfo(message, stack, errorCookie, errorType); // Only report native errors here. JS errors are reported // inside {@link #updateJSError} after source mapping. if (mRedBoxHandler != null && errorType == ErrorType.NATIVE) { mRedBoxHandler.handleRedbox(message, stack, RedBoxHandler.ErrorType.NATIVE); mRedBoxDialog.resetReporting(true); } else { mRedBoxDialog.resetReporting(false); } mRedBoxDialog.show(); } }); }
private void updateLastErrorInfo( final String message, final StackFrame[] stack, final int errorCookie, final ErrorType errorType) { mLastErrorTitle = message; mLastErrorStack = stack; mLastErrorCookie = errorCookie; mLastErrorType = errorType; }
public StackAdapter(String title, StackFrame[] stack) { mTitle = title; mStack = stack; }
public void setExceptionDetails(String title, StackFrame[] stack) { mStackView.setAdapter(new StackAdapter(title, stack)); }
@Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { new OpenStackFrameTask(mDevSupportManager).executeOnExecutor( AsyncTask.THREAD_POOL_EXECUTOR, (StackFrame) mStackView.getAdapter().getItem(position)); }
@Override public @Nullable StackFrame[] getLastErrorStack() { return mLastErrorStack; }
/** * Report the information from the redbox and set up a callback listener. */ void reportRedbox( String title, StackFrame[] stack, String sourceUrl, ReportCompletedListener reportCompletedListener);
@Override public @Nullable StackFrame[] getLastErrorStack() { return null; }
/** * Handle the information from the redbox. */ void handleRedbox(String title, StackFrame[] stack, ErrorType errorType);
@Nullable StackFrame[] getLastErrorStack();