diff --git a/Catlog/AndroidManifest.xml b/Catlog/AndroidManifest.xml
index 7af230c..e8be9ca 100644
--- a/Catlog/AndroidManifest.xml
+++ b/Catlog/AndroidManifest.xml
@@ -9,13 +9,18 @@
-
+
-
-
+
+
+
+
+
+
+
diff --git a/Catlog/src/com/nolanlawson/logcat/LogcatActivity.java b/Catlog/src/com/nolanlawson/logcat/LogcatActivity.java
index 0ba30ec..c70ac1d 100644
--- a/Catlog/src/com/nolanlawson/logcat/LogcatActivity.java
+++ b/Catlog/src/com/nolanlawson/logcat/LogcatActivity.java
@@ -13,9 +13,12 @@
import android.app.AlertDialog.Builder;
import android.app.ListActivity;
import android.app.ProgressDialog;
+import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ResolveInfo;
import android.content.res.ColorStateList;
import android.graphics.drawable.ColorDrawable;
import android.os.AsyncTask;
@@ -95,9 +98,9 @@ public class LogcatActivity extends ListActivity implements TextWatcher, OnScrol
// how many suggestions to keep in the autosuggestions text
private static final int MAX_NUM_SUGGESTIONS = 1000;
- // id for context menu entry
- private static final int CONTEXT_MENU_FILTER_ID = 0;
- private static final int CONTEXT_MENU_COPY_ID = 1;
+ // id for context menu entry
+ private static final int CONTEXT_MENU_FILTER_ID = 0;
+ private static final int CONTEXT_MENU_COPY_ID = 1;
private static UtilLogger log = new UtilLogger(LogcatActivity.class);
@@ -237,33 +240,96 @@ public void onClick(DialogInterface dialog, int which) {
private void doAfterInitialMessage(Intent intent) {
// handle an intent that was sent from an external application
-
- if (intent != null && Intents.ACTION_LAUNCH.equals(intent.getAction())) {
-
- String filter = intent.getStringExtra(Intents.EXTRA_FILTER);
- String level = intent.getStringExtra(Intents.EXTRA_LEVEL);
-
- if (!TextUtils.isEmpty(filter)) {
- silentlySetSearchText(filter);
- }
-
-
- if (!TextUtils.isEmpty(level)) {
- CharSequence[] logLevels = getResources().getStringArray(R.array.log_levels_values);
- int logLevelLimit = ArrayUtil.indexOf(logLevels, level.toUpperCase(Locale.US));
-
- if (logLevelLimit == -1) {
- String invalidLevel = String.format(getString(R.string.toast_invalid_level), level);
- Toast.makeText(this, invalidLevel, Toast.LENGTH_LONG).show();
- } else {
- adapter.setLogLevelLimit(logLevelLimit);
- logLevelChanged();
- }
-
+
+ if (intent == null) {
+ return;
+ }
+
+ if (Intents.ACTION_LAUNCH.equals(intent.getAction())) {
+ processLaunchIntent(intent);
+ return;
+ }
+
+ if (Intents.ACTION_SEND_EMAIL.equals(intent.getAction())) {
+ processSendMailIntent(intent);
+ return;
+ }
+ }
+
+ private void processLaunchIntent(Intent intent) {
+
+ String filter = intent.getStringExtra(Intents.EXTRA_FILTER);
+ String level = intent.getStringExtra(Intents.EXTRA_LEVEL);
+
+ if (!TextUtils.isEmpty(filter)) {
+ silentlySetSearchText(filter);
+ }
+
+ if (!TextUtils.isEmpty(level)) {
+ CharSequence[] logLevels = getResources().getStringArray(R.array.log_levels_values);
+ int logLevelLimit = ArrayUtil.indexOf(logLevels, level.toUpperCase(Locale.US));
+
+ if (logLevelLimit == -1) {
+ String invalidLevel = String.format(getString(R.string.toast_invalid_level), level);
+ Toast.makeText(this, invalidLevel, Toast.LENGTH_LONG).show();
+ } else {
+ adapter.setLogLevelLimit(logLevelLimit);
+ logLevelChanged();
}
}
}
+ private void processSendMailIntent(Intent intent) {
+
+ // Get and check the "extra" info provided by the app that created the Intent
+ String[] mailRecipients = intent.getStringArrayExtra(Intents.EXTRA_MAIL_RECIPIENTS);
+ String mailService = intent.getStringExtra(Intents.EXTRA_MAIL_SERVICE);
+ String mailSubject = intent.getStringExtra(Intents.EXTRA_MAIL_SUBJECT);
+ boolean mailDeviceInfo = intent.getBooleanExtra(Intents.EXTRA_MAIL_DEVICE_INFO, false);
+ boolean mailAttachment = intent.getBooleanExtra(Intents.EXTRA_MAIL_ATTACHMENT, false);
+
+ if (mailRecipients.length < 1 || TextUtils.isEmpty(mailRecipients[0]) ||
+ TextUtils.isEmpty(mailService)) {
+ return;
+ }
+ if (TextUtils.isEmpty(mailSubject)) {
+ mailSubject = getString(R.string.subject_log_report);
+ }
+
+ // Despite the name of the method, this is NOT done on a background thread when this is
+ // launched via an Intent from external app
+ SendLogDetails sendLogDetails =
+ getSendLogDetailsInBackground(!mailAttachment, mailDeviceInfo);
+
+ // Get list of all apps that can handle sending text or files
+ List resolveInfoAllAvailable = getPackageManager().queryIntentActivities(
+ SenderAppAdapter.createDummyIntent(sendLogDetails.getAttachmentType()), 0);
+
+ // Filter to find the app that is specified by the Intent's "service" extra info
+ List activityInfoMatches = new ArrayList();
+ for (ResolveInfo resolveInfo : resolveInfoAllAvailable) {
+ if ((resolveInfo.activityInfo.name.toLowerCase()).contains(mailService.toLowerCase())) {
+ activityInfoMatches.add(resolveInfo.activityInfo);
+ }
+ }
+
+ // Ensure only one matches, ignore if ambiguous
+ if (activityInfoMatches.size() != 1) {
+ return;
+ }
+ ActivityInfo activityInfo = activityInfoMatches.get(0);
+
+ // Launch the email app
+ ComponentName componentName = new ComponentName(activityInfo.applicationInfo.packageName,
+ activityInfo.name);
+ Intent actionSendIntent = SenderAppAdapter.createSendIntent(mailSubject,
+ sendLogDetails.getBody(),
+ sendLogDetails.getAttachmentType(),
+ sendLogDetails.getAttachment());
+ actionSendIntent.putExtra(Intent.EXTRA_EMAIL, mailRecipients);
+ actionSendIntent.setComponent(componentName);
+ startActivity(actionSendIntent);
+ }
@Override
public void onResume() {
@@ -1051,7 +1117,7 @@ private SendLogDetails getSendLogDetailsInBackground(boolean asText, boolean inc
if (includeDeviceInfo) {
// include device info
- String deviceInfo = BuildHelper.getBuildInformationAsString();
+ String deviceInfo = BuildHelper.getBuildInformationAsString(this);
if (asText) {
// append to top of body
body.append(deviceInfo).append('\n');
diff --git a/Catlog/src/com/nolanlawson/logcat/data/SenderAppAdapter.java b/Catlog/src/com/nolanlawson/logcat/data/SenderAppAdapter.java
index 661adf3..8094dc0 100644
--- a/Catlog/src/com/nolanlawson/logcat/data/SenderAppAdapter.java
+++ b/Catlog/src/com/nolanlawson/logcat/data/SenderAppAdapter.java
@@ -151,17 +151,15 @@ private void filter(List apps) {
/**
* Create an intent just for querying available apps.
- * @param moreThanOneAttachment
- * @return
*/
- private static Intent createDummyIntent(SendLogDetails.AttachmentType attachmentType) {
+ public static Intent createDummyIntent(SendLogDetails.AttachmentType attachmentType) {
Intent actionSendIntent = new Intent(android.content.Intent.ACTION_SEND);
actionSendIntent.setType(attachmentType.getMimeType());
return actionSendIntent;
}
- private static Intent createSendIntent(String subject, String body, SendLogDetails.AttachmentType attachmentType, File attachment) {
+ public static Intent createSendIntent(String subject, String body, SendLogDetails.AttachmentType attachmentType, File attachment) {
String action = android.content.Intent.ACTION_SEND;
Intent actionSendIntent = new Intent(action);
diff --git a/Catlog/src/com/nolanlawson/logcat/helper/BuildHelper.java b/Catlog/src/com/nolanlawson/logcat/helper/BuildHelper.java
index d4889d7..ccdd7b0 100644
--- a/Catlog/src/com/nolanlawson/logcat/helper/BuildHelper.java
+++ b/Catlog/src/com/nolanlawson/logcat/helper/BuildHelper.java
@@ -7,7 +7,9 @@
import java.util.SortedMap;
import java.util.TreeMap;
+import android.app.Activity;
import android.os.Build;
+import android.provider.Settings;
public class BuildHelper {
@@ -21,8 +23,12 @@ public class BuildHelper {
// public static final Strings of android.os.Build.Version
private static final List BUILD_VERSION_FIELDS = Arrays.asList(
"CODENAME", "INCREMENTAL", "RELEASE", "SDK_INT");
-
- public static String getBuildInformationAsString() {
+
+ // public static final Strings of android.provider.Settings.Secure (String values only)
+ private static final List SETTINGS_SECURE_CONSTANTS = Arrays.asList(
+ Settings.Secure.ANDROID_ID);
+
+ public static String getBuildInformationAsString(Activity androidActivity) {
SortedMap keysToValues = new TreeMap();
for (String buildField : BUILD_FIELDS) {
@@ -31,19 +37,22 @@ public static String getBuildInformationAsString() {
for (String buildVersionField : BUILD_VERSION_FIELDS) {
putKeyValue(Build.VERSION.class, buildVersionField, keysToValues);
}
-
- StringBuilder stringBuilder = new StringBuilder();
+ for (String settingsSecureConstant : SETTINGS_SECURE_CONSTANTS) {
+ putSettingsSecure(androidActivity, settingsSecureConstant, keysToValues);
+ }
+
+ StringBuilder stringBuilder = new StringBuilder();
for (Entry entry : keysToValues.entrySet()) {
stringBuilder.append(entry.getKey()).append(": ").append(entry.getValue()).append('\n');
}
return stringBuilder.toString();
}
- private static void putKeyValue(Class> clazz, String buildField, SortedMap keysToValues) {
+ private static void putKeyValue(Class> clazz, String fieldName, SortedMap keysToValues) {
try {
- Field field = clazz.getField(buildField);
+ Field field = clazz.getField(fieldName);
Object value = field.get(null);
- String key = clazz.getSimpleName().toLowerCase() + "." + buildField.toLowerCase();
+ String key = clazz.getSimpleName().toLowerCase() + "." + fieldName.toLowerCase();
keysToValues.put(key, String.valueOf(value));
} catch (SecurityException e) {
// ignore
@@ -53,5 +62,15 @@ private static void putKeyValue(Class> clazz, String buildField, SortedMap keysToValues) {
+ try {
+ Object value = Settings.Secure.getString(androidActivity.getContentResolver(), constantName);
+ String key = "settings.secure" + "." + constantName.toLowerCase();
+ keysToValues.put(key, String.valueOf(value));
+ } catch (Exception e) {
+ // ignore
+ }
+ }
}
diff --git a/Catlog/src/com/nolanlawson/logcat/intents/Intents.java b/Catlog/src/com/nolanlawson/logcat/intents/Intents.java
index 51a4cc3..657f89e 100644
--- a/Catlog/src/com/nolanlawson/logcat/intents/Intents.java
+++ b/Catlog/src/com/nolanlawson/logcat/intents/Intents.java
@@ -2,8 +2,24 @@
public class Intents {
+ // NB. ACTION_LAUNCH and ACTION_SEND_EMAIL must match specifications in the manifest
+
public static final String ACTION_LAUNCH = "com.nolanlawson.logcat.intents.LAUNCH";
public static final String EXTRA_FILTER = "filter";
public static final String EXTRA_LEVEL = "level";
-
+
+
+ public static final String ACTION_SEND_EMAIL = "com.nolanlawson.logcat.intents.SEND_EMAIL";
+
+ // String array of email addresses, at least one must be specified
+ public static final String EXTRA_MAIL_RECIPIENTS = "recipients";
+
+ // Service can be "gmail" or "email" or something else that uniquely identifies the service
+ public static final String EXTRA_MAIL_SERVICE = "service";
+
+ public static final String EXTRA_MAIL_SUBJECT = "subject"; // String, optional
+
+ public static final String EXTRA_MAIL_DEVICE_INFO = "device_info"; // Boolean
+
+ public static final String EXTRA_MAIL_ATTACHMENT = "attachment"; // Boolean, false = in-body
}