diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml
index 2be7b2583..3d4c53d54 100644
--- a/src/main/AndroidManifest.xml
+++ b/src/main/AndroidManifest.xml
@@ -312,6 +312,9 @@
android:configChanges="orientation"
android:exported="false"/>
+
+
collectAndSendLog())
+ .setNegativeButton(android.R.string.cancel, (dialog, whichButton) -> finish())
+ .show();
+ }
+ else{
+ collectAndSendLog();
+ } */
+
+ collectAndSendLog();
+ }
+
+ @SuppressWarnings("unchecked")
+ void collectAndSendLog(){
+ /*Usage: logcat [options] [filterspecs]
+ options include:
+ -s Set default filter to silent.
+ Like specifying filterspec '*:s'
+ -f Log to file. Default to stdout
+ -r [] Rotate log every kbytes. (16 if unspecified). Requires -f
+ -n Sets max number of rotated logs to , default 4
+ -v Sets the log print format, where is one of:
+
+ brief process tag thread raw time threadtime long
+
+ -c clear (flush) the entire log and exit
+ -d dump the log and then exit (don't block)
+ -g get the size of the log's ring buffer and exit
+ -b request alternate ring buffer
+ ('main' (default), 'radio', 'events')
+ -B output the log in binary
+ filterspecs are a series of
+ [:priority]
+
+ where is a log component tag (or * for all) and priority is:
+ V Verbose
+ D Debug
+ I Info
+ W Warn
+ E Error
+ F Fatal
+ S Silent (supress all output)
+
+ '*' means '*:d' and by itself means :v
+
+ If not specified on the commandline, filterspec is set from ANDROID_LOG_TAGS.
+ If no filterspec is found, filter defaults to '*:I'
+
+ If not specified with -v, format is set from ANDROID_PRINTF_LOG
+ or defaults to "brief"*/
+
+ ArrayList list = new ArrayList();
+
+ if (mFormat != null){
+ list.add("-v");
+ list.add(mFormat);
+ }
+
+ if (mBuffer != null){
+ list.add("-b");
+ list.add(mBuffer);
+ }
+
+ if (mFilterSpecs != null){
+ for (String filterSpec : mFilterSpecs){
+ list.add(filterSpec);
+ }
+ }
+
+ mCollectLogTask = (CollectLogTask) new CollectLogTask().execute(list);
+ }
+
+ private class CollectLogTask extends AsyncTask, Void, File>{
+ @Override
+ protected void onPreExecute(){
+ showProgressDialog(getString(R.string.acquiring_log_progress_dialog_message));
+ }
+
+ @Override
+ protected File doInBackground(ArrayList... params){
+ final StringBuilder log = new StringBuilder();
+ File logFile = new File(getCacheDir(),"logs/logcat.txt");
+
+ logFile.delete();
+ logFile.getParentFile().mkdirs();
+
+ try{
+ ArrayList commandLine = new ArrayList();
+ commandLine.add("logcat");
+ commandLine.add("-d");
+ ArrayList arguments = ((params != null) && (params.length > 0)) ? params[0] : null;
+ if (null != arguments){
+ commandLine.addAll(arguments);
+ }
+
+ Process process = Runtime.getRuntime().exec(commandLine.toArray(new String[0]));
+ BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
+
+ String line;
+ while ((line = bufferedReader.readLine()) != null){
+ log.append(line);
+ log.append(LINE_SEPARATOR);
+ }
+
+ FileWriter fr = new FileWriter(logFile);
+ BufferedWriter writer = new BufferedWriter(fr);
+
+ if (mAdditonalInfo != null){
+ log.insert(0, LINE_SEPARATOR);
+ log.insert(0, mAdditonalInfo);
+ }
+
+ writer.write(log.toString());
+ }
+ catch (IOException e){
+ Log.e(Config.LOGTAG, "CollectLogTask.doInBackground failed", e);
+ }
+
+ return logFile;
+ }
+
+ @Override
+ protected void onPostExecute(File logFile){
+ if (null != logFile){
+ Uri uri = FileProvider.getUriForFile(SendLogActivity.this, getPackageName() + ".files", logFile);
+
+ new ShareCompat
+ .IntentBuilder(SendLogActivity.this)
+ .setType("text/*")
+ .addStream(uri)
+ .setChooserTitle(getString(R.string.chooser_title))
+ .startChooser();
+
+ /* Intent sharingIntent = new Intent(Intent.ACTION_SEND);
+ sharingIntent.setType("text/*");
+ sharingIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ sharingIntent.putExtra(Intent.EXTRA_STREAM, uri);
+ startActivity(Intent.createChooser(sharingIntent, getString(R.string.chooser_title)));*/
+ dismissProgressDialog();
+ dismissMainDialog();
+ finish();
+ }
+ else{
+ dismissProgressDialog();
+ showErrorDialog(getString(R.string.failed_to_get_log_message));
+ }
+ }
+ }
+
+ void showErrorDialog(String errorMessage){
+ new AlertDialog.Builder(this)
+ .setTitle(getString(R.string.app_name))
+ .setMessage(errorMessage)
+ .setIcon(android.R.drawable.ic_dialog_alert)
+ .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener(){
+ public void onClick(DialogInterface dialog, int whichButton){
+ finish();
+ }
+ })
+ .show();
+ }
+
+ void dismissMainDialog(){
+ if (null != mMainDialog && mMainDialog.isShowing()){
+ mMainDialog.dismiss();
+ mMainDialog = null;
+ }
+ }
+
+ void showProgressDialog(String message){
+ mProgressDialog = new ProgressDialog(this);
+ mProgressDialog.setIndeterminate(true);
+ mProgressDialog.setMessage(message);
+ mProgressDialog.setCancelable(true);
+ mProgressDialog.setOnCancelListener(new DialogInterface.OnCancelListener(){
+ public void onCancel(DialogInterface dialog){
+ cancellCollectTask();
+ finish();
+ }
+ });
+ mProgressDialog.show();
+ }
+
+ private void dismissProgressDialog(){
+ if (null != mProgressDialog && mProgressDialog.isShowing())
+ {
+ mProgressDialog.dismiss();
+ mProgressDialog = null;
+ }
+ }
+
+ void cancellCollectTask(){
+ if (mCollectLogTask != null && mCollectLogTask.getStatus() == AsyncTask.Status.RUNNING)
+ {
+ mCollectLogTask.cancel(true);
+ mCollectLogTask = null;
+ }
+ }
+
+ @Override
+ protected void onPause(){
+ cancellCollectTask();
+ dismissProgressDialog();
+ dismissMainDialog();
+
+ super.onPause();
+ }
+
+ private static String getVersionNumber(Context context)
+ {
+ String version = "?";
+ try
+ {
+ PackageInfo packagInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
+ version = packagInfo.versionName;
+ }
+ catch (PackageManager.NameNotFoundException e){};
+
+ return version;
+ }
+
+ private String getFormattedKernelVersion()
+ {
+ String procVersionStr;
+
+ try {
+ BufferedReader reader = new BufferedReader(new FileReader("/proc/version"), 256);
+ try {
+ procVersionStr = reader.readLine();
+ } finally {
+ reader.close();
+ }
+
+ final String PROC_VERSION_REGEX =
+ "\\w+\\s+" + /* ignore: Linux */
+ "\\w+\\s+" + /* ignore: version */
+ "([^\\s]+)\\s+" + /* group 1: 2.6.22-omap1 */
+ "\\(([^\\s@]+(?:@[^\\s.]+)?)[^)]*\\)\\s+" + /* group 2: (xxxxxx@xxxxx.constant) */
+ "\\([^)]+\\)\\s+" + /* ignore: (gcc ..) */
+ "([^\\s]+)\\s+" + /* group 3: #26 */
+ "(?:PREEMPT\\s+)?" + /* ignore: PREEMPT (optional) */
+ "(.+)"; /* group 4: date */
+
+ Pattern p = Pattern.compile(PROC_VERSION_REGEX);
+ Matcher m = p.matcher(procVersionStr);
+
+ if (!m.matches()) {
+ Log.e(TAG, "Regex did not match on /proc/version: " + procVersionStr);
+ return "Unavailable";
+ } else if (m.groupCount() < 4) {
+ Log.e(TAG, "Regex match on /proc/version only returned " + m.groupCount()
+ + " groups");
+ return "Unavailable";
+ } else {
+ return (new StringBuilder(m.group(1)).append("\n").append(
+ m.group(2)).append(" ").append(m.group(3)).append("\n")
+ .append(m.group(4))).toString();
+ }
+ } catch (IOException e) {
+ Log.e(TAG,
+ "IO Exception when getting kernel version for Device Info screen",
+ e);
+
+ return "Unavailable";
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java b/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java
index 021fc5fad..605851c7b 100644
--- a/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java
@@ -1,6 +1,7 @@
package eu.siacs.conversations.ui;
import android.app.FragmentManager;
+import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
@@ -28,6 +29,7 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import java.io.File;
+import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.security.KeyStoreException;
@@ -319,6 +321,16 @@ public class SettingsActivity extends XmppActivity implements OnSharedPreference
});
}
+ final Preference sendLogsPreference = mSettingsFragment.findPreference("send_logs");
+ if (sendLogsPreference != null) {
+ sendLogsPreference.setOnPreferenceClickListener(
+ preference -> {
+ final Intent intent = new Intent(this, SendLogActivity.class);
+ startActivity(intent);
+ return true;
+ });
+ }
+
if (Config.ONLY_INTERNAL_STORAGE) {
final Preference cleanCachePreference = mSettingsFragment.findPreference("clean_cache");
if (cleanCachePreference != null) {
diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml
index 25cf99588..ba780b3da 100644
--- a/src/main/res/values/strings.xml
+++ b/src/main/res/values/strings.xml
@@ -330,6 +330,8 @@
Prevents the operating system from killing your connection
Create backup
Backup files will be stored in %s
+ Send report
+ It can help us to fix your problem
Creating backup files
Your backup has been created
The backup files have been stored in %s
diff --git a/src/main/res/values/strings_logs_reporter.xml b/src/main/res/values/strings_logs_reporter.xml
new file mode 100644
index 000000000..b60f785a4
--- /dev/null
+++ b/src/main/res/values/strings_logs_reporter.xml
@@ -0,0 +1,18 @@
+
+
+ Android device log
+ Acquiring log from the system...
+ "Select an application to send the log"
+ "Failed to get the log from the system."
+ "This application will attempt to collect the device log.
+The collected log will be sent using an application of your choice.
+You also will have an opportunity to see and modify the data being sent."
+
+
+Log Collector version: %1$s\n
+Device model: %2$s\n
+Firmware version: %3$s\n
+Kernel version: %4$s\n
+Build number: %5$s\n
+
+
\ No newline at end of file
diff --git a/src/main/res/values/themes.xml b/src/main/res/values/themes.xml
index 11a671c54..08d23429a 100644
--- a/src/main/res/values/themes.xml
+++ b/src/main/res/values/themes.xml
@@ -390,6 +390,15 @@
- @drawable/background
+
+