Browse files

Remove built-in log collection in favour of Log Collector.

  • Loading branch information...
1 parent dd0c09f commit e9917f1ffe93f9d9963463db849e3768beafccee @chrisboyle committed Sep 30, 2011
View
2 AndroidManifest.xml
@@ -15,8 +15,6 @@
android:anyDensity="true" />
<!-- For saved games -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- <!-- For crash reports -->
- <uses-permission android:name="android.permission.READ_LOGS" />
<application android:icon="@drawable/icon" android:label="@string/app_name" android:debuggable="true">
<activity android:name=".SGTPuzzles" android:windowSoftInputMode="adjustPan"
android:label="@string/app_name" android:stateNotNeeded="true" android:launchMode="singleTask" android:configChanges="keyboard|keyboardHidden|orientation|screenSize">
View
1 res/values/strings.xml
@@ -41,6 +41,7 @@ Revision: %s"</string>
<!-- {0} = version, {1} = device model number -->
<string name="email_subject">Puzzles v{0} on {1} / {2} / {3}</string>
<!-- Crash report dialog -->
+ <string name="prompt_install_log_collector">Install the free and open source Log Collector application to collect the device log and send it to the developer. I will launch it with appropriate options after you install.</string>
<string name="crash_subject">Crash: Puzzles v{0} on {1} / {2} / {3}</string>
<string name="crash_preamble">Please describe what you were doing just before the crash if possible, and then press Send:</string>
<string name="crashtitle">Well, this is embarrassing...</string>
View
128 src/name/boyle/chris/sgtpuzzles/CrashHandler.java
@@ -1,22 +1,33 @@
package name.boyle.chris.sgtpuzzles;
-import java.io.IOException;
-import java.text.MessageFormat;
+import java.util.List;
import android.app.Activity;
import android.app.AlertDialog;
-import android.app.ProgressDialog;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.content.SharedPreferences;
-import android.os.AsyncTask;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.net.Uri;
import android.os.Bundle;
+import android.os.PatternMatcher;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
-import android.widget.Toast;
public class CrashHandler extends Activity
{
- public static final String TAG = "CrashHandler";
+ public static final String LOG_COLLECTOR_PACKAGE_NAME = "com.xtralogic.android.logcollector";//$NON-NLS-1$
+ public static final String ACTION_SEND_LOG = "com.xtralogic.logcollector.intent.action.SEND_LOG";//$NON-NLS-1$
+ public static final String EXTRA_SEND_INTENT_ACTION = "com.xtralogic.logcollector.intent.extra.SEND_INTENT_ACTION";//$NON-NLS-1$
+ public static final String EXTRA_DATA = "com.xtralogic.logcollector.intent.extra.DATA";//$NON-NLS-1$
+ public static final String EXTRA_ADDITIONAL_INFO = "com.xtralogic.logcollector.intent.extra.ADDITIONAL_INFO";//$NON-NLS-1$
+ public static final String EXTRA_FILTER_SPECS = "com.xtralogic.logcollector.intent.extra.FILTER_SPECS";//$NON-NLS-1$
+ public static final String EXTRA_FORMAT = "com.xtralogic.logcollector.intent.extra.FORMAT";//$NON-NLS-1$
protected void onCreate(Bundle state)
{
super.onCreate(state);
@@ -26,59 +37,74 @@ protected void onCreate(Bundle state)
c = (Button)findViewById(R.id.close);
final CheckBox cl = (CheckBox)findViewById(R.id.forget);
b.setOnClickListener(new View.OnClickListener(){public void onClick(View v){
- final ProgressDialog progress = new ProgressDialog(CrashHandler.this);
- progress.setMessage(getString(R.string.getting_log));
- progress.setIndeterminate(true);
- progress.setCancelable(false);
- progress.show();
- final AsyncTask<Void, Void, Void> task = new AsyncTask<Void,Void,Void>(){
- String log;
- Process process;
- @Override
- protected Void doInBackground(Void... v) {
- try {
- process = Runtime.getRuntime().exec(new String[]{"logcat","-d","-v","threadtime"});
- log = SGTPuzzles.readAllOf(process.getInputStream());
- } catch (IOException e) {
- e.printStackTrace();
- Toast.makeText(CrashHandler.this, e.toString(), Toast.LENGTH_LONG).show();
- }
- return null;
- }
- @Override
- protected void onCancelled() {
- process.destroy();
- }
- @Override
- protected void onPostExecute(Void v) {
- progress.setMessage(getString(R.string.starting_email));
- boolean ok = SGTPuzzles.tryEmailAuthor(CrashHandler.this, true,
- getString(R.string.crash_preamble)+"\n\n\n\nLog:\n"+log);
- progress.dismiss();
- if (ok) {
- if (cl.isChecked()) clearState();
- finish();
- }
- }
- }.execute();
- b.postDelayed(new Runnable(){public void run(){
- if (task.getStatus() == AsyncTask.Status.FINISHED) return;
- // It's probably one of these devices where some fool broke logcat.
- progress.dismiss();
- task.cancel(true);
+ if (cl.isChecked()) clearState();
+ final PackageManager packageManager = getPackageManager();
+ final Intent intent = new Intent(ACTION_SEND_LOG);
+ List<ResolveInfo> list = packageManager.queryIntentActivities(intent,
+ PackageManager.MATCH_DEFAULT_ONLY);
+ final boolean isInstalled = list.size() > 0;
+ if (! isInstalled) {
+ IntentFilter i = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
+ i.addDataScheme("package");
+ i.addDataPath(LOG_COLLECTOR_PACKAGE_NAME, PatternMatcher.PATTERN_LITERAL);
+ registerReceiver(new BroadcastReceiver() {
+ @Override public void onReceive(Context context, Intent intent) {
+ // User has just installed Log Collector - let's start
+ // it, with specific options, before they get tempted to
+ // click "Open" themselves with no options and no
+ // destination
+ sendLog();
+ unregisterReceiver(this);
+ }}, i);
new AlertDialog.Builder(CrashHandler.this)
- .setMessage(MessageFormat.format(getString(R.string.get_log_failed), getString(R.string.author_email)))
- .setCancelable(true)
- .setIcon(android.R.drawable.ic_dialog_alert)
- .show();
- }}, 3000);
+ .setTitle(getString(R.string.app_name))
+ .setIcon(android.R.drawable.ic_dialog_info)
+ .setMessage(R.string.prompt_install_log_collector)
+ .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener(){
+ public void onClick(DialogInterface dialog, int whichButton){
+ Intent marketIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + LOG_COLLECTOR_PACKAGE_NAME));
+ marketIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ startActivity(marketIntent);
+ }
+ })
+ .setNegativeButton(android.R.string.cancel, null)
+ .show();
+ } else {
+ sendLog();
+ }
}});
c.setOnClickListener(new View.OnClickListener(){public void onClick(View v){
if (cl.isChecked()) clearState();
finish();
}});
}
+ protected void sendLog()
+ {
+ Intent intent = new Intent(ACTION_SEND_LOG);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.putExtra(EXTRA_SEND_INTENT_ACTION, Intent.ACTION_SENDTO);
+ intent.putExtra(EXTRA_DATA, Uri.parse("mailto:" + getString(R.string.author_email)));
+ intent.putExtra(EXTRA_ADDITIONAL_INFO, getString(R.string.crash_preamble)+"\n\n\n");
+ intent.putExtra(Intent.EXTRA_SUBJECT, SGTPuzzles.getEmailSubject(this, true));
+
+ intent.putExtra(EXTRA_FORMAT, "threadtime");
+
+ String[] filterSpecs = new String[] {
+ "AndroidRuntime:E",
+ SGTPuzzles.TAG + ":V",
+ "DEBUG:I",
+ "System.err:V",
+ //"dalvikvm:D",
+ //"ActivityManager:I",
+ "WindowManager:I",
+ "*:S",
+ };
+ intent.putExtra(EXTRA_FILTER_SPECS, filterSpecs);
+
+ startActivity(intent);
+ }
+
void clearState()
{
SharedPreferences.Editor ed = getSharedPreferences("state", MODE_PRIVATE).edit();
View
20 src/name/boyle/chris/sgtpuzzles/SGTPuzzles.java
@@ -380,21 +380,24 @@ private void about()
messageBox(title, msg, 0);
}
- static boolean tryEmailAuthor(Context c, boolean isCrash, String body)
+ static String getEmailSubject(Context c, boolean isCrash)
{
- String addr = c.getString(R.string.author_email);
- Intent i = new Intent(Intent.ACTION_SEND);
String modVer = "";
try {
Process p = Runtime.getRuntime().exec(new String[]{"getprop","ro.modversion"});
modVer = readAllOf(p.getInputStream()).trim();
} catch (Exception e) {}
if (modVer.length() == 0) modVer = "original";
- // second empty address because of http://code.google.com/p/k9mail/issues/detail?id=589
- i.putExtra(Intent.EXTRA_EMAIL, new String[]{addr, ""});
- i.putExtra(Intent.EXTRA_SUBJECT, MessageFormat.format(c.getString(
- isCrash ? R.string.crash_subject : R.string.email_subject),
- getVersion(c), Build.MODEL, modVer, Build.FINGERPRINT));
+ return MessageFormat.format(c.getString(
+ isCrash ? R.string.crash_subject : R.string.email_subject),
+ getVersion(c), Build.MODEL, modVer, Build.FINGERPRINT);
+ }
+
+ static boolean tryEmailAuthor(Context c, boolean isCrash, String body)
+ {
+ Intent i = new Intent(Intent.ACTION_SEND);
+ i.putExtra(Intent.EXTRA_EMAIL, new String[]{c.getString(R.string.author_email)});
+ i.putExtra(Intent.EXTRA_SUBJECT, getEmailSubject(c, isCrash));
i.setType("message/rfc822");
i.putExtra(Intent.EXTRA_TEXT, body!=null ? body : "");
try {
@@ -777,6 +780,7 @@ void nativeCrashed()
}
new RuntimeException("crashed here (native trace should follow after the Java trace)").printStackTrace();
startActivity(new Intent(this, CrashHandler.class));
+ finish();
}
static String readAllOf(InputStream s) throws IOException

0 comments on commit e9917f1

Please sign in to comment.