aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java80
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayFragment.java189
-rw-r--r--OpenKeychain/src/main/res/menu/log_display.xml4
-rw-r--r--OpenKeychain/src/main/res/values/strings.xml13
4 files changed, 98 insertions, 188 deletions
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java
index 6e9aca30d..41691933e 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java
@@ -20,6 +20,7 @@ package org.sufficientlysecure.keychain.operations.results;
import android.app.Activity;
import android.content.Intent;
+import android.content.res.Resources;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.annotation.NonNull;
@@ -52,6 +53,8 @@ import java.util.List;
*/
public abstract class OperationResult implements Parcelable {
+ final static String INDENTATION_WHITESPACE = " ";
+
public static final String EXTRA_RESULT = "operation_result";
/**
@@ -166,6 +169,27 @@ public abstract class OperationResult implements Parcelable {
", mIndent=" + mIndent +
'}';
}
+
+ StringBuilder getPrintableLogEntry(Resources resources, int indent) {
+
+ StringBuilder result = new StringBuilder();
+ int padding = mIndent +indent;
+ if (padding > INDENTATION_WHITESPACE.length()) {
+ padding = INDENTATION_WHITESPACE.length();
+ }
+ result.append(INDENTATION_WHITESPACE, 0, padding);
+ result.append(LOG_LEVEL_NAME[mType.mLevel.ordinal()]).append(' ');
+
+ // special case: first parameter may be a quantity
+ if (mParameters != null && mParameters.length > 0 && mParameters[0] instanceof Integer) {
+ result.append(resources.getQuantityString(mType.getMsgId(), (Integer) mParameters[0], mParameters));
+ } else {
+ result.append(resources.getString(mType.getMsgId(), mParameters));
+ }
+
+ return result;
+ }
+
}
public static class SubLogEntryParcel extends LogEntryParcel {
@@ -202,6 +226,17 @@ public abstract class OperationResult implements Parcelable {
dest.writeParcelable(mSubResult, 0);
}
+ @Override
+ StringBuilder getPrintableLogEntry(Resources resources, int indent) {
+
+ LogEntryParcel subEntry = mSubResult.getLog().getLast();
+ if (subEntry != null) {
+ return subEntry.getPrintableLogEntry(resources, mIndent +indent);
+ } else {
+ return super.getPrintableLogEntry(resources, indent);
+ }
+ }
+
}
public Showable createNotify(final Activity activity) {
@@ -245,15 +280,15 @@ public abstract class OperationResult implements Parcelable {
}
return Notify.create(activity, logText, Notify.LENGTH_LONG, style,
- new ActionListener() {
- @Override
- public void onAction() {
- Intent intent = new Intent(
- activity, LogDisplayActivity.class);
- intent.putExtra(LogDisplayFragment.EXTRA_RESULT, OperationResult.this);
- activity.startActivity(intent);
- }
- }, R.string.snackbar_details);
+ new ActionListener() {
+ @Override
+ public void onAction() {
+ Intent intent = new Intent(
+ activity, LogDisplayActivity.class);
+ intent.putExtra(LogDisplayFragment.EXTRA_RESULT, OperationResult.this);
+ activity.startActivity(intent);
+ }
+ }, R.string.snackbar_details);
}
@@ -803,14 +838,7 @@ public abstract class OperationResult implements Parcelable {
MSG_LV_FETCH_ERROR_URL (LogLevel.ERROR, R.string.msg_lv_fetch_error_url),
MSG_LV_FETCH_ERROR_IO (LogLevel.ERROR, R.string.msg_lv_fetch_error_io),
MSG_LV_FETCH_ERROR_FORMAT(LogLevel.ERROR, R.string.msg_lv_fetch_error_format),
- MSG_LV_FETCH_ERROR_NOTHING (LogLevel.ERROR, R.string.msg_lv_fetch_error_nothing),
-
- //export log
- MSG_EXPORT_LOG(LogLevel.START,R.string.msg_export_log_start),
- MSG_EXPORT_LOG_EXPORT_ERROR_NO_FILE(LogLevel.ERROR,R.string.msg_export_log_error_no_file),
- MSG_EXPORT_LOG_EXPORT_ERROR_FOPEN(LogLevel.ERROR,R.string.msg_export_log_error_fopen),
- MSG_EXPORT_LOG_EXPORT_ERROR_WRITING(LogLevel.ERROR,R.string.msg_export_log_error_writing),
- MSG_EXPORT_LOG_EXPORT_SUCCESS (LogLevel.OK, R.string.msg_export_log_success);
+ MSG_LV_FETCH_ERROR_NOTHING (LogLevel.ERROR, R.string.msg_lv_fetch_error_nothing);
public final int mMsgId;
public final LogLevel mLevel;
@@ -833,6 +861,10 @@ public abstract class OperationResult implements Parcelable {
OK, // should occur once at the end of a successful operation
CANCELLED, // should occur once at the end of a cancelled operation
}
+ // for print of debug log. keep those in sync with above!
+ static final String[] LOG_LEVEL_NAME = new String[] {
+ "[DEBUG]", "[INFO]", "[WARN]", "[ERROR]", "[START]", "[OK]", "[CANCEL]"
+ };
@Override
public int describeContents() {
@@ -931,6 +963,20 @@ public abstract class OperationResult implements Parcelable {
public Iterator<LogEntryParcel> iterator() {
return mParcels.iterator();
}
+
+ /**
+ * returns an indented String of an entire OperationLog
+ * @param indent padding to add at the start of all log entries, made for use with SubLogs
+ * @return printable, indented version of passed operationLog
+ */
+ public String getPrintableOperationLog(Resources resources, int indent) {
+ StringBuilder log = new StringBuilder();
+ for (LogEntryParcel entry : this) {
+ log.append(entry.getPrintableLogEntry(resources, indent)).append("\n");
+ }
+ return log.toString().substring(0, log.length() -1); // get rid of extra new line
+ }
+
}
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayFragment.java
index 4de83337e..43c8d2643 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayFragment.java
@@ -18,11 +18,12 @@
package org.sufficientlysecure.keychain.ui;
+import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
+import android.net.Uri;
import android.os.Bundle;
-import android.os.Parcel;
import android.support.v4.app.ListFragment;
import android.util.TypedValue;
import android.view.LayoutInflater;
@@ -37,19 +38,19 @@ import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
-import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.operations.results.OperationResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogEntryParcel;
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogLevel;
import org.sufficientlysecure.keychain.operations.results.OperationResult.SubLogEntryParcel;
+import org.sufficientlysecure.keychain.provider.TemporaryStorageProvider;
import org.sufficientlysecure.keychain.ui.util.FormattingUtils;
-import org.sufficientlysecure.keychain.util.FileHelper;
-import org.sufficientlysecure.keychain.util.Log;
+import org.sufficientlysecure.keychain.ui.util.Notify;
+import org.sufficientlysecure.keychain.ui.util.Notify.Style;
+
+import java.io.IOException;
+import java.io.OutputStream;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.PrintWriter;
public class LogDisplayFragment extends ListFragment implements OnItemClickListener {
@@ -60,6 +61,8 @@ public class LogDisplayFragment extends ListFragment implements OnItemClickListe
public static final String EXTRA_RESULT = "log";
protected int mTextColor;
+ private Uri mLogTempFile;
+
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -118,170 +121,40 @@ public class LogDisplayFragment extends ListFragment implements OnItemClickListe
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_log_display_export_log:
- exportLog();
+ shareLog();
break;
}
return super.onOptionsItemSelected(item);
}
- private void exportLog() {
- showExportLogDialog(new File(Constants.Path.APP_DIR, "export.log"));
- }
-
- private void writeToLogFile(final OperationResult.OperationLog operationLog, final File f) {
- OperationResult.OperationLog currLog = new OperationResult.OperationLog();
- currLog.add(OperationResult.LogType.MSG_EXPORT_LOG, 0);
-
- boolean error = false;
-
- PrintWriter pw = null;
- try {
- pw = new PrintWriter(f);
- pw.print(getPrintableOperationLog(operationLog, ""));
- if (pw.checkError()) {//IOException
- Log.e(Constants.TAG, "Log Export I/O Exception " + f.getAbsolutePath());
- currLog.add(OperationResult.LogType.MSG_EXPORT_LOG_EXPORT_ERROR_WRITING, 1);
- error = true;
- }
- } catch (FileNotFoundException e) {
- Log.e(Constants.TAG, "File not found for exporting log " + f.getAbsolutePath());
- currLog.add(OperationResult.LogType.MSG_EXPORT_LOG_EXPORT_ERROR_FOPEN, 1);
- error = true;
- }
- if (pw != null) {
- pw.close();
- if (!error && pw.checkError()) {//check if it is only pw.close() which generated error
- currLog.add(OperationResult.LogType.MSG_EXPORT_LOG_EXPORT_ERROR_WRITING, 1);
- error = true;
- }
- }
-
- if (!error) {
- currLog.add(OperationResult.LogType.MSG_EXPORT_LOG_EXPORT_SUCCESS, 1);
- }
-
- int opResultCode = error ? OperationResult.RESULT_ERROR : OperationResult.RESULT_OK;
- OperationResult opResult = new LogExportResult(opResultCode, currLog);
- opResult.createNotify(getActivity()).show();
- }
-
- /**
- * returns an indented String of an entire OperationLog
- *
- * @param opLog log to be converted to indented, printable format
- * @param basePadding padding to add at the start of all log entries, made for use with SubLogs
- * @return printable, indented version of passed operationLog
- */
- private String getPrintableOperationLog(OperationResult.OperationLog opLog, String basePadding) {
- String log = "";
- for (LogEntryParcel anOpLog : opLog) {
- log += getPrintableLogEntry(anOpLog, basePadding) + "\n";
- }
- log = log.substring(0, log.length() - 1);//gets rid of extra new line
- return log;
- }
-
- /**
- * returns an indented String of a LogEntryParcel including any sub-logs it may contain
- *
- * @param entryParcel log entryParcel whose String representation is to be obtained
- * @return indented version of passed log entryParcel in a readable format
- */
- private String getPrintableLogEntry(OperationResult.LogEntryParcel entryParcel,
- String basePadding) {
-
- final String indent = " ";//4 spaces = 1 Indent level
-
- String padding = basePadding;
- for (int i = 0; i < entryParcel.mIndent; i++) {
- padding += indent;
- }
- String logText = padding;
-
- switch (entryParcel.mType.mLevel) {
- case DEBUG:
- logText += "[DEBUG]";
- break;
- case INFO:
- logText += "[INFO]";
- break;
- case WARN:
- logText += "[WARN]";
- break;
- case ERROR:
- logText += "[ERROR]";
- break;
- case START:
- logText += "[START]";
- break;
- case OK:
- logText += "[OK]";
- break;
- case CANCELLED:
- logText += "[CANCELLED]";
- break;
- }
+ private void shareLog() {
- // special case: first parameter may be a quantity
- if (entryParcel.mParameters != null && entryParcel.mParameters.length > 0
- && entryParcel.mParameters[0] instanceof Integer) {
- logText += getResources().getQuantityString(entryParcel.mType.getMsgId(),
- (Integer) entryParcel.mParameters[0],
- entryParcel.mParameters);
- } else {
- logText += getResources().getString(entryParcel.mType.getMsgId(),
- entryParcel.mParameters);
+ Activity activity = getActivity();
+ if (activity == null) {
+ return;
}
- if (entryParcel instanceof SubLogEntryParcel) {
- OperationResult subResult = ((SubLogEntryParcel) entryParcel).getSubResult();
- LogEntryParcel subEntry = subResult.getLog().getLast();
- if (subEntry != null) {
- //the first line of log of subResult is same as entryParcel, so replace logText
- logText = getPrintableOperationLog(subResult.getLog(), padding);
+ String log = mResult.getLog().getPrintableOperationLog(getResources(), 0);
+
+ // if there is no log temp file yet, create one
+ if (mLogTempFile == null) {
+ mLogTempFile = TemporaryStorageProvider.createFile(getActivity(), "openkeychain_log.txt", "text/plain");
+ try {
+ OutputStream outputStream = activity.getContentResolver().openOutputStream(mLogTempFile);
+ outputStream.write(log.getBytes());
+ } catch (IOException e) {
+ Notify.create(activity, R.string.error_log_share_internal, Style.ERROR).show();
+ return;
}
}
- return logText;
- }
-
- private void showExportLogDialog(final File exportFile) {
-
- String title = this.getString(R.string.title_export_log);
-
- String message = this.getString(R.string.specify_file_to_export_log_to);
-
- FileHelper.saveDocumentDialog(new FileHelper.FileDialogCallback() {
- @Override
- public void onFileSelected(File file, boolean checked) {
- writeToLogFile(mResult.getLog(), file);
- }
- }, this.getActivity().getSupportFragmentManager(), title, message, exportFile, null);
- }
-
- private static class LogExportResult extends OperationResult {
-
- public static Creator<LogExportResult> CREATOR = new Creator<LogExportResult>() {
- public LogExportResult createFromParcel(final Parcel source) {
- return new LogExportResult(source);
- }
-
- public LogExportResult[] newArray(final int size) {
- return new LogExportResult[size];
- }
- };
-
- public LogExportResult(int result, OperationLog log) {
- super(result, log);
- }
+ Intent intent = new Intent(Intent.ACTION_SEND);
+ intent.putExtra(Intent.EXTRA_STREAM, mLogTempFile);
+ intent.setType("text/plain");
+ intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ startActivity(intent);
- /**
- * trivial but necessary to implement the Parcelable protocol.
- */
- public LogExportResult(Parcel source) {
- super(source);
- }
}
@Override
diff --git a/OpenKeychain/src/main/res/menu/log_display.xml b/OpenKeychain/src/main/res/menu/log_display.xml
index 7a2f77b79..a7f7e286d 100644
--- a/OpenKeychain/src/main/res/menu/log_display.xml
+++ b/OpenKeychain/src/main/res/menu/log_display.xml
@@ -4,8 +4,8 @@
<item
android:id="@+id/menu_log_display_export_log"
- android:icon="@drawable/ic_save_white_24dp"
- android:title="@string/menu_export_log"
+ android:icon="@drawable/ic_share_black_24dp"
+ android:title="@string/menu_share_log"
app:showAsAction="ifRoom|withText" />
</menu>
diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml
index d55d128d3..151c66613 100644
--- a/OpenKeychain/src/main/res/values/strings.xml
+++ b/OpenKeychain/src/main/res/values/strings.xml
@@ -37,7 +37,6 @@
<string name="title_exchange_keys">"Exchange Keys"</string>
<string name="title_advanced_key_info">"Extended Information"</string>
<string name="title_delete_secret_key">"Delete YOUR key '%s'?"</string>
- <string name="title_export_log">"Export Log"</string>
<string name="title_manage_my_keys">"Manage my keys"</string>
<!-- section -->
@@ -117,7 +116,7 @@
<string name="menu_advanced">"Extended information"</string>
<string name="menu_certify_fingerprint">"Confirm via fingerprint"</string>
<string name="menu_certify_fingerprint_word">"Confirm via words"</string>
- <string name="menu_export_log">"Export Log"</string>
+ <string name="menu_share_log">"Share Log"</string>
<string name="menu_keyserver_add">"Add"</string>
@@ -322,8 +321,6 @@
<string name="key_creation_el_gamal_info">"Note: only subkeys support ElGamal."</string>
<string name="key_not_found">"Couldn't find key %08X."</string>
- <string name="specify_file_to_export_log_to">"Please specify file to export to. \nWARNING: File will be overwritten if it exists."</string>
-
<plurals name="bad_keys_encountered">"
<item quantity="one">"%d bad secret key ignored. Perhaps you exported with the option\n --export-secret-subkeys\nMake sure you export with\n --export-secret-keys\ninstead.""</item>
<item quantity="other">"%d bad secret keys ignored. Perhaps you exported with the option\n --export-secret-subkeys\nMake sure you export with\n --export-secret-keys\ninstead.""</item>
@@ -1383,13 +1380,6 @@
<string name="msg_keybase_error_specific">"%s"</string>
<string name="msg_keybase_error_msg_payload_mismatch">"Decrypted proof post does not match expected value"</string>
- <!-- Messages for Export Log operation -->
- <string name="msg_export_log_start">"Exporting log"</string>
- <string name="msg_export_log_error_fopen">"Error opening file"</string>
- <string name="msg_export_log_error_no_file">"No file name specified!"</string>
- <string name="msg_export_log_error_writing">"I/O error writing to file!"</string>
- <string name="msg_export_log_success">"Log exported successfully!"</string>
-
<!-- PassphraseCache -->
<string name="passp_cache_notif_click_to_clear">"Touch to clear passwords."</string>
<plurals name="passp_cache_notif_n_keys">
@@ -1452,6 +1442,7 @@
<string name="error_multi_clipboard">"Encryption of multiple files to clipboard not supported."</string>
<string name="error_detached_signature">"Sign-only operation of binary files is not supported, select at least one encryption key."</string>
<string name="error_empty_text">"Type some text to encrypt!"</string>
+ <string name="error_log_share_internal">"Internal error while preparing log!"</string>
<string name="key_colon">"Key:"</string>
<string name="exchange_description">"To start a key exchange, choose the number of participants on the right side, then hit the “Start exchange” button.\n\nYou will be asked two more questions to make sure only the right participants are in the exchange and their fingerprints are correct."</string>
<string name="btn_start_exchange">"Start exchange"</string>