Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use Intent.ACTION_APP_ERROR as a means for a "feedback" framework in Android?

I would like to reuse the Intent.ACTION_BUG_REPORT in my app, as a simple means of getting user feedback.

Google Maps uses it as their "Feedback" option. But I've not been successful in firing the event.

I'm using the following in a onOptionsItemSelected(MenuItem item):

    Intent intent = new Intent(Intent.ACTION_BUG_REPORT);
    startActivity(intent);

And in my AndroidManifest.xml I've declared the following under my Activity:

    <intent-filter>
       <action android:name="android.intent.action.BUG_REPORT" />
       <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>

However, nothing seems to happen besides the screen "blink" when I select the option. The App or intent doesn't crash, it doesn't log anything. Tried it both in the Emulator and on an ICS 4.0.4 device.

I'm clealy missing something, but what?

Edit

Intent.ACTION_APP_ERROR (constant android.intent.action.BUG_REPORT) was added in API level 14, http://developer.android.com/reference/android/content/Intent.html#ACTION_APP_ERROR

like image 352
kaderud Avatar asked May 11 '12 22:05

kaderud


2 Answers

This was solved with the help from the link in @TomTasche comment above. Use built-in feedback mechanism on Android.

In my AndroidManifest.xml I added the following to the <Activity> where I want to call the Feedback agent from.

<intent-filter>
   <action android:name="android.intent.action.APP_ERROR" />
   <category android:name="android.intent.category.DEFAULT" />
</intent-filter>

And I made a simple method called sendFeedback() (code from TomTasche blogpost)

@SuppressWarnings("unused")
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
private void sendFeedback() {
    try {
        int i = 3 / 0;
    } catch (Exception e) {
    ApplicationErrorReport report = new ApplicationErrorReport();
    report.packageName = report.processName = getApplication().getPackageName();
    report.time = System.currentTimeMillis();
    report.type = ApplicationErrorReport.TYPE_CRASH;
    report.systemApp = false;

    ApplicationErrorReport.CrashInfo crash = new ApplicationErrorReport.CrashInfo();
    crash.exceptionClassName = e.getClass().getSimpleName();
    crash.exceptionMessage = e.getMessage();

    StringWriter writer = new StringWriter();
    PrintWriter printer = new PrintWriter(writer);
    e.printStackTrace(printer);

    crash.stackTrace = writer.toString();

    StackTraceElement stack = e.getStackTrace()[0];
    crash.throwClassName = stack.getClassName();
    crash.throwFileName = stack.getFileName();
    crash.throwLineNumber = stack.getLineNumber();
    crash.throwMethodName = stack.getMethodName();

    report.crashInfo = crash;

    Intent intent = new Intent(Intent.ACTION_APP_ERROR);
    intent.putExtra(Intent.EXTRA_BUG_REPORT, report);
    startActivity(intent);
    }
}

And from my SettingsActivity I call it like:

      findPreference(sFeedbackKey).setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
          public final boolean onPreferenceClick(Preference paramAnonymousPreference) {
              sendFeedback();
              finish();
              return true;
          }
      });         

Verified working with Android 2.3.7 and 4.2.2.

When the sendFeedback() method is called, a "Complete action using"-dialog is opened where the user can select from three actions/icons.

Complete action using

The calling app, which returns to the app, and Google Play and the Feedback agent. Selecting either Google Play Storeor Send feedback will open the built-in Android feedback agent as intended.

Send feedback

I haven't investigated further if it's possible to skip the "Complete action using"-step, it's probably possible with the correct parameters passed to the Intent. So far, this does exactly what I wanted for now.

like image 149
kaderud Avatar answered Oct 13 '22 23:10

kaderud


Please don't mix two different intents Intent.ACTION_BUG_REPORT and Intent.ACTION_APP_ERROR. The first one is designed for old error reporting and feedback and it's supported from API v1. The second one is for sending advanced error reports (supports ApplicationErrorReport object where you can store a lot of useful informations) and was added in API v14.

For sending feedback, I am testing bellow code in my new version of APP (it also create a screenshot of the activity). This starts com.google.android.gms.feedback.FeedbackActivity, which is part of Google Play services. But question is where then I'll find the feedbacks?!

protected void sendFeedback(Activity activity) {
    activity.bindService(new Intent(Intent.ACTION_BUG_REPORT), new FeedbackServiceConnection(activity.getWindow()), BIND_AUTO_CREATE);
}

protected static class FeedbackServiceConnection implements ServiceConnection {
    private static int MAX_WIDTH = 600;
    private static int MAX_HEIGHT = 600;

    protected final Window mWindow;

    public FeedbackServiceConnection(Window window) {
        this.mWindow = window;
    }

    public void onServiceConnected(ComponentName name, IBinder service) {
        try {
            Parcel parcel = Parcel.obtain();
            Bitmap bitmap = getScreenshot();
            if (bitmap != null) {
                bitmap.writeToParcel(parcel, 0);
            }
            service.transact(IBinder.FIRST_CALL_TRANSACTION, parcel, null, 0);
            parcel.recycle();
        } catch (RemoteException e) {
            Log.e("ServiceConn", e.getMessage(), e);
        }
    }

    public void onServiceDisconnected(ComponentName name) { }

    private Bitmap getScreenshot() {
        try {
            View rootView = mWindow.getDecorView().getRootView();
            rootView.setDrawingCacheEnabled(true);
            Bitmap bitmap = rootView.getDrawingCache();
            if (bitmap != null)
            {
                double height = bitmap.getHeight();
                double width = bitmap.getWidth();
                double ratio = Math.min(MAX_WIDTH / width, MAX_HEIGHT / height);
                return Bitmap.createScaledBitmap(bitmap, (int)Math.round(width * ratio), (int)Math.round(height * ratio), true);
            }
        } catch (Exception e) {
            Log.e("Screenshoter", "Error getting current screenshot: ", e);
        }
        return null;
    }
}
like image 23
Arcao Avatar answered Oct 13 '22 21:10

Arcao