Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions Catlog/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,18 @@
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</intent-filter>

<intent-filter>
<action android:name="com.nolanlawson.logcat.intents.LAUNCH" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
</intent-filter>

<intent-filter>
<action android:name="com.nolanlawson.logcat.intents.SEND_EMAIL"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>

<activity android:name=".AboutActivity" android:theme="@android:style/Theme.Dialog" />

Expand Down
120 changes: 93 additions & 27 deletions Catlog/src/com/nolanlawson/logcat/LogcatActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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<ResolveInfo> resolveInfoAllAvailable = getPackageManager().queryIntentActivities(
SenderAppAdapter.createDummyIntent(sendLogDetails.getAttachmentType()), 0);

// Filter to find the app that is specified by the Intent's "service" extra info
List<ActivityInfo> activityInfoMatches = new ArrayList<ActivityInfo>();
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() {
Expand Down Expand Up @@ -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');
Expand Down
6 changes: 2 additions & 4 deletions Catlog/src/com/nolanlawson/logcat/data/SenderAppAdapter.java
Original file line number Diff line number Diff line change
Expand Up @@ -151,17 +151,15 @@ private void filter(List<ResolveInfo> 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);
Expand Down
35 changes: 27 additions & 8 deletions Catlog/src/com/nolanlawson/logcat/helper/BuildHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -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 {

Expand All @@ -21,8 +23,12 @@ public class BuildHelper {
// public static final Strings of android.os.Build.Version
private static final List<String> 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<String> SETTINGS_SECURE_CONSTANTS = Arrays.asList(
Settings.Secure.ANDROID_ID);

public static String getBuildInformationAsString(Activity androidActivity) {
SortedMap<String, String> keysToValues = new TreeMap<String, String>();

for (String buildField : BUILD_FIELDS) {
Expand All @@ -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<String, String> 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<String, String> keysToValues) {
private static void putKeyValue(Class<?> clazz, String fieldName, SortedMap<String, String> 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
Expand All @@ -53,5 +62,15 @@ private static void putKeyValue(Class<?> clazz, String buildField, SortedMap<Str
// ignore
}
}


private static void putSettingsSecure(Activity androidActivity, String constantName,
SortedMap<String, String> 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
}
}
}
18 changes: 17 additions & 1 deletion Catlog/src/com/nolanlawson/logcat/intents/Intents.java
Original file line number Diff line number Diff line change
Expand Up @@ -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
}