Skip to content

Commit d091090

Browse files
Merge pull request commons-app#920 from Bluesir9/fix_736_send_app_logs
Allow user to send app logs
2 parents 1f88b6d + 0cc096c commit d091090

File tree

7 files changed

+155
-1
lines changed

7 files changed

+155
-1
lines changed

app/src/main/AndroidManifest.xml

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS"/>
1515
<uses-permission android:name="android.permission.MANAGE_DOCUMENTS"/>
1616
<uses-permission android:name="com.google.android.apps.photos.permission.GOOGLE_PHOTOS"/>
17+
<uses-permission android:name="android.permission.READ_LOGS"/>
1718

1819
<application
1920
android:name=".CommonsApplication"

app/src/main/java/fr/free/nrw/commons/Utils.java

+35
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,10 @@
1313
import org.xmlpull.v1.XmlPullParserException;
1414

1515
import java.io.BufferedInputStream;
16+
import java.io.BufferedReader;
1617
import java.io.IOException;
1718
import java.io.InputStream;
19+
import java.io.InputStreamReader;
1820
import java.io.StringWriter;
1921
import java.io.UnsupportedEncodingException;
2022
import java.math.BigInteger;
@@ -281,4 +283,37 @@ public static boolean isNullOrWhiteSpace(String value) {
281283
public static boolean isDarkTheme(Context context) {
282284
return PreferenceManager.getDefaultSharedPreferences(context).getBoolean("theme", false);
283285
}
286+
287+
/**
288+
* Will be used to fetch the logs generated by the app ever since the beginning of times....
289+
* i.e. since the time the app started.
290+
*
291+
* @return String containing all the logs since the time the app started
292+
*/
293+
public static String getAppLogs() {
294+
final String processId = Integer.toString(android.os.Process.myPid());
295+
296+
StringBuilder stringBuilder = new StringBuilder();
297+
298+
try {
299+
String[] command = new String[] {"logcat","-d","-v","threadtime"};
300+
301+
Process process = Runtime.getRuntime().exec(command);
302+
303+
BufferedReader bufferedReader = new BufferedReader(
304+
new InputStreamReader(process.getInputStream())
305+
);
306+
307+
String line;
308+
while ((line = bufferedReader.readLine()) != null) {
309+
if (line.contains(processId)) {
310+
stringBuilder.append(line);
311+
}
312+
}
313+
} catch (IOException ioe) {
314+
Timber.e("getAppLogs failed", ioe);
315+
}
316+
317+
return stringBuilder.toString();
318+
}
284319
}

app/src/main/java/fr/free/nrw/commons/settings/SettingsFragment.java

+77
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,39 @@
11
package fr.free.nrw.commons.settings;
22

3+
import android.Manifest;
34
import android.app.AlertDialog;
5+
import android.content.ActivityNotFoundException;
6+
import android.content.Context;
7+
import android.content.Intent;
48
import android.content.SharedPreferences;
9+
import android.content.pm.PackageManager;
10+
import android.net.Uri;
11+
import android.os.Build;
512
import android.os.Bundle;
613
import android.preference.CheckBoxPreference;
714
import android.preference.EditTextPreference;
815
import android.preference.ListPreference;
16+
import android.preference.Preference;
917
import android.preference.PreferenceFragment;
1018
import android.preference.PreferenceManager;
19+
import android.support.annotation.NonNull;
20+
import android.support.v4.app.ActivityCompat;
21+
import android.support.v4.content.ContextCompat;
22+
import android.support.v4.content.FileProvider;
23+
import android.widget.Toast;
1124

25+
import java.io.File;
26+
27+
import fr.free.nrw.commons.BuildConfig;
1228
import fr.free.nrw.commons.CommonsApplication;
1329
import fr.free.nrw.commons.R;
1430
import fr.free.nrw.commons.Utils;
31+
import fr.free.nrw.commons.utils.FileUtils;
1532

1633
public class SettingsFragment extends PreferenceFragment {
34+
35+
private static final int REQUEST_CODE_WRITE_EXTERNAL_STORAGE = 100;
36+
1737
@Override
1838
public void onCreate(Bundle savedInstanceState) {
1939
super.onCreate(savedInstanceState);
@@ -66,6 +86,63 @@ public void onCreate(Bundle savedInstanceState) {
6686
return true;
6787
});
6888

89+
Preference sendLogsPreference = findPreference("sendLogFile");
90+
sendLogsPreference.setOnPreferenceClickListener(preference -> {
91+
//first we need to check if we have the necessary permissions
92+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
93+
if (ContextCompat.checkSelfPermission(
94+
getActivity(),
95+
Manifest.permission.WRITE_EXTERNAL_STORAGE)
96+
==
97+
PackageManager.PERMISSION_GRANTED) {
98+
sendAppLogsViaEmail();
99+
} else {
100+
//first get the necessary permission
101+
requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
102+
REQUEST_CODE_WRITE_EXTERNAL_STORAGE);
103+
}
104+
} else {
105+
sendAppLogsViaEmail();
106+
}
107+
108+
return true;
109+
});
110+
}
111+
112+
@Override
113+
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
114+
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
115+
if (requestCode == REQUEST_CODE_WRITE_EXTERNAL_STORAGE) {
116+
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
117+
sendAppLogsViaEmail();
118+
}
119+
}
120+
}
121+
122+
private void sendAppLogsViaEmail() {
123+
String appLogs = Utils.getAppLogs();
124+
File appLogsFile = FileUtils.createAndGetAppLogsFile(appLogs);
125+
126+
Context applicationContext = getActivity().getApplicationContext();
127+
Uri appLogsFilePath = FileProvider.getUriForFile(
128+
getActivity(),
129+
applicationContext.getPackageName() + ".provider",
130+
appLogsFile
131+
);
132+
133+
Intent feedbackIntent = new Intent(Intent.ACTION_SEND);
134+
feedbackIntent.setType("message/rfc822");
135+
feedbackIntent.putExtra(Intent.EXTRA_EMAIL,
136+
new String[]{CommonsApplication.FEEDBACK_EMAIL});
137+
feedbackIntent.putExtra(Intent.EXTRA_SUBJECT,
138+
String.format(CommonsApplication.FEEDBACK_EMAIL_SUBJECT,
139+
BuildConfig.VERSION_NAME));
140+
feedbackIntent.putExtra(Intent.EXTRA_STREAM,appLogsFilePath);
69141

142+
try {
143+
startActivity(feedbackIntent);
144+
} catch (ActivityNotFoundException e) {
145+
Toast.makeText(getActivity(), R.string.no_email_client, Toast.LENGTH_SHORT).show();
146+
}
70147
}
71148
}

app/src/main/java/fr/free/nrw/commons/utils/FileUtils.java

+33
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
11
package fr.free.nrw.commons.utils;
22

3+
import android.os.Environment;
4+
35
import java.io.BufferedReader;
46
import java.io.File;
7+
import java.io.FileOutputStream;
58
import java.io.IOException;
69
import java.io.InputStreamReader;
10+
import java.io.OutputStream;
11+
import java.io.OutputStreamWriter;
712

813
import fr.free.nrw.commons.CommonsApplication;
14+
import timber.log.Timber;
915

1016
public class FileUtils {
1117
/**
@@ -53,5 +59,32 @@ public static boolean deleteFile(File file) {
5359
return deletedAll;
5460
}
5561

62+
public static File createAndGetAppLogsFile(String logs) {
63+
try {
64+
File commonsAppDirectory = new File(Environment.getExternalStorageDirectory().toString() + "/CommonsApp");
65+
if (!commonsAppDirectory.exists()) {
66+
commonsAppDirectory.mkdir();
67+
}
68+
69+
File logsFile = new File(commonsAppDirectory,"logs.txt");
70+
if (logsFile.exists()) {
71+
//old logs file is useless
72+
logsFile.delete();
73+
}
5674

75+
logsFile.createNewFile();
76+
77+
FileOutputStream outputStream = new FileOutputStream(logsFile);
78+
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream);
79+
outputStreamWriter.append(logs);
80+
outputStreamWriter.close();
81+
outputStream.flush();
82+
outputStream.close();
83+
84+
return logsFile;
85+
} catch (IOException ioe) {
86+
Timber.e(ioe);
87+
return null;
88+
}
89+
}
5790
}

app/src/main/res/values/strings.xml

+3-1
Original file line numberDiff line numberDiff line change
@@ -207,5 +207,7 @@ Tap this message (or hit back) to skip this step.</string>
207207
<string name="give_permission">Give permission</string>
208208
<string name="use_external_storage">Use external storage</string>
209209
<string name="use_external_storage_summary">Save pictures taken with the in-app camera on your device</string>
210-
<string name="login_to_your_account">Login to your account</string>
210+
<string name="send_log_file">Send log file</string>
211+
<string name="send_log_file_description">Send log file to developers via email</string>
212+
<string name="login_to_your_account">Login to your account</string>
211213
</resources>

app/src/main/res/xml/preferences.xml

+5
Original file line numberDiff line numberDiff line change
@@ -53,4 +53,9 @@
5353
android:summary="@string/use_external_storage_summary"
5454
/>
5555

56+
<Preference
57+
android:key="sendLogFile"
58+
android:title="@string/send_log_file"
59+
android:summary="@string/send_log_file_description"/>
60+
5661
</PreferenceScreen>
+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<paths>
33
<cache-path name="images" path="images/" />
4+
<external-path name="logs"/>
45
</paths>

0 commit comments

Comments
 (0)