/** * Copyright (c) 2013, Redsolution LTD. All rights reserved. * * This file is part of Xabber project; you can redistribute it and/or * modify it under the terms of the GNU General Public License, Version 3. * * Xabber is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License, * along with this program. If not, see http://www.gnu.org/licenses/. */ package com.xabber.android.data.message.chat; import android.database.Cursor; import android.net.Uri; import android.os.Parcelable; import com.xabber.android.data.Application; import com.xabber.android.data.log.LogManager; import com.xabber.android.data.OnLoadListener; import com.xabber.android.data.SettingsManager; import com.xabber.android.data.account.AccountItem; import com.xabber.android.data.account.listeners.OnAccountRemovedListener; import com.xabber.android.data.database.sqlite.NotifyVisibleTable; import com.xabber.android.data.database.sqlite.PrivateChatTable; import com.xabber.android.data.database.sqlite.ShowTextTable; import com.xabber.android.data.database.sqlite.SoundTable; import com.xabber.android.data.database.sqlite.Suppress100Table; import com.xabber.android.data.database.sqlite.VibroTable; import com.xabber.android.data.entity.AccountJid; import com.xabber.android.data.entity.BaseEntity; import com.xabber.android.data.entity.NestedMap; import com.xabber.android.data.entity.UserJid; import com.xabber.android.data.roster.RosterManager; import org.jxmpp.stringprep.XmppStringprepException; import java.util.HashSet; import java.util.Set; /** * Manage chat specific options. * * @author alexander.ivanov */ public class ChatManager implements OnLoadListener, OnAccountRemovedListener { public static final Uri EMPTY_SOUND = Uri .parse("com.xabber.android.data.message.ChatManager.EMPTY_SOUND"); private static final Object PRIVATE_CHAT = new Object(); private static ChatManager instance; /** * Stored input for user in account. */ private final NestedMap<ChatInput> chatInputs; /** * List of chats whose messages mustn't be saved for user in account. */ private final NestedMap<Object> privateChats; /** * Whether notification in visible chat should be used for user in account. */ private final NestedMap<Boolean> notifyVisible; /** * Whether text of incoming message should be shown in notification bar for * user in account. */ private final NestedMap<ShowMessageTextInNotification> showText; /** * Whether vibro notification should be used for user in account. */ private final NestedMap<Boolean> makeVibro; /** * Sound, associated with chat for user in account. */ private final NestedMap<Uri> sounds; /** * Whether 'This room is not anonymous'-messages (Status Code 100) should be suppressed */ private final NestedMap<Boolean> suppress100; /** * chat scroll states - position of message list */ private final NestedMap<Parcelable> scrollStates; public static ChatManager getInstance() { if (instance == null) { instance = new ChatManager(); } return instance; } private ChatManager() { chatInputs = new NestedMap<>(); privateChats = new NestedMap<>(); sounds = new NestedMap<>(); showText = new NestedMap<>(); makeVibro = new NestedMap<>(); notifyVisible = new NestedMap<>(); suppress100 = new NestedMap<>(); scrollStates = new NestedMap<>(); } @Override public void onLoad() { final Set<BaseEntity> privateChats = new HashSet<>(); final NestedMap<Boolean> notifyVisible = new NestedMap<>(); final NestedMap<ShowMessageTextInNotification> showText = new NestedMap<>(); final NestedMap<Boolean> makeVibro = new NestedMap<>(); final NestedMap<Uri> sounds = new NestedMap<>(); final NestedMap<Boolean> suppress100 = new NestedMap<>(); Cursor cursor; cursor = PrivateChatTable.getInstance().list(); try { if (cursor.moveToFirst()) { do { try { privateChats.add(RosterManager.getInstance().getAbstractContact( AccountJid.from(PrivateChatTable.getAccount(cursor)), UserJid.from(PrivateChatTable.getUser(cursor)) )); } catch (UserJid.UserJidCreateException | XmppStringprepException e) { LogManager.exception(this, e); } } while (cursor.moveToNext()); } } finally { cursor.close(); } cursor = NotifyVisibleTable.getInstance().list(); try { if (cursor.moveToFirst()) { do { notifyVisible.put(NotifyVisibleTable.getAccount(cursor), NotifyVisibleTable.getUser(cursor), NotifyVisibleTable.getValue(cursor)); } while (cursor.moveToNext()); } } finally { cursor.close(); } cursor = ShowTextTable.getInstance().list(); try { if (cursor.moveToFirst()) { do { showText.put(ShowTextTable.getAccount(cursor), ShowTextTable.getUser(cursor), ShowTextTable.getValue(cursor)); } while (cursor.moveToNext()); } } finally { cursor.close(); } cursor = VibroTable.getInstance().list(); try { if (cursor.moveToFirst()) { do { makeVibro.put(VibroTable.getAccount(cursor), VibroTable.getUser(cursor), VibroTable.getValue(cursor)); } while (cursor.moveToNext()); } } finally { cursor.close(); } cursor = SoundTable.getInstance().list(); try { if (cursor.moveToFirst()) { do { sounds.put(SoundTable.getAccount(cursor), SoundTable.getUser(cursor), SoundTable.getValue(cursor)); } while (cursor.moveToNext()); } } finally { cursor.close(); } cursor = Suppress100Table.getInstance().list(); try { if (cursor.moveToFirst()) { do { makeVibro.put(Suppress100Table.getAccount(cursor), Suppress100Table.getUser(cursor), Suppress100Table.getValue(cursor)); } while (cursor.moveToNext()); } } finally { cursor.close(); } Application.getInstance().runOnUiThread(new Runnable() { @Override public void run() { onLoaded(privateChats, notifyVisible, showText, makeVibro, sounds, suppress100); } }); } private void onLoaded(Set<BaseEntity> privateChats, NestedMap<Boolean> notifyVisible, NestedMap<ShowMessageTextInNotification> showText, NestedMap<Boolean> vibro, NestedMap<Uri> sounds, NestedMap<Boolean> suppress100) { for (BaseEntity baseEntity : privateChats) { this.privateChats.put(baseEntity.getAccount().toString(), baseEntity.getUser().toString(), PRIVATE_CHAT); } this.notifyVisible.addAll(notifyVisible); this.showText.addAll(showText); this.makeVibro.addAll(vibro); this.sounds.addAll(sounds); this.suppress100.addAll(suppress100); } @Override public void onAccountRemoved(AccountItem accountItem) { chatInputs.clear(accountItem.getAccount().toString()); privateChats.clear(accountItem.getAccount().toString()); sounds.clear(accountItem.getAccount().toString()); showText.clear(accountItem.getAccount().toString()); makeVibro.clear(accountItem.getAccount().toString()); notifyVisible.clear(accountItem.getAccount().toString()); suppress100.clear(accountItem.getAccount().toString()); } /** * Whether to save history for specified chat. * * @param account * @param user * @return */ public boolean isSaveMessages(AccountJid account, UserJid user) { return privateChats.get(account.toString(), user.toString()) != PRIVATE_CHAT; } /** * Sets whether to save history for specified chat. * * @param account * @param user * @param save */ public void setSaveMessages(final AccountJid account, final UserJid user, final boolean save) { if (save) { privateChats.remove(account.toString(), user.toString()); } else { privateChats.put(account.toString(), user.toString(), PRIVATE_CHAT); } Application.getInstance().runInBackgroundUserRequest(new Runnable() { @Override public void run() { if (save) { PrivateChatTable.getInstance().remove(account.toString(), user.toString()); } else { PrivateChatTable.getInstance().write(account.toString(), user.toString()); } } }); } /** * @param account * @param user * @return typed but not sent message. */ public String getTypedMessage(AccountJid account, UserJid user) { ChatInput chat = chatInputs.get(account.toString(), user.toString()); if (chat == null) { return ""; } return chat.getTypedMessage(); } /** * @param account * @param user * @return Start selection position. */ public int getSelectionStart(AccountJid account, UserJid user) { ChatInput chat = chatInputs.get(account.toString(), user.toString()); if (chat == null) { return 0; } return chat.getSelectionStart(); } /** * @param account * @param user * @return End selection position. */ public int getSelectionEnd(AccountJid account, UserJid user) { ChatInput chat = chatInputs.get(account.toString(), user.toString()); if (chat == null) { return 0; } return chat.getSelectionEnd(); } /** * Sets typed message and selection options for specified chat. * * @param account * @param user * @param typedMessage * @param selectionStart * @param selectionEnd */ public void setTyped(AccountJid account, UserJid user, String typedMessage, int selectionStart, int selectionEnd) { ChatInput chat = chatInputs.get(account.toString(), user.toString()); if (chat == null) { chat = new ChatInput(); chatInputs.put(account.toString(), user.toString(), chat); } chat.setTyped(typedMessage, selectionStart, selectionEnd); } /** * @param account * @param user * @return Whether notification in visible chat must be shown. Common value * if there is no user specific value. */ public boolean isNotifyVisible(AccountJid account, UserJid user) { Boolean value = notifyVisible.get(account.toString(), user.toString()); if (value == null) { return SettingsManager.eventsVisibleChat(); } return value; } public void setNotifyVisible(final AccountJid account, final UserJid user, final boolean value) { notifyVisible.put(account.toString(), user.toString(), value); Application.getInstance().runInBackgroundUserRequest(new Runnable() { @Override public void run() { NotifyVisibleTable.getInstance().write(account.toString(), user.toString(), value); } }); } /** * @param account * @param user * @return Whether text of messages must be shown in notification area. * Common value if there is no user specific value. */ public boolean isShowText(AccountJid account, UserJid user) { switch (getShowText(account, user)) { case show: return true; case hide: return false; case default_settings: default: return SettingsManager.eventsShowText(); } } public ShowMessageTextInNotification getShowText(AccountJid account, UserJid user) { ShowMessageTextInNotification showMessageTextInNotification = showText.get(account.toString(), user.toString()); if (showMessageTextInNotification == null) { return ShowMessageTextInNotification.default_settings; } else { return showMessageTextInNotification; } } public void setShowText(final AccountJid account, final UserJid user, final ShowMessageTextInNotification value) { showText.put(account.toString(), user.toString(), value); Application.getInstance().runInBackgroundUserRequest(new Runnable() { @Override public void run() { ShowTextTable.getInstance().write(account.toString(), user.toString(), value); } }); } /** * @param account * @param user * @return Whether vibro should be used while notification. Common value if * there is no user specific value. */ public boolean isMakeVibro(AccountJid account, UserJid user) { Boolean value = makeVibro.get(account.toString(), user.toString()); if (value == null) { return SettingsManager.eventsVibro(); } return value; } public void setMakeVibro(final AccountJid account, final UserJid user, final boolean value) { makeVibro.put(account.toString(), user.toString(), value); Application.getInstance().runInBackgroundUserRequest(new Runnable() { @Override public void run() { VibroTable.getInstance().write(account.toString(), user.toString(), value); } }); } /** * @param account * @param user * @return Sound for notification. Common value if there is no user specific * value. */ public Uri getSound(AccountJid account, UserJid user) { Uri value = sounds.get(account.toString(), user.toString()); if (value == null) { return SettingsManager.eventsSound(); } if (EMPTY_SOUND.equals(value)) { return null; } return value; } public void setSound(final AccountJid account, final UserJid user, final Uri value) { sounds.put(account.toString(), user.toString(), value == null ? EMPTY_SOUND : value); Application.getInstance().runInBackgroundUserRequest(new Runnable() { @Override public void run() { SoundTable.getInstance().write(account.toString(), user.toString(), value == null ? EMPTY_SOUND : value); } }); } /** * @param account * @param user * @return Whether 'This Room is not Anonymous'-messages (Status Code 100) should be suppressed. */ public boolean isSuppress100(AccountJid account, UserJid user) { Boolean value = suppress100.get(account.toString(), user.toString()); if (value == null) return SettingsManager.eventsSuppress100(); return value; } public void setSuppress100(final AccountJid account, final UserJid user, final boolean value) { suppress100.put(account.toString(), user.toString(), value); Application.getInstance().runInBackgroundUserRequest(new Runnable() { @Override public void run() { Suppress100Table.getInstance().write(account.toString(), user.toString(), value); } }); } public Parcelable getScrollState(AccountJid account, UserJid user) { return scrollStates.get(account.toString(), user.toString()); } public void setScrollState(AccountJid account, UserJid user, Parcelable parcelable) { scrollStates.put(account.toString(), user.toString(), parcelable); } public void clearScrollStates() { scrollStates.clear(); } }