Merge pull request #1426 from fiaxh/export_logs
Preference to backup logs to SD card
This commit is contained in:
commit
6f7fb7dec6
|
@ -149,6 +149,7 @@
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value="eu.siacs.conversations.ui.SettingsActivity" />
|
android:value="eu.siacs.conversations.ui.SettingsActivity" />
|
||||||
</activity>
|
</activity>
|
||||||
|
<service android:name=".services.ExportLogsService" />
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|
|
@ -21,6 +21,7 @@ import org.whispersystems.libaxolotl.state.SignedPreKeyRecord;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
|
@ -407,6 +408,43 @@ public class DatabaseBackend extends SQLiteOpenHelper {
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Iterable<Message> getMessagesIterable(final Conversation conversation){
|
||||||
|
return new Iterable<Message>() {
|
||||||
|
@Override
|
||||||
|
public Iterator<Message> iterator() {
|
||||||
|
class MessageIterator implements Iterator<Message>{
|
||||||
|
SQLiteDatabase db = getReadableDatabase();
|
||||||
|
String[] selectionArgs = { conversation.getUuid() };
|
||||||
|
Cursor cursor = db.query(Message.TABLENAME, null, Message.CONVERSATION
|
||||||
|
+ "=?", selectionArgs, null, null, Message.TIME_SENT
|
||||||
|
+ " ASC", null);
|
||||||
|
|
||||||
|
public MessageIterator() {
|
||||||
|
cursor.moveToFirst();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
return !cursor.isAfterLast();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Message next() {
|
||||||
|
Message message = Message.fromCursor(cursor);
|
||||||
|
cursor.moveToNext();
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void remove() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new MessageIterator();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
public Conversation findConversation(final Account account, final Jid contactJid) {
|
public Conversation findConversation(final Account account, final Jid contactJid) {
|
||||||
SQLiteDatabase db = this.getReadableDatabase();
|
SQLiteDatabase db = this.getReadableDatabase();
|
||||||
String[] selectionArgs = { account.getUuid(),
|
String[] selectionArgs = { account.getUuid(),
|
||||||
|
|
|
@ -0,0 +1,141 @@
|
||||||
|
package eu.siacs.conversations.services;
|
||||||
|
|
||||||
|
import android.app.NotificationManager;
|
||||||
|
import android.app.Service;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.IBinder;
|
||||||
|
import android.support.v4.app.NotificationCompat;
|
||||||
|
|
||||||
|
import eu.siacs.conversations.R;
|
||||||
|
import eu.siacs.conversations.entities.Account;
|
||||||
|
import eu.siacs.conversations.entities.Conversation;
|
||||||
|
import eu.siacs.conversations.entities.Message;
|
||||||
|
import eu.siacs.conversations.persistance.DatabaseBackend;
|
||||||
|
import eu.siacs.conversations.persistance.FileBackend;
|
||||||
|
import eu.siacs.conversations.xmpp.jid.Jid;
|
||||||
|
|
||||||
|
import java.io.BufferedWriter;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileWriter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
|
public class ExportLogsService extends Service {
|
||||||
|
|
||||||
|
private static final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
|
||||||
|
private static final String DIRECTORY_STRING_FORMAT = FileBackend.getConversationsFileDirectory() + "/logs/%s";
|
||||||
|
private static final String MESSAGE_STRING_FORMAT = "(%s) %s: %s\n";
|
||||||
|
private static final int NOTIFICATION_ID = 1;
|
||||||
|
private static AtomicBoolean running = new AtomicBoolean(false);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||||
|
if (running.compareAndSet(false, true)) {
|
||||||
|
new Thread(
|
||||||
|
new Runnable() {
|
||||||
|
DatabaseBackend databaseBackend = DatabaseBackend.getInstance(getBaseContext());
|
||||||
|
List<Account> accounts = databaseBackend.getAccounts();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
List<Conversation> conversations = databaseBackend.getConversations(Conversation.STATUS_AVAILABLE);
|
||||||
|
conversations.addAll(databaseBackend.getConversations(Conversation.STATUS_ARCHIVED));
|
||||||
|
|
||||||
|
NotificationManager mNotifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||||
|
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(getBaseContext());
|
||||||
|
mBuilder.setContentTitle(getString(R.string.notification_export_logs_title))
|
||||||
|
.setSmallIcon(R.drawable.ic_notification)
|
||||||
|
.setProgress(conversations.size(), 0, false);
|
||||||
|
startForeground(NOTIFICATION_ID, mBuilder.build());
|
||||||
|
|
||||||
|
int progress = 0;
|
||||||
|
for (Conversation conversation : conversations) {
|
||||||
|
writeToFile(conversation);
|
||||||
|
progress++;
|
||||||
|
mBuilder.setProgress(conversations.size(), progress, false);
|
||||||
|
mNotifyManager.notify(NOTIFICATION_ID, mBuilder.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
running.set(false);
|
||||||
|
stopForeground(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeToFile(Conversation conversation) {
|
||||||
|
Jid accountJid = resolveAccountUuid(conversation.getAccountUuid());
|
||||||
|
Jid contactJid = conversation.getJid();
|
||||||
|
|
||||||
|
File dir = new File(String.format(DIRECTORY_STRING_FORMAT,
|
||||||
|
accountJid.toBareJid().toString()));
|
||||||
|
dir.mkdirs();
|
||||||
|
|
||||||
|
BufferedWriter bw = null;
|
||||||
|
try {
|
||||||
|
for (Message message : databaseBackend.getMessagesIterable(conversation)) {
|
||||||
|
if (message.getType() == Message.TYPE_TEXT || message.hasFileOnRemoteHost()) {
|
||||||
|
String date = simpleDateFormat.format(new Date(message.getTimeSent()));
|
||||||
|
if (bw == null) {
|
||||||
|
bw = new BufferedWriter(new FileWriter(
|
||||||
|
new File(dir, contactJid.toBareJid().toString() + ".txt")));
|
||||||
|
}
|
||||||
|
String jid = null;
|
||||||
|
switch (message.getStatus()) {
|
||||||
|
case Message.STATUS_RECEIVED:
|
||||||
|
jid = getMessageCounterpart(message);
|
||||||
|
break;
|
||||||
|
case Message.STATUS_SEND:
|
||||||
|
case Message.STATUS_SEND_RECEIVED:
|
||||||
|
case Message.STATUS_SEND_DISPLAYED:
|
||||||
|
jid = accountJid.toBareJid().toString();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (jid != null) {
|
||||||
|
String body = message.hasFileOnRemoteHost() ? message.getFileParams().url.toString() : message.getBody();
|
||||||
|
bw.write(String.format(MESSAGE_STRING_FORMAT, date, jid,
|
||||||
|
body.replace("\\\n", "\\ \n").replace("\n", "\\ \n")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
if (bw != null) {
|
||||||
|
bw.close();
|
||||||
|
}
|
||||||
|
} catch (IOException e1) {
|
||||||
|
e1.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Jid resolveAccountUuid(String accountUuid) {
|
||||||
|
for (Account account : accounts) {
|
||||||
|
if (account.getUuid().equals(accountUuid)) {
|
||||||
|
return account.getJid();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getMessageCounterpart(Message message) {
|
||||||
|
String trueCounterpart = (String) message.getContentValues().get(Message.TRUE_COUNTERPART);
|
||||||
|
if (trueCounterpart != null) {
|
||||||
|
return trueCounterpart;
|
||||||
|
} else {
|
||||||
|
return message.getCounterpart().toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
|
}
|
||||||
|
return START_STICKY;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IBinder onBind(Intent intent) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
package eu.siacs.conversations.ui;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.preference.Preference;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
|
||||||
|
import eu.siacs.conversations.services.ExportLogsService;
|
||||||
|
|
||||||
|
public class ExportLogsPreference extends Preference {
|
||||||
|
|
||||||
|
public ExportLogsPreference(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||||
|
super(context, attrs, defStyleAttr);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExportLogsPreference(Context context, AttributeSet attrs) {
|
||||||
|
super(context, attrs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExportLogsPreference(Context context) {
|
||||||
|
super(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void onClick() {
|
||||||
|
final Intent startIntent = new Intent(getContext(), ExportLogsService.class);
|
||||||
|
getContext().startService(startIntent);
|
||||||
|
super.onClick();
|
||||||
|
}
|
||||||
|
}
|
|
@ -367,6 +367,9 @@
|
||||||
<string name="conversations_foreground_service">Conversations</string>
|
<string name="conversations_foreground_service">Conversations</string>
|
||||||
<string name="pref_keep_foreground_service">Keep service in foreground</string>
|
<string name="pref_keep_foreground_service">Keep service in foreground</string>
|
||||||
<string name="pref_keep_foreground_service_summary">Prevents the operating system from killing your connection</string>
|
<string name="pref_keep_foreground_service_summary">Prevents the operating system from killing your connection</string>
|
||||||
|
<string name="pref_export_logs">Export Logs</string>
|
||||||
|
<string name="pref_export_logs_summary">Write logs to SD card</string>
|
||||||
|
<string name="notification_export_logs_title">Writing logs to SD card</string>
|
||||||
<string name="choose_file">Choose file</string>
|
<string name="choose_file">Choose file</string>
|
||||||
<string name="receiving_x_file">Receiving %1$s (%2$d%% completed)</string>
|
<string name="receiving_x_file">Receiving %1$s (%2$d%% completed)</string>
|
||||||
<string name="download_x_file">Download %s</string>
|
<string name="download_x_file">Download %s</string>
|
||||||
|
|
|
@ -170,6 +170,10 @@
|
||||||
android:key="keep_foreground_service"
|
android:key="keep_foreground_service"
|
||||||
android:summary="@string/pref_keep_foreground_service_summary"
|
android:summary="@string/pref_keep_foreground_service_summary"
|
||||||
android:title="@string/pref_keep_foreground_service"/>
|
android:title="@string/pref_keep_foreground_service"/>
|
||||||
|
<eu.siacs.conversations.ui.ExportLogsPreference
|
||||||
|
android:key="export_logs"
|
||||||
|
android:title="@string/pref_export_logs"
|
||||||
|
android:summary="@string/pref_export_logs_summary"/>
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
</PreferenceScreen>
|
</PreferenceScreen>
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue