diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 06f9a0eae..c178f1b5b 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -168,8 +168,8 @@
android:windowSoftInputMode="stateUnchanged"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
-
diff --git a/build.gradle b/build.gradle
index dc6d16cec..c5c1595e9 100644
--- a/build.gradle
+++ b/build.gradle
@@ -74,9 +74,6 @@ dependencies {
compile 'com.google.android.exoplayer:exoplayer:r2.3.1'
- compile('org.whispersystems:libpastelog:1.1.2') {
- exclude group: 'com.squareup.okhttp3', module: 'okhttp'
- }
compile 'org.whispersystems:signal-service-android:2.7.6'
compile 'com.journeyapps:zxing-android-embedded:3.4.0'
@@ -162,7 +159,6 @@ dependencyVerification {
'com.google.android.gms:play-services-places:abf3a4a3b146ec7e6e753be62775e512868cf37d6f88ffe2d81167b33b57132b',
'com.google.android.gms:play-services-maps:45e8021e7ddac4a44a82a0e9698991389ded3023d35c58f38dbd86d54211ec0e',
'com.google.android.exoplayer:exoplayer:955085aa611a8f7cf6c61b88ae03d1a392f4ad94c9bfbc153f3dedb9ffb14718',
- 'org.whispersystems:libpastelog:fe56b4db9ec743c8b565e3e4caa9228fafe132dc0bf82000d6e359b97a81177c',
'org.whispersystems:signal-service-android:823eed29e64fb0aa30d2078cb5ec0245e2a0713a4028121329c5c28788ef27f8',
'me.leolin:ShortcutBadger:e3cb3e7625892129b0c92dd5e4bc649faffdd526d5af26d9c45ee31ff8851774',
'se.emilsjolander:stickylistheaders:a08ca948aa6b220f09d82f16bbbac395f6b78897e9eeac6a9f0b0ba755928eeb',
diff --git a/res/layout/fragment_view_log.xml b/res/layout/fragment_view_log.xml
new file mode 100644
index 000000000..6bbd9a197
--- /dev/null
+++ b/res/layout/fragment_view_log.xml
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/layout/log_submit_activity.xml b/res/layout/log_view_activity.xml
similarity index 100%
rename from res/layout/log_submit_activity.xml
rename to res/layout/log_view_activity.xml
diff --git a/res/menu/view_log.xml b/res/menu/view_log.xml
new file mode 100644
index 000000000..0fab81912
--- /dev/null
+++ b/res/menu/view_log.xml
@@ -0,0 +1,8 @@
+
+
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 45537b12e..1d48a2072 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1526,5 +1526,7 @@
Contact
Encryption
Edit name
+ View log
+ View log
diff --git a/res/xml/preferences_advanced.xml b/res/xml/preferences_advanced.xml
index 4a70e139d..43d1f5983 100644
--- a/res/xml/preferences_advanced.xml
+++ b/res/xml/preferences_advanced.xml
@@ -20,7 +20,7 @@
-
+
diff --git a/src/org/thoughtcrime/securesms/LogSubmitActivity.java b/src/org/thoughtcrime/securesms/LogSubmitActivity.java
deleted file mode 100644
index e7d1a4d7d..000000000
--- a/src/org/thoughtcrime/securesms/LogSubmitActivity.java
+++ /dev/null
@@ -1,78 +0,0 @@
-package org.thoughtcrime.securesms;
-
-import android.content.ActivityNotFoundException;
-import android.content.Intent;
-import android.os.Bundle;
-import android.support.v4.app.FragmentTransaction;
-import android.util.Log;
-import android.view.MenuItem;
-import android.widget.Toast;
-
-import org.thoughtcrime.securesms.util.DynamicTheme;
-import org.whispersystems.libpastelog.SubmitLogFragment;
-
-/**
- * Activity for submitting logcat logs to a pastebin service.
- */
-public class LogSubmitActivity extends BaseActionBarActivity implements SubmitLogFragment.OnLogSubmittedListener {
-
- private static final String TAG = LogSubmitActivity.class.getSimpleName();
- private DynamicTheme dynamicTheme = new DynamicTheme();
-
- @Override
- protected void onCreate(Bundle icicle) {
- dynamicTheme.onCreate(this);
- super.onCreate(icicle);
- setContentView(R.layout.log_submit_activity);
- getSupportActionBar().setDisplayHomeAsUpEnabled(true);
- SubmitLogFragment fragment = SubmitLogFragment.newInstance();
- FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
- transaction.replace(R.id.fragment_container, fragment);
- transaction.commit();
- }
-
- @Override
- protected void onResume() {
- dynamicTheme.onResume(this);
- super.onResume();
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- super.onOptionsItemSelected(item);
- switch (item.getItemId()) {
- case android.R.id.home:
- finish();
- return true;
- }
-
- return false;
- }
-
- @Override
- public void onSuccess() {
- Toast.makeText(getApplicationContext(), R.string.log_submit_activity__thanks, Toast.LENGTH_LONG).show();
- finish();
- }
-
- @Override
- public void onFailure() {
- Toast.makeText(getApplicationContext(), R.string.log_submit_activity__log_fetch_failed, Toast.LENGTH_LONG).show();
- finish();
- }
-
- @Override
- public void onCancel() {
- finish();
- }
-
- @Override
- public void startActivity(Intent intent) {
- try {
- super.startActivity(intent);
- } catch (ActivityNotFoundException e) {
- Log.w(TAG, e);
- Toast.makeText(this, R.string.log_submit_activity__no_browser_installed, Toast.LENGTH_LONG).show();
- }
- }
-}
diff --git a/src/org/thoughtcrime/securesms/LogViewActivity.java b/src/org/thoughtcrime/securesms/LogViewActivity.java
new file mode 100644
index 000000000..bf50d8f63
--- /dev/null
+++ b/src/org/thoughtcrime/securesms/LogViewActivity.java
@@ -0,0 +1,74 @@
+package org.thoughtcrime.securesms;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentTransaction;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.widget.Toast;
+
+import org.thoughtcrime.securesms.util.DynamicLanguage;
+import org.thoughtcrime.securesms.util.DynamicTheme;
+import org.thoughtcrime.securesms.util.Util;
+
+public class LogViewActivity extends PassphraseRequiredActionBarActivity {
+
+ private static final String TAG = LogViewActivity.class.getSimpleName();
+
+ private final DynamicTheme dynamicTheme = new DynamicTheme();
+ private final DynamicLanguage dynamicLanguage = new DynamicLanguage();
+
+ LogViewFragment logViewFragment;
+
+ @Override
+ protected void onPreCreate() {
+ dynamicTheme.onCreate(this);
+ dynamicLanguage.onCreate(this);
+ }
+
+ @Override
+ protected void onCreate(Bundle icicle, boolean ready) {
+ setContentView(R.layout.log_view_activity);
+ logViewFragment = LogViewFragment.newInstance();
+ FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+ transaction.replace(R.id.fragment_container, logViewFragment);
+ transaction.commit();
+
+ getSupportActionBar().setDisplayHomeAsUpEnabled(true);
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ dynamicTheme.onResume(this);
+ dynamicLanguage.onResume(this);
+ }
+
+ @Override
+ public boolean onPrepareOptionsMenu(Menu menu) {
+ MenuInflater inflater = this.getMenuInflater();
+ menu.clear();
+
+ inflater.inflate(R.menu.view_log, menu);
+
+ super.onPrepareOptionsMenu(menu);
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ super.onOptionsItemSelected(item);
+ switch (item.getItemId()) {
+ case android.R.id.home:
+ finish();
+ return true;
+
+ case R.id.copy_log_to_clipboard:
+ Util.writeTextToClipboard(this, logViewFragment.getLogText());
+ Toast.makeText(getApplicationContext(), R.string.done, Toast.LENGTH_SHORT).show();
+ return true;
+ }
+
+ return false;
+ }
+}
diff --git a/src/org/thoughtcrime/securesms/LogViewFragment.java b/src/org/thoughtcrime/securesms/LogViewFragment.java
new file mode 100644
index 000000000..7a8088d3c
--- /dev/null
+++ b/src/org/thoughtcrime/securesms/LogViewFragment.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2014 Open Whisper Systems
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package org.thoughtcrime.securesms;
+
+import android.annotation.TargetApi;
+import android.app.ActivityManager;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.AsyncTask;
+import android.os.Build;
+import android.os.Build.VERSION;
+import android.os.Build.VERSION_CODES;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.EditText;
+
+import org.thoughtcrime.securesms.util.Scrubber;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.lang.ref.WeakReference;
+import java.util.Locale;
+
+public class LogViewFragment extends Fragment {
+ private static final String TAG = LogViewFragment.class.getSimpleName();
+
+ private EditText logPreview;
+
+ public static LogViewFragment newInstance()
+ {
+ LogViewFragment fragment = new LogViewFragment();
+
+ return fragment;
+ }
+
+ public LogViewFragment() { }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ // Inflate the layout for this fragment
+ return inflater.inflate(R.layout.fragment_view_log, container, false);
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+
+ logPreview = (EditText) getView().findViewById(R.id.log_preview);
+ new PopulateLogcatAsyncTask(getActivity()).execute();
+ }
+
+ public String getLogText() {
+ return logPreview==null? "null" : logPreview.getText().toString();
+ }
+
+ private static String grabLogcat() {
+ try {
+ final Process process = Runtime.getRuntime().exec("logcat -d");
+ final BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
+ final StringBuilder log = new StringBuilder();
+ final String separator = System.getProperty("line.separator");
+
+ String line;
+ while ((line = bufferedReader.readLine()) != null) {
+ log.append(line);
+ log.append(separator);
+ }
+ return log.toString();
+ } catch (IOException ioe) {
+ Log.w(TAG, "IOException when trying to read logcat.", ioe);
+ return null;
+ }
+ }
+
+ private class PopulateLogcatAsyncTask extends AsyncTask {
+ private WeakReference weakContext;
+
+ public PopulateLogcatAsyncTask(Context context) {
+ this.weakContext = new WeakReference<>(context);
+ }
+
+ @Override
+ protected String doInBackground(Void... voids) {
+ Context context = weakContext.get();
+ if (context == null) return null;
+
+ return buildDescription(context) + "\n" + new Scrubber().scrub(grabLogcat());
+ }
+
+ @Override
+ protected void onPreExecute() {
+ super.onPreExecute();
+ logPreview.setText(R.string.one_moment);
+ }
+
+ @Override
+ protected void onPostExecute(String logcat) {
+ super.onPostExecute(logcat);
+ if (TextUtils.isEmpty(logcat)) {
+ // the log is in english, so it is fine if some of explaining strings are in english as well
+ logPreview.setText("Could not read the log on your device. You can still use ADB to get a debug log instead.");
+ return;
+ }
+ logPreview.setText(logcat);
+ }
+ }
+
+ private static long asMegs(long bytes) {
+ return bytes / 1048576L;
+ }
+
+ public static String getMemoryUsage(Context context) {
+ Runtime info = Runtime.getRuntime();
+ info.totalMemory();
+ return String.format(Locale.ENGLISH, "%dM (%.2f%% free, %dM max)",
+ asMegs(info.totalMemory()),
+ (float)info.freeMemory() / info.totalMemory() * 100f,
+ asMegs(info.maxMemory()));
+ }
+
+ @TargetApi(VERSION_CODES.KITKAT)
+ public static String getMemoryClass(Context context) {
+ ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
+ String lowMem = "";
+
+ if (VERSION.SDK_INT >= VERSION_CODES.KITKAT && activityManager.isLowRamDevice()) {
+ lowMem = ", low-mem device";
+ }
+ return activityManager.getMemoryClass() + lowMem;
+ }
+
+ private static String buildDescription(Context context) {
+ final PackageManager pm = context.getPackageManager();
+ final StringBuilder builder = new StringBuilder();
+
+
+ builder.append("Device : ")
+ .append(Build.MANUFACTURER).append(" ")
+ .append(Build.MODEL).append(" (")
+ .append(Build.PRODUCT).append(")\n");
+ builder.append("Android : ").append(VERSION.RELEASE).append(" (")
+ .append(VERSION.INCREMENTAL).append(", ")
+ .append(Build.DISPLAY).append(")\n");
+ builder.append("Memory : ").append(getMemoryUsage(context)).append("\n");
+ builder.append("Memclass: ").append(getMemoryClass(context)).append("\n");
+ builder.append("OS Host : ").append(Build.HOST).append("\n");
+ builder.append("App : ");
+ try {
+ builder.append(pm.getApplicationLabel(pm.getApplicationInfo(context.getPackageName(), 0)))
+ .append(" ")
+ .append(pm.getPackageInfo(context.getPackageName(), 0).versionName)
+ .append("\n");
+ } catch (PackageManager.NameNotFoundException nnfe) {
+ builder.append("Unknown\n");
+ }
+
+ return builder.toString();
+ }
+}
diff --git a/src/org/thoughtcrime/securesms/preferences/AdvancedPreferenceFragment.java b/src/org/thoughtcrime/securesms/preferences/AdvancedPreferenceFragment.java
index 429f31a01..396e234df 100644
--- a/src/org/thoughtcrime/securesms/preferences/AdvancedPreferenceFragment.java
+++ b/src/org/thoughtcrime/securesms/preferences/AdvancedPreferenceFragment.java
@@ -19,7 +19,7 @@ import com.b44t.messenger.DcContext;
import com.b44t.messenger.DcEventCenter;
import org.thoughtcrime.securesms.ApplicationPreferencesActivity;
-import org.thoughtcrime.securesms.LogSubmitActivity;
+import org.thoughtcrime.securesms.LogViewActivity;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.connect.ApplicationDcContext;
import org.thoughtcrime.securesms.connect.DcHelper;
@@ -62,8 +62,8 @@ public class AdvancedPreferenceFragment extends CorrectedPreferenceFragment
Preference manageKeys = this.findPreference("pref_manage_keys");
manageKeys.setOnPreferenceClickListener(new ManageKeysListener());
- Preference submitDebugLog = this.findPreference("pref_submit_debug_logs");
- submitDebugLog.setOnPreferenceClickListener(new SubmitDebugLogListener());
+ Preference submitDebugLog = this.findPreference("pref_view_log");
+ submitDebugLog.setOnPreferenceClickListener(new ViewLogListener());
submitDebugLog.setSummary(getVersion(getActivity()));
}
@@ -114,10 +114,10 @@ public class AdvancedPreferenceFragment extends CorrectedPreferenceFragment
}
}
- private class SubmitDebugLogListener implements Preference.OnPreferenceClickListener {
+ private class ViewLogListener implements Preference.OnPreferenceClickListener {
@Override
public boolean onPreferenceClick(Preference preference) {
- final Intent intent = new Intent(getActivity(), LogSubmitActivity.class);
+ final Intent intent = new Intent(getActivity(), LogViewActivity.class);
startActivity(intent);
return true;
}
diff --git a/src/org/thoughtcrime/securesms/util/Scrubber.java b/src/org/thoughtcrime/securesms/util/Scrubber.java
new file mode 100644
index 000000000..ce85f1402
--- /dev/null
+++ b/src/org/thoughtcrime/securesms/util/Scrubber.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2014 Open Whisper Systems
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package org.thoughtcrime.securesms.util;
+
+import android.util.Log;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Scrub data for possibly sensitive information
+ */
+public class Scrubber {
+ private static final String TAG = Scrubber.class.getSimpleName();
+ private static final Pattern E164_PATTERN = Pattern.compile("\\+\\d{10,15}");
+
+ private static final Pattern[] DEFAULTS = new Pattern[] {
+ E164_PATTERN
+ };
+
+ private final Pattern[] patterns;
+ public Scrubber(Pattern... patterns) {
+ this.patterns = patterns;
+ }
+
+ public Scrubber() {
+ this(DEFAULTS);
+ }
+
+ public String scrub(final String in) {
+ Log.d(TAG, "scrubbing input");
+ String out = in;
+ for (Pattern pattern : patterns) {
+ Matcher matcher = pattern.matcher(out);
+ while (matcher.find()) {
+
+ StringBuilder builder = new StringBuilder(out.substring(0, matcher.start()));
+ final String censored = matcher.group().substring(0,1) +
+ new String(new char[matcher.group().length()-3]).replace("\0", "*") +
+ matcher.group().substring(matcher.group().length()-2);
+ builder.append(censored);
+ builder.append(out.substring(matcher.end()));
+ Log.i(TAG, "replacing a match on /" + pattern.toString() + "/ => " + censored);
+ out = builder.toString();
+ }
+ }
+ return out;
+ }
+}
diff --git a/src/org/thoughtcrime/securesms/util/Util.java b/src/org/thoughtcrime/securesms/util/Util.java
index e0c076365..ada510fd9 100644
--- a/src/org/thoughtcrime/securesms/util/Util.java
+++ b/src/org/thoughtcrime/securesms/util/Util.java
@@ -36,10 +36,12 @@ import android.text.SpannableString;
import android.text.TextUtils;
import android.text.style.StyleSpan;
import android.util.Log;
+import android.widget.Toast;
import com.google.android.mms.pdu_alt.EncodedStringValue;
import org.thoughtcrime.securesms.BuildConfig;
+import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.components.ComposeText;
import org.thoughtcrime.securesms.database.Address;
@@ -332,9 +334,12 @@ public class Util {
}
public static void writeTextToClipboard(@NonNull Context context, @NonNull String text) {
- {
+ try {
ClipboardManager clipboardManager = (ClipboardManager)context.getSystemService(Context.CLIPBOARD_SERVICE);
- clipboardManager.setPrimaryClip(ClipData.newPlainText("Safety numbers", text));
+ clipboardManager.setPrimaryClip(ClipData.newPlainText(context.getString(R.string.app_name), text));
+ }
+ catch(Exception e) {
+ e.printStackTrace();
}
}