diff options
-rw-r--r-- | src/main/AndroidManifest.xml | 1 | ||||
-rw-r--r-- | src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java | 38 | ||||
-rw-r--r-- | src/main/java/eu/siacs/conversations/services/ExportLogsService.java | 141 | ||||
-rw-r--r-- | src/main/java/eu/siacs/conversations/ui/ExportLogsPreference.java | 29 | ||||
-rw-r--r-- | src/main/res/values/strings.xml | 3 | ||||
-rw-r--r-- | src/main/res/xml/preferences.xml | 4 |
6 files changed, 216 insertions, 0 deletions
diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml index 89ea620a..07863ffc 100644 --- a/src/main/AndroidManifest.xml +++ b/src/main/AndroidManifest.xml @@ -149,6 +149,7 @@ android:name="android.support.PARENT_ACTIVITY" android:value="eu.siacs.conversations.ui.SettingsActivity" /> </activity> + <service android:name=".services.ExportLogsService" /> </application> </manifest> diff --git a/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java b/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java index d420c1cd..be827929 100644 --- a/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java +++ b/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java @@ -21,6 +21,7 @@ import org.whispersystems.libaxolotl.state.SignedPreKeyRecord; import java.io.IOException; import java.util.ArrayList; import java.util.HashSet; +import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList; @@ -407,6 +408,43 @@ public class DatabaseBackend extends SQLiteOpenHelper { 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) { SQLiteDatabase db = this.getReadableDatabase(); String[] selectionArgs = { account.getUuid(), diff --git a/src/main/java/eu/siacs/conversations/services/ExportLogsService.java b/src/main/java/eu/siacs/conversations/services/ExportLogsService.java new file mode 100644 index 00000000..41b34699 --- /dev/null +++ b/src/main/java/eu/siacs/conversations/services/ExportLogsService.java @@ -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; + } +}
\ No newline at end of file diff --git a/src/main/java/eu/siacs/conversations/ui/ExportLogsPreference.java b/src/main/java/eu/siacs/conversations/ui/ExportLogsPreference.java new file mode 100644 index 00000000..a4e178bd --- /dev/null +++ b/src/main/java/eu/siacs/conversations/ui/ExportLogsPreference.java @@ -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(); + } +}
\ No newline at end of file diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index aafcc2af..22e810ea 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -367,6 +367,9 @@ <string name="conversations_foreground_service">Conversations</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_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="receiving_x_file">Receiving %1$s (%2$d%% completed)</string> <string name="download_x_file">Download %s</string> diff --git a/src/main/res/xml/preferences.xml b/src/main/res/xml/preferences.xml index 6663c22b..c78e9ede 100644 --- a/src/main/res/xml/preferences.xml +++ b/src/main/res/xml/preferences.xml @@ -170,6 +170,10 @@ android:key="keep_foreground_service" android:summary="@string/pref_keep_foreground_service_summary" 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> </PreferenceScreen> |