mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-27 21:03:54 +01:00
Merge pull request #920 from Bluesir9/fix_736_send_app_logs
Allow user to send app logs
This commit is contained in:
commit
d09109006d
7 changed files with 155 additions and 1 deletions
|
|
@ -14,6 +14,7 @@
|
||||||
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS"/>
|
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS"/>
|
||||||
<uses-permission android:name="android.permission.MANAGE_DOCUMENTS"/>
|
<uses-permission android:name="android.permission.MANAGE_DOCUMENTS"/>
|
||||||
<uses-permission android:name="com.google.android.apps.photos.permission.GOOGLE_PHOTOS"/>
|
<uses-permission android:name="com.google.android.apps.photos.permission.GOOGLE_PHOTOS"/>
|
||||||
|
<uses-permission android:name="android.permission.READ_LOGS"/>
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:name=".CommonsApplication"
|
android:name=".CommonsApplication"
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,10 @@ import org.xmlpull.v1.XmlPullParser;
|
||||||
import org.xmlpull.v1.XmlPullParserException;
|
import org.xmlpull.v1.XmlPullParserException;
|
||||||
|
|
||||||
import java.io.BufferedInputStream;
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.BufferedReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
import java.io.StringWriter;
|
import java.io.StringWriter;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
|
|
@ -281,4 +283,37 @@ public class Utils {
|
||||||
public static boolean isDarkTheme(Context context) {
|
public static boolean isDarkTheme(Context context) {
|
||||||
return PreferenceManager.getDefaultSharedPreferences(context).getBoolean("theme", false);
|
return PreferenceManager.getDefaultSharedPreferences(context).getBoolean("theme", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will be used to fetch the logs generated by the app ever since the beginning of times....
|
||||||
|
* i.e. since the time the app started.
|
||||||
|
*
|
||||||
|
* @return String containing all the logs since the time the app started
|
||||||
|
*/
|
||||||
|
public static String getAppLogs() {
|
||||||
|
final String processId = Integer.toString(android.os.Process.myPid());
|
||||||
|
|
||||||
|
StringBuilder stringBuilder = new StringBuilder();
|
||||||
|
|
||||||
|
try {
|
||||||
|
String[] command = new String[] {"logcat","-d","-v","threadtime"};
|
||||||
|
|
||||||
|
Process process = Runtime.getRuntime().exec(command);
|
||||||
|
|
||||||
|
BufferedReader bufferedReader = new BufferedReader(
|
||||||
|
new InputStreamReader(process.getInputStream())
|
||||||
|
);
|
||||||
|
|
||||||
|
String line;
|
||||||
|
while ((line = bufferedReader.readLine()) != null) {
|
||||||
|
if (line.contains(processId)) {
|
||||||
|
stringBuilder.append(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
Timber.e("getAppLogs failed", ioe);
|
||||||
|
}
|
||||||
|
|
||||||
|
return stringBuilder.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,39 @@
|
||||||
package fr.free.nrw.commons.settings;
|
package fr.free.nrw.commons.settings;
|
||||||
|
|
||||||
|
import android.Manifest;
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
|
import android.content.ActivityNotFoundException;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.preference.CheckBoxPreference;
|
import android.preference.CheckBoxPreference;
|
||||||
import android.preference.EditTextPreference;
|
import android.preference.EditTextPreference;
|
||||||
import android.preference.ListPreference;
|
import android.preference.ListPreference;
|
||||||
|
import android.preference.Preference;
|
||||||
import android.preference.PreferenceFragment;
|
import android.preference.PreferenceFragment;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.v4.app.ActivityCompat;
|
||||||
|
import android.support.v4.content.ContextCompat;
|
||||||
|
import android.support.v4.content.FileProvider;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
import fr.free.nrw.commons.BuildConfig;
|
||||||
import fr.free.nrw.commons.CommonsApplication;
|
import fr.free.nrw.commons.CommonsApplication;
|
||||||
import fr.free.nrw.commons.R;
|
import fr.free.nrw.commons.R;
|
||||||
import fr.free.nrw.commons.Utils;
|
import fr.free.nrw.commons.Utils;
|
||||||
|
import fr.free.nrw.commons.utils.FileUtils;
|
||||||
|
|
||||||
public class SettingsFragment extends PreferenceFragment {
|
public class SettingsFragment extends PreferenceFragment {
|
||||||
|
|
||||||
|
private static final int REQUEST_CODE_WRITE_EXTERNAL_STORAGE = 100;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
@ -66,6 +86,63 @@ public class SettingsFragment extends PreferenceFragment {
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Preference sendLogsPreference = findPreference("sendLogFile");
|
||||||
|
sendLogsPreference.setOnPreferenceClickListener(preference -> {
|
||||||
|
//first we need to check if we have the necessary permissions
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
|
if (ContextCompat.checkSelfPermission(
|
||||||
|
getActivity(),
|
||||||
|
Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
||||||
|
==
|
||||||
|
PackageManager.PERMISSION_GRANTED) {
|
||||||
|
sendAppLogsViaEmail();
|
||||||
|
} else {
|
||||||
|
//first get the necessary permission
|
||||||
|
requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
|
||||||
|
REQUEST_CODE_WRITE_EXTERNAL_STORAGE);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sendAppLogsViaEmail();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||||
|
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||||
|
if (requestCode == REQUEST_CODE_WRITE_EXTERNAL_STORAGE) {
|
||||||
|
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||||
|
sendAppLogsViaEmail();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendAppLogsViaEmail() {
|
||||||
|
String appLogs = Utils.getAppLogs();
|
||||||
|
File appLogsFile = FileUtils.createAndGetAppLogsFile(appLogs);
|
||||||
|
|
||||||
|
Context applicationContext = getActivity().getApplicationContext();
|
||||||
|
Uri appLogsFilePath = FileProvider.getUriForFile(
|
||||||
|
getActivity(),
|
||||||
|
applicationContext.getPackageName() + ".provider",
|
||||||
|
appLogsFile
|
||||||
|
);
|
||||||
|
|
||||||
|
Intent feedbackIntent = new Intent(Intent.ACTION_SEND);
|
||||||
|
feedbackIntent.setType("message/rfc822");
|
||||||
|
feedbackIntent.putExtra(Intent.EXTRA_EMAIL,
|
||||||
|
new String[]{CommonsApplication.FEEDBACK_EMAIL});
|
||||||
|
feedbackIntent.putExtra(Intent.EXTRA_SUBJECT,
|
||||||
|
String.format(CommonsApplication.FEEDBACK_EMAIL_SUBJECT,
|
||||||
|
BuildConfig.VERSION_NAME));
|
||||||
|
feedbackIntent.putExtra(Intent.EXTRA_STREAM,appLogsFilePath);
|
||||||
|
|
||||||
|
try {
|
||||||
|
startActivity(feedbackIntent);
|
||||||
|
} catch (ActivityNotFoundException e) {
|
||||||
|
Toast.makeText(getActivity(), R.string.no_email_client, Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,17 @@
|
||||||
package fr.free.nrw.commons.utils;
|
package fr.free.nrw.commons.utils;
|
||||||
|
|
||||||
|
import android.os.Environment;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.io.OutputStreamWriter;
|
||||||
|
|
||||||
import fr.free.nrw.commons.CommonsApplication;
|
import fr.free.nrw.commons.CommonsApplication;
|
||||||
|
import timber.log.Timber;
|
||||||
|
|
||||||
public class FileUtils {
|
public class FileUtils {
|
||||||
/**
|
/**
|
||||||
|
|
@ -53,5 +59,32 @@ public class FileUtils {
|
||||||
return deletedAll;
|
return deletedAll;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static File createAndGetAppLogsFile(String logs) {
|
||||||
|
try {
|
||||||
|
File commonsAppDirectory = new File(Environment.getExternalStorageDirectory().toString() + "/CommonsApp");
|
||||||
|
if (!commonsAppDirectory.exists()) {
|
||||||
|
commonsAppDirectory.mkdir();
|
||||||
|
}
|
||||||
|
|
||||||
|
File logsFile = new File(commonsAppDirectory,"logs.txt");
|
||||||
|
if (logsFile.exists()) {
|
||||||
|
//old logs file is useless
|
||||||
|
logsFile.delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
logsFile.createNewFile();
|
||||||
|
|
||||||
|
FileOutputStream outputStream = new FileOutputStream(logsFile);
|
||||||
|
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream);
|
||||||
|
outputStreamWriter.append(logs);
|
||||||
|
outputStreamWriter.close();
|
||||||
|
outputStream.flush();
|
||||||
|
outputStream.close();
|
||||||
|
|
||||||
|
return logsFile;
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
Timber.e(ioe);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -207,5 +207,7 @@ Tap this message (or hit back) to skip this step.</string>
|
||||||
<string name="give_permission">Give permission</string>
|
<string name="give_permission">Give permission</string>
|
||||||
<string name="use_external_storage">Use external storage</string>
|
<string name="use_external_storage">Use external storage</string>
|
||||||
<string name="use_external_storage_summary">Save pictures taken with the in-app camera on your device</string>
|
<string name="use_external_storage_summary">Save pictures taken with the in-app camera on your device</string>
|
||||||
<string name="login_to_your_account">Login to your account</string>
|
<string name="send_log_file">Send log file</string>
|
||||||
|
<string name="send_log_file_description">Send log file to developers via email</string>
|
||||||
|
<string name="login_to_your_account">Login to your account</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
||||||
|
|
@ -53,4 +53,9 @@
|
||||||
android:summary="@string/use_external_storage_summary"
|
android:summary="@string/use_external_storage_summary"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<Preference
|
||||||
|
android:key="sendLogFile"
|
||||||
|
android:title="@string/send_log_file"
|
||||||
|
android:summary="@string/send_log_file_description"/>
|
||||||
|
|
||||||
</PreferenceScreen>
|
</PreferenceScreen>
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<paths>
|
<paths>
|
||||||
<cache-path name="images" path="images/" />
|
<cache-path name="images" path="images/" />
|
||||||
|
<external-path name="logs"/>
|
||||||
</paths>
|
</paths>
|
||||||
Loading…
Add table
Add a link
Reference in a new issue