From 4ce51dc06903cb84c924d7da9e3d9a2e9a0c1691 Mon Sep 17 00:00:00 2001 From: Rennie Petersen Date: Tue, 21 Oct 2014 12:34:29 +0200 Subject: [PATCH 1/2] Adding Settings.Secure.ANDROID_ID to the device_info --- .../nolanlawson/logcat/LogcatActivity.java | 2 +- .../logcat/helper/BuildHelper.java | 35 ++++++++++++++----- 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/Catlog/src/com/nolanlawson/logcat/LogcatActivity.java b/Catlog/src/com/nolanlawson/logcat/LogcatActivity.java index 0ba30ec..0d822ec 100644 --- a/Catlog/src/com/nolanlawson/logcat/LogcatActivity.java +++ b/Catlog/src/com/nolanlawson/logcat/LogcatActivity.java @@ -1051,7 +1051,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/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 + } + } } From 8193400d7f584d825b59769f301dfb21476ad181 Mon Sep 17 00:00:00 2001 From: Rennie Petersen Date: Wed, 22 Oct 2014 15:14:35 +0200 Subject: [PATCH 2/2] Add an Intent so other apps can use Catlog to send logcat info via email This facility can be used by another app by doing something like this: Intent androidIntent = new Intent("com.nolanlawson.logcat.intents.SEND_EMAIL"); androidIntent.putExtra("recipients", new String[]{"some@email.com"}); androidIntent.putExtra("service", "email"); // Exchange email client, "gmail", etc. also possible androidIntent.putExtra("subject", "Logcat file from Android device"); androidIntent.putExtra("device_info", true); androidIntent.putExtra("attachment", true); androidIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // May be necessary startActivity(androidIntent); --- Catlog/AndroidManifest.xml | 11 +- .../nolanlawson/logcat/LogcatActivity.java | 118 ++++++++++++++---- .../logcat/data/SenderAppAdapter.java | 6 +- .../nolanlawson/logcat/intents/Intents.java | 18 ++- 4 files changed, 119 insertions(+), 34 deletions(-) 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 0d822ec..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() { 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/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 }