diff options
4 files changed, 156 insertions, 106 deletions
diff --git a/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java b/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java index d095e2fa..0b3b2990 100644 --- a/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java +++ b/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java @@ -52,7 +52,7 @@ public class DatabaseBackend extends SQLiteOpenHelper { private static DatabaseBackend instance = null; private static final String DATABASE_NAME = "history"; - private static final int DATABASE_VERSION = 27; + private static final int DATABASE_VERSION = 28; private static String CREATE_CONTATCS_STATEMENT = "create table " + Contact.TABLENAME + "(" + Contact.ACCOUNT + " TEXT, " @@ -250,86 +250,7 @@ public class DatabaseBackend extends SQLiteOpenHelper { db.execSQL("update " + Account.TABLENAME + " set " + Account.ROSTERVERSION + " = NULL"); } if (oldVersion < 14 && newVersion >= 14) { - // migrate db to new, canonicalized JID domainpart representation - - // Conversation table - Cursor cursor = db.rawQuery("select * from " + Conversation.TABLENAME, new String[0]); - while (cursor.moveToNext()) { - String newJid; - try { - newJid = Jid.fromString( - cursor.getString(cursor.getColumnIndex(Conversation.CONTACTJID)) - ).toString(); - } catch (InvalidJidException ignored) { - Log.e(Config.LOGTAG, "Failed to migrate Conversation CONTACTJID " - + cursor.getString(cursor.getColumnIndex(Conversation.CONTACTJID)) - + ": " + ignored + ". Skipping..."); - continue; - } - - String updateArgs[] = { - newJid, - cursor.getString(cursor.getColumnIndex(Conversation.UUID)), - }; - db.execSQL("update " + Conversation.TABLENAME - + " set " + Conversation.CONTACTJID + " = ? " - + " where " + Conversation.UUID + " = ?", updateArgs); - } - cursor.close(); - - // Contact table - cursor = db.rawQuery("select * from " + Contact.TABLENAME, new String[0]); - while (cursor.moveToNext()) { - String newJid; - try { - newJid = Jid.fromString( - cursor.getString(cursor.getColumnIndex(Contact.JID)) - ).toString(); - } catch (InvalidJidException ignored) { - Log.e(Config.LOGTAG, "Failed to migrate Contact JID " - + cursor.getString(cursor.getColumnIndex(Contact.JID)) - + ": " + ignored + ". Skipping..."); - continue; - } - - String updateArgs[] = { - newJid, - cursor.getString(cursor.getColumnIndex(Contact.ACCOUNT)), - cursor.getString(cursor.getColumnIndex(Contact.JID)), - }; - db.execSQL("update " + Contact.TABLENAME - + " set " + Contact.JID + " = ? " - + " where " + Contact.ACCOUNT + " = ? " - + " AND " + Contact.JID + " = ?", updateArgs); - } - cursor.close(); - - // Account table - cursor = db.rawQuery("select * from " + Account.TABLENAME, new String[0]); - while (cursor.moveToNext()) { - String newServer; - try { - newServer = Jid.fromParts( - cursor.getString(cursor.getColumnIndex(Account.USERNAME)), - cursor.getString(cursor.getColumnIndex(Account.SERVER)), - "mobile" - ).getDomainpart(); - } catch (InvalidJidException ignored) { - Log.e(Config.LOGTAG, "Failed to migrate Account SERVER " - + cursor.getString(cursor.getColumnIndex(Account.SERVER)) - + ": " + ignored + ". Skipping..."); - continue; - } - - String updateArgs[] = { - newServer, - cursor.getString(cursor.getColumnIndex(Account.UUID)), - }; - db.execSQL("update " + Account.TABLENAME - + " set " + Account.SERVER + " = ? " - + " where " + Account.UUID + " = ?", updateArgs); - } - cursor.close(); + canonicalizeJids(db); } if (oldVersion < 15 && newVersion >= 15) { recreateAxolotlDb(db); @@ -406,6 +327,93 @@ public class DatabaseBackend extends SQLiteOpenHelper { if (oldVersion < 27 && newVersion >= 27) { db.execSQL("DELETE FROM "+ServiceDiscoveryResult.TABLENAME); } + + if (oldVersion < 28 && newVersion >= 28) { + canonicalizeJids(db); + } + } + + private void canonicalizeJids(SQLiteDatabase db) { + // migrate db to new, canonicalized JID domainpart representation + + // Conversation table + Cursor cursor = db.rawQuery("select * from " + Conversation.TABLENAME, new String[0]); + while (cursor.moveToNext()) { + String newJid; + try { + newJid = Jid.fromString( + cursor.getString(cursor.getColumnIndex(Conversation.CONTACTJID)) + ).toString(); + } catch (InvalidJidException ignored) { + Log.e(Config.LOGTAG, "Failed to migrate Conversation CONTACTJID " + + cursor.getString(cursor.getColumnIndex(Conversation.CONTACTJID)) + + ": " + ignored + ". Skipping..."); + continue; + } + + String updateArgs[] = { + newJid, + cursor.getString(cursor.getColumnIndex(Conversation.UUID)), + }; + db.execSQL("update " + Conversation.TABLENAME + + " set " + Conversation.CONTACTJID + " = ? " + + " where " + Conversation.UUID + " = ?", updateArgs); + } + cursor.close(); + + // Contact table + cursor = db.rawQuery("select * from " + Contact.TABLENAME, new String[0]); + while (cursor.moveToNext()) { + String newJid; + try { + newJid = Jid.fromString( + cursor.getString(cursor.getColumnIndex(Contact.JID)) + ).toString(); + } catch (InvalidJidException ignored) { + Log.e(Config.LOGTAG, "Failed to migrate Contact JID " + + cursor.getString(cursor.getColumnIndex(Contact.JID)) + + ": " + ignored + ". Skipping..."); + continue; + } + + String updateArgs[] = { + newJid, + cursor.getString(cursor.getColumnIndex(Contact.ACCOUNT)), + cursor.getString(cursor.getColumnIndex(Contact.JID)), + }; + db.execSQL("update " + Contact.TABLENAME + + " set " + Contact.JID + " = ? " + + " where " + Contact.ACCOUNT + " = ? " + + " AND " + Contact.JID + " = ?", updateArgs); + } + cursor.close(); + + // Account table + cursor = db.rawQuery("select * from " + Account.TABLENAME, new String[0]); + while (cursor.moveToNext()) { + String newServer; + try { + newServer = Jid.fromParts( + cursor.getString(cursor.getColumnIndex(Account.USERNAME)), + cursor.getString(cursor.getColumnIndex(Account.SERVER)), + "mobile" + ).getDomainpart(); + } catch (InvalidJidException ignored) { + Log.e(Config.LOGTAG, "Failed to migrate Account SERVER " + + cursor.getString(cursor.getColumnIndex(Account.SERVER)) + + ": " + ignored + ". Skipping..."); + continue; + } + + String updateArgs[] = { + newServer, + cursor.getString(cursor.getColumnIndex(Account.UUID)), + }; + db.execSQL("update " + Account.TABLENAME + + " set " + Account.SERVER + " = ? " + + " where " + Account.UUID + " = ?", updateArgs); + } + cursor.close(); } public static synchronized DatabaseBackend getInstance(Context context) { diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java index e891f00b..2c8b27b0 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java @@ -67,8 +67,6 @@ import eu.siacs.conversations.xmpp.OnUpdateBlocklist; import eu.siacs.conversations.xmpp.jid.InvalidJidException; import eu.siacs.conversations.xmpp.jid.Jid; -import static eu.siacs.conversations.crypto.axolotl.AxolotlService.AxolotlCapability.MISSING_PRESENCE; - public class ConversationActivity extends XmppActivity implements OnAccountUpdate, OnConversationUpdate, OnRosterUpdate, OnUpdateBlocklist, XmppConnectionService.OnShowErrorToast { @@ -94,9 +92,12 @@ public class ConversationActivity extends XmppActivity private static final String STATE_OPEN_CONVERSATION = "state_open_conversation"; private static final String STATE_PANEL_OPEN = "state_panel_open"; private static final String STATE_PENDING_URI = "state_pending_uri"; + private static final String STATE_FIRST_VISIBLE = "first_visible"; + private static final String STATE_OFFSET_FROM_TOP = "offset_from_top"; - private String mOpenConverstaion = null; + private String mOpenConversation = null; private boolean mPanelOpen = true; + private Pair<Integer,Integer> mScrollPosition = null; final private List<Uri> mPendingImageUris = new ArrayList<>(); final private List<Uri> mPendingFileUris = new ArrayList<>(); private Uri mPendingGeoUri = null; @@ -172,8 +173,16 @@ public class ConversationActivity extends XmppActivity protected void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (savedInstanceState != null) { - mOpenConverstaion = savedInstanceState.getString(STATE_OPEN_CONVERSATION, null); + mOpenConversation = savedInstanceState.getString(STATE_OPEN_CONVERSATION, null); mPanelOpen = savedInstanceState.getBoolean(STATE_PANEL_OPEN, true); + int pos = savedInstanceState.getInt(STATE_FIRST_VISIBLE, -1); + int offset = savedInstanceState.getInt(STATE_OFFSET_FROM_TOP, 1); + if (pos >= 0 && offset <= 0) { + Log.d(Config.LOGTAG,"retrieved scroll position from instanceState "+pos+":"+offset); + mScrollPosition = new Pair<>(pos,offset); + } else { + mScrollPosition = null; + } String pending = savedInstanceState.getString(STATE_PENDING_URI, null); if (pending != null) { mPendingImageUris.clear(); @@ -1081,7 +1090,7 @@ public class ConversationActivity extends XmppActivity @Override protected void onNewIntent(final Intent intent) { if (intent != null && ACTION_VIEW_CONVERSATION.equals(intent.getAction())) { - mOpenConverstaion = null; + mOpenConversation = null; if (xmppConnectionServiceBound) { handleViewConversationIntent(intent); intent.setAction(Intent.ACTION_MAIN); @@ -1131,6 +1140,11 @@ public class ConversationActivity extends XmppActivity Conversation conversation = getSelectedConversation(); if (conversation != null) { savedInstanceState.putString(STATE_OPEN_CONVERSATION, conversation.getUuid()); + Pair<Integer,Integer> scrollPosition = mConversationFragment.getScrollPosition(); + if (scrollPosition != null) { + savedInstanceState.putInt(STATE_FIRST_VISIBLE, scrollPosition.first); + savedInstanceState.putInt(STATE_OFFSET_FROM_TOP, scrollPosition.second); + } } else { savedInstanceState.remove(STATE_OPEN_CONVERSATION); } @@ -1190,7 +1204,7 @@ public class ConversationActivity extends XmppActivity } finish(); } - } else if (selectConversationByUuid(mOpenConverstaion)) { + } else if (selectConversationByUuid(mOpenConversation)) { if (mPanelOpen) { showConversationsOverview(); } else { @@ -1199,8 +1213,11 @@ public class ConversationActivity extends XmppActivity updateActionBarTitle(true); } } - this.mConversationFragment.reInit(getSelectedConversation()); - mOpenConverstaion = null; + if (this.mConversationFragment.reInit(getSelectedConversation())) { + Log.d(Config.LOGTAG,"setting scroll position on fragment"); + this.mConversationFragment.setScrollPosition(mScrollPosition); + } + mOpenConversation = null; } else if (intent != null && ACTION_VIEW_CONVERSATION.equals(intent.getAction())) { clearPending(); handleViewConversationIntent(intent); diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java index edee551b..80b5ff82 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java @@ -12,6 +12,8 @@ import android.content.IntentSender.SendIntentException; import android.os.Bundle; import android.os.Handler; import android.text.InputType; +import android.util.Log; +import android.util.Pair; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; import android.view.Gravity; @@ -153,7 +155,11 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa View v = messagesView.getChildAt(0); final int pxOffset = (v == null) ? 0 : v.getTop(); ConversationFragment.this.conversation.populateWithMessages(ConversationFragment.this.messageList); - updateStatusMessages(); + try { + updateStatusMessages(); + } catch (IllegalStateException e) { + Log.d(Config.LOGTAG,"caught illegal state exception while updating status messages"); + } messageListAdapter.notifyDataSetChanged(); int pos = Math.max(getIndexOf(uuid,messageList),0); messagesView.setSelectionFromTop(pos, pxOffset); @@ -210,6 +216,28 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa } return -1; } + + public Pair<Integer,Integer> getScrollPosition() { + if (this.messagesView.getCount() == 0 || + this.messagesView.getLastVisiblePosition() == this.messagesView.getCount() - 1) { + return null; + } else { + final int pos = messagesView.getFirstVisiblePosition(); + final View view = messagesView.getChildAt(0); + if (view == null) { + return null; + } else { + return new Pair<>(pos, view.getTop()); + } + } + } + + public void setScrollPosition(Pair<Integer,Integer> scrollPosition) { + if (scrollPosition != null) { + this.messagesView.setSelectionFromTop(scrollPosition.first, scrollPosition.second); + } + } + protected OnClickListener clickToDecryptListener = new OnClickListener() { @Override @@ -736,9 +764,9 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa } } - public void reInit(Conversation conversation) { + public boolean reInit(Conversation conversation) { if (conversation == null) { - return; + return false; } this.activity = (ConversationActivity) getActivity(); setupIme(); @@ -774,6 +802,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa pos = i < 0 ? bottom : i; } messagesView.setSelection(pos); + return pos == bottom; } } diff --git a/src/main/java/eu/siacs/conversations/xmpp/jid/Jid.java b/src/main/java/eu/siacs/conversations/xmpp/jid/Jid.java index a15abe14..6430d41e 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jid/Jid.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jid/Jid.java @@ -21,10 +21,6 @@ public final class Jid { private final String domainpart; private final String resourcepart; - // It's much more efficient to store the ful JID as well as the parts instead of figuring them - // all out every time (since some characters are displayed but aren't used for comparisons). - private final String displayjid; - public String getLocalpart() { return localpart; } @@ -73,7 +69,6 @@ public final class Jid { Jid fromCache = Jid.cache.get(jid); if (fromCache != null) { - displayjid = fromCache.displayjid; localpart = fromCache.localpart; domainpart = fromCache.domainpart; resourcepart = fromCache.resourcepart; @@ -94,8 +89,6 @@ public final class Jid { throw new InvalidJidException(InvalidJidException.INVALID_CHARACTER); } - String finaljid; - final int domainpartStart; final int atLoc = jid.indexOf("@"); final int slashLoc = jid.indexOf("/"); @@ -103,7 +96,6 @@ public final class Jid { // or there are one or more "@" signs but they're all in the resourcepart (eg. "example.net/@/rp@"): if (atCount == 0 || (atCount > 0 && slashLoc != -1 && atLoc > slashLoc)) { localpart = ""; - finaljid = ""; domainpartStart = 0; } else { final String lp = jid.substring(0, atLoc); @@ -116,7 +108,6 @@ public final class Jid { throw new InvalidJidException(InvalidJidException.INVALID_PART_LENGTH); } domainpartStart = atLoc + 1; - finaljid = lp + "@"; } final String dp; @@ -135,7 +126,6 @@ public final class Jid { } catch (final StringprepException e) { throw new InvalidJidException(InvalidJidException.STRINGPREP_FAIL, e); } - finaljid = finaljid + dp + "/" + rp; } else { resourcepart = ""; try{ @@ -143,7 +133,6 @@ public final class Jid { } catch (final StringprepException e) { throw new InvalidJidException(InvalidJidException.STRINGPREP_FAIL, e); } - finaljid = finaljid + dp; } // Remove trailing "." before storing the domain part. @@ -167,8 +156,6 @@ public final class Jid { } Jid.cache.put(jid, this); - - this.displayjid = finaljid; } public Jid toBareJid() { @@ -191,7 +178,16 @@ public final class Jid { @Override public String toString() { - return displayjid; + String out; + if (hasLocalpart()) { + out = localpart + '@' + domainpart; + } else { + out = domainpart; + } + if (!resourcepart.isEmpty()) { + out += '/'+resourcepart; + } + return out; } @Override |