2017-10-16 20:11:42 +00:00
|
|
|
/*
|
2012-07-19 21:22:03 +00:00
|
|
|
* Copyright (C) 2011 Whisper Systems
|
|
|
|
*
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program 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/>.
|
|
|
|
*/
|
2019-02-01 03:28:40 +00:00
|
|
|
package org.thoughtcrime.securesms.conversation;
|
2012-07-19 21:22:03 +00:00
|
|
|
|
2017-11-25 06:00:30 +00:00
|
|
|
import android.Manifest;
|
2017-11-14 18:49:54 +00:00
|
|
|
import android.annotation.SuppressLint;
|
2016-11-20 23:56:47 +00:00
|
|
|
import android.annotation.TargetApi;
|
2022-01-14 13:06:28 +00:00
|
|
|
import android.app.Activity;
|
2022-01-29 16:04:56 +00:00
|
|
|
import android.app.PendingIntent;
|
2013-06-18 21:43:27 +00:00
|
|
|
import android.content.ActivityNotFoundException;
|
2013-03-06 03:32:15 +00:00
|
|
|
import android.content.BroadcastReceiver;
|
|
|
|
import android.content.Context;
|
|
|
|
import android.content.Intent;
|
|
|
|
import android.content.IntentFilter;
|
2021-01-21 00:12:44 +00:00
|
|
|
import android.content.pm.ActivityInfo;
|
2022-05-26 20:32:52 +00:00
|
|
|
import android.content.res.ColorStateList;
|
2015-07-07 21:25:41 +00:00
|
|
|
import android.content.res.Configuration;
|
2018-08-25 17:33:14 +00:00
|
|
|
import android.graphics.Bitmap;
|
2015-07-01 00:45:39 +00:00
|
|
|
import android.graphics.Color;
|
2019-10-07 18:43:36 +00:00
|
|
|
import android.graphics.PorterDuff;
|
2020-03-25 15:30:15 +00:00
|
|
|
import android.graphics.drawable.Drawable;
|
2019-02-25 23:21:37 +00:00
|
|
|
import android.hardware.Camera;
|
2013-03-06 03:32:15 +00:00
|
|
|
import android.net.Uri;
|
|
|
|
import android.os.AsyncTask;
|
2015-11-24 19:47:50 +00:00
|
|
|
import android.os.Build;
|
2013-03-06 03:32:15 +00:00
|
|
|
import android.os.Bundle;
|
2015-11-18 22:52:26 +00:00
|
|
|
import android.os.Vibrator;
|
2016-03-29 22:52:54 +00:00
|
|
|
import android.provider.Browser;
|
2013-10-17 00:28:36 +00:00
|
|
|
import android.provider.ContactsContract;
|
2021-12-07 20:34:44 +00:00
|
|
|
import android.provider.Settings;
|
2013-03-06 03:32:15 +00:00
|
|
|
import android.text.Editable;
|
2020-11-04 20:00:12 +00:00
|
|
|
import android.text.SpannableStringBuilder;
|
2013-03-06 03:32:15 +00:00
|
|
|
import android.text.TextWatcher;
|
2021-07-23 20:22:08 +00:00
|
|
|
import android.text.method.LinkMovementMethod;
|
2013-03-06 03:32:15 +00:00
|
|
|
import android.view.KeyEvent;
|
2022-01-14 13:06:28 +00:00
|
|
|
import android.view.LayoutInflater;
|
2014-06-29 03:40:57 +00:00
|
|
|
import android.view.Menu;
|
|
|
|
import android.view.MenuInflater;
|
|
|
|
import android.view.MenuItem;
|
2019-12-03 21:57:21 +00:00
|
|
|
import android.view.MotionEvent;
|
2013-03-06 03:32:15 +00:00
|
|
|
import android.view.View;
|
|
|
|
import android.view.View.OnClickListener;
|
2014-05-29 03:53:34 +00:00
|
|
|
import android.view.View.OnFocusChangeListener;
|
2013-03-06 03:32:15 +00:00
|
|
|
import android.view.View.OnKeyListener;
|
2022-01-14 13:06:28 +00:00
|
|
|
import android.view.ViewGroup;
|
2017-02-16 20:28:06 +00:00
|
|
|
import android.view.WindowManager;
|
2013-03-06 03:32:15 +00:00
|
|
|
import android.view.inputmethod.EditorInfo;
|
2015-06-09 14:37:20 +00:00
|
|
|
import android.widget.Button;
|
2021-07-22 14:10:57 +00:00
|
|
|
import android.widget.FrameLayout;
|
2015-05-18 17:26:32 +00:00
|
|
|
import android.widget.ImageButton;
|
2021-01-20 02:54:10 +00:00
|
|
|
import android.widget.ImageView;
|
2013-03-06 03:32:15 +00:00
|
|
|
import android.widget.TextView;
|
|
|
|
import android.widget.Toast;
|
2012-07-19 21:22:03 +00:00
|
|
|
|
2022-01-28 17:24:44 +00:00
|
|
|
import androidx.activity.OnBackPressedCallback;
|
2022-05-26 20:32:52 +00:00
|
|
|
import androidx.annotation.ColorInt;
|
2022-06-10 19:20:02 +00:00
|
|
|
import androidx.annotation.ColorRes;
|
2019-11-12 14:18:57 +00:00
|
|
|
import androidx.annotation.IdRes;
|
2019-08-30 21:45:35 +00:00
|
|
|
import androidx.annotation.NonNull;
|
|
|
|
import androidx.annotation.Nullable;
|
2020-07-08 15:54:47 +00:00
|
|
|
import androidx.annotation.WorkerThread;
|
2019-08-30 21:45:35 +00:00
|
|
|
import androidx.appcompat.app.AlertDialog;
|
|
|
|
import androidx.appcompat.widget.SearchView;
|
|
|
|
import androidx.appcompat.widget.Toolbar;
|
2021-06-24 16:52:54 +00:00
|
|
|
import androidx.core.app.ActivityCompat;
|
2020-11-10 15:20:54 +00:00
|
|
|
import androidx.core.content.ContextCompat;
|
2019-08-30 21:45:35 +00:00
|
|
|
import androidx.core.content.pm.ShortcutInfoCompat;
|
|
|
|
import androidx.core.content.pm.ShortcutManagerCompat;
|
2020-11-04 20:00:12 +00:00
|
|
|
import androidx.core.graphics.drawable.DrawableCompat;
|
2019-08-30 21:45:35 +00:00
|
|
|
import androidx.core.graphics.drawable.IconCompat;
|
2022-05-26 20:32:52 +00:00
|
|
|
import androidx.core.view.MenuItemCompat;
|
2022-01-14 13:06:28 +00:00
|
|
|
import androidx.fragment.app.Fragment;
|
2021-07-02 13:28:45 +00:00
|
|
|
import androidx.lifecycle.Lifecycle;
|
|
|
|
import androidx.lifecycle.Observer;
|
2022-01-14 13:06:28 +00:00
|
|
|
import androidx.lifecycle.ViewModelProvider;
|
2022-05-26 20:32:52 +00:00
|
|
|
import androidx.recyclerview.widget.RecyclerView;
|
2019-08-30 21:45:35 +00:00
|
|
|
|
2022-05-26 20:32:52 +00:00
|
|
|
import com.airbnb.lottie.SimpleColorFilter;
|
2020-08-05 20:45:52 +00:00
|
|
|
import com.annimon.stream.Collectors;
|
2019-02-25 21:58:10 +00:00
|
|
|
import com.annimon.stream.Stream;
|
2020-07-08 15:54:47 +00:00
|
|
|
import com.bumptech.glide.load.engine.DiskCacheStrategy;
|
2020-03-25 15:30:15 +00:00
|
|
|
import com.bumptech.glide.request.target.CustomTarget;
|
|
|
|
import com.bumptech.glide.request.transition.Transition;
|
2020-12-02 18:20:38 +00:00
|
|
|
import com.google.android.material.button.MaterialButton;
|
2021-07-23 20:22:08 +00:00
|
|
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
2013-11-26 01:00:20 +00:00
|
|
|
|
2017-02-18 04:43:24 +00:00
|
|
|
import org.greenrobot.eventbus.EventBus;
|
|
|
|
import org.greenrobot.eventbus.Subscribe;
|
|
|
|
import org.greenrobot.eventbus.ThreadMode;
|
2022-09-20 14:13:58 +00:00
|
|
|
import org.signal.core.util.PendingIntentFlags;
|
2022-08-05 21:00:11 +00:00
|
|
|
import org.signal.core.util.StringUtil;
|
2021-03-01 20:44:33 +00:00
|
|
|
import org.signal.core.util.ThreadUtil;
|
2020-12-04 23:31:58 +00:00
|
|
|
import org.signal.core.util.concurrent.SignalExecutors;
|
2022-04-29 13:54:48 +00:00
|
|
|
import org.signal.core.util.concurrent.SimpleTask;
|
2020-12-04 23:31:58 +00:00
|
|
|
import org.signal.core.util.logging.Log;
|
2022-03-24 17:23:23 +00:00
|
|
|
import org.signal.libsignal.protocol.InvalidMessageException;
|
|
|
|
import org.signal.libsignal.protocol.util.Pair;
|
2020-04-16 15:30:51 +00:00
|
|
|
import org.thoughtcrime.securesms.BlockUnblockDialog;
|
2019-02-01 03:28:40 +00:00
|
|
|
import org.thoughtcrime.securesms.GroupMembersDialog;
|
2019-11-14 19:35:08 +00:00
|
|
|
import org.thoughtcrime.securesms.MainActivity;
|
2019-02-01 03:28:40 +00:00
|
|
|
import org.thoughtcrime.securesms.MuteDialog;
|
|
|
|
import org.thoughtcrime.securesms.PromptMmsActivity;
|
|
|
|
import org.thoughtcrime.securesms.R;
|
|
|
|
import org.thoughtcrime.securesms.ShortcutLauncherActivity;
|
2019-06-11 06:18:45 +00:00
|
|
|
import org.thoughtcrime.securesms.attachments.Attachment;
|
|
|
|
import org.thoughtcrime.securesms.attachments.TombstoneAttachment;
|
2015-11-18 22:52:26 +00:00
|
|
|
import org.thoughtcrime.securesms.audio.AudioRecorder;
|
2022-05-02 17:29:42 +00:00
|
|
|
import org.thoughtcrime.securesms.badges.gifts.thanks.GiftThanksSheet;
|
2015-05-18 17:26:32 +00:00
|
|
|
import org.thoughtcrime.securesms.components.AnimatingToggle;
|
2015-03-11 21:23:45 +00:00
|
|
|
import org.thoughtcrime.securesms.components.ComposeText;
|
2019-02-01 17:06:59 +00:00
|
|
|
import org.thoughtcrime.securesms.components.ConversationSearchBottomBar;
|
2015-11-18 22:52:26 +00:00
|
|
|
import org.thoughtcrime.securesms.components.HidingLinearLayout;
|
2015-09-22 00:41:27 +00:00
|
|
|
import org.thoughtcrime.securesms.components.InputAwareLayout;
|
2015-11-18 22:52:26 +00:00
|
|
|
import org.thoughtcrime.securesms.components.InputPanel;
|
2015-07-02 23:47:03 +00:00
|
|
|
import org.thoughtcrime.securesms.components.KeyboardAwareLinearLayout.OnKeyboardShownListener;
|
2015-06-09 14:37:20 +00:00
|
|
|
import org.thoughtcrime.securesms.components.SendButton;
|
2019-04-17 14:21:30 +00:00
|
|
|
import org.thoughtcrime.securesms.components.TooltipPopup;
|
2020-11-11 19:14:54 +00:00
|
|
|
import org.thoughtcrime.securesms.components.TypingStatusSender;
|
2021-06-29 16:34:49 +00:00
|
|
|
import org.thoughtcrime.securesms.components.emoji.EmojiEventListener;
|
2018-04-27 00:03:54 +00:00
|
|
|
import org.thoughtcrime.securesms.components.emoji.EmojiStrings;
|
2019-04-17 14:21:30 +00:00
|
|
|
import org.thoughtcrime.securesms.components.emoji.MediaKeyboard;
|
2022-04-29 13:54:48 +00:00
|
|
|
import org.thoughtcrime.securesms.components.emoji.RecentEmojiPageModel;
|
2017-06-07 01:03:09 +00:00
|
|
|
import org.thoughtcrime.securesms.components.identity.UnverifiedBannerView;
|
2016-01-04 21:02:22 +00:00
|
|
|
import org.thoughtcrime.securesms.components.location.SignalPlace;
|
2020-08-05 20:45:52 +00:00
|
|
|
import org.thoughtcrime.securesms.components.mention.MentionAnnotation;
|
2021-12-07 20:34:44 +00:00
|
|
|
import org.thoughtcrime.securesms.components.reminder.BubbleOptOutReminder;
|
2017-11-16 00:29:00 +00:00
|
|
|
import org.thoughtcrime.securesms.components.reminder.ExpiredBuildReminder;
|
2020-11-09 13:30:58 +00:00
|
|
|
import org.thoughtcrime.securesms.components.reminder.GroupsV1MigrationSuggestionsReminder;
|
2020-10-15 16:32:50 +00:00
|
|
|
import org.thoughtcrime.securesms.components.reminder.PendingGroupJoinRequestsReminder;
|
2019-11-12 14:18:57 +00:00
|
|
|
import org.thoughtcrime.securesms.components.reminder.Reminder;
|
2015-11-09 22:51:53 +00:00
|
|
|
import org.thoughtcrime.securesms.components.reminder.ReminderView;
|
2018-06-11 16:37:01 +00:00
|
|
|
import org.thoughtcrime.securesms.components.reminder.ServiceOutageReminder;
|
2017-11-16 00:29:00 +00:00
|
|
|
import org.thoughtcrime.securesms.components.reminder.UnauthorizedReminder;
|
2021-06-24 16:52:54 +00:00
|
|
|
import org.thoughtcrime.securesms.components.settings.conversation.ConversationSettingsActivity;
|
2021-07-02 13:28:45 +00:00
|
|
|
import org.thoughtcrime.securesms.components.voice.VoiceNoteDraft;
|
|
|
|
import org.thoughtcrime.securesms.components.voice.VoiceNoteMediaController;
|
|
|
|
import org.thoughtcrime.securesms.components.voice.VoiceNotePlaybackState;
|
2021-07-07 17:23:37 +00:00
|
|
|
import org.thoughtcrime.securesms.components.voice.VoiceNotePlayerView;
|
2013-10-17 00:28:36 +00:00
|
|
|
import org.thoughtcrime.securesms.contacts.ContactAccessor;
|
|
|
|
import org.thoughtcrime.securesms.contacts.ContactAccessor.ContactData;
|
2022-07-11 15:54:30 +00:00
|
|
|
import org.thoughtcrime.securesms.contacts.paged.ContactSearchKey;
|
2022-04-29 13:54:48 +00:00
|
|
|
import org.thoughtcrime.securesms.contacts.sync.ContactDiscovery;
|
2018-04-27 00:03:54 +00:00
|
|
|
import org.thoughtcrime.securesms.contactshare.Contact;
|
|
|
|
import org.thoughtcrime.securesms.contactshare.ContactShareEditActivity;
|
|
|
|
import org.thoughtcrime.securesms.contactshare.ContactUtil;
|
2018-10-29 22:14:31 +00:00
|
|
|
import org.thoughtcrime.securesms.contactshare.SimpleTextWatcher;
|
2020-06-06 23:26:21 +00:00
|
|
|
import org.thoughtcrime.securesms.conversation.ConversationGroupViewModel.GroupActiveState;
|
2020-08-05 20:45:52 +00:00
|
|
|
import org.thoughtcrime.securesms.conversation.ConversationMessage.ConversationMessageFactory;
|
2021-07-02 13:28:45 +00:00
|
|
|
import org.thoughtcrime.securesms.conversation.drafts.DraftViewModel;
|
2020-12-02 18:20:38 +00:00
|
|
|
import org.thoughtcrime.securesms.conversation.ui.groupcall.GroupCallViewModel;
|
2022-08-01 14:55:40 +00:00
|
|
|
import org.thoughtcrime.securesms.conversation.ui.inlinequery.InlineQuery;
|
|
|
|
import org.thoughtcrime.securesms.conversation.ui.inlinequery.InlineQueryChangedListener;
|
|
|
|
import org.thoughtcrime.securesms.conversation.ui.inlinequery.InlineQueryResultsController;
|
|
|
|
import org.thoughtcrime.securesms.conversation.ui.inlinequery.InlineQueryViewModel;
|
2020-07-27 13:58:58 +00:00
|
|
|
import org.thoughtcrime.securesms.conversation.ui.mentions.MentionsPickerViewModel;
|
2021-06-15 14:07:41 +00:00
|
|
|
import org.thoughtcrime.securesms.crypto.ReentrantSessionLock;
|
2014-11-03 23:16:04 +00:00
|
|
|
import org.thoughtcrime.securesms.crypto.SecurityEvent;
|
2022-11-29 15:47:12 +00:00
|
|
|
import org.thoughtcrime.securesms.database.DraftTable.Draft;
|
|
|
|
import org.thoughtcrime.securesms.database.DraftTable.Drafts;
|
|
|
|
import org.thoughtcrime.securesms.database.GroupTable;
|
|
|
|
import org.thoughtcrime.securesms.database.IdentityTable.VerifiedStatus;
|
|
|
|
import org.thoughtcrime.securesms.database.RecipientTable;
|
|
|
|
import org.thoughtcrime.securesms.database.RecipientTable.RegisteredState;
|
2021-11-18 17:36:52 +00:00
|
|
|
import org.thoughtcrime.securesms.database.SignalDatabase;
|
2022-11-29 15:47:12 +00:00
|
|
|
import org.thoughtcrime.securesms.database.ThreadTable;
|
2017-06-07 01:03:09 +00:00
|
|
|
import org.thoughtcrime.securesms.database.identity.IdentityRecordList;
|
2021-09-29 16:38:34 +00:00
|
|
|
import org.thoughtcrime.securesms.database.model.IdentityRecord;
|
2020-08-05 20:45:52 +00:00
|
|
|
import org.thoughtcrime.securesms.database.model.Mention;
|
2021-11-11 18:12:51 +00:00
|
|
|
import org.thoughtcrime.securesms.database.model.MessageId;
|
2018-02-07 22:01:37 +00:00
|
|
|
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
|
|
|
import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
|
2019-12-03 21:57:21 +00:00
|
|
|
import org.thoughtcrime.securesms.database.model.ReactionRecord;
|
2019-04-17 14:21:30 +00:00
|
|
|
import org.thoughtcrime.securesms.database.model.StickerRecord;
|
2022-03-14 19:49:46 +00:00
|
|
|
import org.thoughtcrime.securesms.database.model.StoryType;
|
2019-10-15 19:47:54 +00:00
|
|
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
2020-12-02 18:20:38 +00:00
|
|
|
import org.thoughtcrime.securesms.events.GroupCallPeekEvent;
|
2017-11-16 00:29:00 +00:00
|
|
|
import org.thoughtcrime.securesms.events.ReminderUpdateEvent;
|
2022-10-13 15:33:13 +00:00
|
|
|
import org.thoughtcrime.securesms.exporter.flow.SmsExportActivity;
|
2020-07-24 19:40:06 +00:00
|
|
|
import org.thoughtcrime.securesms.groups.GroupId;
|
2020-05-12 18:09:47 +00:00
|
|
|
import org.thoughtcrime.securesms.groups.ui.GroupChangeFailureReason;
|
|
|
|
import org.thoughtcrime.securesms.groups.ui.GroupErrors;
|
2020-03-31 15:01:43 +00:00
|
|
|
import org.thoughtcrime.securesms.groups.ui.LeaveGroupDialog;
|
2020-10-15 16:32:50 +00:00
|
|
|
import org.thoughtcrime.securesms.groups.ui.invitesandrequests.ManagePendingAndRequestingMembersActivity;
|
2020-11-12 14:52:21 +00:00
|
|
|
import org.thoughtcrime.securesms.groups.ui.migration.GroupsV1MigrationInitiationBottomSheetDialogFragment;
|
2020-11-09 13:30:58 +00:00
|
|
|
import org.thoughtcrime.securesms.groups.ui.migration.GroupsV1MigrationSuggestionsDialog;
|
2019-11-12 14:18:57 +00:00
|
|
|
import org.thoughtcrime.securesms.insights.InsightsLauncher;
|
|
|
|
import org.thoughtcrime.securesms.invites.InviteReminderModel;
|
|
|
|
import org.thoughtcrime.securesms.invites.InviteReminderRepository;
|
2022-10-05 21:09:28 +00:00
|
|
|
import org.thoughtcrime.securesms.jobs.ForceUpdateGroupV2Job;
|
2020-10-15 19:49:09 +00:00
|
|
|
import org.thoughtcrime.securesms.jobs.GroupV1MigrationJob;
|
2020-07-24 19:40:06 +00:00
|
|
|
import org.thoughtcrime.securesms.jobs.GroupV2UpdateSelfProfileKeyJob;
|
2020-05-07 19:51:54 +00:00
|
|
|
import org.thoughtcrime.securesms.jobs.RequestGroupV2InfoJob;
|
2017-05-20 01:01:40 +00:00
|
|
|
import org.thoughtcrime.securesms.jobs.RetrieveProfileJob;
|
2018-06-11 16:37:01 +00:00
|
|
|
import org.thoughtcrime.securesms.jobs.ServiceOutageDetectionJob;
|
2021-05-26 13:47:14 +00:00
|
|
|
import org.thoughtcrime.securesms.keyboard.KeyboardPage;
|
|
|
|
import org.thoughtcrime.securesms.keyboard.KeyboardPagerViewModel;
|
|
|
|
import org.thoughtcrime.securesms.keyboard.emoji.EmojiKeyboardPageFragment;
|
|
|
|
import org.thoughtcrime.securesms.keyboard.emoji.search.EmojiSearchFragment;
|
|
|
|
import org.thoughtcrime.securesms.keyboard.gif.GifKeyboardPageFragment;
|
2022-02-03 18:48:52 +00:00
|
|
|
import org.thoughtcrime.securesms.keyboard.sticker.StickerKeyboardPageFragment;
|
|
|
|
import org.thoughtcrime.securesms.keyboard.sticker.StickerSearchDialogFragment;
|
2021-04-06 16:03:33 +00:00
|
|
|
import org.thoughtcrime.securesms.keyvalue.PaymentsValues;
|
2020-05-28 16:24:04 +00:00
|
|
|
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
2022-10-18 00:41:35 +00:00
|
|
|
import org.thoughtcrime.securesms.keyvalue.SmsExportPhase;
|
2019-04-17 14:21:30 +00:00
|
|
|
import org.thoughtcrime.securesms.linkpreview.LinkPreview;
|
|
|
|
import org.thoughtcrime.securesms.linkpreview.LinkPreviewRepository;
|
|
|
|
import org.thoughtcrime.securesms.linkpreview.LinkPreviewViewModel;
|
2022-05-26 20:32:52 +00:00
|
|
|
import org.thoughtcrime.securesms.main.Material3OnScrollHelperBinder;
|
2019-06-27 16:14:54 +00:00
|
|
|
import org.thoughtcrime.securesms.maps.PlacePickerActivity;
|
2019-12-03 16:05:03 +00:00
|
|
|
import org.thoughtcrime.securesms.mediaoverview.MediaOverviewActivity;
|
2019-04-17 14:21:30 +00:00
|
|
|
import org.thoughtcrime.securesms.mediasend.Media;
|
2020-01-08 20:56:51 +00:00
|
|
|
import org.thoughtcrime.securesms.mediasend.MediaSendActivityResult;
|
2021-09-02 20:04:43 +00:00
|
|
|
import org.thoughtcrime.securesms.mediasend.v2.MediaSelectionActivity;
|
2022-02-11 18:03:51 +00:00
|
|
|
import org.thoughtcrime.securesms.messagedetails.MessageDetailsFragment;
|
2020-11-23 18:10:35 +00:00
|
|
|
import org.thoughtcrime.securesms.messagerequests.MessageRequestState;
|
2020-02-19 22:08:34 +00:00
|
|
|
import org.thoughtcrime.securesms.messagerequests.MessageRequestViewModel;
|
|
|
|
import org.thoughtcrime.securesms.messagerequests.MessageRequestsBottomView;
|
Major storage layer refactoring to set the stage for clean GCM.
1) We now try to hand out cursors at a minimum. There has always been
a fairly clean insertion layer that handles encrypting message bodies,
but the process of decrypting message bodies has always been less than
ideal. Here we introduce a "Reader" interface that will decrypt message
bodies when appropriate and return objects that encapsulate record state.
No more MessageDisplayHelper. The MmsSmsDatabase interface is also more
sane.
2) We finally rid ourselves of the technical debt associated with TextSecure's
initial usage of the default SMS DB. In that world, we weren't able to use
anything other than the default "Inbox, Outbox, Sent" types to describe a
message, and had to overload the message content itself with a set of
local "prefixes" to describe what it was (encrypted, asymetric encrypted,
remote encrypted, a key exchange, procssed key exchange), and so on.
This includes a major schema update that transforms the "type" field into
a bitmask that describes everything that used to be encoded in a prefix,
and prefixes have been completely eliminated from the system.
No more Prefix.java
3) Refactoring of the MultipartMessageHandler code. It's less of a mess, and
hopefully more clear as to what's going on.
The next step is to remove what we can from SmsTransportDetails and genericize
that interface for a GCM equivalent.
2013-04-20 19:22:04 +00:00
|
|
|
import org.thoughtcrime.securesms.mms.AttachmentManager;
|
2015-11-18 22:52:26 +00:00
|
|
|
import org.thoughtcrime.securesms.mms.AudioSlide;
|
2020-07-10 13:30:00 +00:00
|
|
|
import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader;
|
2018-11-20 17:59:23 +00:00
|
|
|
import org.thoughtcrime.securesms.mms.GifSlide;
|
2017-10-16 20:11:42 +00:00
|
|
|
import org.thoughtcrime.securesms.mms.GlideApp;
|
|
|
|
import org.thoughtcrime.securesms.mms.GlideRequests;
|
2018-09-20 20:27:18 +00:00
|
|
|
import org.thoughtcrime.securesms.mms.ImageSlide;
|
2015-07-28 20:17:01 +00:00
|
|
|
import org.thoughtcrime.securesms.mms.MediaConstraints;
|
2014-02-24 08:19:54 +00:00
|
|
|
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
|
2018-04-24 18:09:54 +00:00
|
|
|
import org.thoughtcrime.securesms.mms.QuoteId;
|
|
|
|
import org.thoughtcrime.securesms.mms.QuoteModel;
|
Major storage layer refactoring to set the stage for clean GCM.
1) We now try to hand out cursors at a minimum. There has always been
a fairly clean insertion layer that handles encrypting message bodies,
but the process of decrypting message bodies has always been less than
ideal. Here we introduce a "Reader" interface that will decrypt message
bodies when appropriate and return objects that encapsulate record state.
No more MessageDisplayHelper. The MmsSmsDatabase interface is also more
sane.
2) We finally rid ourselves of the technical debt associated with TextSecure's
initial usage of the default SMS DB. In that world, we weren't able to use
anything other than the default "Inbox, Outbox, Sent" types to describe a
message, and had to overload the message content itself with a set of
local "prefixes" to describe what it was (encrypted, asymetric encrypted,
remote encrypted, a key exchange, procssed key exchange), and so on.
This includes a major schema update that transforms the "type" field into
a bitmask that describes everything that used to be encoded in a prefix,
and prefixes have been completely eliminated from the system.
No more Prefix.java
3) Refactoring of the MultipartMessageHandler code. It's less of a mess, and
hopefully more clear as to what's going on.
The next step is to remove what we can from SmsTransportDetails and genericize
that interface for a GCM equivalent.
2013-04-20 19:22:04 +00:00
|
|
|
import org.thoughtcrime.securesms.mms.Slide;
|
2015-11-18 22:52:26 +00:00
|
|
|
import org.thoughtcrime.securesms.mms.SlideDeck;
|
2021-03-01 20:44:33 +00:00
|
|
|
import org.thoughtcrime.securesms.mms.SlideFactory.MediaType;
|
2019-04-17 14:21:30 +00:00
|
|
|
import org.thoughtcrime.securesms.mms.StickerSlide;
|
2018-11-20 17:59:23 +00:00
|
|
|
import org.thoughtcrime.securesms.mms.VideoSlide;
|
2018-08-16 16:47:43 +00:00
|
|
|
import org.thoughtcrime.securesms.notifications.NotificationChannels;
|
2022-05-12 18:37:28 +00:00
|
|
|
import org.thoughtcrime.securesms.notifications.v2.ConversationId;
|
2017-11-25 06:00:30 +00:00
|
|
|
import org.thoughtcrime.securesms.permissions.Permissions;
|
2020-11-04 20:00:12 +00:00
|
|
|
import org.thoughtcrime.securesms.profiles.spoofing.ReviewBannerView;
|
|
|
|
import org.thoughtcrime.securesms.profiles.spoofing.ReviewCardDialogFragment;
|
2019-02-26 01:47:30 +00:00
|
|
|
import org.thoughtcrime.securesms.providers.BlobProvider;
|
2021-05-05 16:49:18 +00:00
|
|
|
import org.thoughtcrime.securesms.ratelimit.RecaptchaProofBottomSheetFragment;
|
2020-07-29 16:44:23 +00:00
|
|
|
import org.thoughtcrime.securesms.reactions.ReactionsBottomSheetDialogFragment;
|
2020-05-05 17:53:57 +00:00
|
|
|
import org.thoughtcrime.securesms.reactions.any.ReactWithAnyEmojiBottomSheetDialogFragment;
|
2019-08-07 18:22:51 +00:00
|
|
|
import org.thoughtcrime.securesms.recipients.LiveRecipient;
|
Major storage layer refactoring to set the stage for clean GCM.
1) We now try to hand out cursors at a minimum. There has always been
a fairly clean insertion layer that handles encrypting message bodies,
but the process of decrypting message bodies has always been less than
ideal. Here we introduce a "Reader" interface that will decrypt message
bodies when appropriate and return objects that encapsulate record state.
No more MessageDisplayHelper. The MmsSmsDatabase interface is also more
sane.
2) We finally rid ourselves of the technical debt associated with TextSecure's
initial usage of the default SMS DB. In that world, we weren't able to use
anything other than the default "Inbox, Outbox, Sent" types to describe a
message, and had to overload the message content itself with a set of
local "prefixes" to describe what it was (encrypted, asymetric encrypted,
remote encrypted, a key exchange, procssed key exchange), and so on.
This includes a major schema update that transforms the "type" field into
a bitmask that describes everything that used to be encoded in a prefix,
and prefixes have been completely eliminated from the system.
No more Prefix.java
3) Refactoring of the MultipartMessageHandler code. It's less of a mess, and
hopefully more clear as to what's going on.
The next step is to remove what we can from SmsTransportDetails and genericize
that interface for a GCM equivalent.
2013-04-20 19:22:04 +00:00
|
|
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
2019-04-17 14:21:30 +00:00
|
|
|
import org.thoughtcrime.securesms.recipients.RecipientExporter;
|
Major storage layer refactoring to set the stage for clean GCM.
1) We now try to hand out cursors at a minimum. There has always been
a fairly clean insertion layer that handles encrypting message bodies,
but the process of decrypting message bodies has always been less than
ideal. Here we introduce a "Reader" interface that will decrypt message
bodies when appropriate and return objects that encapsulate record state.
No more MessageDisplayHelper. The MmsSmsDatabase interface is also more
sane.
2) We finally rid ourselves of the technical debt associated with TextSecure's
initial usage of the default SMS DB. In that world, we weren't able to use
anything other than the default "Inbox, Outbox, Sent" types to describe a
message, and had to overload the message content itself with a set of
local "prefixes" to describe what it was (encrypted, asymetric encrypted,
remote encrypted, a key exchange, procssed key exchange), and so on.
This includes a major schema update that transforms the "type" field into
a bitmask that describes everything that used to be encoded in a prefix,
and prefixes have been completely eliminated from the system.
No more Prefix.java
3) Refactoring of the MultipartMessageHandler code. It's less of a mess, and
hopefully more clear as to what's going on.
The next step is to remove what we can from SmsTransportDetails and genericize
that interface for a GCM equivalent.
2013-04-20 19:22:04 +00:00
|
|
|
import org.thoughtcrime.securesms.recipients.RecipientFormattingException;
|
2019-10-01 12:17:25 +00:00
|
|
|
import org.thoughtcrime.securesms.recipients.RecipientId;
|
2019-11-19 16:01:07 +00:00
|
|
|
import org.thoughtcrime.securesms.recipients.RecipientUtil;
|
2021-05-19 00:23:59 +00:00
|
|
|
import org.thoughtcrime.securesms.recipients.ui.disappearingmessages.RecipientDisappearingMessagesActivity;
|
2019-10-16 22:37:08 +00:00
|
|
|
import org.thoughtcrime.securesms.registration.RegistrationNavigationActivity;
|
2022-07-11 15:54:30 +00:00
|
|
|
import org.thoughtcrime.securesms.safety.SafetyNumberBottomSheet;
|
2021-06-24 16:52:54 +00:00
|
|
|
import org.thoughtcrime.securesms.search.MessageResult;
|
Major storage layer refactoring to set the stage for clean GCM.
1) We now try to hand out cursors at a minimum. There has always been
a fairly clean insertion layer that handles encrypting message bodies,
but the process of decrypting message bodies has always been less than
ideal. Here we introduce a "Reader" interface that will decrypt message
bodies when appropriate and return objects that encapsulate record state.
No more MessageDisplayHelper. The MmsSmsDatabase interface is also more
sane.
2) We finally rid ourselves of the technical debt associated with TextSecure's
initial usage of the default SMS DB. In that world, we weren't able to use
anything other than the default "Inbox, Outbox, Sent" types to describe a
message, and had to overload the message content itself with a set of
local "prefixes" to describe what it was (encrypted, asymetric encrypted,
remote encrypted, a key exchange, procssed key exchange), and so on.
This includes a major schema update that transforms the "type" field into
a bitmask that describes everything that used to be encoded in a prefix,
and prefixes have been completely eliminated from the system.
No more Prefix.java
3) Refactoring of the MultipartMessageHandler code. It's less of a mess, and
hopefully more clear as to what's going on.
The next step is to remove what we can from SmsTransportDetails and genericize
that interface for a GCM equivalent.
2013-04-20 19:22:04 +00:00
|
|
|
import org.thoughtcrime.securesms.service.KeyCachingService;
|
|
|
|
import org.thoughtcrime.securesms.sms.MessageSender;
|
|
|
|
import org.thoughtcrime.securesms.sms.OutgoingEncryptedMessage;
|
|
|
|
import org.thoughtcrime.securesms.sms.OutgoingTextMessage;
|
2021-06-29 16:34:49 +00:00
|
|
|
import org.thoughtcrime.securesms.stickers.StickerEventListener;
|
2019-04-17 14:21:30 +00:00
|
|
|
import org.thoughtcrime.securesms.stickers.StickerLocator;
|
|
|
|
import org.thoughtcrime.securesms.stickers.StickerManagementActivity;
|
|
|
|
import org.thoughtcrime.securesms.stickers.StickerPackInstallEvent;
|
|
|
|
import org.thoughtcrime.securesms.stickers.StickerSearchRepository;
|
2022-05-12 18:37:28 +00:00
|
|
|
import org.thoughtcrime.securesms.stories.StoryViewerArgs;
|
2022-04-29 13:54:48 +00:00
|
|
|
import org.thoughtcrime.securesms.stories.viewer.StoryViewerActivity;
|
2020-08-26 15:51:25 +00:00
|
|
|
import org.thoughtcrime.securesms.util.AsynchronousCallback;
|
2018-08-25 17:33:14 +00:00
|
|
|
import org.thoughtcrime.securesms.util.BitmapUtil;
|
2020-11-25 18:11:17 +00:00
|
|
|
import org.thoughtcrime.securesms.util.BubbleUtil;
|
2015-02-16 10:38:09 +00:00
|
|
|
import org.thoughtcrime.securesms.util.CharacterCalculator.CharacterState;
|
2018-04-27 00:03:54 +00:00
|
|
|
import org.thoughtcrime.securesms.util.CommunicationActions;
|
2020-11-10 15:20:54 +00:00
|
|
|
import org.thoughtcrime.securesms.util.ContextUtil;
|
2020-11-17 13:58:28 +00:00
|
|
|
import org.thoughtcrime.securesms.util.ConversationUtil;
|
2022-04-29 13:54:48 +00:00
|
|
|
import org.thoughtcrime.securesms.util.Debouncer;
|
2020-03-25 15:30:15 +00:00
|
|
|
import org.thoughtcrime.securesms.util.DrawableUtil;
|
2021-01-20 02:54:10 +00:00
|
|
|
import org.thoughtcrime.securesms.util.FullscreenHelper;
|
2017-06-07 01:03:09 +00:00
|
|
|
import org.thoughtcrime.securesms.util.IdentityUtil;
|
2022-04-29 13:54:48 +00:00
|
|
|
import org.thoughtcrime.securesms.util.LifecycleDisposable;
|
2022-05-26 20:32:52 +00:00
|
|
|
import org.thoughtcrime.securesms.util.Material3OnScrollHelper;
|
2015-09-05 00:33:22 +00:00
|
|
|
import org.thoughtcrime.securesms.util.MediaUtil;
|
2022-05-10 13:10:35 +00:00
|
|
|
import org.thoughtcrime.securesms.util.MessageRecordUtil;
|
2020-01-08 20:56:51 +00:00
|
|
|
import org.thoughtcrime.securesms.util.MessageUtil;
|
2020-09-09 14:22:22 +00:00
|
|
|
import org.thoughtcrime.securesms.util.PlayStoreUtil;
|
2017-12-05 19:52:03 +00:00
|
|
|
import org.thoughtcrime.securesms.util.ServiceUtil;
|
2021-08-23 14:05:48 +00:00
|
|
|
import org.thoughtcrime.securesms.util.SignalLocalMetrics;
|
2020-10-26 16:41:30 +00:00
|
|
|
import org.thoughtcrime.securesms.util.SmsUtil;
|
2020-11-04 20:00:12 +00:00
|
|
|
import org.thoughtcrime.securesms.util.SpanUtil;
|
2013-07-10 01:26:18 +00:00
|
|
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
2019-04-17 14:21:30 +00:00
|
|
|
import org.thoughtcrime.securesms.util.TextSecurePreferences.MediaKeyboardMode;
|
2014-11-12 19:15:05 +00:00
|
|
|
import org.thoughtcrime.securesms.util.Util;
|
2015-10-14 04:44:01 +00:00
|
|
|
import org.thoughtcrime.securesms.util.ViewUtil;
|
2020-11-13 18:43:58 +00:00
|
|
|
import org.thoughtcrime.securesms.util.WindowUtil;
|
2015-11-09 22:51:53 +00:00
|
|
|
import org.thoughtcrime.securesms.util.concurrent.AssertedSuccessListener;
|
2015-06-22 15:46:43 +00:00
|
|
|
import org.thoughtcrime.securesms.util.concurrent.ListenableFuture;
|
|
|
|
import org.thoughtcrime.securesms.util.concurrent.SettableFuture;
|
2017-01-19 02:46:40 +00:00
|
|
|
import org.thoughtcrime.securesms.util.views.Stub;
|
2022-04-29 13:54:48 +00:00
|
|
|
import org.thoughtcrime.securesms.verify.VerifyIdentityActivity;
|
2021-01-20 02:54:10 +00:00
|
|
|
import org.thoughtcrime.securesms.wallpaper.ChatWallpaper;
|
|
|
|
import org.thoughtcrime.securesms.wallpaper.ChatWallpaperDimLevelUtil;
|
2021-02-19 19:18:05 +00:00
|
|
|
import org.whispersystems.signalservice.api.SignalSessionLock;
|
Major storage layer refactoring to set the stage for clean GCM.
1) We now try to hand out cursors at a minimum. There has always been
a fairly clean insertion layer that handles encrypting message bodies,
but the process of decrypting message bodies has always been less than
ideal. Here we introduce a "Reader" interface that will decrypt message
bodies when appropriate and return objects that encapsulate record state.
No more MessageDisplayHelper. The MmsSmsDatabase interface is also more
sane.
2) We finally rid ourselves of the technical debt associated with TextSecure's
initial usage of the default SMS DB. In that world, we weren't able to use
anything other than the default "Inbox, Outbox, Sent" types to describe a
message, and had to overload the message content itself with a set of
local "prefixes" to describe what it was (encrypted, asymetric encrypted,
remote encrypted, a key exchange, procssed key exchange), and so on.
This includes a major schema update that transforms the "type" field into
a bitmask that describes everything that used to be encoded in a prefix,
and prefixes have been completely eliminated from the system.
No more Prefix.java
3) Refactoring of the MultipartMessageHandler code. It's less of a mess, and
hopefully more clear as to what's going on.
The next step is to remove what we can from SmsTransportDetails and genericize
that interface for a GCM equivalent.
2013-04-20 19:22:04 +00:00
|
|
|
|
|
|
|
import java.io.IOException;
|
2021-07-29 18:07:39 +00:00
|
|
|
import java.security.SecureRandom;
|
2020-08-05 20:45:52 +00:00
|
|
|
import java.util.ArrayList;
|
2018-04-27 00:03:54 +00:00
|
|
|
import java.util.Collections;
|
Major storage layer refactoring to set the stage for clean GCM.
1) We now try to hand out cursors at a minimum. There has always been
a fairly clean insertion layer that handles encrypting message bodies,
but the process of decrypting message bodies has always been less than
ideal. Here we introduce a "Reader" interface that will decrypt message
bodies when appropriate and return objects that encapsulate record state.
No more MessageDisplayHelper. The MmsSmsDatabase interface is also more
sane.
2) We finally rid ourselves of the technical debt associated with TextSecure's
initial usage of the default SMS DB. In that world, we weren't able to use
anything other than the default "Inbox, Outbox, Sent" types to describe a
message, and had to overload the message content itself with a set of
local "prefixes" to describe what it was (encrypted, asymetric encrypted,
remote encrypted, a key exchange, procssed key exchange), and so on.
This includes a major schema update that transforms the "type" field into
a bitmask that describes everything that used to be encoded in a prefix,
and prefixes have been completely eliminated from the system.
No more Prefix.java
3) Refactoring of the MultipartMessageHandler code. It's less of a mess, and
hopefully more clear as to what's going on.
The next step is to remove what we can from SmsTransportDetails and genericize
that interface for a GCM equivalent.
2013-04-20 19:22:04 +00:00
|
|
|
import java.util.List;
|
2020-06-07 21:22:35 +00:00
|
|
|
import java.util.Locale;
|
2020-07-08 15:54:47 +00:00
|
|
|
import java.util.Objects;
|
2022-03-14 19:49:46 +00:00
|
|
|
import java.util.Optional;
|
2020-08-05 20:45:52 +00:00
|
|
|
import java.util.Set;
|
2015-11-18 22:52:26 +00:00
|
|
|
import java.util.concurrent.ExecutionException;
|
2020-07-08 15:54:47 +00:00
|
|
|
import java.util.concurrent.TimeUnit;
|
|
|
|
import java.util.concurrent.TimeoutException;
|
2018-07-25 15:30:48 +00:00
|
|
|
import java.util.concurrent.atomic.AtomicBoolean;
|
|
|
|
import java.util.concurrent.atomic.AtomicInteger;
|
Major storage layer refactoring to set the stage for clean GCM.
1) We now try to hand out cursors at a minimum. There has always been
a fairly clean insertion layer that handles encrypting message bodies,
but the process of decrypting message bodies has always been less than
ideal. Here we introduce a "Reader" interface that will decrypt message
bodies when appropriate and return objects that encapsulate record state.
No more MessageDisplayHelper. The MmsSmsDatabase interface is also more
sane.
2) We finally rid ourselves of the technical debt associated with TextSecure's
initial usage of the default SMS DB. In that world, we weren't able to use
anything other than the default "Inbox, Outbox, Sent" types to describe a
message, and had to overload the message content itself with a set of
local "prefixes" to describe what it was (encrypted, asymetric encrypted,
remote encrypted, a key exchange, procssed key exchange), and so on.
This includes a major schema update that transforms the "type" field into
a bitmask that describes everything that used to be encoded in a prefix,
and prefixes have been completely eliminated from the system.
No more Prefix.java
3) Refactoring of the MultipartMessageHandler code. It's less of a mess, and
hopefully more clear as to what's going on.
The next step is to remove what we can from SmsTransportDetails and genericize
that interface for a GCM equivalent.
2013-04-20 19:22:04 +00:00
|
|
|
|
2022-08-01 14:55:40 +00:00
|
|
|
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
2022-07-19 17:53:54 +00:00
|
|
|
import io.reactivex.rxjava3.core.Flowable;
|
2022-08-01 14:55:40 +00:00
|
|
|
import io.reactivex.rxjava3.disposables.Disposable;
|
2022-07-19 17:53:54 +00:00
|
|
|
|
2022-08-01 14:55:40 +00:00
|
|
|
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
|
2022-11-29 15:47:12 +00:00
|
|
|
import static org.thoughtcrime.securesms.database.GroupTable.GroupRecord;
|
2014-02-22 18:54:43 +00:00
|
|
|
|
2012-07-19 21:22:03 +00:00
|
|
|
/**
|
2022-01-14 13:06:28 +00:00
|
|
|
* Fragment for displaying a message thread, as well as
|
2012-07-19 21:22:03 +00:00
|
|
|
* composing/sending a new message into that thread.
|
|
|
|
*
|
|
|
|
* @author Moxie Marlinspike
|
|
|
|
*
|
|
|
|
*/
|
2017-11-14 18:49:54 +00:00
|
|
|
@SuppressLint("StaticFieldLeak")
|
2022-01-14 13:06:28 +00:00
|
|
|
public class ConversationParentFragment extends Fragment
|
2014-04-15 10:43:14 +00:00
|
|
|
implements ConversationFragment.ConversationFragmentListener,
|
2015-02-10 11:15:50 +00:00
|
|
|
AttachmentManager.AttachmentListener,
|
2015-06-08 18:07:46 +00:00
|
|
|
OnKeyboardShownListener,
|
2016-12-26 23:14:23 +00:00
|
|
|
InputPanel.Listener,
|
2019-02-01 17:06:59 +00:00
|
|
|
InputPanel.MediaListener,
|
2019-02-25 23:21:37 +00:00
|
|
|
ComposeText.CursorPositionChangedListener,
|
2019-04-17 14:21:30 +00:00
|
|
|
ConversationSearchBottomBar.EventListener,
|
2021-06-29 16:34:49 +00:00
|
|
|
StickerEventListener,
|
2020-05-05 17:53:57 +00:00
|
|
|
AttachmentKeyboard.Callback,
|
|
|
|
ConversationReactionOverlay.OnReactionSelectedListener,
|
2020-06-26 15:10:54 +00:00
|
|
|
ReactWithAnyEmojiBottomSheetDialogFragment.Callback,
|
2022-07-11 15:54:30 +00:00
|
|
|
SafetyNumberBottomSheet.Callbacks,
|
2021-05-26 13:47:14 +00:00
|
|
|
ReactionsBottomSheetDialogFragment.Callback,
|
|
|
|
MediaKeyboard.MediaKeyboardListener,
|
2021-06-29 16:34:49 +00:00
|
|
|
EmojiEventListener,
|
2021-05-26 13:47:14 +00:00
|
|
|
GifKeyboardPageFragment.Host,
|
|
|
|
EmojiKeyboardPageFragment.Callback,
|
2022-02-03 18:48:52 +00:00
|
|
|
EmojiSearchFragment.Callback,
|
2022-05-26 20:32:52 +00:00
|
|
|
StickerKeyboardPageFragment.Callback,
|
|
|
|
Material3OnScrollHelperBinder,
|
|
|
|
MessageDetailsFragment.Callback
|
2013-04-26 01:59:49 +00:00
|
|
|
{
|
2020-03-25 15:30:15 +00:00
|
|
|
|
|
|
|
private static final int SHORTCUT_ICON_SIZE = Build.VERSION.SDK_INT >= 26 ? ViewUtil.dpToPx(72) : ViewUtil.dpToPx(48 + 16 * 2);
|
|
|
|
|
2022-01-14 13:06:28 +00:00
|
|
|
private static final String TAG = Log.tag(ConversationParentFragment.class);
|
2012-07-19 21:22:03 +00:00
|
|
|
|
2020-08-21 19:06:47 +00:00
|
|
|
private static final String STATE_REACT_WITH_ANY_PAGE = "STATE_REACT_WITH_ANY_PAGE";
|
2021-06-25 12:28:55 +00:00
|
|
|
private static final String STATE_IS_SEARCH_REQUESTED = "STATE_IS_SEARCH_REQUESTED";
|
2021-06-24 16:52:54 +00:00
|
|
|
|
2022-07-19 15:49:28 +00:00
|
|
|
private static final String ARG_INTENT_DATA = "arg.intent.data";
|
|
|
|
|
2021-06-24 16:52:54 +00:00
|
|
|
private static final int REQUEST_CODE_SETTINGS = 1000;
|
2020-08-21 19:06:47 +00:00
|
|
|
|
2018-04-27 00:03:54 +00:00
|
|
|
private static final int PICK_GALLERY = 1;
|
|
|
|
private static final int PICK_DOCUMENT = 2;
|
|
|
|
private static final int PICK_AUDIO = 3;
|
|
|
|
private static final int PICK_CONTACT = 4;
|
|
|
|
private static final int GET_CONTACT_DETAILS = 5;
|
|
|
|
private static final int GROUP_EDIT = 6;
|
|
|
|
private static final int TAKE_PHOTO = 7;
|
|
|
|
private static final int ADD_CONTACT = 8;
|
|
|
|
private static final int PICK_LOCATION = 9;
|
2021-05-26 13:47:14 +00:00
|
|
|
public static final int PICK_GIF = 10;
|
2018-04-27 00:03:54 +00:00
|
|
|
private static final int SMS_DEFAULT = 11;
|
2019-03-13 23:05:25 +00:00
|
|
|
private static final int MEDIA_SENDER = 12;
|
2012-07-19 21:22:03 +00:00
|
|
|
|
2022-01-29 16:04:56 +00:00
|
|
|
private static final int REQUEST_CODE_PIN_SHORTCUT = 902;
|
|
|
|
private static final String ACTION_PINNED_SHORTCUT = "action_pinned_shortcut";
|
|
|
|
|
2021-01-27 20:34:59 +00:00
|
|
|
private GlideRequests glideRequests;
|
|
|
|
protected ComposeText composeText;
|
|
|
|
private AnimatingToggle buttonToggle;
|
|
|
|
private SendButton sendButton;
|
|
|
|
private ImageButton attachButton;
|
|
|
|
protected ConversationTitleView titleView;
|
|
|
|
private TextView charactersLeft;
|
|
|
|
private ConversationFragment fragment;
|
|
|
|
private Button unblockButton;
|
2022-10-13 15:33:13 +00:00
|
|
|
private Stub<View> smsExportStub;
|
2021-01-27 20:34:59 +00:00
|
|
|
private Button registerButton;
|
|
|
|
private InputAwareLayout container;
|
|
|
|
protected Stub<ReminderView> reminderView;
|
|
|
|
private Stub<UnverifiedBannerView> unverifiedBannerView;
|
|
|
|
private Stub<ReviewBannerView> reviewBanner;
|
2022-08-05 21:00:11 +00:00
|
|
|
private ComposeTextWatcher typingTextWatcher;
|
2021-01-27 20:34:59 +00:00
|
|
|
private ConversationSearchBottomBar searchNav;
|
|
|
|
private MenuItem searchViewItem;
|
|
|
|
private MessageRequestsBottomView messageRequestBottomView;
|
|
|
|
private ConversationReactionDelegate reactionDelegate;
|
2021-07-22 14:10:57 +00:00
|
|
|
private Stub<FrameLayout> voiceNotePlayerViewStub;
|
2022-06-17 17:22:14 +00:00
|
|
|
private View navigationBarBackground;
|
2012-07-19 21:22:03 +00:00
|
|
|
|
2020-01-30 03:13:44 +00:00
|
|
|
private AttachmentManager attachmentManager;
|
|
|
|
private AudioRecorder audioRecorder;
|
|
|
|
private BroadcastReceiver securityUpdateReceiver;
|
|
|
|
private Stub<MediaKeyboard> emojiDrawerStub;
|
|
|
|
private Stub<AttachmentKeyboard> attachmentKeyboardStub;
|
|
|
|
protected HidingLinearLayout quickAttachmentToggle;
|
|
|
|
protected HidingLinearLayout inlineAttachmentToggle;
|
|
|
|
private InputPanel inputPanel;
|
2020-07-17 18:32:53 +00:00
|
|
|
private View noLongerMemberBanner;
|
2021-07-23 20:22:08 +00:00
|
|
|
private Stub<TextView> cannotSendInAnnouncementGroupBanner;
|
2020-08-26 15:51:25 +00:00
|
|
|
private View requestingMemberBanner;
|
|
|
|
private View cancelJoinRequest;
|
2022-01-31 17:46:44 +00:00
|
|
|
private Stub<View> releaseChannelUnmute;
|
2020-07-27 13:58:58 +00:00
|
|
|
private Stub<View> mentionsSuggestions;
|
2020-12-02 18:20:38 +00:00
|
|
|
private MaterialButton joinGroupCallButton;
|
2020-12-14 22:26:07 +00:00
|
|
|
private boolean callingTooltipShown;
|
2021-01-20 02:54:10 +00:00
|
|
|
private ImageView wallpaper;
|
|
|
|
private View wallpaperDim;
|
2021-02-09 16:42:57 +00:00
|
|
|
private Toolbar toolbar;
|
2022-05-26 20:32:52 +00:00
|
|
|
private View toolbarBackground;
|
2022-01-29 16:04:56 +00:00
|
|
|
private BroadcastReceiver pinnedShortcutReceiver;
|
2019-02-01 17:06:59 +00:00
|
|
|
|
2019-04-17 14:21:30 +00:00
|
|
|
private LinkPreviewViewModel linkPreviewViewModel;
|
|
|
|
private ConversationSearchViewModel searchViewModel;
|
|
|
|
private ConversationStickerViewModel stickerViewModel;
|
2020-01-30 03:13:44 +00:00
|
|
|
private ConversationViewModel viewModel;
|
2019-11-12 14:18:57 +00:00
|
|
|
private InviteReminderModel inviteReminderModel;
|
2020-06-06 23:26:21 +00:00
|
|
|
private ConversationGroupViewModel groupViewModel;
|
2020-10-13 14:57:00 +00:00
|
|
|
private MentionsPickerViewModel mentionsViewModel;
|
2022-08-01 14:55:40 +00:00
|
|
|
private InlineQueryViewModel inlineQueryViewModel;
|
2020-12-02 18:20:38 +00:00
|
|
|
private GroupCallViewModel groupCallViewModel;
|
2021-06-07 19:55:26 +00:00
|
|
|
private VoiceRecorderWakeLock voiceRecorderWakeLock;
|
2021-07-02 13:28:45 +00:00
|
|
|
private DraftViewModel draftViewModel;
|
|
|
|
private VoiceNoteMediaController voiceNoteMediaController;
|
2021-07-22 14:10:57 +00:00
|
|
|
private VoiceNotePlayerView voiceNotePlayerView;
|
2022-05-26 20:32:52 +00:00
|
|
|
private Material3OnScrollHelper material3OnScrollHelper;
|
2022-08-01 14:55:40 +00:00
|
|
|
private InlineQueryResultsController inlineQueryResultsController;
|
2022-10-29 20:58:01 +00:00
|
|
|
private OnBackPressedCallback backPressedCallback;
|
2012-07-19 21:22:03 +00:00
|
|
|
|
2019-08-07 18:22:51 +00:00
|
|
|
private LiveRecipient recipient;
|
|
|
|
private long threadId;
|
|
|
|
private int distributionType;
|
2022-08-05 21:00:11 +00:00
|
|
|
private int reactWithAnyEmojiStartPage = -1;
|
|
|
|
private boolean isSearchRequested = false;
|
2012-07-19 21:22:03 +00:00
|
|
|
|
2022-08-05 21:00:11 +00:00
|
|
|
private final LifecycleDisposable disposables = new LifecycleDisposable();
|
|
|
|
private final Debouncer optionsMenuDebouncer = new Debouncer(50);
|
|
|
|
private final Debouncer textDraftSaveDebouncer = new Debouncer(500);
|
2022-03-16 14:10:01 +00:00
|
|
|
|
2022-02-24 19:33:09 +00:00
|
|
|
private IdentityRecordList identityRecords = new IdentityRecordList(Collections.emptyList());
|
|
|
|
private Callback callback;
|
|
|
|
private RecentEmojiPageModel recentEmojis;
|
2012-07-19 21:22:03 +00:00
|
|
|
|
2022-07-19 15:49:28 +00:00
|
|
|
public static ConversationParentFragment create(Intent intent) {
|
|
|
|
ConversationParentFragment fragment = new ConversationParentFragment();
|
|
|
|
Bundle bundle = new Bundle();
|
|
|
|
|
|
|
|
bundle.putAll(ConversationIntents.createParentFragmentArguments(intent));
|
|
|
|
fragment.setArguments(bundle);
|
|
|
|
|
|
|
|
return fragment;
|
|
|
|
}
|
|
|
|
|
2012-07-19 21:22:03 +00:00
|
|
|
@Override
|
2022-01-14 13:06:28 +00:00
|
|
|
public @NonNull View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
|
|
|
return inflater.inflate(R.layout.conversation_activity, container, false);
|
2014-12-15 20:25:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2022-01-14 13:06:28 +00:00
|
|
|
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
2022-03-16 14:10:01 +00:00
|
|
|
disposables.bindTo(getViewLifecycleOwner());
|
|
|
|
|
2022-01-14 13:06:28 +00:00
|
|
|
if (requireActivity() instanceof Callback) {
|
|
|
|
callback = (Callback) requireActivity();
|
|
|
|
} else if (getParentFragment() instanceof Callback) {
|
|
|
|
callback = (Callback) getParentFragment();
|
|
|
|
} else {
|
|
|
|
throw new ClassCastException("Cannot cast activity or parent fragment into a Callback object");
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO [alex] LargeScreenSupport -- This check will no longer be valid / necessary
|
2022-07-19 15:49:28 +00:00
|
|
|
if (ConversationIntents.isInvalid(requireArguments())) {
|
2019-10-01 12:17:25 +00:00
|
|
|
Log.w(TAG, "[onCreate] Missing recipientId!");
|
2019-11-14 19:35:08 +00:00
|
|
|
// TODO [greyson] Navigation
|
2022-01-14 13:06:28 +00:00
|
|
|
startActivity(MainActivity.clearTop(requireContext()));
|
|
|
|
requireActivity().finish();
|
2019-10-01 12:17:25 +00:00
|
|
|
return;
|
|
|
|
}
|
2021-06-07 19:55:26 +00:00
|
|
|
|
2022-01-14 13:06:28 +00:00
|
|
|
voiceNoteMediaController = new VoiceNoteMediaController(requireActivity());
|
|
|
|
voiceRecorderWakeLock = new VoiceRecorderWakeLock(requireActivity());
|
|
|
|
|
|
|
|
// TODO [alex] LargeScreenSupport -- Should be removed once we move to multi-pane layout.
|
|
|
|
new FullscreenHelper(requireActivity()).showSystemUI();
|
2021-01-20 02:54:10 +00:00
|
|
|
|
2022-07-19 15:49:28 +00:00
|
|
|
ConversationIntents.Args args = ConversationIntents.Args.from(requireArguments());
|
2022-05-02 17:29:42 +00:00
|
|
|
if (savedInstanceState == null && args.getGiftBadge() != null) {
|
|
|
|
GiftThanksSheet.show(getChildFragmentManager(), args.getRecipientId(), args.getGiftBadge());
|
|
|
|
}
|
2020-11-24 17:22:41 +00:00
|
|
|
|
2021-06-25 12:28:55 +00:00
|
|
|
isSearchRequested = args.isWithSearchOpen();
|
|
|
|
|
2020-11-25 15:36:33 +00:00
|
|
|
reportShortcutLaunch(args.getRecipientId());
|
2015-06-09 14:37:20 +00:00
|
|
|
|
2022-01-14 13:06:28 +00:00
|
|
|
requireActivity().getWindow().getDecorView().setBackgroundResource(R.color.signal_background_primary);
|
|
|
|
|
|
|
|
fragment = (ConversationFragment) getChildFragmentManager().findFragmentById(R.id.fragment_content);
|
|
|
|
if (fragment == null) {
|
|
|
|
fragment = new ConversationFragment();
|
|
|
|
getChildFragmentManager().beginTransaction()
|
|
|
|
.replace(R.id.fragment_content, fragment)
|
|
|
|
.commitNow();
|
|
|
|
}
|
2017-11-14 02:01:05 +00:00
|
|
|
|
2012-07-19 21:22:03 +00:00
|
|
|
initializeReceivers();
|
2022-01-14 13:06:28 +00:00
|
|
|
initializeViews(view);
|
2021-01-20 02:54:10 +00:00
|
|
|
updateWallpaper(args.getWallpaper());
|
2020-11-25 15:36:33 +00:00
|
|
|
initializeResources(args);
|
2019-01-15 08:41:05 +00:00
|
|
|
initializeLinkPreviewObserver();
|
2019-02-01 17:06:59 +00:00
|
|
|
initializeSearchObserver();
|
2019-04-17 14:21:30 +00:00
|
|
|
initializeStickerObserver();
|
2020-11-25 15:36:33 +00:00
|
|
|
initializeViewModel(args);
|
2020-06-06 23:26:21 +00:00
|
|
|
initializeGroupViewModel();
|
2020-10-15 14:56:08 +00:00
|
|
|
initializeMentionsViewModel();
|
2020-12-02 18:20:38 +00:00
|
|
|
initializeGroupCallViewModel();
|
2021-07-02 13:28:45 +00:00
|
|
|
initializeDraftViewModel();
|
2020-06-06 23:26:21 +00:00
|
|
|
initializeEnabledCheck();
|
2020-10-15 16:32:50 +00:00
|
|
|
initializePendingRequestsBanner();
|
2020-11-12 14:52:21 +00:00
|
|
|
initializeGroupV1MigrationsBanners();
|
2022-01-14 13:06:28 +00:00
|
|
|
|
2022-07-22 13:47:40 +00:00
|
|
|
Flowable<ConversationSecurityInfo> observableSecurityInfo = viewModel.getConversationSecurityInfo(args.getRecipientId());
|
2021-03-16 14:37:40 +00:00
|
|
|
|
2022-07-22 13:47:40 +00:00
|
|
|
disposables.add(observableSecurityInfo.subscribe(this::handleSecurityChange));
|
|
|
|
disposables.add(observableSecurityInfo.firstOrError().subscribe(unused -> onInitialSecurityConfigurationLoaded()));
|
2022-07-18 15:41:05 +00:00
|
|
|
|
2019-11-12 14:18:57 +00:00
|
|
|
initializeInsightObserver();
|
2022-01-14 13:06:28 +00:00
|
|
|
initializeActionBar();
|
2022-01-28 17:24:44 +00:00
|
|
|
|
2022-03-16 14:10:01 +00:00
|
|
|
disposables.add(viewModel.getStoryViewState().subscribe(titleView::setStoryRingFromState));
|
2022-02-25 19:06:12 +00:00
|
|
|
|
2022-10-29 20:58:01 +00:00
|
|
|
backPressedCallback = new OnBackPressedCallback(true) {
|
2022-01-28 17:24:44 +00:00
|
|
|
@Override
|
|
|
|
public void handleOnBackPressed() {
|
|
|
|
onBackPressed();
|
|
|
|
}
|
2022-10-29 20:58:01 +00:00
|
|
|
};
|
|
|
|
requireActivity().getOnBackPressedDispatcher().addCallback(getViewLifecycleOwner(), backPressedCallback);
|
2022-05-25 14:28:40 +00:00
|
|
|
|
|
|
|
if (isSearchRequested && savedInstanceState == null) {
|
|
|
|
onCreateOptionsMenu(toolbar.getMenu(), requireActivity().getMenuInflater());
|
|
|
|
}
|
2022-06-03 22:07:29 +00:00
|
|
|
|
|
|
|
sendButton.post(() -> sendButton.triggerSelectedChangedEvent());
|
2012-07-19 21:22:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2022-01-14 13:06:28 +00:00
|
|
|
public void onResume() {
|
2012-07-19 21:22:03 +00:00
|
|
|
super.onResume();
|
2013-06-21 18:56:59 +00:00
|
|
|
|
2022-01-14 13:06:28 +00:00
|
|
|
// TODO [alex] LargeScreenSupport -- Remove these lines.
|
|
|
|
WindowUtil.setLightNavigationBarFromTheme(requireActivity());
|
|
|
|
WindowUtil.setLightStatusBarFromTheme(requireActivity());
|
2021-02-09 16:42:57 +00:00
|
|
|
|
2019-04-17 14:21:30 +00:00
|
|
|
EventBus.getDefault().register(this);
|
2022-10-29 20:58:01 +00:00
|
|
|
backPressedCallback.setEnabled(true);
|
2022-07-19 17:53:54 +00:00
|
|
|
viewModel.checkIfMmsIsEnabled();
|
2017-06-07 01:03:09 +00:00
|
|
|
initializeIdentityRecords();
|
2022-06-03 22:07:29 +00:00
|
|
|
composeText.setMessageSendType(sendButton.getSelectedSendType());
|
2015-06-09 14:37:20 +00:00
|
|
|
|
2019-08-07 18:22:51 +00:00
|
|
|
Recipient recipientSnapshot = recipient.get();
|
|
|
|
|
|
|
|
titleView.setTitle(glideRequests, recipientSnapshot);
|
2022-07-22 13:47:40 +00:00
|
|
|
setBlockedUserState(recipientSnapshot, viewModel.getConversationStateSnapshot().getSecurityInfo());
|
2012-07-19 21:22:03 +00:00
|
|
|
calculateCharactersRemaining();
|
2013-02-04 02:41:34 +00:00
|
|
|
|
2022-01-24 19:21:21 +00:00
|
|
|
if (recipientSnapshot.getGroupId().isPresent() && recipientSnapshot.getGroupId().get().isV2() && !recipientSnapshot.isBlocked()) {
|
2020-07-24 19:40:06 +00:00
|
|
|
GroupId.V2 groupId = recipientSnapshot.getGroupId().get().requireV2();
|
|
|
|
|
|
|
|
ApplicationDependencies.getJobManager()
|
|
|
|
.startChain(new RequestGroupV2InfoJob(groupId))
|
2021-05-06 14:07:23 +00:00
|
|
|
.then(GroupV2UpdateSelfProfileKeyJob.withoutLimits(groupId))
|
2020-07-24 19:40:06 +00:00
|
|
|
.enqueue();
|
2021-01-08 23:37:03 +00:00
|
|
|
|
2022-10-05 21:09:28 +00:00
|
|
|
ForceUpdateGroupV2Job.enqueueIfNecessary(groupId);
|
|
|
|
|
2021-01-08 23:37:03 +00:00
|
|
|
if (viewModel.getArgs().isFirstTimeInSelfCreatedGroup()) {
|
2022-01-14 13:06:28 +00:00
|
|
|
groupViewModel.inviteFriendsOneTimeIfJustSelfInGroup(getChildFragmentManager(), groupId);
|
2021-01-08 23:37:03 +00:00
|
|
|
}
|
2020-05-07 19:51:54 +00:00
|
|
|
}
|
|
|
|
|
2020-12-02 18:20:38 +00:00
|
|
|
if (groupCallViewModel != null) {
|
2021-03-31 18:30:30 +00:00
|
|
|
groupCallViewModel.peekGroupCall();
|
2020-12-02 18:20:38 +00:00
|
|
|
}
|
|
|
|
|
2020-11-25 18:11:17 +00:00
|
|
|
setVisibleThread(threadId);
|
2020-12-01 20:41:13 +00:00
|
|
|
ConversationUtil.refreshRecipientShortcuts();
|
2021-05-05 16:49:18 +00:00
|
|
|
|
|
|
|
if (SignalStore.rateLimit().needsRecaptcha()) {
|
2022-01-14 13:06:28 +00:00
|
|
|
RecaptchaProofBottomSheetFragment.show(getChildFragmentManager());
|
2021-05-05 16:49:18 +00:00
|
|
|
}
|
2012-07-19 21:22:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2022-01-14 13:06:28 +00:00
|
|
|
public void onPause() {
|
2013-03-05 01:43:04 +00:00
|
|
|
super.onPause();
|
2020-11-25 18:11:17 +00:00
|
|
|
if (!isInBubble()) {
|
|
|
|
ApplicationDependencies.getMessageNotifier().clearVisibleThread();
|
|
|
|
}
|
|
|
|
|
2022-01-14 13:06:28 +00:00
|
|
|
if (requireActivity().isFinishing()) requireActivity().overridePendingTransition(R.anim.fade_scale_in, R.anim.slide_to_end);
|
2015-11-18 22:52:26 +00:00
|
|
|
inputPanel.onPause();
|
|
|
|
|
2017-02-14 06:35:47 +00:00
|
|
|
fragment.setLastSeen(System.currentTimeMillis());
|
|
|
|
markLastSeen();
|
2017-02-18 04:43:24 +00:00
|
|
|
EventBus.getDefault().unregister(this);
|
2022-06-10 19:20:02 +00:00
|
|
|
material3OnScrollHelper.setColorImmediate();
|
2017-02-18 04:43:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2022-01-14 13:06:28 +00:00
|
|
|
public void onStop() {
|
2017-02-18 04:43:24 +00:00
|
|
|
super.onStop();
|
|
|
|
EventBus.getDefault().unregister(this);
|
2012-07-19 21:22:03 +00:00
|
|
|
}
|
|
|
|
|
2015-09-23 22:47:48 +00:00
|
|
|
@Override
|
|
|
|
public void onConfigurationChanged(Configuration newConfig) {
|
2018-08-02 13:25:33 +00:00
|
|
|
Log.i(TAG, "onConfigurationChanged(" + newConfig.orientation + ")");
|
2015-06-08 18:07:46 +00:00
|
|
|
super.onConfigurationChanged(newConfig);
|
2022-06-03 22:07:29 +00:00
|
|
|
composeText.setMessageSendType(sendButton.getSelectedSendType());
|
2017-01-19 19:31:41 +00:00
|
|
|
|
|
|
|
if (emojiDrawerStub.resolved() && container.getCurrentInput() == emojiDrawerStub.get()) {
|
|
|
|
container.hideAttachedInput(true);
|
|
|
|
}
|
2020-02-06 16:06:41 +00:00
|
|
|
|
2021-01-27 20:34:59 +00:00
|
|
|
if (reactionDelegate.isShowing()) {
|
|
|
|
reactionDelegate.hide();
|
2020-02-06 16:06:41 +00:00
|
|
|
}
|
2022-08-01 14:55:40 +00:00
|
|
|
|
|
|
|
if (inlineQueryResultsController != null) {
|
|
|
|
inlineQueryResultsController.onOrientationChange(newConfig.orientation == ORIENTATION_LANDSCAPE);
|
|
|
|
}
|
2015-06-08 18:07:46 +00:00
|
|
|
}
|
|
|
|
|
2012-07-19 21:22:03 +00:00
|
|
|
@Override
|
2022-01-14 13:06:28 +00:00
|
|
|
public void onDestroy() {
|
|
|
|
if (securityUpdateReceiver != null) requireActivity().unregisterReceiver(securityUpdateReceiver);
|
2022-01-29 16:04:56 +00:00
|
|
|
if (pinnedShortcutReceiver != null) requireActivity().unregisterReceiver(pinnedShortcutReceiver);
|
2012-07-19 21:22:03 +00:00
|
|
|
super.onDestroy();
|
|
|
|
}
|
|
|
|
|
2022-01-14 13:06:28 +00:00
|
|
|
// TODO [alex] LargeScreenSupport -- Pipe in events from activity
|
2019-12-03 21:57:21 +00:00
|
|
|
public boolean dispatchTouchEvent(MotionEvent ev) {
|
2022-01-14 13:06:28 +00:00
|
|
|
return reactionDelegate.applyTouchEvent(ev);
|
2019-12-03 21:57:21 +00:00
|
|
|
}
|
|
|
|
|
2012-07-19 21:22:03 +00:00
|
|
|
@Override
|
2015-12-18 22:37:11 +00:00
|
|
|
public void onActivityResult(final int reqCode, int resultCode, Intent data) {
|
2018-08-02 13:25:33 +00:00
|
|
|
Log.i(TAG, "onActivityResult called: " + reqCode + ", " + resultCode + " , " + data);
|
2012-07-19 21:22:03 +00:00
|
|
|
super.onActivityResult(reqCode, resultCode, data);
|
|
|
|
|
2017-03-15 01:05:48 +00:00
|
|
|
if ((data == null && reqCode != TAKE_PHOTO && reqCode != SMS_DEFAULT) ||
|
2022-01-14 13:06:28 +00:00
|
|
|
(resultCode != Activity.RESULT_OK && reqCode != SMS_DEFAULT))
|
2017-03-15 01:05:48 +00:00
|
|
|
{
|
2019-01-15 08:41:05 +00:00
|
|
|
updateLinkPreviewState();
|
2022-01-14 13:06:28 +00:00
|
|
|
SignalStore.settings().setDefaultSms(Util.isDefaultSmsProvider(requireContext()));
|
2017-03-15 01:05:48 +00:00
|
|
|
return;
|
|
|
|
}
|
2015-05-18 17:26:32 +00:00
|
|
|
|
2012-07-19 21:22:03 +00:00
|
|
|
switch (reqCode) {
|
2017-04-18 23:33:03 +00:00
|
|
|
case PICK_DOCUMENT:
|
2022-01-14 13:06:28 +00:00
|
|
|
setMedia(data.getData(), MediaType.DOCUMENT);
|
2012-07-19 21:22:03 +00:00
|
|
|
break;
|
|
|
|
case PICK_AUDIO:
|
2022-01-14 13:06:28 +00:00
|
|
|
setMedia(data.getData(), MediaType.AUDIO);
|
2012-07-19 21:22:03 +00:00
|
|
|
break;
|
2018-04-27 00:03:54 +00:00
|
|
|
case PICK_CONTACT:
|
2022-07-22 13:47:40 +00:00
|
|
|
if (viewModel.isPushAvailable() && !isSmsForced()) {
|
2018-06-29 18:08:13 +00:00
|
|
|
openContactShareEditor(data.getData());
|
|
|
|
} else {
|
|
|
|
addAttachmentContactInfo(data.getData());
|
|
|
|
}
|
2018-04-27 00:03:54 +00:00
|
|
|
break;
|
|
|
|
case GET_CONTACT_DETAILS:
|
|
|
|
sendSharedContact(data.getParcelableArrayListExtra(ContactShareEditActivity.KEY_CONTACTS));
|
2013-10-17 00:28:36 +00:00
|
|
|
break;
|
2014-02-20 23:41:52 +00:00
|
|
|
case GROUP_EDIT:
|
2019-08-07 18:22:51 +00:00
|
|
|
Recipient recipientSnapshot = recipient.get();
|
|
|
|
|
|
|
|
onRecipientChanged(recipientSnapshot);
|
|
|
|
titleView.setTitle(glideRequests, recipientSnapshot);
|
2022-11-17 00:08:50 +00:00
|
|
|
NotificationChannels.getInstance().updateContactChannelName(recipientSnapshot);
|
2022-07-22 13:47:40 +00:00
|
|
|
setBlockedUserState(recipientSnapshot, viewModel.getConversationStateSnapshot().getSecurityInfo());
|
2021-06-25 12:28:55 +00:00
|
|
|
invalidateOptionsMenu();
|
2014-02-20 23:41:52 +00:00
|
|
|
break;
|
2015-07-11 01:45:55 +00:00
|
|
|
case TAKE_PHOTO:
|
2019-10-15 16:51:16 +00:00
|
|
|
handleImageFromDeviceCameraApp();
|
2015-07-11 01:45:55 +00:00
|
|
|
break;
|
2015-10-16 13:39:27 +00:00
|
|
|
case ADD_CONTACT:
|
2020-06-08 17:20:07 +00:00
|
|
|
SimpleTask.run(() -> {
|
|
|
|
try {
|
2022-03-18 17:33:23 +00:00
|
|
|
ContactDiscovery.refresh(requireContext(), recipient.get(), false);
|
2020-06-08 17:20:07 +00:00
|
|
|
} catch (IOException e) {
|
|
|
|
Log.w(TAG, "Failed to refresh user after adding to contacts.");
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}, nothing -> onRecipientChanged(recipient.get()));
|
2015-10-16 13:39:27 +00:00
|
|
|
break;
|
2015-12-18 22:37:11 +00:00
|
|
|
case PICK_LOCATION:
|
2019-06-27 16:14:54 +00:00
|
|
|
SignalPlace place = new SignalPlace(PlacePickerActivity.addressFromData(data));
|
2018-01-25 03:17:44 +00:00
|
|
|
attachmentManager.setLocation(place, getCurrentMediaConstraints());
|
2022-08-05 21:00:11 +00:00
|
|
|
draftViewModel.setLocationDraft(place);
|
2015-12-18 22:37:11 +00:00
|
|
|
break;
|
2017-01-18 19:01:13 +00:00
|
|
|
case SMS_DEFAULT:
|
2022-07-19 17:53:54 +00:00
|
|
|
viewModel.updateSecurityInfo();
|
2017-01-18 19:01:13 +00:00
|
|
|
break;
|
2022-04-05 14:56:58 +00:00
|
|
|
case PICK_GIF:
|
2019-03-13 23:05:25 +00:00
|
|
|
case MEDIA_SENDER:
|
2021-09-02 20:04:43 +00:00
|
|
|
MediaSendActivityResult result = MediaSendActivityResult.fromData(data);
|
2021-02-25 17:19:58 +00:00
|
|
|
|
|
|
|
if (!Objects.equals(result.getRecipientId(), recipient.getId())) {
|
|
|
|
Log.w(TAG, "Result's recipientId did not match ours! Result: " + result.getRecipientId() + ", Activity: " + recipient.getId());
|
2022-01-14 13:06:28 +00:00
|
|
|
Toast.makeText(requireContext(), R.string.ConversationActivity_error_sending_media, Toast.LENGTH_SHORT).show();
|
2021-02-25 17:19:58 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-06-03 22:07:29 +00:00
|
|
|
sendButton.setSendType(result.getMessageSendType());
|
2018-11-20 17:59:23 +00:00
|
|
|
|
2020-01-08 20:56:51 +00:00
|
|
|
if (result.isPushPreUpload()) {
|
|
|
|
sendMediaMessage(result);
|
|
|
|
return;
|
|
|
|
}
|
2018-11-20 17:59:23 +00:00
|
|
|
|
2021-07-29 20:24:20 +00:00
|
|
|
long expiresIn = TimeUnit.SECONDS.toMillis(recipient.get().getExpiresInSeconds());
|
2020-01-08 20:56:51 +00:00
|
|
|
boolean initiating = threadId == -1;
|
2022-03-14 19:49:46 +00:00
|
|
|
QuoteModel quote = result.isViewOnce() ? null : inputPanel.getQuote().orElse(null);
|
2020-01-08 20:56:51 +00:00
|
|
|
SlideDeck slideDeck = new SlideDeck();
|
2020-08-05 20:45:52 +00:00
|
|
|
List<Mention> mentions = new ArrayList<>(result.getMentions());
|
2018-11-20 17:59:23 +00:00
|
|
|
|
2020-01-08 20:56:51 +00:00
|
|
|
for (Media mediaItem : result.getNonUploadedMedia()) {
|
2018-11-20 17:59:23 +00:00
|
|
|
if (MediaUtil.isVideoType(mediaItem.getMimeType())) {
|
2022-03-14 19:49:46 +00:00
|
|
|
slideDeck.addSlide(new VideoSlide(requireContext(), mediaItem.getUri(), mediaItem.getSize(), mediaItem.isVideoGif(), mediaItem.getWidth(), mediaItem.getHeight(), mediaItem.getCaption().orElse(null), mediaItem.getTransformProperties().orElse(null)));
|
2018-11-20 17:59:23 +00:00
|
|
|
} else if (MediaUtil.isGif(mediaItem.getMimeType())) {
|
2022-03-14 19:49:46 +00:00
|
|
|
slideDeck.addSlide(new GifSlide(requireContext(), mediaItem.getUri(), mediaItem.getSize(), mediaItem.getWidth(), mediaItem.getHeight(), mediaItem.isBorderless(), mediaItem.getCaption().orElse(null)));
|
2018-11-20 17:59:23 +00:00
|
|
|
} else if (MediaUtil.isImageType(mediaItem.getMimeType())) {
|
2022-03-14 19:49:46 +00:00
|
|
|
slideDeck.addSlide(new ImageSlide(requireContext(), mediaItem.getUri(), mediaItem.getMimeType(), mediaItem.getSize(), mediaItem.getWidth(), mediaItem.getHeight(), mediaItem.isBorderless(), mediaItem.getCaption().orElse(null), null, mediaItem.getTransformProperties().orElse(null)));
|
2018-11-20 17:59:23 +00:00
|
|
|
} else {
|
|
|
|
Log.w(TAG, "Asked to send an unexpected mimeType: '" + mediaItem.getMimeType() + "'. Skipping.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-14 13:06:28 +00:00
|
|
|
final Context context = requireContext().getApplicationContext();
|
2019-02-25 21:58:10 +00:00
|
|
|
|
2021-02-25 17:19:58 +00:00
|
|
|
sendMediaMessage(result.getRecipientId(),
|
2022-06-21 21:27:57 +00:00
|
|
|
result.getMessageSendType(),
|
2020-01-08 20:56:51 +00:00
|
|
|
result.getBody(),
|
2019-04-17 14:21:30 +00:00
|
|
|
slideDeck,
|
2019-06-11 06:18:45 +00:00
|
|
|
quote,
|
2019-04-17 14:21:30 +00:00
|
|
|
Collections.emptyList(),
|
|
|
|
Collections.emptyList(),
|
2020-08-05 20:45:52 +00:00
|
|
|
mentions,
|
2019-04-17 14:21:30 +00:00
|
|
|
expiresIn,
|
2020-01-08 20:56:51 +00:00
|
|
|
result.isViewOnce(),
|
2019-04-17 14:21:30 +00:00
|
|
|
initiating,
|
2021-08-23 14:05:48 +00:00
|
|
|
true,
|
|
|
|
null).addListener(new AssertedSuccessListener<Void>() {
|
2019-02-25 21:58:10 +00:00
|
|
|
@Override
|
|
|
|
public void onSuccess(Void result) {
|
|
|
|
AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
|
|
|
|
Stream.of(slideDeck.getSlides())
|
|
|
|
.map(Slide::getUri)
|
|
|
|
.withoutNulls()
|
2019-03-13 23:05:25 +00:00
|
|
|
.filter(BlobProvider::isAuthority)
|
2019-02-26 01:47:30 +00:00
|
|
|
.forEach(uri -> BlobProvider.getInstance().delete(context, uri));
|
2019-02-25 21:58:10 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
2018-11-20 17:59:23 +00:00
|
|
|
|
|
|
|
break;
|
2012-07-19 21:22:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-21 19:06:47 +00:00
|
|
|
@Override
|
2022-01-14 13:06:28 +00:00
|
|
|
public void onSaveInstanceState(@NonNull Bundle outState) {
|
2020-08-21 19:06:47 +00:00
|
|
|
super.onSaveInstanceState(outState);
|
|
|
|
|
|
|
|
outState.putInt(STATE_REACT_WITH_ANY_PAGE, reactWithAnyEmojiStartPage);
|
2021-06-25 12:28:55 +00:00
|
|
|
outState.putBoolean(STATE_IS_SEARCH_REQUESTED, isSearchRequested);
|
2020-08-21 19:06:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2022-01-14 13:06:28 +00:00
|
|
|
public void onViewStateRestored(Bundle savedInstanceState) {
|
|
|
|
super.onViewStateRestored(savedInstanceState);
|
2020-08-21 19:06:47 +00:00
|
|
|
|
2022-01-14 13:06:28 +00:00
|
|
|
if (savedInstanceState != null) {
|
|
|
|
reactWithAnyEmojiStartPage = savedInstanceState.getInt(STATE_REACT_WITH_ANY_PAGE, -1);
|
|
|
|
isSearchRequested = savedInstanceState.getBoolean(STATE_IS_SEARCH_REQUESTED, false);
|
|
|
|
}
|
2020-08-21 19:06:47 +00:00
|
|
|
}
|
|
|
|
|
2022-07-19 17:53:54 +00:00
|
|
|
private void onInitialSecurityConfigurationLoaded() {
|
|
|
|
Log.d(TAG, "Initial security configuration loaded.");
|
2022-07-22 15:50:40 +00:00
|
|
|
if (getContext() == null) {
|
|
|
|
Log.w(TAG, "Fragment has become detached from context. Ignoring configuration call.");
|
|
|
|
return;
|
2022-07-19 17:53:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
initializeProfiles();
|
|
|
|
initializeGv1Migration();
|
|
|
|
|
|
|
|
Log.d(TAG, "Initializing draft from initial security configuration load...");
|
|
|
|
initializeDraft(viewModel.getArgs()).addListener(new AssertedSuccessListener<Boolean>() {
|
|
|
|
@Override
|
|
|
|
public void onSuccess(Boolean loadedDraft) {
|
2022-07-22 15:50:40 +00:00
|
|
|
Log.d(TAG, "Initial security configuration loaded.");
|
|
|
|
if (getContext() == null) {
|
|
|
|
Log.w(TAG, "Fragment has become detached from context. Ignoring draft load.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-07-19 17:53:54 +00:00
|
|
|
if (loadedDraft != null && loadedDraft) {
|
|
|
|
Log.i(TAG, "Finished loading draft");
|
|
|
|
ThreadUtil.runOnMain(() -> {
|
|
|
|
if (fragment != null && fragment.isResumed()) {
|
|
|
|
fragment.moveToLastSeen();
|
|
|
|
} else {
|
|
|
|
Log.w(TAG, "Wanted to move to the last seen position, but the fragment was in an invalid state");
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2022-08-10 20:45:43 +00:00
|
|
|
composeText.addTextChangedListener(typingTextWatcher);
|
2022-07-19 17:53:54 +00:00
|
|
|
composeText.setSelection(composeText.length(), composeText.length());
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2020-11-25 18:11:17 +00:00
|
|
|
private void setVisibleThread(long threadId) {
|
|
|
|
if (!isInBubble()) {
|
2022-01-14 13:06:28 +00:00
|
|
|
// TODO [alex] LargeScreenSupport -- Inform MainActivityViewModel that the conversation was opened.
|
2022-05-12 18:37:28 +00:00
|
|
|
ApplicationDependencies.getMessageNotifier().setVisibleThread(ConversationId.forConversation(threadId));
|
2020-11-25 18:11:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-17 13:58:28 +00:00
|
|
|
private void reportShortcutLaunch(@NonNull RecipientId recipientId) {
|
2022-01-14 13:06:28 +00:00
|
|
|
ShortcutManagerCompat.reportShortcutUsed(requireContext(), ConversationUtil.getShortcutId(recipientId));
|
2020-11-17 13:58:28 +00:00
|
|
|
}
|
|
|
|
|
2019-10-15 16:51:16 +00:00
|
|
|
private void handleImageFromDeviceCameraApp() {
|
|
|
|
if (attachmentManager.getCaptureUri() == null) {
|
|
|
|
Log.w(TAG, "No image available.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
Uri mediaUri = BlobProvider.getInstance()
|
2022-01-14 13:06:28 +00:00
|
|
|
.forData(requireContext().getContentResolver().openInputStream(attachmentManager.getCaptureUri()), 0L)
|
2019-10-15 16:51:16 +00:00
|
|
|
.withMimeType(MediaUtil.IMAGE_JPEG)
|
2022-01-14 13:06:28 +00:00
|
|
|
.createForSingleSessionOnDisk(requireContext());
|
2019-10-15 16:51:16 +00:00
|
|
|
|
2022-01-14 13:06:28 +00:00
|
|
|
requireContext().getContentResolver().delete(attachmentManager.getCaptureUri(), null, null);
|
2019-10-15 16:51:16 +00:00
|
|
|
|
2022-01-14 13:06:28 +00:00
|
|
|
setMedia(mediaUri, MediaType.IMAGE);
|
2019-10-15 16:51:16 +00:00
|
|
|
} catch (IOException ioe) {
|
|
|
|
Log.w(TAG, "Could not handle public image", ioe);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-29 22:52:54 +00:00
|
|
|
@Override
|
|
|
|
public void startActivity(Intent intent) {
|
|
|
|
if (intent.getStringExtra(Browser.EXTRA_APPLICATION_ID) != null) {
|
|
|
|
intent.removeExtra(Browser.EXTRA_APPLICATION_ID);
|
|
|
|
}
|
2016-08-14 10:23:51 +00:00
|
|
|
|
|
|
|
try {
|
|
|
|
super.startActivity(intent);
|
|
|
|
} catch (ActivityNotFoundException e) {
|
|
|
|
Log.w(TAG, e);
|
2022-01-14 13:06:28 +00:00
|
|
|
Toast.makeText(requireContext(), R.string.ConversationActivity_there_is_no_app_available_to_handle_this_link_on_your_device, Toast.LENGTH_LONG).show();
|
2016-08-14 10:23:51 +00:00
|
|
|
}
|
2016-03-29 22:52:54 +00:00
|
|
|
}
|
|
|
|
|
2012-07-19 21:22:03 +00:00
|
|
|
@Override
|
2022-01-14 13:06:28 +00:00
|
|
|
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
2012-07-19 21:22:03 +00:00
|
|
|
menu.clear();
|
|
|
|
|
2020-06-06 23:26:21 +00:00
|
|
|
GroupActiveState groupActiveState = groupViewModel.getGroupActiveState().getValue();
|
|
|
|
boolean isActiveGroup = groupActiveState != null && groupActiveState.isActiveGroup();
|
|
|
|
boolean isActiveV2Group = groupActiveState != null && groupActiveState.isActiveV2Group();
|
2020-06-08 15:31:55 +00:00
|
|
|
boolean isInActiveGroup = groupActiveState != null && !groupActiveState.isActiveGroup();
|
2020-06-06 23:26:21 +00:00
|
|
|
|
2022-02-07 15:16:31 +00:00
|
|
|
if (isInMessageRequest() && recipient != null && !recipient.get().isBlocked()) {
|
2020-06-06 23:26:21 +00:00
|
|
|
if (isActiveGroup) {
|
2020-02-19 22:08:34 +00:00
|
|
|
inflater.inflate(R.menu.conversation_message_requests_group, menu);
|
|
|
|
}
|
|
|
|
|
2022-01-14 13:06:28 +00:00
|
|
|
super.onCreateOptionsMenu(menu, inflater);
|
2020-02-19 22:08:34 +00:00
|
|
|
}
|
|
|
|
|
2022-07-22 13:47:40 +00:00
|
|
|
if (viewModel.isPushAvailable()) {
|
2021-07-29 20:24:20 +00:00
|
|
|
if (recipient.get().getExpiresInSeconds() > 0) {
|
2020-06-08 15:31:55 +00:00
|
|
|
if (!isInActiveGroup) {
|
|
|
|
inflater.inflate(R.menu.conversation_expiring_on, menu);
|
|
|
|
}
|
2019-12-03 20:26:05 +00:00
|
|
|
titleView.showExpiring(recipient);
|
2016-09-26 03:04:13 +00:00
|
|
|
} else {
|
2020-06-08 15:31:55 +00:00
|
|
|
if (!isInActiveGroup) {
|
|
|
|
inflater.inflate(R.menu.conversation_expiring_off, menu);
|
|
|
|
}
|
2019-12-03 20:26:05 +00:00
|
|
|
titleView.clearExpiring();
|
2016-09-26 03:04:13 +00:00
|
|
|
}
|
|
|
|
}
|
2016-08-16 03:23:56 +00:00
|
|
|
|
2012-08-08 02:03:28 +00:00
|
|
|
if (isSingleConversation()) {
|
2022-10-13 15:33:13 +00:00
|
|
|
if (viewModel.isPushAvailable()) {
|
|
|
|
inflater.inflate(R.menu.conversation_callable_secure, menu);
|
2022-10-20 19:50:38 +00:00
|
|
|
} else if (!recipient.get().isReleaseNotes() && SignalStore.misc().getSmsExportPhase().allowSmsFeatures()) {
|
2022-10-13 15:33:13 +00:00
|
|
|
inflater.inflate(R.menu.conversation_callable_insecure, menu);
|
|
|
|
}
|
2012-10-21 21:34:09 +00:00
|
|
|
} else if (isGroupConversation()) {
|
2021-03-23 15:20:07 +00:00
|
|
|
if (isActiveV2Group && Build.VERSION.SDK_INT > 19) {
|
2020-11-11 20:11:03 +00:00
|
|
|
inflater.inflate(R.menu.conversation_callable_groupv2, menu);
|
2020-12-02 18:20:38 +00:00
|
|
|
if (groupCallViewModel != null && Boolean.TRUE.equals(groupCallViewModel.hasActiveGroupCall().getValue())) {
|
|
|
|
hideMenuItem(menu, R.id.menu_video_secure);
|
|
|
|
}
|
2020-12-14 22:26:07 +00:00
|
|
|
showGroupCallingTooltip();
|
2020-11-11 20:11:03 +00:00
|
|
|
}
|
|
|
|
|
2012-10-21 21:34:09 +00:00
|
|
|
inflater.inflate(R.menu.conversation_group_options, menu);
|
2013-04-26 01:59:49 +00:00
|
|
|
|
2014-02-18 04:25:40 +00:00
|
|
|
if (!isPushGroupConversation()) {
|
|
|
|
inflater.inflate(R.menu.conversation_mms_group_options, menu);
|
2022-11-29 15:47:12 +00:00
|
|
|
if (distributionType == ThreadTable.DistributionTypes.BROADCAST) {
|
2014-02-18 04:25:40 +00:00
|
|
|
menu.findItem(R.id.menu_distribution_broadcast).setChecked(true);
|
|
|
|
} else {
|
|
|
|
menu.findItem(R.id.menu_distribution_conversation).setChecked(true);
|
|
|
|
}
|
2013-04-26 01:59:49 +00:00
|
|
|
}
|
2020-10-05 16:59:00 +00:00
|
|
|
|
|
|
|
inflater.inflate(R.menu.conversation_active_group_options, menu);
|
2012-08-08 02:03:28 +00:00
|
|
|
}
|
|
|
|
|
2012-07-19 21:22:03 +00:00
|
|
|
inflater.inflate(R.menu.conversation, menu);
|
2014-06-03 23:24:44 +00:00
|
|
|
|
2022-03-29 20:33:01 +00:00
|
|
|
if (isInMessageRequest() && !recipient.get().isBlocked()) {
|
|
|
|
hideMenuItem(menu, R.id.menu_conversation_settings);
|
|
|
|
}
|
|
|
|
|
2022-07-22 13:47:40 +00:00
|
|
|
if (isSingleConversation() && !viewModel.isPushAvailable() && !recipient.get().isReleaseNotes()) {
|
2015-09-29 21:26:37 +00:00
|
|
|
inflater.inflate(R.menu.conversation_insecure, menu);
|
|
|
|
}
|
|
|
|
|
2020-06-07 23:28:19 +00:00
|
|
|
if (recipient != null && recipient.get().isMuted()) inflater.inflate(R.menu.conversation_muted, menu);
|
|
|
|
else inflater.inflate(R.menu.conversation_unmuted, menu);
|
2015-06-09 14:37:20 +00:00
|
|
|
|
2022-07-02 19:11:23 +00:00
|
|
|
if (isSingleConversation() && getRecipient().getContactUri() == null && !recipient.get().isReleaseNotes() && !recipient.get().isSelf()) {
|
2014-06-03 23:24:44 +00:00
|
|
|
inflater.inflate(R.menu.conversation_add_to_contacts, menu);
|
|
|
|
}
|
|
|
|
|
2020-10-19 20:27:49 +00:00
|
|
|
if (recipient != null && recipient.get().isSelf()) {
|
2022-07-22 13:47:40 +00:00
|
|
|
if (viewModel.isPushAvailable()) {
|
2020-04-27 15:42:34 +00:00
|
|
|
hideMenuItem(menu, R.id.menu_call_secure);
|
|
|
|
hideMenuItem(menu, R.id.menu_video_secure);
|
2019-12-03 20:26:05 +00:00
|
|
|
} else {
|
2020-04-27 15:42:34 +00:00
|
|
|
hideMenuItem(menu, R.id.menu_call_insecure);
|
2019-12-03 20:26:05 +00:00
|
|
|
}
|
2019-01-14 07:30:54 +00:00
|
|
|
|
2020-04-27 15:42:34 +00:00
|
|
|
hideMenuItem(menu, R.id.menu_mute_notifications);
|
2019-01-14 07:30:54 +00:00
|
|
|
}
|
|
|
|
|
2020-04-22 15:12:08 +00:00
|
|
|
if (recipient != null && recipient.get().isBlocked()) {
|
2022-07-22 13:47:40 +00:00
|
|
|
if (viewModel.isPushAvailable()) {
|
2020-04-27 15:42:34 +00:00
|
|
|
hideMenuItem(menu, R.id.menu_call_secure);
|
|
|
|
hideMenuItem(menu, R.id.menu_video_secure);
|
|
|
|
hideMenuItem(menu, R.id.menu_expiring_messages);
|
|
|
|
hideMenuItem(menu, R.id.menu_expiring_messages_off);
|
2020-04-22 15:12:08 +00:00
|
|
|
} else {
|
2020-04-27 15:42:34 +00:00
|
|
|
hideMenuItem(menu, R.id.menu_call_insecure);
|
2020-04-22 15:12:08 +00:00
|
|
|
}
|
2020-04-23 15:06:52 +00:00
|
|
|
|
2020-04-27 15:42:34 +00:00
|
|
|
hideMenuItem(menu, R.id.menu_mute_notifications);
|
2020-04-22 15:12:08 +00:00
|
|
|
}
|
|
|
|
|
2022-01-31 17:46:44 +00:00
|
|
|
if (recipient != null && recipient.get().isReleaseNotes()) {
|
|
|
|
hideMenuItem(menu, R.id.menu_add_shortcut);
|
|
|
|
}
|
|
|
|
|
2020-06-17 15:46:59 +00:00
|
|
|
hideMenuItem(menu, R.id.menu_group_recipients);
|
2020-06-07 12:31:18 +00:00
|
|
|
|
2020-06-06 23:26:21 +00:00
|
|
|
if (isActiveV2Group) {
|
2020-05-26 17:19:05 +00:00
|
|
|
hideMenuItem(menu, R.id.menu_mute_notifications);
|
|
|
|
hideMenuItem(menu, R.id.menu_conversation_settings);
|
2020-10-05 16:59:00 +00:00
|
|
|
} else if (isGroupConversation()) {
|
2020-06-06 01:30:46 +00:00
|
|
|
hideMenuItem(menu, R.id.menu_conversation_settings);
|
2020-05-26 17:19:05 +00:00
|
|
|
}
|
|
|
|
|
2020-11-25 18:11:17 +00:00
|
|
|
hideMenuItem(menu, R.id.menu_create_bubble);
|
2022-03-16 14:10:01 +00:00
|
|
|
disposables.add(viewModel.canShowAsBubble().subscribe(canShowAsBubble -> {
|
2020-11-25 18:11:17 +00:00
|
|
|
MenuItem item = menu.findItem(R.id.menu_create_bubble);
|
|
|
|
|
|
|
|
if (item != null) {
|
|
|
|
item.setVisible(canShowAsBubble && !isInBubble());
|
|
|
|
}
|
2022-03-16 14:10:01 +00:00
|
|
|
}));
|
2020-11-25 18:11:17 +00:00
|
|
|
|
2021-07-16 16:20:30 +00:00
|
|
|
if (threadId == -1L) {
|
|
|
|
hideMenuItem(menu, R.id.menu_view_media);
|
|
|
|
}
|
|
|
|
|
2019-02-01 17:06:59 +00:00
|
|
|
searchViewItem = menu.findItem(R.id.menu_search);
|
|
|
|
|
|
|
|
SearchView searchView = (SearchView) searchViewItem.getActionView();
|
|
|
|
SearchView.OnQueryTextListener queryListener = new SearchView.OnQueryTextListener() {
|
|
|
|
@Override
|
|
|
|
public boolean onQueryTextSubmit(String query) {
|
2019-10-21 04:49:06 +00:00
|
|
|
searchViewModel.onQueryUpdated(query, threadId, true);
|
2019-02-01 17:06:59 +00:00
|
|
|
searchNav.showLoading();
|
2022-02-01 14:04:53 +00:00
|
|
|
viewModel.setSearchQuery(query);
|
2019-02-01 17:06:59 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean onQueryTextChange(String query) {
|
2019-10-21 04:49:06 +00:00
|
|
|
searchViewModel.onQueryUpdated(query, threadId, false);
|
2019-02-01 17:06:59 +00:00
|
|
|
searchNav.showLoading();
|
2022-02-01 14:04:53 +00:00
|
|
|
viewModel.setSearchQuery(query);
|
2019-02-01 17:06:59 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
searchViewItem.setOnActionExpandListener(new MenuItem.OnActionExpandListener() {
|
|
|
|
@Override
|
|
|
|
public boolean onMenuItemActionExpand(MenuItem item) {
|
|
|
|
searchView.setOnQueryTextListener(queryListener);
|
2022-03-11 11:44:07 +00:00
|
|
|
isSearchRequested = true;
|
2019-02-01 17:06:59 +00:00
|
|
|
searchViewModel.onSearchOpened();
|
|
|
|
searchNav.setVisibility(View.VISIBLE);
|
|
|
|
searchNav.setData(0, 0);
|
2021-07-23 20:22:08 +00:00
|
|
|
inputPanel.setHideForSearch(true);
|
2019-02-01 17:06:59 +00:00
|
|
|
|
|
|
|
for (int i = 0; i < menu.size(); i++) {
|
|
|
|
if (!menu.getItem(i).equals(searchViewItem)) {
|
|
|
|
menu.getItem(i).setVisible(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean onMenuItemActionCollapse(MenuItem item) {
|
|
|
|
searchView.setOnQueryTextListener(null);
|
2021-06-25 12:28:55 +00:00
|
|
|
isSearchRequested = false;
|
2019-02-01 17:06:59 +00:00
|
|
|
searchViewModel.onSearchClosed();
|
|
|
|
searchNav.setVisibility(View.GONE);
|
2021-07-23 20:22:08 +00:00
|
|
|
inputPanel.setHideForSearch(false);
|
2022-02-01 14:04:53 +00:00
|
|
|
viewModel.setSearchQuery(null);
|
2022-07-22 13:47:40 +00:00
|
|
|
setBlockedUserState(recipient.get(), viewModel.getConversationStateSnapshot().getSecurityInfo());
|
2019-02-01 17:06:59 +00:00
|
|
|
invalidateOptionsMenu();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2020-12-19 20:57:14 +00:00
|
|
|
searchView.setMaxWidth(Integer.MAX_VALUE);
|
|
|
|
|
2021-06-25 12:28:55 +00:00
|
|
|
if (isSearchRequested) {
|
|
|
|
if (searchViewItem.expandActionView()) {
|
|
|
|
searchViewModel.onSearchOpened();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-14 13:06:28 +00:00
|
|
|
super.onCreateOptionsMenu(menu, inflater);
|
2022-05-26 20:32:52 +00:00
|
|
|
|
|
|
|
int toolbarTextAndIconColor = getResources().getColor(wallpaper.getDrawable() != null ? R.color.signal_colorNeutralInverse : R.color.signal_colorOnSurface);
|
|
|
|
setToolbarActionItemTint(toolbar, toolbarTextAndIconColor);
|
2012-07-19 21:22:03 +00:00
|
|
|
}
|
|
|
|
|
2021-06-25 12:28:55 +00:00
|
|
|
public void invalidateOptionsMenu() {
|
2022-02-07 14:12:03 +00:00
|
|
|
if (!isSearchRequested && getActivity() != null) {
|
2022-03-17 13:00:10 +00:00
|
|
|
optionsMenuDebouncer.publish(() -> {
|
|
|
|
if (getActivity() != null) {
|
|
|
|
onCreateOptionsMenu(toolbar.getMenu(), requireActivity().getMenuInflater());
|
|
|
|
}
|
|
|
|
});
|
2021-06-25 12:28:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-19 21:22:03 +00:00
|
|
|
@Override
|
2022-05-25 14:28:40 +00:00
|
|
|
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
|
2012-07-19 21:22:03 +00:00
|
|
|
super.onOptionsItemSelected(item);
|
2022-05-25 14:28:40 +00:00
|
|
|
int itemId = item.getItemId();
|
|
|
|
|
|
|
|
if (itemId == R.id.menu_call_secure) {
|
|
|
|
handleDial(getRecipient(), true);
|
|
|
|
} else if (itemId == R.id.menu_video_secure) {
|
|
|
|
handleVideo(getRecipient());
|
|
|
|
} else if (itemId == R.id.menu_call_insecure) {
|
|
|
|
handleDial(getRecipient(), false);
|
|
|
|
} else if (itemId == R.id.menu_view_media) {
|
|
|
|
handleViewMedia();
|
|
|
|
} else if (itemId == R.id.menu_add_shortcut) {
|
|
|
|
handleAddShortcut();
|
|
|
|
} else if (itemId == R.id.menu_search) {
|
|
|
|
handleSearch();
|
|
|
|
} else if (itemId == R.id.menu_add_to_contacts) {
|
|
|
|
handleAddToContacts();
|
|
|
|
} else if (itemId == R.id.menu_group_recipients) {
|
|
|
|
handleDisplayGroupRecipients();
|
|
|
|
} else if (itemId == R.id.menu_distribution_broadcast) {
|
|
|
|
handleDistributionBroadcastEnabled(item);
|
|
|
|
} else if (itemId == R.id.menu_distribution_conversation) {
|
|
|
|
handleDistributionConversationEnabled(item);
|
|
|
|
} else if (itemId == R.id.menu_group_settings) {
|
|
|
|
handleManageGroup();
|
|
|
|
} else if (itemId == R.id.menu_leave) {
|
|
|
|
handleLeavePushGroup();
|
|
|
|
} else if (itemId == R.id.menu_invite) {
|
|
|
|
handleInviteLink();
|
|
|
|
} else if (itemId == R.id.menu_mute_notifications) {
|
|
|
|
handleMuteNotifications();
|
|
|
|
} else if (itemId == R.id.menu_unmute_notifications) {
|
|
|
|
handleUnmuteNotifications();
|
|
|
|
} else if (itemId == R.id.menu_conversation_settings) {
|
|
|
|
handleConversationSettings();
|
|
|
|
} else if (itemId == R.id.menu_expiring_messages_off || itemId == R.id.menu_expiring_messages) {
|
|
|
|
handleSelectMessageExpiration();
|
|
|
|
} else if (itemId == R.id.menu_create_bubble) {
|
|
|
|
handleCreateBubble();
|
|
|
|
} else if (itemId == android.R.id.home) {
|
|
|
|
requireActivity().finish();
|
|
|
|
} else {
|
|
|
|
return false;
|
2012-07-19 21:22:03 +00:00
|
|
|
}
|
|
|
|
|
2022-05-25 14:28:40 +00:00
|
|
|
return true;
|
2012-07-19 21:22:03 +00:00
|
|
|
}
|
|
|
|
|
2013-06-28 03:57:27 +00:00
|
|
|
public void onBackPressed() {
|
2018-08-02 13:25:33 +00:00
|
|
|
Log.d(TAG, "onBackPressed()");
|
2021-01-27 20:34:59 +00:00
|
|
|
if (reactionDelegate.isShowing()) {
|
|
|
|
reactionDelegate.hide();
|
2020-10-23 16:43:29 +00:00
|
|
|
} else if (container.isInputOpen()) {
|
|
|
|
container.hideCurrentInput(composeText);
|
2022-06-17 17:22:14 +00:00
|
|
|
navigationBarBackground.setVisibility(View.GONE);
|
2022-03-11 11:44:07 +00:00
|
|
|
} else if (isSearchRequested) {
|
2022-03-25 18:38:14 +00:00
|
|
|
if (searchViewItem != null) {
|
|
|
|
searchViewItem.collapseActionView();
|
|
|
|
}
|
2022-10-29 20:58:01 +00:00
|
|
|
} else if (isInBubble()) {
|
|
|
|
backPressedCallback.setEnabled(false);
|
|
|
|
requireActivity().onBackPressed();
|
2020-10-23 16:43:29 +00:00
|
|
|
} else {
|
2022-01-28 17:24:44 +00:00
|
|
|
requireActivity().finish();
|
2020-10-23 16:43:29 +00:00
|
|
|
}
|
2013-06-28 03:57:27 +00:00
|
|
|
}
|
|
|
|
|
2015-07-02 23:47:03 +00:00
|
|
|
@Override
|
|
|
|
public void onKeyboardShown() {
|
2015-11-22 18:44:53 +00:00
|
|
|
inputPanel.onKeyboardShown();
|
2022-12-15 18:32:22 +00:00
|
|
|
if (emojiDrawerStub.resolved() && emojiDrawerStub.get().isShowing()) {
|
|
|
|
if (emojiDrawerStub.get().isEmojiSearchMode()) {
|
|
|
|
inputPanel.setToIme();
|
|
|
|
} else {
|
|
|
|
emojiDrawerStub.get().hide(true);
|
|
|
|
}
|
2022-05-13 15:47:57 +00:00
|
|
|
}
|
2022-05-19 12:53:12 +00:00
|
|
|
if (attachmentKeyboardStub.resolved() && attachmentKeyboardStub.get().isShowing()) {
|
2022-06-17 17:22:14 +00:00
|
|
|
navigationBarBackground.setVisibility(View.GONE);
|
2022-05-19 12:53:12 +00:00
|
|
|
attachmentKeyboardStub.get().hide(true);
|
|
|
|
}
|
2015-07-02 23:47:03 +00:00
|
|
|
}
|
|
|
|
|
2017-11-16 00:29:00 +00:00
|
|
|
@Subscribe(threadMode = ThreadMode.MAIN)
|
|
|
|
public void onEvent(ReminderUpdateEvent event) {
|
2019-11-12 14:18:57 +00:00
|
|
|
updateReminders();
|
2017-11-16 00:29:00 +00:00
|
|
|
}
|
|
|
|
|
2021-07-20 16:08:52 +00:00
|
|
|
@SuppressLint("MissingSuperCall")
|
2017-11-25 06:00:30 +00:00
|
|
|
@Override
|
|
|
|
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
|
|
|
Permissions.onRequestPermissionsResult(this, requestCode, permissions, grantResults);
|
|
|
|
}
|
|
|
|
|
2020-01-30 03:13:44 +00:00
|
|
|
@Override
|
|
|
|
public void onAttachmentMediaClicked(@NonNull Media media) {
|
|
|
|
linkPreviewViewModel.onUserCancel();
|
2022-06-03 22:07:29 +00:00
|
|
|
startActivityForResult(MediaSelectionActivity.editor(requireActivity(), sendButton.getSelectedSendType(), Collections.singletonList(media), recipient.getId(), composeText.getTextTrimmed()), MEDIA_SENDER);
|
2020-02-04 05:00:06 +00:00
|
|
|
container.hideCurrentInput(composeText);
|
2020-01-30 03:13:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onAttachmentSelectorClicked(@NonNull AttachmentKeyboardButton button) {
|
|
|
|
switch (button) {
|
|
|
|
case GALLERY:
|
2022-06-03 22:07:29 +00:00
|
|
|
AttachmentManager.selectGallery(this, MEDIA_SENDER, recipient.get(), composeText.getTextTrimmed(), sendButton.getSelectedSendType(), inputPanel.getQuote().isPresent());
|
2020-01-30 03:13:44 +00:00
|
|
|
break;
|
2021-06-04 00:34:53 +00:00
|
|
|
case FILE:
|
2022-01-25 13:58:52 +00:00
|
|
|
AttachmentManager.selectDocument(this, PICK_DOCUMENT);
|
2020-01-30 03:13:44 +00:00
|
|
|
break;
|
|
|
|
case CONTACT:
|
2022-01-25 13:58:52 +00:00
|
|
|
AttachmentManager.selectContactInfo(this, PICK_CONTACT);
|
2020-01-30 03:13:44 +00:00
|
|
|
break;
|
|
|
|
case LOCATION:
|
2022-06-17 16:45:44 +00:00
|
|
|
AttachmentManager.selectLocation(this, PICK_LOCATION, getSendButtonColor(sendButton.getSelectedSendType()));
|
2020-01-30 03:13:44 +00:00
|
|
|
break;
|
2021-04-06 16:03:33 +00:00
|
|
|
case PAYMENT:
|
2022-11-01 15:50:41 +00:00
|
|
|
AttachmentManager.selectPayment(this, recipient.get());
|
2021-04-06 16:03:33 +00:00
|
|
|
break;
|
|
|
|
|
2020-01-30 03:13:44 +00:00
|
|
|
}
|
2020-02-04 05:00:06 +00:00
|
|
|
|
|
|
|
container.hideCurrentInput(composeText);
|
2020-01-30 03:13:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onAttachmentPermissionsRequested() {
|
|
|
|
Permissions.with(this)
|
|
|
|
.request(Manifest.permission.READ_EXTERNAL_STORAGE)
|
|
|
|
.onAllGranted(() -> viewModel.onAttachmentKeyboardOpen())
|
2020-10-19 21:16:29 +00:00
|
|
|
.withPermanentDenialDialog(getString(R.string.AttachmentManager_signal_requires_the_external_storage_permission_in_order_to_attach_photos_videos_or_audio))
|
2020-01-30 03:13:44 +00:00
|
|
|
.execute();
|
|
|
|
}
|
|
|
|
|
|
|
|
//////// Event Handlers
|
2012-07-19 21:22:03 +00:00
|
|
|
|
2016-08-16 03:23:56 +00:00
|
|
|
private void handleSelectMessageExpiration() {
|
2021-05-19 00:23:59 +00:00
|
|
|
if (isPushGroupConversation() && !isActiveGroup()) {
|
2017-01-03 21:36:34 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-01-14 13:06:28 +00:00
|
|
|
startActivity(RecipientDisappearingMessagesActivity.forRecipient(requireContext(), recipient.getId()));
|
2016-08-16 03:23:56 +00:00
|
|
|
}
|
|
|
|
|
2015-06-09 14:37:20 +00:00
|
|
|
private void handleMuteNotifications() {
|
2022-01-14 13:06:28 +00:00
|
|
|
MuteDialog.show(requireActivity(), until -> {
|
2017-12-05 19:52:03 +00:00
|
|
|
new AsyncTask<Void, Void, Void>() {
|
|
|
|
@Override
|
|
|
|
protected Void doInBackground(Void... params) {
|
2021-11-18 17:36:52 +00:00
|
|
|
SignalDatabase.recipients().setMuted(recipient.getId(), until);
|
2015-06-09 14:37:20 +00:00
|
|
|
|
2017-12-05 19:52:03 +00:00
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
2015-06-09 14:37:20 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2022-03-30 17:44:13 +00:00
|
|
|
private void handleStoryRingClick() {
|
2022-05-12 18:37:28 +00:00
|
|
|
startActivity(StoryViewerActivity.createIntent(
|
|
|
|
requireContext(),
|
|
|
|
new StoryViewerArgs.Builder(recipient.getId(), recipient.get().shouldHideStory())
|
2022-08-30 18:12:21 +00:00
|
|
|
.isFromQuote(true)
|
2022-05-12 18:37:28 +00:00
|
|
|
.build()));
|
2022-03-30 17:44:13 +00:00
|
|
|
}
|
|
|
|
|
2015-07-08 19:22:51 +00:00
|
|
|
private void handleConversationSettings() {
|
2020-06-17 15:46:59 +00:00
|
|
|
if (isGroupConversation()) {
|
2020-06-16 17:07:25 +00:00
|
|
|
handleManageGroup();
|
2020-06-02 19:09:48 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-03-29 20:33:01 +00:00
|
|
|
if (isInMessageRequest() && !recipient.get().isBlocked()) return;
|
2020-02-19 22:08:34 +00:00
|
|
|
|
2022-01-14 13:06:28 +00:00
|
|
|
Intent intent = ConversationSettingsActivity.forRecipient(requireContext(), recipient.getId());
|
|
|
|
Bundle bundle = ConversationSettingsActivity.createTransitionBundle(requireActivity(), titleView.findViewById(R.id.contact_photo_image), toolbar);
|
2021-06-24 16:52:54 +00:00
|
|
|
|
2022-01-14 13:06:28 +00:00
|
|
|
ActivityCompat.startActivity(requireActivity(), intent, bundle);
|
2015-07-08 19:22:51 +00:00
|
|
|
}
|
|
|
|
|
2015-06-09 14:37:20 +00:00
|
|
|
private void handleUnmuteNotifications() {
|
|
|
|
new AsyncTask<Void, Void, Void>() {
|
|
|
|
@Override
|
|
|
|
protected Void doInBackground(Void... params) {
|
2021-11-18 17:36:52 +00:00
|
|
|
SignalDatabase.recipients().setMuted(recipient.getId(), 0);
|
2015-06-09 14:37:20 +00:00
|
|
|
return null;
|
|
|
|
}
|
2017-10-23 20:03:32 +00:00
|
|
|
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
2015-06-09 14:37:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private void handleUnblock() {
|
2022-01-14 13:06:28 +00:00
|
|
|
final Context context = requireContext().getApplicationContext();
|
|
|
|
BlockUnblockDialog.showUnblockFor(requireContext(), getLifecycle(), recipient.get(), () -> {
|
2020-04-23 15:06:52 +00:00
|
|
|
SignalExecutors.BOUNDED.execute(() -> {
|
2022-10-06 12:57:30 +00:00
|
|
|
RecipientUtil.unblock(recipient.get());
|
2020-04-23 15:06:52 +00:00
|
|
|
});
|
|
|
|
});
|
2015-06-09 14:37:20 +00:00
|
|
|
}
|
|
|
|
|
2016-11-20 23:56:47 +00:00
|
|
|
@TargetApi(Build.VERSION_CODES.KITKAT)
|
|
|
|
private void handleMakeDefaultSms() {
|
2022-01-14 13:06:28 +00:00
|
|
|
startActivityForResult(SmsUtil.getSmsRoleIntent(requireContext()), SMS_DEFAULT);
|
2016-11-20 23:56:47 +00:00
|
|
|
}
|
|
|
|
|
2017-12-25 23:57:33 +00:00
|
|
|
private void handleRegisterForSignal() {
|
2022-01-14 13:06:28 +00:00
|
|
|
startActivity(RegistrationNavigationActivity.newIntentForReRegistration(requireContext()));
|
2017-12-25 23:57:33 +00:00
|
|
|
}
|
|
|
|
|
2014-12-13 02:31:20 +00:00
|
|
|
private void handleInviteLink() {
|
2019-05-23 11:02:15 +00:00
|
|
|
String inviteText = getString(R.string.ConversationActivity_lets_switch_to_signal, getString(R.string.install_url));
|
2019-03-15 22:31:52 +00:00
|
|
|
|
2022-10-13 15:33:13 +00:00
|
|
|
if (viewModel.isDefaultSmsApplication() && SignalStore.misc().getSmsExportPhase().isSmsSupported()) {
|
2019-03-15 22:31:52 +00:00
|
|
|
composeText.appendInvite(inviteText);
|
2022-10-13 15:33:13 +00:00
|
|
|
} else if (recipient.get().hasSmsAddress()) {
|
2019-03-15 22:31:52 +00:00
|
|
|
Intent intent = new Intent(Intent.ACTION_SENDTO);
|
2019-09-07 03:40:06 +00:00
|
|
|
intent.setData(Uri.parse("smsto:" + recipient.get().requireSmsAddress()));
|
2019-03-15 22:31:52 +00:00
|
|
|
intent.putExtra("sms_body", inviteText);
|
|
|
|
intent.putExtra(Intent.EXTRA_TEXT, inviteText);
|
|
|
|
startActivity(intent);
|
2022-10-13 15:33:13 +00:00
|
|
|
} else {
|
|
|
|
Intent sendIntent = new Intent();
|
|
|
|
sendIntent.setAction(Intent.ACTION_SEND);
|
|
|
|
sendIntent.putExtra(Intent.EXTRA_TEXT, inviteText);
|
|
|
|
sendIntent.setType("text/plain");
|
|
|
|
if (sendIntent.resolveActivity(requireContext().getPackageManager()) != null) {
|
|
|
|
startActivity(Intent.createChooser(sendIntent, getString(R.string.InviteActivity_invite_to_signal)));
|
|
|
|
} else {
|
|
|
|
Toast.makeText(requireContext(), R.string.InviteActivity_no_app_to_share_to, Toast.LENGTH_LONG).show();
|
|
|
|
}
|
2014-12-13 02:31:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-19 02:11:30 +00:00
|
|
|
private void handleViewMedia() {
|
2022-01-14 13:06:28 +00:00
|
|
|
startActivity(MediaOverviewActivity.forThread(requireContext(), threadId));
|
2015-01-19 02:11:30 +00:00
|
|
|
}
|
|
|
|
|
2018-04-08 10:55:30 +00:00
|
|
|
private void handleAddShortcut() {
|
2019-09-07 03:40:06 +00:00
|
|
|
Log.i(TAG, "Creating home screen shortcut for recipient " + recipient.get().getId());
|
2018-04-08 10:55:30 +00:00
|
|
|
|
2022-01-14 13:06:28 +00:00
|
|
|
final Context context = requireContext().getApplicationContext();
|
2020-03-25 15:30:15 +00:00
|
|
|
final Recipient recipient = this.recipient.get();
|
|
|
|
|
2022-01-29 16:04:56 +00:00
|
|
|
if (pinnedShortcutReceiver == null) {
|
|
|
|
pinnedShortcutReceiver = new BroadcastReceiver() {
|
|
|
|
@Override public void onReceive(Context context, Intent intent) {
|
|
|
|
Toast.makeText(context, context.getString(R.string.ConversationActivity_added_to_home_screen), Toast.LENGTH_LONG).show();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
requireActivity().registerReceiver(pinnedShortcutReceiver, new IntentFilter(ACTION_PINNED_SHORTCUT));
|
|
|
|
}
|
|
|
|
|
2020-03-25 15:30:15 +00:00
|
|
|
GlideApp.with(this)
|
|
|
|
.asBitmap()
|
|
|
|
.load(recipient.getContactPhoto())
|
2022-01-14 13:06:28 +00:00
|
|
|
.error(recipient.getFallbackContactPhoto().asDrawable(context, recipient.getAvatarColor(), false))
|
2020-03-25 15:30:15 +00:00
|
|
|
.into(new CustomTarget<Bitmap>() {
|
|
|
|
@Override
|
|
|
|
public void onLoadFailed(@Nullable Drawable errorDrawable) {
|
|
|
|
if (errorDrawable == null) {
|
|
|
|
throw new AssertionError();
|
|
|
|
}
|
2018-04-08 10:55:30 +00:00
|
|
|
|
2020-03-25 15:30:15 +00:00
|
|
|
Log.w(TAG, "Utilizing fallback photo for shortcut for recipient " + recipient.getId());
|
2018-04-08 10:55:30 +00:00
|
|
|
|
2020-03-25 15:30:15 +00:00
|
|
|
SimpleTask.run(() -> DrawableUtil.toBitmap(errorDrawable, SHORTCUT_ICON_SIZE, SHORTCUT_ICON_SIZE),
|
|
|
|
bitmap -> addIconToHomeScreen(context, bitmap, recipient));
|
|
|
|
}
|
2018-04-08 10:55:30 +00:00
|
|
|
|
2020-03-25 15:30:15 +00:00
|
|
|
@Override
|
|
|
|
public void onResourceReady(@NonNull Bitmap resource, @Nullable Transition<? super Bitmap> transition) {
|
|
|
|
SimpleTask.run(() -> BitmapUtil.createScaledBitmap(resource, SHORTCUT_ICON_SIZE, SHORTCUT_ICON_SIZE),
|
|
|
|
bitmap -> addIconToHomeScreen(context, bitmap, recipient));
|
|
|
|
}
|
2018-04-08 10:55:30 +00:00
|
|
|
|
2020-03-25 15:30:15 +00:00
|
|
|
@Override
|
|
|
|
public void onLoadCleared(@Nullable Drawable placeholder) {
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2020-11-25 18:11:17 +00:00
|
|
|
private void handleCreateBubble() {
|
|
|
|
ConversationIntents.Args args = viewModel.getArgs();
|
|
|
|
|
2022-01-14 13:06:28 +00:00
|
|
|
BubbleUtil.displayAsBubble(requireContext(), args.getRecipientId(), args.getThreadId());
|
|
|
|
requireActivity().finish();
|
2020-11-25 18:11:17 +00:00
|
|
|
}
|
|
|
|
|
2020-03-25 15:30:15 +00:00
|
|
|
private static void addIconToHomeScreen(@NonNull Context context,
|
|
|
|
@NonNull Bitmap bitmap,
|
|
|
|
@NonNull Recipient recipient)
|
|
|
|
{
|
|
|
|
IconCompat icon = IconCompat.createWithAdaptiveBitmap(bitmap);
|
2020-10-19 20:27:49 +00:00
|
|
|
String name = recipient.isSelf() ? context.getString(R.string.note_to_self)
|
2020-03-25 15:30:15 +00:00
|
|
|
: recipient.getDisplayName(context);
|
|
|
|
|
|
|
|
ShortcutInfoCompat shortcutInfoCompat = new ShortcutInfoCompat.Builder(context, recipient.getId().serialize() + '-' + System.currentTimeMillis())
|
|
|
|
.setShortLabel(name)
|
|
|
|
.setIcon(icon)
|
|
|
|
.setIntent(ShortcutLauncherActivity.createIntent(context, recipient.getId()))
|
|
|
|
.build();
|
|
|
|
|
2022-01-29 16:04:56 +00:00
|
|
|
Intent callbackIntent = new Intent(ACTION_PINNED_SHORTCUT);
|
2022-09-20 14:13:58 +00:00
|
|
|
PendingIntent shortcutPinnedCallback = PendingIntent.getBroadcast(context, REQUEST_CODE_PIN_SHORTCUT, callbackIntent, PendingIntentFlags.mutable());
|
2022-01-29 16:04:56 +00:00
|
|
|
|
|
|
|
ShortcutManagerCompat.requestPinShortcut(context, shortcutInfoCompat, shortcutPinnedCallback.getIntentSender());
|
2020-03-25 15:30:15 +00:00
|
|
|
|
|
|
|
bitmap.recycle();
|
2018-04-08 10:55:30 +00:00
|
|
|
}
|
|
|
|
|
2019-02-01 17:06:59 +00:00
|
|
|
private void handleSearch() {
|
|
|
|
searchViewModel.onSearchOpened();
|
|
|
|
}
|
|
|
|
|
2014-02-22 18:54:43 +00:00
|
|
|
private void handleLeavePushGroup() {
|
2017-08-01 15:56:00 +00:00
|
|
|
if (getRecipient() == null) {
|
2022-01-14 13:06:28 +00:00
|
|
|
Toast.makeText(requireContext(), getString(R.string.ConversationActivity_invalid_recipient),
|
2014-02-22 18:54:43 +00:00
|
|
|
Toast.LENGTH_LONG).show();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-01-14 13:06:28 +00:00
|
|
|
LeaveGroupDialog.handleLeavePushGroup(requireActivity(), getRecipient().requireGroupId().requirePush(), () -> requireActivity().finish());
|
2014-02-22 18:54:43 +00:00
|
|
|
}
|
|
|
|
|
2020-06-16 17:07:25 +00:00
|
|
|
private void handleManageGroup() {
|
2022-01-14 13:06:28 +00:00
|
|
|
Intent intent = ConversationSettingsActivity.forGroup(requireContext(), recipient.get().requireGroupId());
|
|
|
|
Bundle bundle = ConversationSettingsActivity.createTransitionBundle(requireContext(), titleView.findViewById(R.id.contact_photo_image), toolbar);
|
2021-06-24 16:52:54 +00:00
|
|
|
|
2022-01-14 13:06:28 +00:00
|
|
|
ActivityCompat.startActivity(requireContext(), intent, bundle);
|
2020-04-27 19:27:31 +00:00
|
|
|
}
|
|
|
|
|
2013-04-26 01:59:49 +00:00
|
|
|
private void handleDistributionBroadcastEnabled(MenuItem item) {
|
2022-11-29 15:47:12 +00:00
|
|
|
distributionType = ThreadTable.DistributionTypes.BROADCAST;
|
2022-08-05 21:00:11 +00:00
|
|
|
draftViewModel.setDistributionType(distributionType);
|
2013-04-26 01:59:49 +00:00
|
|
|
item.setChecked(true);
|
|
|
|
|
|
|
|
if (threadId != -1) {
|
|
|
|
new AsyncTask<Void, Void, Void>() {
|
|
|
|
@Override
|
|
|
|
protected Void doInBackground(Void... params) {
|
2022-11-29 15:47:12 +00:00
|
|
|
SignalDatabase.threads().setDistributionType(threadId, ThreadTable.DistributionTypes.BROADCAST);
|
2013-04-26 01:59:49 +00:00
|
|
|
return null;
|
|
|
|
}
|
2017-10-23 20:03:32 +00:00
|
|
|
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
2013-04-26 01:59:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void handleDistributionConversationEnabled(MenuItem item) {
|
2022-11-29 15:47:12 +00:00
|
|
|
distributionType = ThreadTable.DistributionTypes.CONVERSATION;
|
2022-08-05 21:00:11 +00:00
|
|
|
draftViewModel.setDistributionType(distributionType);
|
2013-04-26 01:59:49 +00:00
|
|
|
item.setChecked(true);
|
|
|
|
|
|
|
|
if (threadId != -1) {
|
|
|
|
new AsyncTask<Void, Void, Void>() {
|
|
|
|
@Override
|
|
|
|
protected Void doInBackground(Void... params) {
|
2022-11-29 15:47:12 +00:00
|
|
|
SignalDatabase.threads().setDistributionType(threadId, ThreadTable.DistributionTypes.CONVERSATION);
|
2013-04-26 01:59:49 +00:00
|
|
|
return null;
|
|
|
|
}
|
2017-10-23 20:03:32 +00:00
|
|
|
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
2013-04-26 01:59:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-27 18:45:56 +00:00
|
|
|
private void handleDial(final Recipient recipient, boolean isSecure) {
|
2015-09-22 00:41:27 +00:00
|
|
|
if (recipient == null) return;
|
|
|
|
|
2018-09-27 18:45:56 +00:00
|
|
|
if (isSecure) {
|
2022-09-02 15:30:45 +00:00
|
|
|
CommunicationActions.startVoiceCall(this, recipient);
|
2015-09-22 00:41:27 +00:00
|
|
|
} else {
|
2022-09-02 15:30:45 +00:00
|
|
|
CommunicationActions.startInsecureCall(this, recipient);
|
2015-09-22 00:41:27 +00:00
|
|
|
}
|
2012-07-19 21:22:03 +00:00
|
|
|
}
|
|
|
|
|
2019-12-03 20:26:05 +00:00
|
|
|
private void handleVideo(final Recipient recipient) {
|
|
|
|
if (recipient == null) return;
|
|
|
|
|
2021-08-25 17:21:11 +00:00
|
|
|
if (recipient.isPushV2Group() && groupCallViewModel.hasActiveGroupCall().getValue() == Boolean.FALSE && groupViewModel.isNonAdminInAnnouncementGroup()) {
|
2022-01-14 13:06:28 +00:00
|
|
|
new MaterialAlertDialogBuilder(requireContext()).setTitle(R.string.ConversationActivity_cant_start_group_call)
|
2021-07-23 20:22:08 +00:00
|
|
|
.setMessage(R.string.ConversationActivity_only_admins_of_this_group_can_start_a_call)
|
|
|
|
.setPositiveButton(android.R.string.ok, (d, w) -> d.dismiss())
|
|
|
|
.show();
|
|
|
|
} else {
|
2022-09-02 15:30:45 +00:00
|
|
|
CommunicationActions.startVideoCall(this, recipient);
|
2021-07-23 20:22:08 +00:00
|
|
|
}
|
2019-12-03 20:26:05 +00:00
|
|
|
}
|
|
|
|
|
2012-10-21 21:34:09 +00:00
|
|
|
private void handleDisplayGroupRecipients() {
|
2022-01-14 13:06:28 +00:00
|
|
|
new GroupMembersDialog(requireActivity(), getRecipient()).display();
|
2012-10-21 21:34:09 +00:00
|
|
|
}
|
|
|
|
|
2014-06-03 23:24:44 +00:00
|
|
|
private void handleAddToContacts() {
|
2019-09-07 03:40:06 +00:00
|
|
|
if (recipient.get().isGroup()) return;
|
2017-07-26 16:59:15 +00:00
|
|
|
|
2015-12-12 06:57:18 +00:00
|
|
|
try {
|
2019-08-07 18:22:51 +00:00
|
|
|
startActivityForResult(RecipientExporter.export(recipient.get()).asAddContactIntent(), ADD_CONTACT);
|
2015-12-12 06:57:18 +00:00
|
|
|
} catch (ActivityNotFoundException e) {
|
|
|
|
Log.w(TAG, e);
|
|
|
|
}
|
2013-10-17 00:28:36 +00:00
|
|
|
}
|
|
|
|
|
2017-10-05 18:07:44 +00:00
|
|
|
private boolean handleDisplayQuickContact() {
|
2020-02-19 22:08:34 +00:00
|
|
|
if (isInMessageRequest() || recipient.get().isGroup()) return false;
|
2017-10-05 18:07:44 +00:00
|
|
|
|
2019-08-07 18:22:51 +00:00
|
|
|
if (recipient.get().getContactUri() != null) {
|
2022-01-14 13:06:28 +00:00
|
|
|
ContactsContract.QuickContact.showQuickContact(requireContext(), titleView, recipient.get().getContactUri(), ContactsContract.QuickContact.MODE_LARGE, null);
|
2017-10-05 18:07:44 +00:00
|
|
|
} else {
|
|
|
|
handleAddToContacts();
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-07-19 21:22:03 +00:00
|
|
|
private void handleAddAttachment() {
|
2022-07-22 13:47:40 +00:00
|
|
|
if (viewModel.getConversationStateSnapshot().isMmsEnabled() || viewModel.isPushAvailable()) {
|
2020-01-30 03:13:44 +00:00
|
|
|
viewModel.getRecentMedia().removeObservers(this);
|
|
|
|
|
|
|
|
if (attachmentKeyboardStub.resolved() && container.isInputOpen() && container.getCurrentInput() == attachmentKeyboardStub.get()) {
|
|
|
|
container.showSoftkey(composeText);
|
|
|
|
} else {
|
2022-01-14 13:06:28 +00:00
|
|
|
viewModel.getRecentMedia().observe(getViewLifecycleOwner(), media -> attachmentKeyboardStub.get().onMediaChanged(media));
|
2020-01-30 03:13:44 +00:00
|
|
|
attachmentKeyboardStub.get().setCallback(this);
|
2021-02-05 21:18:21 +00:00
|
|
|
attachmentKeyboardStub.get().setWallpaperEnabled(recipient.get().hasWallpaper());
|
2021-04-06 16:03:33 +00:00
|
|
|
|
|
|
|
updatePaymentsAvailable();
|
|
|
|
|
2020-01-30 03:13:44 +00:00
|
|
|
container.show(composeText, attachmentKeyboardStub.get());
|
2022-06-17 17:22:14 +00:00
|
|
|
navigationBarBackground.setVisibility(View.VISIBLE);
|
2020-01-30 03:13:44 +00:00
|
|
|
|
|
|
|
viewModel.onAttachmentKeyboardOpen();
|
2017-01-19 02:46:40 +00:00
|
|
|
}
|
2013-03-05 01:43:04 +00:00
|
|
|
} else {
|
2013-09-16 07:55:01 +00:00
|
|
|
handleManualMmsRequired();
|
2013-03-05 01:43:04 +00:00
|
|
|
}
|
2012-07-19 21:22:03 +00:00
|
|
|
}
|
|
|
|
|
2021-04-06 16:03:33 +00:00
|
|
|
private void updatePaymentsAvailable() {
|
|
|
|
if (!attachmentKeyboardStub.resolved()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
PaymentsValues paymentsValues = SignalStore.paymentsValues();
|
|
|
|
|
|
|
|
if (paymentsValues.getPaymentsAvailability().isSendAllowed() &&
|
|
|
|
!recipient.get().isSelf() &&
|
|
|
|
!recipient.get().isGroup() &&
|
|
|
|
recipient.get().isRegistered() &&
|
|
|
|
!recipient.get().isForceSmsSelection())
|
|
|
|
{
|
|
|
|
attachmentKeyboardStub.get().filterAttachmentKeyboardButtons(null);
|
|
|
|
} else {
|
|
|
|
attachmentKeyboardStub.get().filterAttachmentKeyboardButtons(btn -> btn != AttachmentKeyboardButton.PAYMENT);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-16 07:55:01 +00:00
|
|
|
private void handleManualMmsRequired() {
|
2022-01-14 13:06:28 +00:00
|
|
|
Toast.makeText(requireContext(), R.string.MmsDownloader_error_reading_mms_settings, Toast.LENGTH_LONG).show();
|
2013-09-16 07:55:01 +00:00
|
|
|
|
2022-07-19 15:49:28 +00:00
|
|
|
Bundle extras = requireArguments();
|
2022-01-14 13:06:28 +00:00
|
|
|
Intent intent = new Intent(requireContext(), PromptMmsActivity.class);
|
2022-07-19 15:49:28 +00:00
|
|
|
|
|
|
|
intent.putExtras(extras);
|
2013-09-16 07:55:01 +00:00
|
|
|
startActivity(intent);
|
|
|
|
}
|
|
|
|
|
2020-06-26 15:10:54 +00:00
|
|
|
private void handleRecentSafetyNumberChange() {
|
|
|
|
List<IdentityRecord> records = identityRecords.getUnverifiedRecords();
|
|
|
|
records.addAll(identityRecords.getUntrustedRecords());
|
2022-07-11 15:54:30 +00:00
|
|
|
SafetyNumberBottomSheet
|
|
|
|
.forIdentityRecordsAndDestination(
|
|
|
|
records,
|
|
|
|
new ContactSearchKey.RecipientSearchKey.KnownRecipient(recipient.getId())
|
|
|
|
)
|
|
|
|
.show(getChildFragmentManager());
|
2017-06-07 01:03:09 +00:00
|
|
|
}
|
|
|
|
|
2020-06-26 15:10:54 +00:00
|
|
|
@Override
|
2022-07-11 15:54:30 +00:00
|
|
|
public void onMessageResentAfterSafetyNumberChangeInBottomSheet() {
|
2021-06-10 20:06:32 +00:00
|
|
|
Log.d(TAG, "onMessageResentAfterSafetyNumberChange");
|
2020-06-26 15:10:54 +00:00
|
|
|
initializeIdentityRecords().addListener(new AssertedSuccessListener<Boolean>() {
|
|
|
|
@Override
|
|
|
|
public void onSuccess(Boolean result) { }
|
|
|
|
});
|
2017-06-07 01:03:09 +00:00
|
|
|
}
|
|
|
|
|
2020-08-27 20:34:26 +00:00
|
|
|
@Override
|
|
|
|
public void onCanceled() { }
|
|
|
|
|
2022-07-22 13:47:40 +00:00
|
|
|
private void handleSecurityChange(@NonNull ConversationSecurityInfo conversationSecurityInfo) {
|
|
|
|
Log.i(TAG, "handleSecurityChange(" + conversationSecurityInfo + ")");
|
2017-09-07 00:54:32 +00:00
|
|
|
|
2022-07-22 13:47:40 +00:00
|
|
|
boolean isPushAvailable = conversationSecurityInfo.isPushAvailable();
|
|
|
|
boolean isMediaMessage = recipient.get().isMmsGroup() || attachmentManager.isAttachmentPresent();
|
2015-09-23 22:47:48 +00:00
|
|
|
|
|
|
|
sendButton.resetAvailableTransports(isMediaMessage);
|
|
|
|
|
2022-02-04 17:01:31 +00:00
|
|
|
boolean smsEnabled = true;
|
2021-04-08 20:18:42 +00:00
|
|
|
|
|
|
|
if (recipient.get().isPushGroup() || (!recipient.get().isMmsGroup() && !recipient.get().hasSmsAddress())) {
|
2022-06-03 22:07:29 +00:00
|
|
|
sendButton.disableTransportType(MessageSendType.TransportType.SMS);
|
2022-02-04 17:01:31 +00:00
|
|
|
smsEnabled = false;
|
|
|
|
}
|
|
|
|
|
2022-07-22 13:47:40 +00:00
|
|
|
if (!isPushAvailable && !isPushGroupConversation() && !recipient.get().isServiceIdOnly() && !recipient.get().isReleaseNotes() && smsEnabled) {
|
2022-06-03 22:07:29 +00:00
|
|
|
sendButton.disableTransportType(MessageSendType.TransportType.SIGNAL);
|
2021-04-08 20:18:42 +00:00
|
|
|
}
|
2015-09-23 22:47:48 +00:00
|
|
|
|
2022-02-04 17:01:31 +00:00
|
|
|
if (!recipient.get().isPushGroup() && recipient.get().isForceSmsSelection() && smsEnabled) {
|
2022-06-03 22:07:29 +00:00
|
|
|
sendButton.setDefaultTransport(MessageSendType.TransportType.SMS);
|
2022-10-13 15:33:13 +00:00
|
|
|
viewModel.insertSmsExportUpdateEvent(recipient.get());
|
2019-04-12 19:22:38 +00:00
|
|
|
} else {
|
2022-07-22 13:47:40 +00:00
|
|
|
if (isPushAvailable || isPushGroupConversation() || recipient.get().isServiceIdOnly() || recipient.get().isReleaseNotes() || !smsEnabled) {
|
2022-06-03 22:07:29 +00:00
|
|
|
sendButton.setDefaultTransport(MessageSendType.TransportType.SIGNAL);
|
2021-05-03 17:45:53 +00:00
|
|
|
} else {
|
2022-06-03 22:07:29 +00:00
|
|
|
sendButton.setDefaultTransport(MessageSendType.TransportType.SMS);
|
2022-10-13 15:33:13 +00:00
|
|
|
viewModel.insertSmsExportUpdateEvent(recipient.get());
|
2021-05-03 17:45:53 +00:00
|
|
|
}
|
2019-04-12 19:22:38 +00:00
|
|
|
}
|
2015-09-23 22:47:48 +00:00
|
|
|
|
|
|
|
calculateCharactersRemaining();
|
2021-06-25 12:28:55 +00:00
|
|
|
invalidateOptionsMenu();
|
2022-07-22 13:47:40 +00:00
|
|
|
setBlockedUserState(recipient.get(), conversationSecurityInfo);
|
2022-07-19 17:53:54 +00:00
|
|
|
onSecurityUpdated();
|
2015-09-23 22:47:48 +00:00
|
|
|
}
|
|
|
|
|
2012-07-19 21:22:03 +00:00
|
|
|
///// Initializers
|
|
|
|
|
2020-11-25 15:36:33 +00:00
|
|
|
private ListenableFuture<Boolean> initializeDraft(@NonNull ConversationIntents.Args args) {
|
2018-07-25 15:30:48 +00:00
|
|
|
final SettableFuture<Boolean> result = new SettableFuture<>();
|
|
|
|
|
2022-07-29 18:55:05 +00:00
|
|
|
long sharedDataTimestamp = args.getShareDataTimestamp();
|
|
|
|
long lastTimestamp = callback.getShareDataTimestamp();
|
|
|
|
boolean hasProcessedShareData = sharedDataTimestamp > 0 && sharedDataTimestamp <= lastTimestamp;
|
2022-08-10 12:50:32 +00:00
|
|
|
|
|
|
|
Log.d(TAG, "Shared this data at " + sharedDataTimestamp + " and last processed share data at " + lastTimestamp);
|
2022-07-18 15:41:05 +00:00
|
|
|
if (hasProcessedShareData) {
|
|
|
|
Log.d(TAG, "Already processed this share data. Skipping.");
|
|
|
|
result.set(false);
|
|
|
|
return result;
|
2022-07-29 18:55:05 +00:00
|
|
|
} else {
|
|
|
|
Log.d(TAG, "Have not processed this share data. Proceeding.");
|
|
|
|
callback.setShareDataTimestamp(sharedDataTimestamp);
|
2022-07-18 15:41:05 +00:00
|
|
|
}
|
|
|
|
|
2020-11-25 15:36:33 +00:00
|
|
|
final CharSequence draftText = args.getDraftText();
|
2022-07-19 15:49:28 +00:00
|
|
|
final Uri draftMedia = ConversationIntents.getIntentData(requireArguments());
|
|
|
|
final String draftContentType = ConversationIntents.getIntentType(requireArguments());
|
2022-01-14 13:06:28 +00:00
|
|
|
final MediaType draftMediaType = MediaType.from(draftContentType);
|
2020-11-25 15:36:33 +00:00
|
|
|
final List<Media> mediaList = args.getMedia();
|
|
|
|
final StickerLocator stickerLocator = args.getStickerLocator();
|
|
|
|
final boolean borderless = args.isBorderless();
|
2019-04-17 14:21:30 +00:00
|
|
|
|
|
|
|
if (stickerLocator != null && draftMedia != null) {
|
2020-02-05 21:34:54 +00:00
|
|
|
Log.d(TAG, "Handling shared sticker.");
|
2020-09-02 16:46:58 +00:00
|
|
|
sendSticker(stickerLocator, Objects.requireNonNull(draftContentType), draftMedia, 0, true);
|
2019-04-17 14:21:30 +00:00
|
|
|
return new SettableFuture<>(false);
|
|
|
|
}
|
2018-11-20 17:59:23 +00:00
|
|
|
|
2020-07-10 13:30:00 +00:00
|
|
|
if (draftMedia != null && draftContentType != null && borderless) {
|
2022-07-18 15:41:05 +00:00
|
|
|
Log.d(TAG, "Handling borderless draft media with content type " + draftContentType);
|
2020-07-10 13:30:00 +00:00
|
|
|
SimpleTask.run(getLifecycle(),
|
|
|
|
() -> getKeyboardImageDetails(draftMedia),
|
|
|
|
details -> sendKeyboardImage(draftMedia, draftContentType, details));
|
|
|
|
return new SettableFuture<>(false);
|
|
|
|
}
|
|
|
|
|
2018-11-20 17:59:23 +00:00
|
|
|
if (!Util.isEmpty(mediaList)) {
|
2020-02-05 21:34:54 +00:00
|
|
|
Log.d(TAG, "Handling shared Media.");
|
2022-06-03 22:07:29 +00:00
|
|
|
Intent sendIntent = MediaSelectionActivity.editor(requireContext(), sendButton.getSelectedSendType(), mediaList, recipient.getId(), draftText);
|
2018-11-20 17:59:23 +00:00
|
|
|
startActivityForResult(sendIntent, MEDIA_SENDER);
|
|
|
|
return new SettableFuture<>(false);
|
|
|
|
}
|
2018-07-25 15:30:48 +00:00
|
|
|
|
|
|
|
if (draftText != null) {
|
2022-07-19 17:53:54 +00:00
|
|
|
Log.d(TAG, "Handling shared text");
|
2019-04-17 14:21:30 +00:00
|
|
|
composeText.setText("");
|
|
|
|
composeText.append(draftText);
|
2018-07-25 15:30:48 +00:00
|
|
|
result.set(true);
|
|
|
|
}
|
2018-11-20 17:59:23 +00:00
|
|
|
|
2018-07-25 15:30:48 +00:00
|
|
|
if (draftMedia != null && draftMediaType != null) {
|
2020-02-05 21:34:54 +00:00
|
|
|
Log.d(TAG, "Handling shared Data.");
|
2018-07-25 15:30:48 +00:00
|
|
|
return setMedia(draftMedia, draftMediaType);
|
|
|
|
}
|
2015-09-05 00:33:22 +00:00
|
|
|
|
2022-08-12 15:39:02 +00:00
|
|
|
if (draftText == null && (draftMedia == null || ConversationIntents.isBubbleIntentUri(draftMedia)) && draftMediaType == null) {
|
2022-07-19 17:53:54 +00:00
|
|
|
Log.d(TAG, "Initializing draft from database");
|
2018-07-25 15:30:48 +00:00
|
|
|
return initializeDraftFromDatabase();
|
2015-05-18 17:26:32 +00:00
|
|
|
} else {
|
|
|
|
updateToggleButtonState();
|
2018-07-25 15:30:48 +00:00
|
|
|
result.set(false);
|
2013-02-04 08:13:07 +00:00
|
|
|
}
|
2018-07-25 15:30:48 +00:00
|
|
|
|
|
|
|
return result;
|
2013-02-04 08:13:07 +00:00
|
|
|
}
|
|
|
|
|
2014-02-22 18:54:43 +00:00
|
|
|
private void initializeEnabledCheck() {
|
2022-01-14 13:06:28 +00:00
|
|
|
groupViewModel.getSelfMemberLevel().observe(getViewLifecycleOwner(), selfMembership -> {
|
2020-08-26 15:51:25 +00:00
|
|
|
boolean canSendMessages;
|
|
|
|
boolean leftGroup;
|
|
|
|
boolean canCancelRequest;
|
|
|
|
|
2021-07-23 20:22:08 +00:00
|
|
|
if (selfMembership == null) {
|
2020-08-26 15:51:25 +00:00
|
|
|
leftGroup = false;
|
|
|
|
canSendMessages = true;
|
|
|
|
canCancelRequest = false;
|
2021-07-23 20:22:08 +00:00
|
|
|
if (cannotSendInAnnouncementGroupBanner.resolved()) {
|
|
|
|
cannotSendInAnnouncementGroupBanner.get().setVisibility(View.GONE);
|
|
|
|
}
|
2020-08-26 15:51:25 +00:00
|
|
|
} else {
|
2021-07-23 20:22:08 +00:00
|
|
|
switch (selfMembership.getMemberLevel()) {
|
2020-08-26 15:51:25 +00:00
|
|
|
case NOT_A_MEMBER:
|
|
|
|
leftGroup = true;
|
|
|
|
canSendMessages = false;
|
|
|
|
canCancelRequest = false;
|
|
|
|
break;
|
|
|
|
case PENDING_MEMBER:
|
|
|
|
leftGroup = false;
|
|
|
|
canSendMessages = false;
|
|
|
|
canCancelRequest = false;
|
|
|
|
break;
|
|
|
|
case REQUESTING_MEMBER:
|
|
|
|
leftGroup = false;
|
|
|
|
canSendMessages = false;
|
|
|
|
canCancelRequest = true;
|
|
|
|
break;
|
|
|
|
case FULL_MEMBER:
|
|
|
|
case ADMINISTRATOR:
|
|
|
|
leftGroup = false;
|
|
|
|
canSendMessages = true;
|
|
|
|
canCancelRequest = false;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
throw new AssertionError();
|
|
|
|
}
|
2021-07-23 20:22:08 +00:00
|
|
|
|
2022-11-29 15:47:12 +00:00
|
|
|
if (!leftGroup && !canCancelRequest && selfMembership.isAnnouncementGroup() && selfMembership.getMemberLevel() != GroupTable.MemberLevel.ADMINISTRATOR) {
|
2021-07-23 20:22:08 +00:00
|
|
|
canSendMessages = false;
|
|
|
|
cannotSendInAnnouncementGroupBanner.get().setVisibility(View.VISIBLE);
|
|
|
|
cannotSendInAnnouncementGroupBanner.get().setMovementMethod(LinkMovementMethod.getInstance());
|
2022-01-14 13:06:28 +00:00
|
|
|
cannotSendInAnnouncementGroupBanner.get().setText(SpanUtil.clickSubstring(requireContext(), R.string.ConversationActivity_only_s_can_send_messages, R.string.ConversationActivity_admins, v -> {
|
|
|
|
ShowAdminsBottomSheetDialog.show(getChildFragmentManager(), getRecipient().requireGroupId().requireV2());
|
2021-07-23 20:22:08 +00:00
|
|
|
}));
|
|
|
|
} else if (cannotSendInAnnouncementGroupBanner.resolved()) {
|
|
|
|
cannotSendInAnnouncementGroupBanner.get().setVisibility(View.GONE);
|
|
|
|
}
|
2020-08-26 15:51:25 +00:00
|
|
|
}
|
|
|
|
|
2022-05-26 20:32:52 +00:00
|
|
|
if (messageRequestBottomView.getVisibility() == View.GONE) {
|
|
|
|
noLongerMemberBanner.setVisibility(leftGroup ? View.VISIBLE : View.GONE);
|
|
|
|
}
|
|
|
|
|
2020-08-26 15:51:25 +00:00
|
|
|
requestingMemberBanner.setVisibility(canCancelRequest ? View.VISIBLE : View.GONE);
|
2021-07-23 20:22:08 +00:00
|
|
|
|
2020-08-26 15:51:25 +00:00
|
|
|
if (canCancelRequest) {
|
|
|
|
cancelJoinRequest.setOnClickListener(v -> ConversationGroupViewModel.onCancelJoinRequest(getRecipient(), new AsynchronousCallback.MainThread<Void, GroupChangeFailureReason>() {
|
|
|
|
@Override
|
|
|
|
public void onComplete(@Nullable Void result) {
|
|
|
|
Log.d(TAG, "Cancel request complete");
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onError(@Nullable GroupChangeFailureReason error) {
|
|
|
|
Log.d(TAG, "Cancel join request failed " + error);
|
2022-01-14 13:06:28 +00:00
|
|
|
Toast.makeText(requireContext(), GroupErrors.getUserDisplayMessage(error), Toast.LENGTH_SHORT).show();
|
2020-08-26 15:51:25 +00:00
|
|
|
}
|
|
|
|
}.toWorkerCallback()));
|
|
|
|
}
|
|
|
|
|
2021-07-23 20:22:08 +00:00
|
|
|
inputPanel.setHideForGroupState(!canSendMessages);
|
2020-08-26 15:51:25 +00:00
|
|
|
inputPanel.setEnabled(canSendMessages);
|
|
|
|
sendButton.setEnabled(canSendMessages);
|
|
|
|
attachButton.setEnabled(canSendMessages);
|
2020-06-06 23:26:21 +00:00
|
|
|
});
|
2014-02-22 18:54:43 +00:00
|
|
|
}
|
|
|
|
|
2020-10-15 16:32:50 +00:00
|
|
|
private void initializePendingRequestsBanner() {
|
|
|
|
groupViewModel.getActionableRequestingMembers()
|
2022-01-14 13:06:28 +00:00
|
|
|
.observe(getViewLifecycleOwner(), actionablePendingGroupRequests -> updateReminders());
|
2020-10-15 16:32:50 +00:00
|
|
|
}
|
|
|
|
|
2020-11-12 14:52:21 +00:00
|
|
|
private void initializeGroupV1MigrationsBanners() {
|
2020-11-09 13:30:58 +00:00
|
|
|
groupViewModel.getGroupV1MigrationSuggestions()
|
2022-01-14 13:06:28 +00:00
|
|
|
.observe(getViewLifecycleOwner(), s -> updateReminders());
|
2020-11-09 13:30:58 +00:00
|
|
|
}
|
|
|
|
|
2018-07-25 15:30:48 +00:00
|
|
|
private ListenableFuture<Boolean> initializeDraftFromDatabase() {
|
|
|
|
SettableFuture<Boolean> future = new SettableFuture<>();
|
|
|
|
|
2022-08-05 21:00:11 +00:00
|
|
|
Disposable disposable = draftViewModel
|
|
|
|
.loadDrafts(threadId)
|
|
|
|
.subscribe(databaseDrafts -> {
|
|
|
|
Drafts drafts = databaseDrafts.getDrafts();
|
|
|
|
CharSequence updatedText = databaseDrafts.getUpdatedText();
|
2020-08-05 20:45:52 +00:00
|
|
|
|
2022-08-05 21:00:11 +00:00
|
|
|
if (drafts.isEmpty()) {
|
|
|
|
future.set(false);
|
|
|
|
updateToggleButtonState();
|
|
|
|
return;
|
|
|
|
}
|
2018-10-29 22:14:31 +00:00
|
|
|
|
2022-08-05 21:00:11 +00:00
|
|
|
AtomicInteger draftsRemaining = new AtomicInteger(drafts.size());
|
|
|
|
AtomicBoolean success = new AtomicBoolean(false);
|
|
|
|
ListenableFuture.Listener<Boolean> listener = new AssertedSuccessListener<Boolean>() {
|
|
|
|
@Override
|
|
|
|
public void onSuccess(Boolean result) {
|
|
|
|
success.compareAndSet(false, result);
|
2018-07-25 15:30:48 +00:00
|
|
|
|
2022-08-05 21:00:11 +00:00
|
|
|
if (draftsRemaining.decrementAndGet() <= 0) {
|
|
|
|
future.set(success.get());
|
|
|
|
}
|
2018-07-25 15:30:48 +00:00
|
|
|
}
|
2022-08-05 21:00:11 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
for (Draft draft : drafts) {
|
|
|
|
try {
|
|
|
|
switch (draft.getType()) {
|
|
|
|
case Draft.TEXT:
|
|
|
|
composeText.setText(updatedText == null ? draft.getValue() : updatedText);
|
|
|
|
listener.onSuccess(true);
|
|
|
|
break;
|
|
|
|
case Draft.LOCATION:
|
|
|
|
attachmentManager.setLocation(SignalPlace.deserialize(draft.getValue()), getCurrentMediaConstraints()).addListener(listener);
|
|
|
|
break;
|
|
|
|
case Draft.IMAGE:
|
|
|
|
setMedia(Uri.parse(draft.getValue()), MediaType.IMAGE).addListener(listener);
|
|
|
|
break;
|
|
|
|
case Draft.AUDIO:
|
|
|
|
setMedia(Uri.parse(draft.getValue()), MediaType.AUDIO).addListener(listener);
|
|
|
|
break;
|
|
|
|
case Draft.VIDEO:
|
|
|
|
setMedia(Uri.parse(draft.getValue()), MediaType.VIDEO).addListener(listener);
|
|
|
|
break;
|
|
|
|
case Draft.QUOTE:
|
|
|
|
SettableFuture<Boolean> quoteResult = new SettableFuture<>();
|
|
|
|
new QuoteRestorationTask(draft.getValue(), quoteResult).execute();
|
|
|
|
quoteResult.addListener(listener);
|
|
|
|
break;
|
|
|
|
case Draft.VOICE_NOTE:
|
|
|
|
listener.onSuccess(true);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} catch (IOException e) {
|
|
|
|
Log.w(TAG, e);
|
2016-01-04 21:02:22 +00:00
|
|
|
}
|
2014-05-22 21:00:53 +00:00
|
|
|
}
|
2015-05-18 17:26:32 +00:00
|
|
|
|
2022-08-05 21:00:11 +00:00
|
|
|
updateToggleButtonState();
|
|
|
|
});
|
|
|
|
|
|
|
|
disposables.add(disposable);
|
2018-07-25 15:30:48 +00:00
|
|
|
|
|
|
|
return future;
|
2013-02-03 04:37:40 +00:00
|
|
|
}
|
|
|
|
|
2015-10-14 04:44:01 +00:00
|
|
|
private void onSecurityUpdated() {
|
2018-08-02 13:25:33 +00:00
|
|
|
Log.i(TAG, "onSecurityUpdated()");
|
2019-11-12 14:18:57 +00:00
|
|
|
updateReminders();
|
2019-08-07 18:22:51 +00:00
|
|
|
updateDefaultSubscriptionId(recipient.get().getDefaultSubscriptionId());
|
2016-02-06 00:10:33 +00:00
|
|
|
}
|
|
|
|
|
2019-11-12 14:18:57 +00:00
|
|
|
private void initializeInsightObserver() {
|
2022-01-14 13:06:28 +00:00
|
|
|
inviteReminderModel = new InviteReminderModel(requireContext(), new InviteReminderRepository(requireContext()));
|
2019-11-12 14:18:57 +00:00
|
|
|
inviteReminderModel.loadReminder(recipient, this::updateReminders);
|
|
|
|
}
|
|
|
|
|
|
|
|
protected void updateReminders() {
|
2022-01-14 13:06:28 +00:00
|
|
|
Context context = getContext();
|
|
|
|
if (callback.onUpdateReminders() || context == null) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-10-15 16:32:50 +00:00
|
|
|
Optional<Reminder> inviteReminder = inviteReminderModel.getReminder();
|
|
|
|
Integer actionableRequestingMembers = groupViewModel.getActionableRequestingMembers().getValue();
|
2020-11-09 13:30:58 +00:00
|
|
|
List<RecipientId> gv1MigrationSuggestions = groupViewModel.getGroupV1MigrationSuggestions().getValue();
|
2017-11-16 00:29:00 +00:00
|
|
|
|
2022-01-14 13:06:28 +00:00
|
|
|
if (UnauthorizedReminder.isEligible(context)) {
|
|
|
|
reminderView.get().showReminder(new UnauthorizedReminder(context));
|
2017-11-16 00:29:00 +00:00
|
|
|
} else if (ExpiredBuildReminder.isEligible()) {
|
2022-01-14 13:06:28 +00:00
|
|
|
reminderView.get().showReminder(new ExpiredBuildReminder(context));
|
2020-09-09 14:22:22 +00:00
|
|
|
reminderView.get().setOnActionClickListener(this::handleReminderAction);
|
2022-01-14 13:06:28 +00:00
|
|
|
} else if (ServiceOutageReminder.isEligible(context)) {
|
2019-10-15 19:47:54 +00:00
|
|
|
ApplicationDependencies.getJobManager().add(new ServiceOutageDetectionJob());
|
2022-01-14 13:06:28 +00:00
|
|
|
reminderView.get().showReminder(new ServiceOutageReminder(context));
|
|
|
|
} else if (SignalStore.account().isRegistered() &&
|
|
|
|
TextSecurePreferences.isShowInviteReminders(context) &&
|
2022-07-22 13:47:40 +00:00
|
|
|
!viewModel.isPushAvailable() &&
|
2022-01-14 13:06:28 +00:00
|
|
|
inviteReminder.isPresent() &&
|
2019-11-12 14:18:57 +00:00
|
|
|
!recipient.get().isGroup()) {
|
|
|
|
reminderView.get().setOnActionClickListener(this::handleReminderAction);
|
|
|
|
reminderView.get().setOnDismissListener(() -> inviteReminderModel.dismissReminder());
|
|
|
|
reminderView.get().showReminder(inviteReminder.get());
|
2020-11-30 18:50:11 +00:00
|
|
|
} else if (actionableRequestingMembers != null && actionableRequestingMembers > 0) {
|
2022-01-14 13:06:28 +00:00
|
|
|
reminderView.get().showReminder(PendingGroupJoinRequestsReminder.create(context, actionableRequestingMembers));
|
2020-10-15 16:32:50 +00:00
|
|
|
reminderView.get().setOnActionClickListener(id -> {
|
|
|
|
if (id == R.id.reminder_action_review_join_requests) {
|
2022-01-14 13:06:28 +00:00
|
|
|
startActivity(ManagePendingAndRequestingMembersActivity.newIntent(context, getRecipient().getGroupId().get().requireV2()));
|
2020-10-15 16:32:50 +00:00
|
|
|
}
|
|
|
|
});
|
2020-11-09 13:30:58 +00:00
|
|
|
} else if (gv1MigrationSuggestions != null && gv1MigrationSuggestions.size() > 0 && recipient.get().isPushV2Group()) {
|
2022-01-14 13:06:28 +00:00
|
|
|
reminderView.get().showReminder(new GroupsV1MigrationSuggestionsReminder(context, gv1MigrationSuggestions));
|
2020-11-09 13:30:58 +00:00
|
|
|
reminderView.get().setOnActionClickListener(actionId -> {
|
|
|
|
if (actionId == R.id.reminder_action_gv1_suggestion_add_members) {
|
2022-01-14 13:06:28 +00:00
|
|
|
GroupsV1MigrationSuggestionsDialog.show(requireActivity(), recipient.get().requireGroupId().requireV2(), gv1MigrationSuggestions);
|
2020-12-16 01:18:47 +00:00
|
|
|
} else if (actionId == R.id.reminder_action_gv1_suggestion_no_thanks) {
|
2022-11-01 18:39:59 +00:00
|
|
|
groupViewModel.onSuggestedMembersBannerDismissed(recipient.get().requireGroupId());
|
2020-11-09 13:30:58 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
reminderView.get().setOnDismissListener(() -> {
|
|
|
|
});
|
2021-12-07 20:34:44 +00:00
|
|
|
} else if (isInBubble() && !SignalStore.tooltips().hasSeenBubbleOptOutTooltip() && Build.VERSION.SDK_INT > 29) {
|
2022-01-14 13:06:28 +00:00
|
|
|
reminderView.get().showReminder(new BubbleOptOutReminder(context));
|
2021-12-07 20:34:44 +00:00
|
|
|
reminderView.get().setOnActionClickListener(actionId -> {
|
|
|
|
SignalStore.tooltips().markBubbleOptOutTooltipSeen();
|
|
|
|
reminderView.get().hide();
|
|
|
|
|
|
|
|
if (actionId == R.id.reminder_action_turn_off) {
|
|
|
|
Intent intent = new Intent(Settings.ACTION_APP_NOTIFICATION_BUBBLE_SETTINGS)
|
2022-01-14 13:06:28 +00:00
|
|
|
.putExtra(Settings.EXTRA_APP_PACKAGE, requireContext().getPackageName())
|
2021-12-07 20:34:44 +00:00
|
|
|
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
|
|
|
startActivity(intent);
|
|
|
|
}
|
|
|
|
});
|
2017-01-19 02:46:40 +00:00
|
|
|
} else if (reminderView.resolved()) {
|
|
|
|
reminderView.get().hide();
|
2015-10-14 04:44:01 +00:00
|
|
|
}
|
|
|
|
}
|
2014-04-14 00:55:20 +00:00
|
|
|
|
2019-11-12 14:18:57 +00:00
|
|
|
private void handleReminderAction(@IdRes int reminderActionId) {
|
2020-11-09 13:30:58 +00:00
|
|
|
if (reminderActionId == R.id.reminder_action_invite) {
|
|
|
|
handleInviteLink();
|
|
|
|
reminderView.get().requestDismiss();
|
|
|
|
} else if (reminderActionId == R.id.reminder_action_view_insights) {
|
2022-01-14 13:06:28 +00:00
|
|
|
InsightsLauncher.showInsightsDashboard(getChildFragmentManager());
|
2020-11-09 13:30:58 +00:00
|
|
|
} else if (reminderActionId == R.id.reminder_action_update_now) {
|
2022-01-14 13:06:28 +00:00
|
|
|
PlayStoreUtil.openPlayStoreOrOurApkDownloadPage(requireContext());
|
2020-11-09 13:30:58 +00:00
|
|
|
} else {
|
|
|
|
throw new IllegalArgumentException("Unknown ID: " + reminderActionId);
|
2019-11-12 14:18:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-06 00:10:33 +00:00
|
|
|
private void updateDefaultSubscriptionId(Optional<Integer> defaultSubscriptionId) {
|
2022-03-14 19:49:46 +00:00
|
|
|
Log.i(TAG, "updateDefaultSubscriptionId(" + defaultSubscriptionId.orElse(null) + ")");
|
2022-06-03 22:07:29 +00:00
|
|
|
sendButton.setDefaultSubscriptionId(defaultSubscriptionId.orElse(null));
|
2016-02-06 00:10:33 +00:00
|
|
|
}
|
|
|
|
|
2017-06-07 01:03:09 +00:00
|
|
|
private ListenableFuture<Boolean> initializeIdentityRecords() {
|
2022-01-14 13:06:28 +00:00
|
|
|
final SettableFuture<Boolean> future = new SettableFuture<>();
|
|
|
|
final Context context = requireContext().getApplicationContext();
|
2017-06-07 01:03:09 +00:00
|
|
|
|
2022-02-22 16:36:23 +00:00
|
|
|
if (SignalStore.account().getAci() == null || SignalStore.account().getPni() == null) {
|
|
|
|
Log.w(TAG, "Not registered! Skipping initializeIdentityRecords()");
|
|
|
|
future.set(false);
|
|
|
|
return future;
|
|
|
|
}
|
|
|
|
|
2017-08-01 15:56:00 +00:00
|
|
|
new AsyncTask<Recipient, Void, Pair<IdentityRecordList, String>>() {
|
2017-06-07 01:03:09 +00:00
|
|
|
@Override
|
2017-08-01 15:56:00 +00:00
|
|
|
protected @NonNull Pair<IdentityRecordList, String> doInBackground(Recipient... params) {
|
2021-09-01 13:41:49 +00:00
|
|
|
List<Recipient> recipients;
|
2017-08-01 15:56:00 +00:00
|
|
|
|
2019-08-07 18:22:51 +00:00
|
|
|
if (params[0].isGroup()) {
|
2022-11-29 15:47:12 +00:00
|
|
|
recipients = SignalDatabase.groups().getGroupMembers(params[0].requireGroupId(), GroupTable.MemberSet.FULL_MEMBERS_EXCLUDING_SELF);
|
2017-08-01 15:56:00 +00:00
|
|
|
} else {
|
2020-06-07 22:52:39 +00:00
|
|
|
recipients = Collections.singletonList(params[0]);
|
2017-08-01 15:56:00 +00:00
|
|
|
}
|
2017-06-07 01:03:09 +00:00
|
|
|
|
2020-06-07 22:52:39 +00:00
|
|
|
long startTime = System.currentTimeMillis();
|
2022-01-26 21:22:19 +00:00
|
|
|
IdentityRecordList identityRecordList = ApplicationDependencies.getProtocolStore().aci().identities().getIdentityRecords(recipients);
|
2020-06-07 21:22:35 +00:00
|
|
|
|
2020-06-07 22:52:39 +00:00
|
|
|
Log.i(TAG, String.format(Locale.US, "Loaded %d identities in %d ms", recipients.size(), System.currentTimeMillis() - startTime));
|
2020-06-07 21:22:35 +00:00
|
|
|
|
2017-08-01 15:56:00 +00:00
|
|
|
String message = null;
|
2017-06-07 01:03:09 +00:00
|
|
|
|
2017-08-01 15:56:00 +00:00
|
|
|
if (identityRecordList.isUnverified()) {
|
2022-01-14 13:06:28 +00:00
|
|
|
message = IdentityUtil.getUnverifiedBannerDescription(context, identityRecordList.getUnverifiedRecipients());
|
2017-06-07 01:03:09 +00:00
|
|
|
}
|
2017-08-01 15:56:00 +00:00
|
|
|
|
|
|
|
return new Pair<>(identityRecordList, message);
|
2017-06-07 01:03:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
protected void onPostExecute(@NonNull Pair<IdentityRecordList, String> result) {
|
2020-01-08 20:56:51 +00:00
|
|
|
Log.i(TAG, "Got identity records: " + result.first().isUnverified());
|
2020-07-21 15:53:25 +00:00
|
|
|
identityRecords = result.first();
|
2017-06-07 01:03:09 +00:00
|
|
|
|
2020-01-08 20:56:51 +00:00
|
|
|
if (result.second() != null) {
|
2018-08-02 13:25:33 +00:00
|
|
|
Log.d(TAG, "Replacing banner...");
|
2020-01-08 20:56:51 +00:00
|
|
|
unverifiedBannerView.get().display(result.second(), result.first().getUnverifiedRecords(),
|
2017-06-07 01:03:09 +00:00
|
|
|
new UnverifiedClickedListener(),
|
|
|
|
new UnverifiedDismissedListener());
|
|
|
|
} else if (unverifiedBannerView.resolved()) {
|
2018-08-02 13:25:33 +00:00
|
|
|
Log.d(TAG, "Clearing banner...");
|
2017-06-07 01:03:09 +00:00
|
|
|
unverifiedBannerView.get().hide();
|
|
|
|
}
|
|
|
|
|
2022-07-22 13:47:40 +00:00
|
|
|
titleView.setVerified(viewModel.isPushAvailable() && identityRecords.isVerified() && !recipient.get().isSelf());
|
2017-06-07 01:03:09 +00:00
|
|
|
|
|
|
|
future.set(true);
|
|
|
|
}
|
|
|
|
|
2019-08-07 18:22:51 +00:00
|
|
|
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, recipient.get());
|
2017-06-07 01:03:09 +00:00
|
|
|
|
|
|
|
return future;
|
|
|
|
}
|
|
|
|
|
2022-01-14 13:06:28 +00:00
|
|
|
private void initializeViews(View view) {
|
|
|
|
toolbar = view.findViewById(R.id.toolbar);
|
2022-05-26 20:32:52 +00:00
|
|
|
toolbarBackground = view.findViewById(R.id.toolbar_background);
|
2022-01-14 13:06:28 +00:00
|
|
|
titleView = view.findViewById(R.id.conversation_title_view);
|
|
|
|
buttonToggle = view.findViewById(R.id.button_toggle);
|
|
|
|
sendButton = view.findViewById(R.id.send_button);
|
|
|
|
attachButton = view.findViewById(R.id.attach_button);
|
|
|
|
composeText = view.findViewById(R.id.embedded_text_editor);
|
|
|
|
charactersLeft = view.findViewById(R.id.space_left);
|
|
|
|
emojiDrawerStub = ViewUtil.findStubById(view, R.id.emoji_drawer_stub);
|
|
|
|
attachmentKeyboardStub = ViewUtil.findStubById(view, R.id.attachment_keyboard_stub);
|
|
|
|
unblockButton = view.findViewById(R.id.unblock_button);
|
2022-10-13 15:33:13 +00:00
|
|
|
smsExportStub = ViewUtil.findStubById(view, R.id.sms_export_stub);
|
2022-01-14 13:06:28 +00:00
|
|
|
registerButton = view.findViewById(R.id.register_button);
|
|
|
|
container = view.findViewById(R.id.layout_container);
|
|
|
|
reminderView = ViewUtil.findStubById(view, R.id.reminder_stub);
|
|
|
|
unverifiedBannerView = ViewUtil.findStubById(view, R.id.unverified_banner_stub);
|
|
|
|
reviewBanner = ViewUtil.findStubById(view, R.id.review_banner_stub);
|
|
|
|
quickAttachmentToggle = view.findViewById(R.id.quick_attachment_toggle);
|
|
|
|
inlineAttachmentToggle = view.findViewById(R.id.inline_attachment_container);
|
|
|
|
inputPanel = view.findViewById(R.id.bottom_panel);
|
|
|
|
searchNav = view.findViewById(R.id.conversation_search_nav);
|
|
|
|
messageRequestBottomView = view.findViewById(R.id.conversation_activity_message_request_bottom_bar);
|
|
|
|
mentionsSuggestions = ViewUtil.findStubById(view, R.id.conversation_mention_suggestions_stub);
|
|
|
|
wallpaper = view.findViewById(R.id.conversation_wallpaper);
|
|
|
|
wallpaperDim = view.findViewById(R.id.conversation_wallpaper_dim);
|
|
|
|
voiceNotePlayerViewStub = ViewUtil.findStubById(view, R.id.voice_note_player_stub);
|
2022-06-17 17:22:14 +00:00
|
|
|
navigationBarBackground = view.findViewById(R.id.navbar_background);
|
2022-01-14 13:06:28 +00:00
|
|
|
|
|
|
|
ImageButton quickCameraToggle = view.findViewById(R.id.quick_camera_toggle);
|
|
|
|
ImageButton inlineAttachmentButton = view.findViewById(R.id.inline_attachment_button);
|
|
|
|
|
|
|
|
Stub<ConversationReactionOverlay> reactionOverlayStub = ViewUtil.findStubById(view, R.id.conversation_reaction_scrubber_stub);
|
2021-01-27 20:34:59 +00:00
|
|
|
reactionDelegate = new ConversationReactionDelegate(reactionOverlayStub);
|
|
|
|
|
2022-01-14 13:06:28 +00:00
|
|
|
noLongerMemberBanner = view.findViewById(R.id.conversation_no_longer_member_banner);
|
|
|
|
cannotSendInAnnouncementGroupBanner = ViewUtil.findStubById(view, R.id.conversation_cannot_send_announcement_stub);
|
|
|
|
requestingMemberBanner = view.findViewById(R.id.conversation_requesting_banner);
|
|
|
|
cancelJoinRequest = view.findViewById(R.id.conversation_cancel_request);
|
2022-01-31 17:46:44 +00:00
|
|
|
releaseChannelUnmute = ViewUtil.findStubById(view, R.id.conversation_release_notes_unmute_stub);
|
2022-01-14 13:06:28 +00:00
|
|
|
joinGroupCallButton = view.findViewById(R.id.conversation_group_call_join);
|
2020-07-17 18:32:53 +00:00
|
|
|
|
2022-06-03 22:07:29 +00:00
|
|
|
sendButton.setPopupContainer((ViewGroup) view);
|
2022-10-13 15:33:13 +00:00
|
|
|
sendButton.setSnackbarContainer(view.findViewById(R.id.fragment_content));
|
2022-06-03 22:07:29 +00:00
|
|
|
|
2021-06-09 20:18:55 +00:00
|
|
|
container.setIsBubble(isInBubble());
|
2015-07-25 14:58:51 +00:00
|
|
|
container.addOnKeyboardShownListener(this);
|
2017-01-19 19:31:41 +00:00
|
|
|
inputPanel.setListener(this);
|
2016-12-26 23:14:23 +00:00
|
|
|
inputPanel.setMediaListener(this);
|
2015-07-25 14:58:51 +00:00
|
|
|
|
2022-10-25 16:31:08 +00:00
|
|
|
attachmentManager = new AttachmentManager(requireContext(), view, this);
|
2022-01-14 13:06:28 +00:00
|
|
|
audioRecorder = new AudioRecorder(requireContext());
|
2022-08-05 21:00:11 +00:00
|
|
|
typingTextWatcher = new ComposeTextWatcher();
|
2012-07-19 21:22:03 +00:00
|
|
|
|
2013-06-28 03:57:27 +00:00
|
|
|
SendButtonListener sendButtonListener = new SendButtonListener();
|
|
|
|
ComposeKeyPressedListener composeKeyPressedListener = new ComposeKeyPressedListener();
|
2012-07-19 21:22:03 +00:00
|
|
|
|
2015-07-21 02:25:54 +00:00
|
|
|
composeText.setOnEditorActionListener(sendButtonListener);
|
2019-02-14 21:55:48 +00:00
|
|
|
composeText.setCursorPositionChangedListener(this);
|
2015-05-18 17:26:32 +00:00
|
|
|
attachButton.setOnClickListener(new AttachButtonListener());
|
2015-07-26 21:49:43 +00:00
|
|
|
attachButton.setOnLongClickListener(new AttachButtonLongClickListener());
|
2012-07-19 21:22:03 +00:00
|
|
|
sendButton.setOnClickListener(sendButtonListener);
|
2013-03-14 00:45:32 +00:00
|
|
|
sendButton.setEnabled(true);
|
2022-06-03 22:07:29 +00:00
|
|
|
sendButton.addOnSelectionChangedListener((newMessageSendType, manuallySelected) -> {
|
2022-06-16 15:41:56 +00:00
|
|
|
if (getContext() == null) {
|
|
|
|
Log.w(TAG, "onSelectionChanged called in detached state. Ignoring.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-12-05 19:52:03 +00:00
|
|
|
calculateCharactersRemaining();
|
2019-01-15 08:41:05 +00:00
|
|
|
updateLinkPreviewState();
|
2022-06-03 22:07:29 +00:00
|
|
|
linkPreviewViewModel.onTransportChanged(newMessageSendType.usesSmsTransport());
|
|
|
|
composeText.setMessageSendType(newMessageSendType);
|
2019-10-07 18:43:36 +00:00
|
|
|
|
2022-06-15 15:19:28 +00:00
|
|
|
updateSendButtonColor(newMessageSendType);
|
2019-10-07 18:43:36 +00:00
|
|
|
|
2022-06-03 22:07:29 +00:00
|
|
|
if (manuallySelected) recordTransportPreference(newMessageSendType);
|
2015-02-16 10:38:09 +00:00
|
|
|
});
|
|
|
|
|
2022-03-30 17:44:13 +00:00
|
|
|
titleView.setOnStoryRingClickListener(v -> handleStoryRingClick());
|
2017-10-03 23:27:12 +00:00
|
|
|
titleView.setOnClickListener(v -> handleConversationSettings());
|
2017-10-05 18:07:44 +00:00
|
|
|
titleView.setOnLongClickListener(v -> handleDisplayQuickContact());
|
2017-09-13 05:48:30 +00:00
|
|
|
unblockButton.setOnClickListener(v -> handleUnblock());
|
2017-12-25 23:57:33 +00:00
|
|
|
registerButton.setOnClickListener(v -> handleRegisterForSignal());
|
2016-11-20 23:56:47 +00:00
|
|
|
|
2013-06-28 03:57:27 +00:00
|
|
|
composeText.setOnKeyListener(composeKeyPressedListener);
|
|
|
|
composeText.addTextChangedListener(composeKeyPressedListener);
|
2012-07-19 21:22:03 +00:00
|
|
|
composeText.setOnEditorActionListener(sendButtonListener);
|
2013-06-28 03:57:27 +00:00
|
|
|
composeText.setOnClickListener(composeKeyPressedListener);
|
2014-05-29 03:53:34 +00:00
|
|
|
composeText.setOnFocusChangeListener(composeKeyPressedListener);
|
2015-04-16 05:38:33 +00:00
|
|
|
|
2020-04-16 15:30:51 +00:00
|
|
|
if (Camera.getNumberOfCameras() > 0) {
|
2019-02-25 23:21:37 +00:00
|
|
|
quickCameraToggle.setVisibility(View.VISIBLE);
|
2015-11-18 22:52:26 +00:00
|
|
|
quickCameraToggle.setOnClickListener(new QuickCameraToggleListener());
|
2015-04-16 05:38:33 +00:00
|
|
|
} else {
|
2015-11-18 22:52:26 +00:00
|
|
|
quickCameraToggle.setVisibility(View.GONE);
|
2015-04-16 05:38:33 +00:00
|
|
|
}
|
2018-08-10 16:18:02 +00:00
|
|
|
|
2019-02-01 17:06:59 +00:00
|
|
|
searchNav.setEventListener(this);
|
|
|
|
|
2018-08-10 16:18:02 +00:00
|
|
|
inlineAttachmentButton.setOnClickListener(v -> handleAddAttachment());
|
2019-12-03 21:57:21 +00:00
|
|
|
|
2021-01-27 20:34:59 +00:00
|
|
|
reactionDelegate.setOnReactionSelectedListener(this);
|
2020-12-02 18:20:38 +00:00
|
|
|
|
|
|
|
joinGroupCallButton.setOnClickListener(v -> handleVideo(getRecipient()));
|
2021-07-07 17:23:37 +00:00
|
|
|
|
2022-01-14 13:06:28 +00:00
|
|
|
voiceNoteMediaController.getVoiceNotePlayerViewState().observe(getViewLifecycleOwner(), state -> {
|
2021-07-07 17:23:37 +00:00
|
|
|
if (state.isPresent()) {
|
2021-07-22 14:10:57 +00:00
|
|
|
requireVoiceNotePlayerView().show();
|
|
|
|
requireVoiceNotePlayerView().setState(state.get());
|
2021-07-07 17:23:37 +00:00
|
|
|
} else if (voiceNotePlayerViewStub.resolved()) {
|
2021-07-22 14:10:57 +00:00
|
|
|
requireVoiceNotePlayerView().hide();
|
2021-07-07 17:23:37 +00:00
|
|
|
}
|
|
|
|
});
|
2021-07-07 19:51:17 +00:00
|
|
|
|
2022-01-14 13:06:28 +00:00
|
|
|
voiceNoteMediaController.getVoiceNotePlaybackState().observe(getViewLifecycleOwner(), inputPanel.getPlaybackStateObserver());
|
2022-05-26 20:32:52 +00:00
|
|
|
|
2022-06-10 19:20:02 +00:00
|
|
|
material3OnScrollHelper = new Material3OnScrollHelper(requireActivity(), Collections.singletonList(toolbarBackground), Collections.emptyList()) {
|
|
|
|
@Override
|
2022-06-15 12:45:28 +00:00
|
|
|
public @NonNull ColorSet getActiveColorSet() {
|
|
|
|
return new ColorSet(getActiveToolbarColor(wallpaper.getDrawable() != null));
|
2022-06-10 19:20:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2022-06-15 12:45:28 +00:00
|
|
|
public @NonNull ColorSet getInactiveColorSet() {
|
|
|
|
return new ColorSet(getInactiveToolbarColor(wallpaper.getDrawable() != null));
|
2022-06-10 19:20:02 +00:00
|
|
|
}
|
|
|
|
};
|
2022-05-26 20:32:52 +00:00
|
|
|
}
|
|
|
|
|
2022-06-15 15:19:28 +00:00
|
|
|
private void updateSendButtonColor(MessageSendType newMessageSendType) {
|
|
|
|
buttonToggle.getBackground().setColorFilter(getSendButtonColor(newMessageSendType), PorterDuff.Mode.MULTIPLY);
|
|
|
|
buttonToggle.getBackground().invalidateSelf();
|
|
|
|
}
|
|
|
|
|
|
|
|
private @ColorInt int getSendButtonColor(MessageSendType newTransport) {
|
2022-06-03 22:07:29 +00:00
|
|
|
if (newTransport.usesSmsTransport()) {
|
|
|
|
return getResources().getColor(newTransport.getBackgroundColorRes());
|
2022-05-26 20:32:52 +00:00
|
|
|
} else if (recipient != null) {
|
|
|
|
return getRecipient().getChatColors().asSingleColor();
|
|
|
|
} else {
|
2022-06-03 22:07:29 +00:00
|
|
|
return getResources().getColor(newTransport.getBackgroundColorRes());
|
2022-05-26 20:32:52 +00:00
|
|
|
}
|
2014-12-25 02:32:51 +00:00
|
|
|
}
|
|
|
|
|
2021-07-22 14:10:57 +00:00
|
|
|
private @NonNull VoiceNotePlayerView requireVoiceNotePlayerView() {
|
|
|
|
if (voiceNotePlayerView == null) {
|
|
|
|
voiceNotePlayerView = voiceNotePlayerViewStub.get().findViewById(R.id.voice_note_player_view);
|
|
|
|
voiceNotePlayerView.setListener(new VoiceNotePlayerViewListener());
|
|
|
|
}
|
|
|
|
|
|
|
|
return voiceNotePlayerView;
|
|
|
|
}
|
|
|
|
|
2021-01-20 02:54:10 +00:00
|
|
|
private void updateWallpaper(@Nullable ChatWallpaper chatWallpaper) {
|
2021-01-20 21:09:36 +00:00
|
|
|
Log.d(TAG, "Setting wallpaper.");
|
2021-01-20 02:54:10 +00:00
|
|
|
if (chatWallpaper != null) {
|
|
|
|
chatWallpaper.loadInto(wallpaper);
|
|
|
|
ChatWallpaperDimLevelUtil.applyDimLevelForNightMode(wallpaperDim, chatWallpaper);
|
2021-02-05 21:18:21 +00:00
|
|
|
inputPanel.setWallpaperEnabled(true);
|
|
|
|
if (attachmentKeyboardStub.resolved()) {
|
|
|
|
attachmentKeyboardStub.get().setWallpaperEnabled(true);
|
|
|
|
}
|
2021-02-09 16:42:57 +00:00
|
|
|
|
2022-06-10 19:20:02 +00:00
|
|
|
material3OnScrollHelper.setColorImmediate();
|
2022-05-26 20:32:52 +00:00
|
|
|
int toolbarTextAndIconColor = getResources().getColor(R.color.signal_colorNeutralInverse);
|
|
|
|
toolbar.setTitleTextColor(toolbarTextAndIconColor);
|
|
|
|
setToolbarActionItemTint(toolbar, toolbarTextAndIconColor);
|
2022-10-18 01:08:48 +00:00
|
|
|
if (!smsExportStub.resolved()) {
|
|
|
|
WindowUtil.setNavigationBarColor(requireActivity(), getResources().getColor(R.color.conversation_navigation_wallpaper));
|
|
|
|
}
|
2021-01-20 02:54:10 +00:00
|
|
|
} else {
|
|
|
|
wallpaper.setImageDrawable(null);
|
|
|
|
wallpaperDim.setVisibility(View.GONE);
|
2021-02-05 21:18:21 +00:00
|
|
|
inputPanel.setWallpaperEnabled(false);
|
|
|
|
if (attachmentKeyboardStub.resolved()) {
|
|
|
|
attachmentKeyboardStub.get().setWallpaperEnabled(false);
|
|
|
|
}
|
2021-02-09 16:42:57 +00:00
|
|
|
|
2022-06-10 19:20:02 +00:00
|
|
|
material3OnScrollHelper.setColorImmediate();
|
2022-05-26 20:32:52 +00:00
|
|
|
int toolbarTextAndIconColor = getResources().getColor(R.color.signal_colorOnSurface);
|
|
|
|
toolbar.setTitleTextColor(toolbarTextAndIconColor);
|
|
|
|
setToolbarActionItemTint(toolbar, toolbarTextAndIconColor);
|
2022-10-18 01:08:48 +00:00
|
|
|
if (!releaseChannelUnmute.resolved() && !smsExportStub.resolved()) {
|
2022-08-08 18:17:28 +00:00
|
|
|
WindowUtil.setNavigationBarColor(requireActivity(), getResources().getColor(R.color.signal_colorBackground));
|
|
|
|
}
|
2021-01-20 02:54:10 +00:00
|
|
|
}
|
2021-01-20 21:09:36 +00:00
|
|
|
fragment.onWallpaperChanged(chatWallpaper);
|
2022-05-26 20:32:52 +00:00
|
|
|
messageRequestBottomView.setWallpaperEnabled(chatWallpaper != null);
|
|
|
|
}
|
|
|
|
|
2022-06-10 19:20:02 +00:00
|
|
|
private static @ColorRes int getActiveToolbarColor(boolean hasWallpaper) {
|
|
|
|
return hasWallpaper ? R.color.conversation_toolbar_color_wallpaper_scrolled
|
|
|
|
: R.color.signal_colorSurface2;
|
2022-05-26 20:32:52 +00:00
|
|
|
}
|
|
|
|
|
2022-06-10 19:20:02 +00:00
|
|
|
private static @ColorRes int getInactiveToolbarColor(boolean hasWallpaper) {
|
|
|
|
return hasWallpaper ? R.color.conversation_toolbar_color_wallpaper
|
|
|
|
: R.color.signal_colorBackground;
|
2022-05-26 20:32:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private void setToolbarActionItemTint(@NonNull Toolbar toolbar, @ColorInt int tint) {
|
|
|
|
for (int i = 0; i < toolbar.getMenu().size(); i++) {
|
|
|
|
MenuItem menuItem = toolbar.getMenu().getItem(i);
|
|
|
|
MenuItemCompat.setIconTintList(menuItem, ColorStateList.valueOf(tint));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (toolbar.getNavigationIcon() != null) {
|
|
|
|
toolbar.getNavigationIcon().setColorFilter(new SimpleColorFilter(tint));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (toolbar.getOverflowIcon() != null) {
|
|
|
|
toolbar.getOverflowIcon().setColorFilter(new SimpleColorFilter(tint));
|
|
|
|
}
|
2021-01-20 02:54:10 +00:00
|
|
|
}
|
|
|
|
|
2015-06-22 15:46:43 +00:00
|
|
|
protected void initializeActionBar() {
|
2022-03-17 13:00:10 +00:00
|
|
|
invalidateOptionsMenu();
|
2022-01-14 13:06:28 +00:00
|
|
|
toolbar.setOnMenuItemClickListener(this::onOptionsItemSelected);
|
2020-11-25 18:11:17 +00:00
|
|
|
|
|
|
|
if (isInBubble()) {
|
2022-01-14 13:06:28 +00:00
|
|
|
toolbar.setNavigationIcon(DrawableUtil.tint(ContextUtil.requireDrawable(requireContext(), R.drawable.ic_notification),
|
|
|
|
ContextCompat.getColor(requireContext(), R.color.signal_accent_primary)));
|
|
|
|
toolbar.setNavigationOnClickListener(unused -> startActivity(MainActivity.clearTop(requireContext())));
|
2020-11-25 18:11:17 +00:00
|
|
|
}
|
2022-01-14 13:06:28 +00:00
|
|
|
|
|
|
|
callback.onInitializeToolbar(toolbar);
|
2020-11-25 18:11:17 +00:00
|
|
|
}
|
|
|
|
|
2021-06-11 11:37:31 +00:00
|
|
|
protected boolean isInBubble() {
|
2022-01-14 13:06:28 +00:00
|
|
|
return callback.isInBubble();
|
2015-06-09 14:37:20 +00:00
|
|
|
}
|
|
|
|
|
2020-11-25 15:36:33 +00:00
|
|
|
private void initializeResources(@NonNull ConversationIntents.Args args) {
|
2019-10-30 04:12:56 +00:00
|
|
|
if (recipient != null) {
|
|
|
|
recipient.removeObservers(this);
|
|
|
|
}
|
|
|
|
|
2020-11-25 15:36:33 +00:00
|
|
|
recipient = Recipient.live(args.getRecipientId());
|
|
|
|
threadId = args.getThreadId();
|
|
|
|
distributionType = args.getDistributionType();
|
2017-10-16 20:11:42 +00:00
|
|
|
glideRequests = GlideApp.with(this);
|
2012-07-19 21:22:03 +00:00
|
|
|
|
2021-03-08 20:27:10 +00:00
|
|
|
Log.i(TAG, "[initializeResources] Recipient: " + recipient.getId() + ", Thread: " + threadId);
|
|
|
|
|
2022-01-14 13:06:28 +00:00
|
|
|
recipient.observe(getViewLifecycleOwner(), this::onRecipientChanged);
|
2015-02-10 11:15:50 +00:00
|
|
|
}
|
|
|
|
|
2019-01-15 08:41:05 +00:00
|
|
|
private void initializeLinkPreviewObserver() {
|
2022-10-06 12:57:30 +00:00
|
|
|
linkPreviewViewModel = new ViewModelProvider(this, (ViewModelProvider.Factory) new LinkPreviewViewModel.Factory(new LinkPreviewRepository())).get(LinkPreviewViewModel.class);
|
2019-01-15 08:41:05 +00:00
|
|
|
|
2022-01-14 13:06:28 +00:00
|
|
|
linkPreviewViewModel.getLinkPreviewState().observe(getViewLifecycleOwner(), previewState -> {
|
2019-01-15 08:41:05 +00:00
|
|
|
if (previewState == null) return;
|
|
|
|
|
|
|
|
if (previewState.isLoading()) {
|
|
|
|
inputPanel.setLinkPreviewLoading();
|
2020-08-13 17:50:38 +00:00
|
|
|
} else if (previewState.hasLinks() && !previewState.getLinkPreview().isPresent()) {
|
2020-08-18 19:28:37 +00:00
|
|
|
inputPanel.setLinkPreviewNoPreview(previewState.getError());
|
2019-01-15 08:41:05 +00:00
|
|
|
} else {
|
|
|
|
inputPanel.setLinkPreview(glideRequests, previewState.getLinkPreview());
|
|
|
|
}
|
|
|
|
|
|
|
|
updateToggleButtonState();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2019-02-01 17:06:59 +00:00
|
|
|
private void initializeSearchObserver() {
|
2022-01-26 21:23:12 +00:00
|
|
|
ConversationSearchViewModel.Factory viewModelFactory = new ConversationSearchViewModel.Factory(getString(R.string.note_to_self));
|
|
|
|
|
2022-10-06 12:57:30 +00:00
|
|
|
searchViewModel = new ViewModelProvider(this, (ViewModelProvider.Factory) viewModelFactory).get(ConversationSearchViewModel.class);
|
2019-02-01 17:06:59 +00:00
|
|
|
|
2022-01-14 13:06:28 +00:00
|
|
|
searchViewModel.getSearchResults().observe(getViewLifecycleOwner(), result -> {
|
2019-02-01 17:06:59 +00:00
|
|
|
if (result == null) return;
|
|
|
|
|
|
|
|
if (!result.getResults().isEmpty()) {
|
|
|
|
MessageResult messageResult = result.getResults().get(result.getPosition());
|
2021-06-10 19:47:12 +00:00
|
|
|
fragment.jumpToMessage(messageResult.getMessageRecipient().getId(), messageResult.getReceivedTimestampMs(), searchViewModel::onMissingResult);
|
2019-02-01 17:06:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
searchNav.setData(result.getPosition(), result.getResults().size());
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2019-04-17 14:21:30 +00:00
|
|
|
private void initializeStickerObserver() {
|
2022-01-14 13:06:28 +00:00
|
|
|
StickerSearchRepository repository = new StickerSearchRepository(requireContext());
|
2019-04-17 14:21:30 +00:00
|
|
|
|
2022-10-06 12:57:30 +00:00
|
|
|
stickerViewModel = new ViewModelProvider(this, (ViewModelProvider.Factory) new ConversationStickerViewModel.Factory(requireActivity().getApplication(), repository))
|
2019-04-17 14:21:30 +00:00
|
|
|
.get(ConversationStickerViewModel.class);
|
|
|
|
|
2022-01-14 13:06:28 +00:00
|
|
|
stickerViewModel.getStickerResults().observe(getViewLifecycleOwner(), stickers -> {
|
2019-04-17 14:21:30 +00:00
|
|
|
if (stickers == null) return;
|
|
|
|
|
|
|
|
inputPanel.setStickerSuggestions(stickers);
|
|
|
|
});
|
|
|
|
|
2022-01-14 13:06:28 +00:00
|
|
|
stickerViewModel.getStickersAvailability().observe(getViewLifecycleOwner(), stickersAvailable -> {
|
2019-04-17 14:21:30 +00:00
|
|
|
if (stickersAvailable == null) return;
|
|
|
|
|
2021-05-12 16:02:44 +00:00
|
|
|
boolean isSystemEmojiPreferred = SignalStore.settings().isPreferSystemEmoji();
|
2022-01-14 13:06:28 +00:00
|
|
|
MediaKeyboardMode keyboardMode = TextSecurePreferences.getMediaKeyboardMode(requireContext());
|
|
|
|
boolean stickerIntro = !TextSecurePreferences.hasSeenStickerIntroTooltip(requireContext());
|
2019-04-17 14:21:30 +00:00
|
|
|
|
|
|
|
if (stickersAvailable) {
|
|
|
|
inputPanel.showMediaKeyboardToggle(true);
|
2021-05-26 13:47:14 +00:00
|
|
|
switch (keyboardMode) {
|
|
|
|
case EMOJI:
|
|
|
|
inputPanel.setMediaKeyboardToggleMode(isSystemEmojiPreferred ? KeyboardPage.STICKER : KeyboardPage.EMOJI);
|
|
|
|
break;
|
|
|
|
case STICKER:
|
|
|
|
inputPanel.setMediaKeyboardToggleMode(KeyboardPage.STICKER);
|
|
|
|
break;
|
|
|
|
case GIF:
|
|
|
|
inputPanel.setMediaKeyboardToggleMode(KeyboardPage.GIF);
|
|
|
|
break;
|
|
|
|
}
|
2019-04-17 14:21:30 +00:00
|
|
|
if (stickerIntro) showStickerIntroductionTooltip();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (emojiDrawerStub.resolved()) {
|
2021-05-26 13:47:14 +00:00
|
|
|
initializeMediaKeyboardProviders();
|
2019-04-17 14:21:30 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2020-11-25 15:36:33 +00:00
|
|
|
private void initializeViewModel(@NonNull ConversationIntents.Args args) {
|
2022-10-06 12:57:30 +00:00
|
|
|
this.viewModel = new ViewModelProvider(this, (ViewModelProvider.Factory) new ConversationViewModel.Factory()).get(ConversationViewModel.class);
|
2020-11-25 15:36:33 +00:00
|
|
|
|
|
|
|
this.viewModel.setArgs(args);
|
2022-01-14 13:06:28 +00:00
|
|
|
this.viewModel.getEvents().observe(getViewLifecycleOwner(), this::onViewModelEvent);
|
2022-03-16 14:10:01 +00:00
|
|
|
disposables.add(this.viewModel.getWallpaper().subscribe(w -> updateWallpaper(w.orElse(null))));
|
2020-01-30 03:13:44 +00:00
|
|
|
}
|
|
|
|
|
2020-06-06 23:26:21 +00:00
|
|
|
private void initializeGroupViewModel() {
|
2022-10-06 12:57:30 +00:00
|
|
|
groupViewModel = new ViewModelProvider(this, (ViewModelProvider.Factory) new ConversationGroupViewModel.Factory()).get(ConversationGroupViewModel.class);
|
2020-06-06 23:26:21 +00:00
|
|
|
recipient.observe(this, groupViewModel::onRecipientChange);
|
2022-01-14 13:06:28 +00:00
|
|
|
groupViewModel.getGroupActiveState().observe(getViewLifecycleOwner(), unused -> invalidateOptionsMenu());
|
|
|
|
groupViewModel.getReviewState().observe(getViewLifecycleOwner(), this::presentGroupReviewBanner);
|
2020-06-06 23:26:21 +00:00
|
|
|
}
|
|
|
|
|
2020-07-27 13:58:58 +00:00
|
|
|
private void initializeMentionsViewModel() {
|
2022-08-01 14:55:40 +00:00
|
|
|
mentionsViewModel = new ViewModelProvider(requireActivity(), new MentionsPickerViewModel.Factory()).get(MentionsPickerViewModel.class);
|
|
|
|
inlineQueryViewModel = new ViewModelProvider(requireActivity()).get(InlineQueryViewModel.class);
|
|
|
|
|
|
|
|
inlineQueryResultsController = new InlineQueryResultsController(
|
|
|
|
requireContext(),
|
|
|
|
inlineQueryViewModel,
|
|
|
|
inputPanel,
|
|
|
|
(ViewGroup) requireView(),
|
|
|
|
composeText,
|
|
|
|
getViewLifecycleOwner()
|
|
|
|
);
|
2022-08-03 03:26:58 +00:00
|
|
|
inlineQueryResultsController.onOrientationChange(getResources().getConfiguration().orientation == ORIENTATION_LANDSCAPE);
|
2020-07-27 13:58:58 +00:00
|
|
|
|
2022-01-14 13:06:28 +00:00
|
|
|
recipient.observe(getViewLifecycleOwner(), r -> {
|
2020-08-18 22:13:45 +00:00
|
|
|
if (r.isPushV2Group() && !mentionsSuggestions.resolved()) {
|
|
|
|
mentionsSuggestions.get();
|
|
|
|
}
|
|
|
|
mentionsViewModel.onRecipientChange(r);
|
|
|
|
});
|
2020-08-05 20:45:52 +00:00
|
|
|
|
2022-08-01 14:55:40 +00:00
|
|
|
composeText.setInlineQueryChangedListener(new InlineQueryChangedListener() {
|
|
|
|
@Override
|
|
|
|
public void onQueryChanged(@NonNull InlineQuery inlineQuery) {
|
|
|
|
if (inlineQuery instanceof InlineQuery.Mention) {
|
|
|
|
if (getRecipient().isPushV2Group() && getRecipient().isActiveGroup()) {
|
|
|
|
if (!mentionsSuggestions.resolved()) {
|
|
|
|
mentionsSuggestions.get();
|
|
|
|
}
|
|
|
|
mentionsViewModel.onQueryChange(inlineQuery.getQuery());
|
|
|
|
}
|
|
|
|
inlineQueryViewModel.onQueryChange(inlineQuery);
|
|
|
|
} else if (inlineQuery instanceof InlineQuery.Emoji) {
|
|
|
|
inlineQueryViewModel.onQueryChange(inlineQuery);
|
|
|
|
mentionsViewModel.onQueryChange(null);
|
|
|
|
} else if (inlineQuery instanceof InlineQuery.NoQuery) {
|
|
|
|
mentionsViewModel.onQueryChange(null);
|
|
|
|
inlineQueryViewModel.onQueryChange(inlineQuery);
|
2020-07-27 13:58:58 +00:00
|
|
|
}
|
2022-08-01 14:55:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void clearQuery() {
|
|
|
|
onQueryChanged(InlineQuery.NoQuery.INSTANCE);
|
2020-07-27 13:58:58 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2020-08-05 20:45:52 +00:00
|
|
|
composeText.setMentionValidator(annotations -> {
|
2020-09-25 16:13:18 +00:00
|
|
|
if (!getRecipient().isPushV2Group() || !getRecipient().isActiveGroup()) {
|
2020-08-05 20:45:52 +00:00
|
|
|
return annotations;
|
|
|
|
}
|
|
|
|
|
2022-07-21 16:29:58 +00:00
|
|
|
Set<String> validRecipientIds = Stream.of(getRecipient().getParticipantIds())
|
|
|
|
.map(id -> MentionAnnotation.idToMentionAnnotationValue(id))
|
2020-08-05 20:45:52 +00:00
|
|
|
.collect(Collectors.toSet());
|
|
|
|
|
|
|
|
return Stream.of(annotations)
|
|
|
|
.filterNot(a -> validRecipientIds.contains(a.getValue()))
|
|
|
|
.toList();
|
|
|
|
});
|
|
|
|
|
2022-01-14 13:06:28 +00:00
|
|
|
mentionsViewModel.getSelectedRecipient().observe(getViewLifecycleOwner(), recipient -> {
|
|
|
|
composeText.replaceTextWithMention(recipient.getDisplayName(requireContext()), recipient.getId());
|
2020-07-27 13:58:58 +00:00
|
|
|
});
|
2022-08-01 14:55:40 +00:00
|
|
|
|
|
|
|
Disposable disposable = inlineQueryViewModel
|
|
|
|
.getSelection()
|
|
|
|
.observeOn(AndroidSchedulers.mainThread())
|
|
|
|
.subscribe(r -> {
|
|
|
|
composeText.replaceText(r);
|
|
|
|
});
|
|
|
|
|
|
|
|
disposables.add(disposable);
|
2020-07-27 13:58:58 +00:00
|
|
|
}
|
|
|
|
|
2020-12-02 18:20:38 +00:00
|
|
|
public void initializeGroupCallViewModel() {
|
2022-01-14 13:06:28 +00:00
|
|
|
groupCallViewModel = new ViewModelProvider(this, new GroupCallViewModel.Factory()).get(GroupCallViewModel.class);
|
2020-12-02 18:20:38 +00:00
|
|
|
|
|
|
|
recipient.observe(this, r -> {
|
2021-03-31 18:30:30 +00:00
|
|
|
groupCallViewModel.onRecipientChange(r);
|
2020-12-02 18:20:38 +00:00
|
|
|
});
|
|
|
|
|
2022-01-14 13:06:28 +00:00
|
|
|
groupCallViewModel.hasActiveGroupCall().observe(getViewLifecycleOwner(), hasActiveCall -> {
|
2020-12-02 18:20:38 +00:00
|
|
|
invalidateOptionsMenu();
|
|
|
|
joinGroupCallButton.setVisibility(hasActiveCall ? View.VISIBLE : View.GONE);
|
|
|
|
});
|
|
|
|
|
2022-01-14 13:06:28 +00:00
|
|
|
groupCallViewModel.groupCallHasCapacity().observe(getViewLifecycleOwner(), hasCapacity -> joinGroupCallButton.setText(hasCapacity ? R.string.ConversationActivity_join : R.string.ConversationActivity_full));
|
2020-12-02 18:20:38 +00:00
|
|
|
}
|
|
|
|
|
2021-07-02 13:28:45 +00:00
|
|
|
public void initializeDraftViewModel() {
|
2022-08-05 21:00:11 +00:00
|
|
|
draftViewModel = new ViewModelProvider(this).get(DraftViewModel.class);
|
2021-07-02 13:28:45 +00:00
|
|
|
|
2022-01-14 13:06:28 +00:00
|
|
|
recipient.observe(getViewLifecycleOwner(), r -> {
|
2021-07-02 13:28:45 +00:00
|
|
|
draftViewModel.onRecipientChanged(r);
|
|
|
|
});
|
|
|
|
|
2022-08-05 21:00:11 +00:00
|
|
|
draftViewModel.setThreadId(threadId);
|
|
|
|
draftViewModel.setDistributionType(distributionType);
|
|
|
|
|
|
|
|
disposables.add(
|
|
|
|
draftViewModel
|
|
|
|
.getState()
|
|
|
|
.distinctUntilChanged(state -> state.getVoiceNoteDraft())
|
|
|
|
.subscribe(state -> {
|
|
|
|
inputPanel.setVoiceNoteDraft(state.getVoiceNoteDraft());
|
|
|
|
updateToggleButtonState();
|
|
|
|
})
|
|
|
|
);
|
2021-07-02 13:28:45 +00:00
|
|
|
}
|
|
|
|
|
2020-12-14 22:26:07 +00:00
|
|
|
private void showGroupCallingTooltip() {
|
2021-03-23 15:20:07 +00:00
|
|
|
if (Build.VERSION.SDK_INT == 19 || !SignalStore.tooltips().shouldShowGroupCallingTooltip() || callingTooltipShown) {
|
2020-12-14 22:26:07 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-01-14 13:06:28 +00:00
|
|
|
View anchor = requireView().findViewById(R.id.menu_video_secure);
|
2020-12-14 22:26:07 +00:00
|
|
|
if (anchor == null) {
|
|
|
|
Log.w(TAG, "Video Call tooltip anchor is null. Skipping tooltip...");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
callingTooltipShown = true;
|
|
|
|
|
|
|
|
SignalStore.tooltips().markGroupCallSpeakerViewSeen();
|
|
|
|
TooltipPopup.forTarget(anchor)
|
2022-01-14 13:06:28 +00:00
|
|
|
.setBackgroundTint(ContextCompat.getColor(requireContext(), R.color.signal_accent_green))
|
2020-12-14 22:26:07 +00:00
|
|
|
.setTextColor(getResources().getColor(R.color.core_white))
|
|
|
|
.setText(R.string.ConversationActivity__tap_here_to_start_a_group_call)
|
|
|
|
.setOnDismissListener(() -> SignalStore.tooltips().markGroupCallingTooltipSeen())
|
|
|
|
.show(TooltipPopup.POSITION_BELOW);
|
|
|
|
}
|
|
|
|
|
2019-04-17 14:21:30 +00:00
|
|
|
private void showStickerIntroductionTooltip() {
|
2022-01-14 13:06:28 +00:00
|
|
|
TextSecurePreferences.setMediaKeyboardMode(requireContext(), MediaKeyboardMode.STICKER);
|
2021-05-26 13:47:14 +00:00
|
|
|
inputPanel.setMediaKeyboardToggleMode(KeyboardPage.STICKER);
|
2019-04-17 14:21:30 +00:00
|
|
|
|
|
|
|
TooltipPopup.forTarget(inputPanel.getMediaKeyboardToggleAnchorView())
|
2020-03-04 13:14:21 +00:00
|
|
|
.setBackgroundTint(getResources().getColor(R.color.core_ultramarine))
|
2019-04-17 14:21:30 +00:00
|
|
|
.setTextColor(getResources().getColor(R.color.core_white))
|
|
|
|
.setText(R.string.ConversationActivity_new_say_it_with_stickers)
|
|
|
|
.setOnDismissListener(() -> {
|
2022-01-14 13:06:28 +00:00
|
|
|
TextSecurePreferences.setHasSeenStickerIntroTooltip(requireContext(), true);
|
2019-04-17 14:21:30 +00:00
|
|
|
EventBus.getDefault().removeStickyEvent(StickerPackInstallEvent.class);
|
|
|
|
})
|
|
|
|
.show(TooltipPopup.POSITION_ABOVE);
|
|
|
|
}
|
|
|
|
|
2020-05-05 17:53:57 +00:00
|
|
|
@Override
|
|
|
|
public void onReactionSelected(MessageRecord messageRecord, String emoji) {
|
2022-01-14 13:06:28 +00:00
|
|
|
final Context context = requireContext().getApplicationContext();
|
2019-12-03 21:57:21 +00:00
|
|
|
|
2021-01-27 20:34:59 +00:00
|
|
|
reactionDelegate.hide();
|
2020-05-05 17:53:57 +00:00
|
|
|
|
2019-12-03 21:57:21 +00:00
|
|
|
SignalExecutors.BOUNDED.execute(() -> {
|
|
|
|
ReactionRecord oldRecord = Stream.of(messageRecord.getReactions())
|
|
|
|
.filter(record -> record.getAuthor().equals(Recipient.self().getId()))
|
|
|
|
.findFirst()
|
|
|
|
.orElse(null);
|
|
|
|
|
|
|
|
if (oldRecord != null && oldRecord.getEmoji().equals(emoji)) {
|
2021-11-11 18:12:51 +00:00
|
|
|
MessageSender.sendReactionRemoval(context, new MessageId(messageRecord.getId(), messageRecord.isMms()), oldRecord);
|
2019-12-03 21:57:21 +00:00
|
|
|
} else {
|
2021-11-11 18:12:51 +00:00
|
|
|
MessageSender.sendNewReaction(context, new MessageId(messageRecord.getId(), messageRecord.isMms()), emoji);
|
2019-12-03 21:57:21 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2020-05-05 17:53:57 +00:00
|
|
|
@Override
|
|
|
|
public void onCustomReactionSelected(@NonNull MessageRecord messageRecord, boolean hasAddedCustomEmoji) {
|
|
|
|
ReactionRecord oldRecord = Stream.of(messageRecord.getReactions())
|
|
|
|
.filter(record -> record.getAuthor().equals(Recipient.self().getId()))
|
|
|
|
.findFirst()
|
|
|
|
.orElse(null);
|
|
|
|
|
|
|
|
if (oldRecord != null && hasAddedCustomEmoji) {
|
2022-01-14 13:06:28 +00:00
|
|
|
final Context context = requireContext().getApplicationContext();
|
2020-05-05 17:53:57 +00:00
|
|
|
|
2021-01-27 20:34:59 +00:00
|
|
|
reactionDelegate.hide();
|
2020-05-05 17:53:57 +00:00
|
|
|
|
|
|
|
SignalExecutors.BOUNDED.execute(() -> MessageSender.sendReactionRemoval(context,
|
2021-11-11 18:12:51 +00:00
|
|
|
new MessageId(messageRecord.getId(), messageRecord.isMms()),
|
2020-05-05 17:53:57 +00:00
|
|
|
oldRecord));
|
|
|
|
} else {
|
2021-06-24 19:14:34 +00:00
|
|
|
reactionDelegate.hideForReactWithAny();
|
2020-05-05 17:53:57 +00:00
|
|
|
|
2020-08-21 19:06:47 +00:00
|
|
|
ReactWithAnyEmojiBottomSheetDialogFragment.createForMessageRecord(messageRecord, reactWithAnyEmojiStartPage)
|
2022-01-14 13:06:28 +00:00
|
|
|
.show(getChildFragmentManager(), "BOTTOM");
|
2020-05-05 17:53:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onReactWithAnyEmojiDialogDismissed() {
|
2021-09-29 16:38:34 +00:00
|
|
|
reactionDelegate.hide();
|
2020-05-05 17:53:57 +00:00
|
|
|
}
|
|
|
|
|
2021-01-21 17:35:00 +00:00
|
|
|
@Override
|
|
|
|
public void onReactWithAnyEmojiSelected(@NonNull String emoji) {
|
2021-09-29 16:38:34 +00:00
|
|
|
reactionDelegate.hide();
|
2021-01-21 17:35:00 +00:00
|
|
|
}
|
|
|
|
|
2019-02-01 17:06:59 +00:00
|
|
|
@Override
|
|
|
|
public void onSearchMoveUpPressed() {
|
|
|
|
searchViewModel.onMoveUp();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onSearchMoveDownPressed() {
|
|
|
|
searchViewModel.onMoveDown();
|
|
|
|
}
|
2019-01-15 08:41:05 +00:00
|
|
|
|
2017-05-20 01:01:40 +00:00
|
|
|
private void initializeProfiles() {
|
2022-07-22 13:47:40 +00:00
|
|
|
if (!viewModel.isPushAvailable()) {
|
2018-08-02 13:25:33 +00:00
|
|
|
Log.i(TAG, "SMS contact, no profile fetch needed.");
|
2017-06-14 16:53:22 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-06-08 23:04:55 +00:00
|
|
|
RetrieveProfileJob.enqueueAsync(recipient.getId());
|
2017-05-20 01:01:40 +00:00
|
|
|
}
|
|
|
|
|
2020-10-15 19:49:09 +00:00
|
|
|
private void initializeGv1Migration() {
|
|
|
|
GroupV1MigrationJob.enqueuePossibleAutoMigrate(recipient.getId());
|
|
|
|
}
|
|
|
|
|
2019-08-07 18:22:51 +00:00
|
|
|
private void onRecipientChanged(@NonNull Recipient recipient) {
|
2022-02-03 18:48:52 +00:00
|
|
|
if (getContext() == null) {
|
|
|
|
Log.w(TAG, "onRecipientChanged called in detached state. Ignoring.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-10-01 19:52:28 +00:00
|
|
|
Log.i(TAG, "onModified(" + recipient.getId() + ") " + recipient.getRegistered());
|
2019-08-07 18:22:51 +00:00
|
|
|
titleView.setTitle(glideRequests, recipient);
|
2022-06-23 15:27:05 +00:00
|
|
|
titleView.setVerified(identityRecords.isVerified() && !recipient.isSelf());
|
2022-07-22 13:47:40 +00:00
|
|
|
setBlockedUserState(recipient, viewModel.getConversationStateSnapshot().getSecurityInfo());
|
2019-11-12 14:18:57 +00:00
|
|
|
updateReminders();
|
2019-08-07 18:22:51 +00:00
|
|
|
updateDefaultSubscriptionId(recipient.getDefaultSubscriptionId());
|
2021-04-06 16:03:33 +00:00
|
|
|
updatePaymentsAvailable();
|
2022-06-15 15:19:28 +00:00
|
|
|
updateSendButtonColor(sendButton.getSelectedSendType());
|
2019-02-01 17:06:59 +00:00
|
|
|
|
2019-08-07 18:22:51 +00:00
|
|
|
if (searchViewItem == null || !searchViewItem.isActionViewExpanded()) {
|
|
|
|
invalidateOptionsMenu();
|
|
|
|
}
|
2020-06-06 23:26:21 +00:00
|
|
|
|
|
|
|
if (groupViewModel != null) {
|
|
|
|
groupViewModel.onRecipientChange(recipient);
|
|
|
|
}
|
2020-10-13 14:57:00 +00:00
|
|
|
|
|
|
|
if (mentionsViewModel != null) {
|
|
|
|
mentionsViewModel.onRecipientChange(recipient);
|
|
|
|
}
|
2020-12-02 18:20:38 +00:00
|
|
|
|
|
|
|
if (groupCallViewModel != null) {
|
2021-03-31 18:30:30 +00:00
|
|
|
groupCallViewModel.onRecipientChange(recipient);
|
2020-12-02 18:20:38 +00:00
|
|
|
}
|
2021-05-18 19:19:33 +00:00
|
|
|
|
2021-07-02 13:28:45 +00:00
|
|
|
if (draftViewModel != null) {
|
|
|
|
draftViewModel.onRecipientChanged(recipient);
|
|
|
|
}
|
|
|
|
|
2021-05-18 19:19:33 +00:00
|
|
|
if (this.threadId == -1) {
|
2021-11-18 17:36:52 +00:00
|
|
|
SimpleTask.run(() -> SignalDatabase.threads().getThreadIdIfExistsFor(recipient.getId()), threadId -> {
|
2021-05-18 19:19:33 +00:00
|
|
|
if (this.threadId != threadId) {
|
|
|
|
Log.d(TAG, "Thread id changed via recipient change");
|
|
|
|
this.threadId = threadId;
|
|
|
|
fragment.reload(recipient, this.threadId);
|
|
|
|
setVisibleThread(this.threadId);
|
2022-08-05 21:00:11 +00:00
|
|
|
draftViewModel.setThreadId(this.threadId);
|
2021-05-18 19:19:33 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
2012-07-19 21:22:03 +00:00
|
|
|
}
|
2014-02-16 02:40:08 +00:00
|
|
|
|
2017-06-07 01:03:09 +00:00
|
|
|
@Subscribe(threadMode = ThreadMode.MAIN)
|
|
|
|
public void onIdentityRecordUpdate(final IdentityRecord event) {
|
|
|
|
initializeIdentityRecords();
|
|
|
|
}
|
|
|
|
|
2019-04-17 14:21:30 +00:00
|
|
|
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
|
|
|
|
public void onStickerPackInstalled(final StickerPackInstallEvent event) {
|
2022-01-14 13:06:28 +00:00
|
|
|
if (!TextSecurePreferences.hasSeenStickerIntroTooltip(requireContext())) return;
|
2019-04-17 14:21:30 +00:00
|
|
|
|
|
|
|
EventBus.getDefault().removeStickyEvent(event);
|
2019-12-19 22:59:42 +00:00
|
|
|
|
|
|
|
if (!inputPanel.isStickerMode()) {
|
|
|
|
TooltipPopup.forTarget(inputPanel.getMediaKeyboardToggleAnchorView())
|
|
|
|
.setText(R.string.ConversationActivity_sticker_pack_installed)
|
|
|
|
.setIconGlideModel(event.getIconGlideModel())
|
|
|
|
.show(TooltipPopup.POSITION_ABOVE);
|
|
|
|
}
|
2019-04-17 14:21:30 +00:00
|
|
|
}
|
|
|
|
|
2020-12-02 18:20:38 +00:00
|
|
|
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
|
|
|
|
public void onGroupCallPeekEvent(@NonNull GroupCallPeekEvent event) {
|
|
|
|
if (groupCallViewModel != null) {
|
|
|
|
groupCallViewModel.onGroupCallPeekEvent(event);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-19 21:22:03 +00:00
|
|
|
private void initializeReceivers() {
|
|
|
|
securityUpdateReceiver = new BroadcastReceiver() {
|
|
|
|
@Override
|
|
|
|
public void onReceive(Context context, Intent intent) {
|
2022-07-19 17:53:54 +00:00
|
|
|
viewModel.updateSecurityInfo();
|
2015-09-23 22:47:48 +00:00
|
|
|
calculateCharactersRemaining();
|
2012-07-19 21:22:03 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2022-01-14 13:06:28 +00:00
|
|
|
requireActivity().registerReceiver(securityUpdateReceiver,
|
|
|
|
new IntentFilter(SecurityEvent.SECURITY_UPDATE_EVENT),
|
|
|
|
KeyCachingService.KEY_PERMISSION, null);
|
2012-07-19 21:22:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//////// Helper Methods
|
|
|
|
|
2018-07-25 15:30:48 +00:00
|
|
|
private ListenableFuture<Boolean> setMedia(@Nullable Uri uri, @NonNull MediaType mediaType) {
|
2021-04-14 19:44:03 +00:00
|
|
|
return setMedia(uri, mediaType, 0, 0, false, false);
|
2018-03-20 18:27:11 +00:00
|
|
|
}
|
|
|
|
|
2021-04-14 19:44:03 +00:00
|
|
|
private ListenableFuture<Boolean> setMedia(@Nullable Uri uri, @NonNull MediaType mediaType, int width, int height, boolean borderless, boolean videoGif) {
|
2018-07-25 15:30:48 +00:00
|
|
|
if (uri == null) {
|
|
|
|
return new SettableFuture<>(false);
|
|
|
|
}
|
2018-05-17 06:40:14 +00:00
|
|
|
|
2022-07-22 13:47:40 +00:00
|
|
|
if (MediaType.VCARD.equals(mediaType) && viewModel.isPushAvailable()) {
|
2018-06-29 18:08:13 +00:00
|
|
|
openContactShareEditor(uri);
|
2018-07-25 15:30:48 +00:00
|
|
|
return new SettableFuture<>(false);
|
2022-01-14 13:06:28 +00:00
|
|
|
} else if (MediaType.IMAGE.equals(mediaType) || MediaType.GIF.equals(mediaType) || MediaType.VIDEO.equals(mediaType)) {
|
|
|
|
String mimeType = MediaUtil.getMimeType(requireContext(), uri);
|
2020-07-08 15:54:47 +00:00
|
|
|
if (mimeType == null) {
|
|
|
|
mimeType = mediaType.toFallbackMimeType();
|
|
|
|
}
|
|
|
|
|
2022-03-14 19:49:46 +00:00
|
|
|
Media media = new Media(uri, mimeType, 0, width, height, 0, 0, borderless, videoGif, Optional.empty(), Optional.empty(), Optional.empty());
|
2022-06-03 22:07:29 +00:00
|
|
|
startActivityForResult(MediaSelectionActivity.editor(requireContext(), sendButton.getSelectedSendType(), Collections.singletonList(media), recipient.getId(), composeText.getTextTrimmed()), MEDIA_SENDER);
|
2018-11-20 17:59:23 +00:00
|
|
|
return new SettableFuture<>(false);
|
2018-06-29 18:08:13 +00:00
|
|
|
} else {
|
2018-07-25 15:30:48 +00:00
|
|
|
return attachmentManager.setMedia(glideRequests, uri, mediaType, getCurrentMediaConstraints(), width, height);
|
2018-06-29 18:08:13 +00:00
|
|
|
}
|
2012-07-19 21:22:03 +00:00
|
|
|
}
|
|
|
|
|
2018-04-27 00:03:54 +00:00
|
|
|
private void openContactShareEditor(Uri contactUri) {
|
2022-06-17 16:45:44 +00:00
|
|
|
Intent intent = ContactShareEditActivity.getIntent(requireContext(), Collections.singletonList(contactUri), getSendButtonColor(sendButton.getSelectedSendType()));
|
2018-04-27 00:03:54 +00:00
|
|
|
startActivityForResult(intent, GET_CONTACT_DETAILS);
|
|
|
|
}
|
|
|
|
|
2014-06-03 23:24:44 +00:00
|
|
|
private void addAttachmentContactInfo(Uri contactUri) {
|
2013-10-17 00:28:36 +00:00
|
|
|
ContactAccessor contactDataList = ContactAccessor.getInstance();
|
2022-01-14 13:06:28 +00:00
|
|
|
ContactData contactData = contactDataList.getContactData(requireContext(), contactUri);
|
2013-10-17 00:28:36 +00:00
|
|
|
|
|
|
|
if (contactData.numbers.size() == 1) composeText.append(contactData.numbers.get(0).number);
|
|
|
|
else if (contactData.numbers.size() > 1) selectContactInfo(contactData);
|
|
|
|
}
|
|
|
|
|
2018-04-27 00:03:54 +00:00
|
|
|
private void sendSharedContact(List<Contact> contacts) {
|
2021-07-29 20:24:20 +00:00
|
|
|
long expiresIn = TimeUnit.SECONDS.toMillis(recipient.get().getExpiresInSeconds());
|
2018-04-27 00:03:54 +00:00
|
|
|
boolean initiating = threadId == -1;
|
|
|
|
|
2022-06-21 21:27:57 +00:00
|
|
|
sendMediaMessage(recipient.getId(), sendButton.getSelectedSendType(), "", attachmentManager.buildSlideDeck(), null, contacts, Collections.emptyList(), Collections.emptyList(), expiresIn, false, initiating, false, null);
|
2018-04-27 00:03:54 +00:00
|
|
|
}
|
|
|
|
|
2013-10-17 00:28:36 +00:00
|
|
|
private void selectContactInfo(ContactData contactData) {
|
2014-12-13 02:31:20 +00:00
|
|
|
final CharSequence[] numbers = new CharSequence[contactData.numbers.size()];
|
2013-10-17 00:28:36 +00:00
|
|
|
final CharSequence[] numberItems = new CharSequence[contactData.numbers.size()];
|
2014-12-13 02:31:20 +00:00
|
|
|
|
2013-10-17 00:28:36 +00:00
|
|
|
for (int i = 0; i < contactData.numbers.size(); i++) {
|
2014-12-13 02:31:20 +00:00
|
|
|
numbers[i] = contactData.numbers.get(i).number;
|
2013-10-17 00:28:36 +00:00
|
|
|
numberItems[i] = contactData.numbers.get(i).type + ": " + contactData.numbers.get(i).number;
|
|
|
|
}
|
|
|
|
|
2022-06-23 13:18:16 +00:00
|
|
|
AlertDialog.Builder builder = new MaterialAlertDialogBuilder(requireContext());
|
2020-11-10 15:20:54 +00:00
|
|
|
builder.setIcon(R.drawable.ic_account_box);
|
2013-10-17 00:28:36 +00:00
|
|
|
builder.setTitle(R.string.ConversationActivity_select_contact_info);
|
|
|
|
|
2017-12-05 19:52:03 +00:00
|
|
|
builder.setItems(numberItems, (dialog, which) -> composeText.append(numbers[which]));
|
2013-10-17 00:28:36 +00:00
|
|
|
builder.show();
|
|
|
|
}
|
|
|
|
|
2022-07-22 13:47:40 +00:00
|
|
|
private void setBlockedUserState(Recipient recipient, @NonNull ConversationSecurityInfo conversationSecurityInfo) {
|
|
|
|
if (!conversationSecurityInfo.isInitialized()) {
|
|
|
|
Log.i(TAG, "Ignoring blocked state update for uninitialized security info.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!conversationSecurityInfo.isPushAvailable() && isPushGroupConversation()) {
|
2017-12-25 23:57:33 +00:00
|
|
|
unblockButton.setVisibility(View.GONE);
|
2021-07-23 20:22:08 +00:00
|
|
|
inputPanel.setHideForBlockedState(true);
|
2022-10-13 15:33:13 +00:00
|
|
|
smsExportStub.setVisibility(View.GONE);
|
2017-12-25 23:57:33 +00:00
|
|
|
registerButton.setVisibility(View.VISIBLE);
|
2022-10-17 15:33:16 +00:00
|
|
|
} else if (!conversationSecurityInfo.isPushAvailable() && !(SignalStore.misc().getSmsExportPhase().isSmsSupported() && conversationSecurityInfo.isDefaultSmsApplication()) && (recipient.hasSmsAddress() || recipient.isMmsGroup())) {
|
2016-11-20 23:56:47 +00:00
|
|
|
unblockButton.setVisibility(View.GONE);
|
2021-07-23 20:22:08 +00:00
|
|
|
inputPanel.setHideForBlockedState(true);
|
2022-10-13 15:33:13 +00:00
|
|
|
smsExportStub.setVisibility(View.VISIBLE);
|
2017-12-25 23:57:33 +00:00
|
|
|
registerButton.setVisibility(View.GONE);
|
2022-10-13 15:33:13 +00:00
|
|
|
|
2022-10-18 01:08:48 +00:00
|
|
|
int color = ContextCompat.getColor(requireContext(), recipient.hasWallpaper() ? R.color.wallpaper_bubble_color : R.color.signal_colorBackground);
|
|
|
|
smsExportStub.get().setBackgroundColor(color);
|
|
|
|
WindowUtil.setNavigationBarColor(requireActivity(), color);
|
|
|
|
|
2022-10-13 15:33:13 +00:00
|
|
|
TextView message = smsExportStub.get().findViewById(R.id.export_sms_message);
|
|
|
|
MaterialButton actionButton = smsExportStub.get().findViewById(R.id.export_sms_button);
|
2022-10-18 00:41:35 +00:00
|
|
|
boolean isPhase1 = SignalStore.misc().getSmsExportPhase() == SmsExportPhase.PHASE_1;
|
2022-10-20 19:50:38 +00:00
|
|
|
|
|
|
|
if (SignalStore.misc().getSmsExportPhase() == SmsExportPhase.PHASE_0) {
|
|
|
|
message.setText(getString(R.string.NewConversationActivity__s_is_not_a_signal_user, recipient.getDisplayName(requireContext())));
|
|
|
|
actionButton.setText(R.string.conversation_activity__enable_signal_for_sms);
|
|
|
|
actionButton.setOnClickListener(v -> {
|
|
|
|
handleMakeDefaultSms();
|
|
|
|
});
|
|
|
|
} else if (conversationSecurityInfo.getHasUnexportedInsecureMessages()) {
|
2022-10-18 00:41:35 +00:00
|
|
|
message.setText(isPhase1 ? R.string.ConversationActivity__sms_messaging_is_currently_disabled_you_can_export_your_messages_to_another_app_on_your_phone
|
|
|
|
: R.string.ConversationActivity__sms_messaging_is_no_longer_supported_in_signal_you_can_export_your_messages_to_another_app_on_your_phone);
|
2022-10-13 15:33:13 +00:00
|
|
|
actionButton.setText(R.string.ConversationActivity__export_sms_messages);
|
|
|
|
actionButton.setOnClickListener(v -> startActivity(SmsExportActivity.createIntent(requireContext())));
|
|
|
|
} else {
|
2022-10-18 00:41:35 +00:00
|
|
|
message.setText(requireContext().getString(isPhase1 ? R.string.ConversationActivity__sms_messaging_is_currently_disabled_invite_s_to_to_signal_to_keep_the_conversation_here
|
|
|
|
: R.string.ConversationActivity__sms_messaging_is_no_longer_supported_in_signal_invite_s_to_to_signal_to_keep_the_conversation_here,
|
|
|
|
recipient.getDisplayName(requireContext())));
|
2022-10-13 15:33:13 +00:00
|
|
|
actionButton.setText(R.string.ConversationActivity__invite_to_signal);
|
|
|
|
actionButton.setOnClickListener(v -> handleInviteLink());
|
|
|
|
}
|
2022-01-31 17:46:44 +00:00
|
|
|
} else if (recipient.isReleaseNotes() && !recipient.isBlocked()) {
|
|
|
|
unblockButton.setVisibility(View.GONE);
|
|
|
|
inputPanel.setHideForBlockedState(true);
|
2022-10-13 15:33:13 +00:00
|
|
|
smsExportStub.setVisibility(View.GONE);
|
2022-01-31 17:46:44 +00:00
|
|
|
registerButton.setVisibility(View.GONE);
|
|
|
|
|
|
|
|
if (recipient.isMuted()) {
|
|
|
|
View unmuteBanner = releaseChannelUnmute.get();
|
|
|
|
unmuteBanner.setVisibility(View.VISIBLE);
|
|
|
|
unmuteBanner.findViewById(R.id.conversation_activity_unmute_button)
|
|
|
|
.setOnClickListener(v -> handleUnmuteNotifications());
|
2022-08-08 18:17:28 +00:00
|
|
|
WindowUtil.setNavigationBarColor(requireActivity(), getResources().getColor(R.color.signal_colorSurface2));
|
2022-01-31 17:46:44 +00:00
|
|
|
} else if (releaseChannelUnmute.resolved()) {
|
|
|
|
releaseChannelUnmute.get().setVisibility(View.GONE);
|
2022-08-08 18:17:28 +00:00
|
|
|
WindowUtil.setNavigationBarColor(requireActivity(), getResources().getColor(R.color.signal_colorBackground));
|
2022-01-31 17:46:44 +00:00
|
|
|
}
|
2015-06-09 14:37:20 +00:00
|
|
|
} else {
|
2020-07-17 18:32:53 +00:00
|
|
|
boolean inactivePushGroup = isPushGroupConversation() && !recipient.isActiveGroup();
|
2021-07-23 20:22:08 +00:00
|
|
|
inputPanel.setHideForBlockedState(inactivePushGroup);
|
2015-06-09 14:37:20 +00:00
|
|
|
unblockButton.setVisibility(View.GONE);
|
2022-10-13 15:33:13 +00:00
|
|
|
smsExportStub.setVisibility(View.GONE);
|
2017-12-25 23:57:33 +00:00
|
|
|
registerButton.setVisibility(View.GONE);
|
2015-06-09 14:37:20 +00:00
|
|
|
}
|
2022-01-31 17:46:44 +00:00
|
|
|
|
|
|
|
if (releaseChannelUnmute.resolved() && !recipient.isReleaseNotes()) {
|
|
|
|
releaseChannelUnmute.get().setVisibility(View.GONE);
|
|
|
|
}
|
2015-06-09 14:37:20 +00:00
|
|
|
}
|
|
|
|
|
2012-07-19 21:22:03 +00:00
|
|
|
private void calculateCharactersRemaining() {
|
2020-08-05 20:45:52 +00:00
|
|
|
String messageBody = composeText.getTextTrimmed().toString();
|
2022-06-03 22:07:29 +00:00
|
|
|
MessageSendType sendType = sendButton.getSelectedSendType();
|
|
|
|
CharacterState characterState = sendType.calculateCharacters(messageBody);
|
2015-03-07 17:02:10 +00:00
|
|
|
|
2015-03-11 21:23:45 +00:00
|
|
|
if (characterState.charactersRemaining <= 15 || characterState.messagesSpent > 1) {
|
2022-01-14 13:06:28 +00:00
|
|
|
charactersLeft.setText(String.format(Locale.getDefault(),
|
2017-12-05 19:52:03 +00:00
|
|
|
"%d/%d (%d)",
|
|
|
|
characterState.charactersRemaining,
|
2019-02-27 03:29:52 +00:00
|
|
|
characterState.maxTotalMessageSize,
|
2017-12-05 19:52:03 +00:00
|
|
|
characterState.messagesSpent));
|
2015-03-11 21:23:45 +00:00
|
|
|
charactersLeft.setVisibility(View.VISIBLE);
|
|
|
|
} else {
|
|
|
|
charactersLeft.setVisibility(View.GONE);
|
2014-01-08 22:29:05 +00:00
|
|
|
}
|
2012-07-19 21:22:03 +00:00
|
|
|
}
|
|
|
|
|
2021-05-26 13:47:14 +00:00
|
|
|
private void initializeMediaKeyboardProviders() {
|
2022-01-25 13:47:05 +00:00
|
|
|
KeyboardPagerViewModel keyboardPagerViewModel = new ViewModelProvider(requireActivity()).get(KeyboardPagerViewModel.class);
|
2019-04-17 14:21:30 +00:00
|
|
|
|
2022-01-14 13:06:28 +00:00
|
|
|
switch (TextSecurePreferences.getMediaKeyboardMode(requireContext())) {
|
2021-05-26 13:47:14 +00:00
|
|
|
case EMOJI:
|
|
|
|
keyboardPagerViewModel.switchToPage(KeyboardPage.EMOJI);
|
|
|
|
break;
|
|
|
|
case STICKER:
|
|
|
|
keyboardPagerViewModel.switchToPage(KeyboardPage.STICKER);
|
|
|
|
break;
|
|
|
|
case GIF:
|
|
|
|
keyboardPagerViewModel.switchToPage(KeyboardPage.GIF);
|
|
|
|
break;
|
2019-04-17 14:21:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-19 22:08:34 +00:00
|
|
|
private boolean isInMessageRequest() {
|
|
|
|
return messageRequestBottomView.getVisibility() == View.VISIBLE;
|
|
|
|
}
|
2019-04-17 14:21:30 +00:00
|
|
|
|
2012-08-02 00:39:36 +00:00
|
|
|
private boolean isSingleConversation() {
|
2019-08-07 18:22:51 +00:00
|
|
|
return getRecipient() != null && !getRecipient().isGroup();
|
2012-10-21 21:34:09 +00:00
|
|
|
}
|
|
|
|
|
2014-02-22 18:54:43 +00:00
|
|
|
private boolean isActiveGroup() {
|
|
|
|
if (!isGroupConversation()) return false;
|
|
|
|
|
2021-11-18 17:36:52 +00:00
|
|
|
Optional<GroupRecord> record = SignalDatabase.groups().getGroup(getRecipient().getId());
|
2017-08-07 23:47:38 +00:00
|
|
|
return record.isPresent() && record.get().isActive();
|
2014-02-22 18:54:43 +00:00
|
|
|
}
|
|
|
|
|
2012-10-21 21:34:09 +00:00
|
|
|
private boolean isGroupConversation() {
|
2019-08-07 18:22:51 +00:00
|
|
|
return getRecipient() != null && getRecipient().isGroup();
|
2012-07-19 21:22:03 +00:00
|
|
|
}
|
|
|
|
|
2014-02-18 04:25:40 +00:00
|
|
|
private boolean isPushGroupConversation() {
|
2019-08-07 18:22:51 +00:00
|
|
|
return getRecipient() != null && getRecipient().isPushGroup();
|
2014-02-18 04:25:40 +00:00
|
|
|
}
|
|
|
|
|
2020-05-12 18:09:47 +00:00
|
|
|
private boolean isPushGroupV1Conversation() {
|
|
|
|
return getRecipient() != null && getRecipient().isPushV1Group();
|
|
|
|
}
|
|
|
|
|
2018-04-27 00:03:54 +00:00
|
|
|
private boolean isSmsForced() {
|
2022-06-03 22:07:29 +00:00
|
|
|
return sendButton.isManualSelection() && sendButton.getSelectedSendType().usesSmsTransport();
|
2018-04-27 00:03:54 +00:00
|
|
|
}
|
|
|
|
|
2017-08-01 15:56:00 +00:00
|
|
|
protected Recipient getRecipient() {
|
2019-08-07 18:22:51 +00:00
|
|
|
return this.recipient.get();
|
2012-07-19 21:22:03 +00:00
|
|
|
}
|
|
|
|
|
2015-06-22 15:46:43 +00:00
|
|
|
protected long getThreadId() {
|
|
|
|
return this.threadId;
|
|
|
|
}
|
|
|
|
|
2012-07-19 21:22:03 +00:00
|
|
|
private String getMessage() throws InvalidMessageException {
|
2020-08-05 20:45:52 +00:00
|
|
|
String rawText = composeText.getTextTrimmed().toString();
|
2012-07-19 21:22:03 +00:00
|
|
|
|
|
|
|
if (rawText.length() < 1 && !attachmentManager.isAttachmentPresent())
|
2012-09-20 02:56:04 +00:00
|
|
|
throw new InvalidMessageException(getString(R.string.ConversationActivity_message_is_empty_exclamation));
|
2012-07-19 21:22:03 +00:00
|
|
|
|
|
|
|
return rawText;
|
|
|
|
}
|
|
|
|
|
2015-09-05 00:33:22 +00:00
|
|
|
private MediaConstraints getCurrentMediaConstraints() {
|
2022-06-03 22:07:29 +00:00
|
|
|
return sendButton.getSelectedSendType().usesSignalTransport()
|
2017-05-08 22:32:59 +00:00
|
|
|
? MediaConstraints.getPushMediaConstraints()
|
2022-06-03 22:07:29 +00:00
|
|
|
: MediaConstraints.getMmsMediaConstraints(sendButton.getSelectedSendType().getSimSubscriptionIdOr(-1));
|
2015-09-05 00:33:22 +00:00
|
|
|
}
|
|
|
|
|
2017-02-14 06:35:47 +00:00
|
|
|
private void markLastSeen() {
|
|
|
|
new AsyncTask<Long, Void, Void>() {
|
|
|
|
@Override
|
|
|
|
protected Void doInBackground(Long... params) {
|
2021-11-18 17:36:52 +00:00
|
|
|
SignalDatabase.threads().setLastSeen(params[0]);
|
2017-02-14 06:35:47 +00:00
|
|
|
return null;
|
|
|
|
}
|
2017-10-23 20:03:32 +00:00
|
|
|
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, threadId);
|
2017-02-14 06:35:47 +00:00
|
|
|
}
|
|
|
|
|
2015-06-22 15:46:43 +00:00
|
|
|
protected void sendComplete(long threadId) {
|
2014-11-08 19:35:58 +00:00
|
|
|
boolean refreshFragment = (threadId != this.threadId);
|
|
|
|
this.threadId = threadId;
|
2012-07-19 21:22:03 +00:00
|
|
|
|
2022-01-14 13:06:28 +00:00
|
|
|
if (fragment == null || !fragment.isVisible() || requireActivity().isFinishing()) {
|
|
|
|
callback.onSendComplete(threadId);
|
2014-11-25 06:48:50 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-02-14 06:35:47 +00:00
|
|
|
fragment.setLastSeen(0);
|
|
|
|
|
2014-02-17 23:47:58 +00:00
|
|
|
if (refreshFragment) {
|
2019-08-07 18:22:51 +00:00
|
|
|
fragment.reload(recipient.get(), threadId);
|
2020-11-25 18:11:17 +00:00
|
|
|
setVisibleThread(threadId);
|
2012-07-19 21:22:03 +00:00
|
|
|
}
|
2014-11-08 19:35:58 +00:00
|
|
|
|
2014-03-26 22:11:56 +00:00
|
|
|
fragment.scrollToBottom();
|
2015-05-18 17:26:32 +00:00
|
|
|
attachmentManager.cleanup();
|
2019-01-15 08:41:05 +00:00
|
|
|
|
|
|
|
updateLinkPreviewState();
|
2022-01-14 13:06:28 +00:00
|
|
|
callback.onSendComplete(threadId);
|
2022-08-05 21:00:11 +00:00
|
|
|
|
|
|
|
draftViewModel.onSendComplete(threadId);
|
2012-07-19 21:22:03 +00:00
|
|
|
}
|
|
|
|
|
2021-08-23 14:05:48 +00:00
|
|
|
private void sendMessage(@Nullable String metricId) {
|
2019-03-28 18:04:38 +00:00
|
|
|
if (inputPanel.isRecordingInLockedMode()) {
|
|
|
|
inputPanel.releaseRecordingLock();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-07-02 13:28:45 +00:00
|
|
|
Draft voiceNote = draftViewModel.getVoiceNoteDraft();
|
|
|
|
if (voiceNote != null) {
|
2022-01-14 13:06:28 +00:00
|
|
|
AudioSlide audioSlide = AudioSlide.createFromVoiceNoteDraft(requireContext(), voiceNote);
|
2021-07-02 13:28:45 +00:00
|
|
|
|
|
|
|
sendVoiceNote(Objects.requireNonNull(audioSlide.getUri()), audioSlide.getFileSize());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-07-19 21:22:03 +00:00
|
|
|
try {
|
2017-08-01 15:56:00 +00:00
|
|
|
Recipient recipient = getRecipient();
|
2016-11-28 17:14:44 +00:00
|
|
|
|
2017-08-01 15:56:00 +00:00
|
|
|
if (recipient == null) {
|
2016-11-28 17:14:44 +00:00
|
|
|
throw new RecipientFormattingException("Badly formatted");
|
|
|
|
}
|
|
|
|
|
2019-03-06 16:12:00 +00:00
|
|
|
String message = getMessage();
|
2022-06-03 22:07:29 +00:00
|
|
|
MessageSendType sendType = sendButton.getSelectedSendType();
|
2021-07-29 20:24:20 +00:00
|
|
|
long expiresIn = TimeUnit.SECONDS.toMillis(recipient.getExpiresInSeconds());
|
2019-03-06 16:12:00 +00:00
|
|
|
boolean initiating = threadId == -1;
|
2022-06-03 22:07:29 +00:00
|
|
|
boolean needsSplit = !sendType.usesSmsTransport() && message.length() > sendType.calculateCharacters(message).maxPrimaryMessageSize;
|
2019-03-06 16:12:00 +00:00
|
|
|
boolean isMediaMessage = attachmentManager.isAttachmentPresent() ||
|
2019-09-07 03:40:06 +00:00
|
|
|
recipient.isGroup() ||
|
|
|
|
recipient.getEmail().isPresent() ||
|
2019-03-06 16:12:00 +00:00
|
|
|
inputPanel.getQuote().isPresent() ||
|
2020-08-05 20:45:52 +00:00
|
|
|
composeText.hasMentions() ||
|
2019-03-06 16:12:00 +00:00
|
|
|
linkPreviewViewModel.hasLinkPreview() ||
|
|
|
|
needsSplit;
|
2015-03-11 21:23:45 +00:00
|
|
|
|
2022-06-21 21:27:57 +00:00
|
|
|
Log.i(TAG, "[sendMessage] recipient: " + recipient.getId() + ", threadId: " + threadId + ", sendType: " + (sendType.usesSignalTransport() ? "signal" : "sms") + ", isManual: " + sendButton.isManualSelection());
|
2012-08-02 00:39:36 +00:00
|
|
|
|
2022-07-19 17:53:54 +00:00
|
|
|
if ((recipient.isMmsGroup() || recipient.getEmail().isPresent()) && !viewModel.getConversationStateSnapshot().isMmsEnabled()) {
|
2013-09-16 07:55:01 +00:00
|
|
|
handleManualMmsRequired();
|
2022-06-21 21:27:57 +00:00
|
|
|
} else if (sendType.usesSignalTransport() && (identityRecords.isUnverified(true) || identityRecords.isUntrusted(true))) {
|
2020-06-26 15:10:54 +00:00
|
|
|
handleRecentSafetyNumberChange();
|
2019-01-15 08:41:05 +00:00
|
|
|
} else if (isMediaMessage) {
|
2022-06-21 21:27:57 +00:00
|
|
|
sendMediaMessage(sendType, expiresIn, false, initiating, metricId);
|
2012-07-19 21:22:03 +00:00
|
|
|
} else {
|
2022-06-21 21:27:57 +00:00
|
|
|
sendTextMessage(sendType, expiresIn, initiating, metricId);
|
2012-07-19 21:22:03 +00:00
|
|
|
}
|
|
|
|
} catch (RecipientFormattingException ex) {
|
2022-01-14 13:06:28 +00:00
|
|
|
Toast.makeText(requireContext(),
|
2012-09-20 02:56:04 +00:00
|
|
|
R.string.ConversationActivity_recipient_is_not_a_valid_sms_or_email_address_exclamation,
|
2012-09-08 03:03:23 +00:00
|
|
|
Toast.LENGTH_LONG).show();
|
2014-02-18 04:25:40 +00:00
|
|
|
Log.w(TAG, ex);
|
2012-07-19 21:22:03 +00:00
|
|
|
} catch (InvalidMessageException ex) {
|
2022-01-14 13:06:28 +00:00
|
|
|
Toast.makeText(requireContext(), R.string.ConversationActivity_message_is_empty_exclamation,
|
2012-09-08 03:03:23 +00:00
|
|
|
Toast.LENGTH_SHORT).show();
|
2014-02-18 04:25:40 +00:00
|
|
|
Log.w(TAG, ex);
|
2012-07-19 21:22:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-08 20:56:51 +00:00
|
|
|
private void sendMediaMessage(@NonNull MediaSendActivityResult result) {
|
2022-12-09 14:48:16 +00:00
|
|
|
long thread = this.threadId;
|
|
|
|
long expiresIn = TimeUnit.SECONDS.toMillis(recipient.get().getExpiresInSeconds());
|
|
|
|
QuoteModel quote = result.isViewOnce() ? null : inputPanel.getQuote().orElse(null);
|
|
|
|
List<Mention> mentions = new ArrayList<>(result.getMentions());
|
|
|
|
OutgoingMediaMessage message = new OutgoingMediaMessage(recipient.get(),
|
|
|
|
result.getBody(),
|
|
|
|
Collections.emptyList(),
|
|
|
|
System.currentTimeMillis(),
|
|
|
|
-1,
|
|
|
|
expiresIn,
|
|
|
|
result.isViewOnce(),
|
|
|
|
distributionType,
|
|
|
|
result.getStoryType(),
|
|
|
|
null,
|
|
|
|
false,
|
|
|
|
quote,
|
|
|
|
Collections.emptyList(),
|
|
|
|
Collections.emptyList(),
|
|
|
|
mentions,
|
|
|
|
Collections.emptySet(),
|
|
|
|
Collections.emptySet(),
|
|
|
|
null,
|
|
|
|
true);
|
2020-01-08 20:56:51 +00:00
|
|
|
|
2022-01-14 13:06:28 +00:00
|
|
|
final Context context = requireContext().getApplicationContext();
|
|
|
|
|
2021-01-15 17:15:07 +00:00
|
|
|
ApplicationDependencies.getTypingStatusSender().onTypingStopped(thread);
|
2020-01-08 20:56:51 +00:00
|
|
|
|
|
|
|
inputPanel.clearQuote();
|
|
|
|
attachmentManager.clear(glideRequests, false);
|
|
|
|
silentlySetComposeText("");
|
|
|
|
|
2022-12-09 14:48:16 +00:00
|
|
|
long id = fragment.stageOutgoingMessage(message);
|
2020-01-08 20:56:51 +00:00
|
|
|
|
|
|
|
SimpleTask.run(() -> {
|
2022-12-09 14:48:16 +00:00
|
|
|
long resultId = MessageSender.sendPushWithPreUploadedMedia(context, message, result.getPreUploadResults(), thread, null);
|
2020-01-08 20:56:51 +00:00
|
|
|
|
2021-11-18 17:36:52 +00:00
|
|
|
int deleted = SignalDatabase.attachments().deleteAbandonedPreuploadedAttachments();
|
2020-01-08 20:56:51 +00:00
|
|
|
Log.i(TAG, "Deleted " + deleted + " abandoned attachments.");
|
|
|
|
|
|
|
|
return resultId;
|
|
|
|
}, this::sendComplete);
|
|
|
|
}
|
|
|
|
|
2022-06-21 21:27:57 +00:00
|
|
|
private void sendMediaMessage(@NonNull MessageSendType sendType, final long expiresIn, final boolean viewOnce, final boolean initiating, @Nullable String metricId)
|
2014-11-08 19:35:58 +00:00
|
|
|
throws InvalidMessageException
|
2014-06-11 22:31:59 +00:00
|
|
|
{
|
2018-08-02 13:25:33 +00:00
|
|
|
Log.i(TAG, "Sending media message...");
|
2021-08-05 21:45:14 +00:00
|
|
|
List<LinkPreview> linkPreviews = linkPreviewViewModel.onSend();
|
2021-02-25 17:19:58 +00:00
|
|
|
sendMediaMessage(recipient.getId(),
|
2022-06-21 21:27:57 +00:00
|
|
|
sendType,
|
2020-08-05 20:45:52 +00:00
|
|
|
getMessage(),
|
|
|
|
attachmentManager.buildSlideDeck(),
|
2022-03-14 19:49:46 +00:00
|
|
|
inputPanel.getQuote().orElse(null),
|
2020-08-05 20:45:52 +00:00
|
|
|
Collections.emptyList(),
|
2021-08-05 21:45:14 +00:00
|
|
|
linkPreviews,
|
2020-08-05 20:45:52 +00:00
|
|
|
composeText.getMentions(),
|
|
|
|
expiresIn,
|
|
|
|
viewOnce,
|
|
|
|
initiating,
|
2021-08-23 14:05:48 +00:00
|
|
|
true,
|
|
|
|
metricId);
|
2015-11-18 22:52:26 +00:00
|
|
|
}
|
|
|
|
|
2021-02-25 17:19:58 +00:00
|
|
|
private ListenableFuture<Void> sendMediaMessage(@NonNull RecipientId recipientId,
|
2022-06-21 21:27:57 +00:00
|
|
|
@NonNull MessageSendType sendType,
|
2020-07-08 15:54:47 +00:00
|
|
|
@NonNull String body,
|
2019-01-15 08:41:05 +00:00
|
|
|
SlideDeck slideDeck,
|
2019-04-17 14:21:30 +00:00
|
|
|
QuoteModel quote,
|
2019-01-15 08:41:05 +00:00
|
|
|
List<Contact> contacts,
|
|
|
|
List<LinkPreview> previews,
|
2020-08-05 20:45:52 +00:00
|
|
|
List<Mention> mentions,
|
2019-01-15 08:41:05 +00:00
|
|
|
final long expiresIn,
|
2019-07-31 23:33:56 +00:00
|
|
|
final boolean viewOnce,
|
2019-04-17 14:21:30 +00:00
|
|
|
final boolean initiating,
|
2021-08-23 14:05:48 +00:00
|
|
|
final boolean clearComposeBox,
|
|
|
|
final @Nullable String metricId)
|
2019-01-15 08:41:05 +00:00
|
|
|
{
|
2022-07-22 13:47:40 +00:00
|
|
|
if (!viewModel.isDefaultSmsApplication() && sendType.usesSmsTransport() && recipient.get().hasSmsAddress()) {
|
2018-12-13 02:15:09 +00:00
|
|
|
showDefaultSmsPrompt();
|
2018-11-20 17:59:23 +00:00
|
|
|
return new SettableFuture<>(null);
|
2018-12-13 02:15:09 +00:00
|
|
|
}
|
|
|
|
|
2022-06-21 21:27:57 +00:00
|
|
|
final boolean sendPush = sendType.usesSignalTransport();
|
2021-05-03 17:45:53 +00:00
|
|
|
final long thread = this.threadId;
|
2021-01-15 17:15:07 +00:00
|
|
|
|
2021-05-03 17:45:53 +00:00
|
|
|
if (sendPush) {
|
2022-06-03 22:07:29 +00:00
|
|
|
MessageUtil.SplitResult splitMessage = MessageUtil.getSplitMessage(requireContext(), body, sendButton.getSelectedSendType().calculateCharacters(body).maxPrimaryMessageSize);
|
2020-01-08 20:56:51 +00:00
|
|
|
body = splitMessage.getBody();
|
2019-02-27 03:29:52 +00:00
|
|
|
|
2020-01-08 20:56:51 +00:00
|
|
|
if (splitMessage.getTextSlide().isPresent()) {
|
|
|
|
slideDeck.addSlide(splitMessage.getTextSlide().get());
|
2019-02-27 03:29:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-09 14:48:16 +00:00
|
|
|
OutgoingMediaMessage outgoingMessageCandidate = new OutgoingMediaMessage(Recipient.resolved(recipientId),
|
|
|
|
OutgoingMediaMessage.buildMessage(slideDeck, body),
|
|
|
|
slideDeck.asAttachments(),
|
|
|
|
System.currentTimeMillis(),
|
|
|
|
sendType.getSimSubscriptionIdOr(-1),
|
|
|
|
expiresIn,
|
|
|
|
viewOnce,
|
|
|
|
distributionType,
|
|
|
|
StoryType.NONE,
|
|
|
|
null,
|
|
|
|
false,
|
|
|
|
quote,
|
|
|
|
contacts,
|
|
|
|
previews,
|
|
|
|
mentions,
|
|
|
|
Collections.emptySet(),
|
|
|
|
Collections.emptySet(),
|
|
|
|
null,
|
|
|
|
false);
|
2014-06-11 22:31:59 +00:00
|
|
|
|
2017-12-05 19:35:15 +00:00
|
|
|
final SettableFuture<Void> future = new SettableFuture<>();
|
2022-01-14 13:06:28 +00:00
|
|
|
final Context context = requireContext().getApplicationContext();
|
2014-11-08 19:35:58 +00:00
|
|
|
|
2017-12-05 19:35:15 +00:00
|
|
|
final OutgoingMediaMessage outgoingMessage;
|
2017-08-17 04:49:41 +00:00
|
|
|
|
2021-05-03 17:45:53 +00:00
|
|
|
if (sendPush) {
|
2022-12-09 14:48:16 +00:00
|
|
|
outgoingMessage = outgoingMessageCandidate.makeSecure();
|
2021-01-15 17:15:07 +00:00
|
|
|
ApplicationDependencies.getTypingStatusSender().onTypingStopped(thread);
|
2017-12-05 19:35:15 +00:00
|
|
|
} else {
|
2022-07-12 13:37:30 +00:00
|
|
|
outgoingMessage = outgoingMessageCandidate.withExpiry(0);
|
2017-12-05 19:35:15 +00:00
|
|
|
}
|
2014-11-08 19:35:58 +00:00
|
|
|
|
2017-12-05 19:35:15 +00:00
|
|
|
Permissions.with(this)
|
2017-12-20 19:21:00 +00:00
|
|
|
.request(Manifest.permission.SEND_SMS, Manifest.permission.READ_SMS)
|
2021-05-03 17:45:53 +00:00
|
|
|
.ifNecessary(!sendPush)
|
2017-12-05 19:35:15 +00:00
|
|
|
.withPermanentDenialDialog(getString(R.string.ConversationActivity_signal_needs_sms_permission_in_order_to_send_an_sms))
|
|
|
|
.onAllGranted(() -> {
|
2019-04-17 14:21:30 +00:00
|
|
|
if (clearComposeBox) {
|
|
|
|
inputPanel.clearQuote();
|
|
|
|
attachmentManager.clear(glideRequests, false);
|
|
|
|
silentlySetComposeText("");
|
|
|
|
}
|
|
|
|
|
2017-12-05 19:35:15 +00:00
|
|
|
final long id = fragment.stageOutgoingMessage(outgoingMessage);
|
|
|
|
|
2020-01-08 20:56:51 +00:00
|
|
|
SimpleTask.run(() -> {
|
2022-06-21 21:27:57 +00:00
|
|
|
return MessageSender.send(context, outgoingMessage, thread, sendType.usesSmsTransport(), metricId, null);
|
2020-01-08 20:56:51 +00:00
|
|
|
}, result -> {
|
|
|
|
sendComplete(result);
|
|
|
|
future.set(null);
|
|
|
|
});
|
2017-12-05 19:35:15 +00:00
|
|
|
})
|
|
|
|
.onAnyDenied(() -> future.set(null))
|
|
|
|
.execute();
|
2015-11-18 22:52:26 +00:00
|
|
|
|
|
|
|
return future;
|
2014-06-11 22:31:59 +00:00
|
|
|
}
|
|
|
|
|
2022-06-21 21:27:57 +00:00
|
|
|
private void sendTextMessage(@NonNull MessageSendType sendType, final long expiresIn, final boolean initiating, final @Nullable String metricId)
|
2014-06-11 22:31:59 +00:00
|
|
|
throws InvalidMessageException
|
|
|
|
{
|
2022-07-22 13:47:40 +00:00
|
|
|
if (!viewModel.isDefaultSmsApplication() && sendType.usesSmsTransport() && recipient.get().hasSmsAddress()) {
|
2018-12-13 02:15:09 +00:00
|
|
|
showDefaultSmsPrompt();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-01-15 17:15:07 +00:00
|
|
|
final long thread = this.threadId;
|
2022-01-14 13:06:28 +00:00
|
|
|
final Context context = requireContext().getApplicationContext();
|
2017-12-05 19:35:15 +00:00
|
|
|
final String messageBody = getMessage();
|
2022-06-21 21:27:57 +00:00
|
|
|
final boolean sendPush = sendType.usesSignalTransport();
|
2017-12-05 19:35:15 +00:00
|
|
|
|
2014-06-11 22:31:59 +00:00
|
|
|
OutgoingTextMessage message;
|
|
|
|
|
2021-05-03 17:45:53 +00:00
|
|
|
if (sendPush) {
|
2019-08-07 18:22:51 +00:00
|
|
|
message = new OutgoingEncryptedMessage(recipient.get(), messageBody, expiresIn);
|
2021-01-15 17:15:07 +00:00
|
|
|
ApplicationDependencies.getTypingStatusSender().onTypingStopped(thread);
|
2014-06-11 22:31:59 +00:00
|
|
|
} else {
|
2022-07-12 13:37:30 +00:00
|
|
|
message = new OutgoingTextMessage(recipient.get(), messageBody, 0, sendType.getSimSubscriptionIdOr(-1));
|
2014-06-11 22:31:59 +00:00
|
|
|
}
|
|
|
|
|
2017-12-05 19:35:15 +00:00
|
|
|
Permissions.with(this)
|
|
|
|
.request(Manifest.permission.SEND_SMS)
|
2021-05-03 17:45:53 +00:00
|
|
|
.ifNecessary(!sendPush)
|
2017-12-05 19:35:15 +00:00
|
|
|
.withPermanentDenialDialog(getString(R.string.ConversationActivity_signal_needs_sms_permission_in_order_to_send_an_sms))
|
|
|
|
.onAllGranted(() -> {
|
2021-07-29 18:07:39 +00:00
|
|
|
final long id = new SecureRandom().nextLong();
|
2021-03-08 20:27:10 +00:00
|
|
|
SimpleTask.run(() -> {
|
2022-06-21 21:27:57 +00:00
|
|
|
return MessageSender.send(context, message, thread, sendType.usesSmsTransport(), metricId, null);
|
2021-03-08 20:27:10 +00:00
|
|
|
}, this::sendComplete);
|
2021-07-29 18:07:39 +00:00
|
|
|
|
|
|
|
silentlySetComposeText("");
|
|
|
|
fragment.stageOutgoingMessage(message, id);
|
2017-12-05 19:35:15 +00:00
|
|
|
})
|
|
|
|
.execute();
|
2014-06-11 22:31:59 +00:00
|
|
|
}
|
|
|
|
|
2018-12-13 02:15:09 +00:00
|
|
|
private void showDefaultSmsPrompt() {
|
2022-06-23 13:18:16 +00:00
|
|
|
new MaterialAlertDialogBuilder(requireContext())
|
2018-12-13 02:15:09 +00:00
|
|
|
.setMessage(R.string.ConversationActivity_signal_cannot_sent_sms_mms_messages_because_it_is_not_your_default_sms_app)
|
|
|
|
.setNegativeButton(R.string.ConversationActivity_no, (dialog, which) -> dialog.dismiss())
|
|
|
|
.setPositiveButton(R.string.ConversationActivity_yes, (dialog, which) -> handleMakeDefaultSms())
|
|
|
|
.show();
|
|
|
|
}
|
|
|
|
|
2015-05-18 17:26:32 +00:00
|
|
|
private void updateToggleButtonState() {
|
2019-03-28 18:04:38 +00:00
|
|
|
if (inputPanel.isRecordingInLockedMode()) {
|
|
|
|
buttonToggle.display(sendButton);
|
|
|
|
quickAttachmentToggle.show();
|
|
|
|
inlineAttachmentToggle.hide();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-08-05 21:00:11 +00:00
|
|
|
if (draftViewModel.getVoiceNoteDraft() != null) {
|
2021-07-02 13:28:45 +00:00
|
|
|
buttonToggle.display(sendButton);
|
|
|
|
quickAttachmentToggle.hide();
|
|
|
|
inlineAttachmentToggle.hide();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-11-20 00:53:12 +00:00
|
|
|
if (composeText.getText().length() == 0 && !attachmentManager.isAttachmentPresent()) {
|
2015-05-18 17:26:32 +00:00
|
|
|
buttonToggle.display(attachButton);
|
2015-06-08 18:07:46 +00:00
|
|
|
quickAttachmentToggle.show();
|
2018-08-10 16:18:02 +00:00
|
|
|
inlineAttachmentToggle.hide();
|
2015-05-18 17:26:32 +00:00
|
|
|
} else {
|
|
|
|
buttonToggle.display(sendButton);
|
2015-06-08 18:07:46 +00:00
|
|
|
quickAttachmentToggle.hide();
|
2018-08-15 19:35:41 +00:00
|
|
|
|
2020-08-13 17:50:38 +00:00
|
|
|
if (!attachmentManager.isAttachmentPresent() && !linkPreviewViewModel.hasLinkPreviewUi()) {
|
2018-08-15 19:35:41 +00:00
|
|
|
inlineAttachmentToggle.show();
|
|
|
|
} else {
|
|
|
|
inlineAttachmentToggle.hide();
|
|
|
|
}
|
2015-05-18 17:26:32 +00:00
|
|
|
}
|
|
|
|
}
|
2014-06-11 22:31:59 +00:00
|
|
|
|
2021-05-05 16:49:18 +00:00
|
|
|
private void onViewModelEvent(@NonNull ConversationViewModel.Event event) {
|
|
|
|
if (event == ConversationViewModel.Event.SHOW_RECAPTCHA) {
|
2022-01-14 13:06:28 +00:00
|
|
|
RecaptchaProofBottomSheetFragment.show(getChildFragmentManager());
|
2021-05-05 16:49:18 +00:00
|
|
|
} else {
|
|
|
|
throw new AssertionError("Unexpected event!");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-15 08:41:05 +00:00
|
|
|
private void updateLinkPreviewState() {
|
2022-07-22 13:47:40 +00:00
|
|
|
if (SignalStore.settings().isLinkPreviewsEnabled() && viewModel.isPushAvailable() && !sendButton.getSelectedSendType().usesSmsTransport() && !attachmentManager.isAttachmentPresent() && getContext() != null) {
|
2019-01-15 08:41:05 +00:00
|
|
|
linkPreviewViewModel.onEnabled();
|
2022-01-14 13:06:28 +00:00
|
|
|
linkPreviewViewModel.onTextChanged(requireContext(), composeText.getTextTrimmed().toString(), composeText.getSelectionStart(), composeText.getSelectionEnd());
|
2019-01-15 08:41:05 +00:00
|
|
|
} else {
|
|
|
|
linkPreviewViewModel.onUserCancel();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-03 22:07:29 +00:00
|
|
|
private void recordTransportPreference(MessageSendType sendType) {
|
2016-02-06 00:10:33 +00:00
|
|
|
new AsyncTask<Void, Void, Void>() {
|
|
|
|
@Override
|
|
|
|
protected Void doInBackground(Void... params) {
|
2022-11-29 15:47:12 +00:00
|
|
|
RecipientTable recipientTable = SignalDatabase.recipients();
|
2019-04-12 19:22:38 +00:00
|
|
|
|
2022-11-29 15:47:12 +00:00
|
|
|
recipientTable.setDefaultSubscriptionId(recipient.getId(), sendType.getSimSubscriptionIdOr(-1));
|
2019-04-12 19:22:38 +00:00
|
|
|
|
2019-08-07 18:22:51 +00:00
|
|
|
if (!recipient.resolve().isPushGroup()) {
|
2022-11-29 15:47:12 +00:00
|
|
|
recipientTable.setForceSmsSelection(recipient.getId(), recipient.get().getRegistered() == RegisteredState.REGISTERED && sendType.usesSmsTransport());
|
2019-05-10 15:13:59 +00:00
|
|
|
}
|
2019-04-12 19:22:38 +00:00
|
|
|
|
2016-02-06 00:10:33 +00:00
|
|
|
return null;
|
|
|
|
}
|
2017-10-23 20:03:32 +00:00
|
|
|
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
2016-02-06 00:10:33 +00:00
|
|
|
}
|
|
|
|
|
2017-11-25 06:00:30 +00:00
|
|
|
@Override
|
|
|
|
public void onRecorderPermissionRequired() {
|
|
|
|
Permissions.with(this)
|
|
|
|
.request(Manifest.permission.RECORD_AUDIO)
|
|
|
|
.ifNecessary()
|
2019-10-07 18:43:36 +00:00
|
|
|
.withRationaleDialog(getString(R.string.ConversationActivity_to_send_audio_messages_allow_signal_access_to_your_microphone), R.drawable.ic_mic_solid_24)
|
2017-11-25 06:00:30 +00:00
|
|
|
.withPermanentDenialDialog(getString(R.string.ConversationActivity_signal_requires_the_microphone_permission_in_order_to_send_audio_messages))
|
|
|
|
.execute();
|
|
|
|
}
|
|
|
|
|
2015-11-18 22:52:26 +00:00
|
|
|
@Override
|
|
|
|
public void onRecorderStarted() {
|
2022-01-14 13:06:28 +00:00
|
|
|
Vibrator vibrator = ServiceUtil.getVibrator(requireContext());
|
2015-11-22 18:44:44 +00:00
|
|
|
vibrator.vibrate(20);
|
2017-12-05 19:52:03 +00:00
|
|
|
|
2022-01-14 13:06:28 +00:00
|
|
|
requireActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
|
|
|
requireActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LOCKED);
|
2015-11-18 22:52:26 +00:00
|
|
|
|
2022-04-29 13:46:06 +00:00
|
|
|
voiceNoteMediaController.pausePlayback();
|
2015-11-22 18:44:44 +00:00
|
|
|
audioRecorder.startRecording();
|
2015-11-18 22:52:26 +00:00
|
|
|
}
|
|
|
|
|
2019-03-28 18:04:38 +00:00
|
|
|
@Override
|
|
|
|
public void onRecorderLocked() {
|
2021-06-07 19:55:26 +00:00
|
|
|
voiceRecorderWakeLock.acquire();
|
2019-03-28 18:04:38 +00:00
|
|
|
updateToggleButtonState();
|
2022-01-14 13:06:28 +00:00
|
|
|
requireActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
|
2019-03-28 18:04:38 +00:00
|
|
|
}
|
|
|
|
|
2015-11-18 22:52:26 +00:00
|
|
|
@Override
|
|
|
|
public void onRecorderFinished() {
|
2021-06-07 19:55:26 +00:00
|
|
|
voiceRecorderWakeLock.release();
|
2019-03-28 18:04:38 +00:00
|
|
|
updateToggleButtonState();
|
2022-01-14 13:06:28 +00:00
|
|
|
Vibrator vibrator = ServiceUtil.getVibrator(requireContext());
|
2015-11-18 22:52:26 +00:00
|
|
|
vibrator.vibrate(20);
|
2017-12-05 19:52:03 +00:00
|
|
|
|
2022-01-14 13:06:28 +00:00
|
|
|
requireActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
|
|
|
requireActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
|
2015-11-18 22:52:26 +00:00
|
|
|
|
2021-07-02 13:28:45 +00:00
|
|
|
ListenableFuture<VoiceNoteDraft> future = audioRecorder.stopRecording();
|
|
|
|
future.addListener(new ListenableFuture.Listener<VoiceNoteDraft>() {
|
2015-11-18 22:52:26 +00:00
|
|
|
@Override
|
2021-07-02 13:28:45 +00:00
|
|
|
public void onSuccess(final @NonNull VoiceNoteDraft result) {
|
|
|
|
sendVoiceNote(result.getUri(), result.getSize());
|
2015-11-18 22:52:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onFailure(ExecutionException e) {
|
2022-01-14 13:06:28 +00:00
|
|
|
Toast.makeText(requireContext(), R.string.ConversationActivity_unable_to_record_audio, Toast.LENGTH_LONG).show();
|
2015-11-18 22:52:26 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onRecorderCanceled() {
|
2021-06-07 19:55:26 +00:00
|
|
|
voiceRecorderWakeLock.release();
|
2019-03-28 18:04:38 +00:00
|
|
|
updateToggleButtonState();
|
2022-01-14 13:06:28 +00:00
|
|
|
Vibrator vibrator = ServiceUtil.getVibrator(requireContext());
|
2015-11-18 22:52:26 +00:00
|
|
|
vibrator.vibrate(50);
|
2017-12-05 19:52:03 +00:00
|
|
|
|
2022-01-14 13:06:28 +00:00
|
|
|
requireActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
|
|
|
requireActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
|
2015-11-18 22:52:26 +00:00
|
|
|
|
2021-07-02 13:28:45 +00:00
|
|
|
ListenableFuture<VoiceNoteDraft> future = audioRecorder.stopRecording();
|
|
|
|
if (getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.RESUMED)) {
|
|
|
|
future.addListener(new DeleteCanceledVoiceNoteListener());
|
|
|
|
} else {
|
2022-08-05 21:00:11 +00:00
|
|
|
draftViewModel.saveEphemeralVoiceNoteDraft(future);
|
2021-07-02 13:28:45 +00:00
|
|
|
}
|
2015-11-18 22:52:26 +00:00
|
|
|
}
|
|
|
|
|
2015-11-22 18:44:53 +00:00
|
|
|
@Override
|
|
|
|
public void onEmojiToggle() {
|
2017-01-19 19:31:41 +00:00
|
|
|
if (!emojiDrawerStub.resolved()) {
|
2021-05-26 13:47:14 +00:00
|
|
|
initializeMediaKeyboardProviders();
|
2017-01-19 19:31:41 +00:00
|
|
|
}
|
|
|
|
|
2022-05-12 17:28:02 +00:00
|
|
|
inputPanel.setMediaKeyboard(emojiDrawerStub.get());
|
2022-01-14 13:06:28 +00:00
|
|
|
emojiDrawerStub.get().setFragmentManager(getChildFragmentManager());
|
|
|
|
|
2017-01-19 19:31:41 +00:00
|
|
|
if (container.getCurrentInput() == emojiDrawerStub.get()) {
|
2022-03-18 18:09:52 +00:00
|
|
|
container.showSoftkey(composeText);
|
2017-01-19 19:31:41 +00:00
|
|
|
} else {
|
|
|
|
container.show(composeText, emojiDrawerStub.get());
|
|
|
|
}
|
2015-11-22 18:44:53 +00:00
|
|
|
}
|
|
|
|
|
2019-01-15 08:41:05 +00:00
|
|
|
@Override
|
|
|
|
public void onLinkPreviewCanceled() {
|
|
|
|
linkPreviewViewModel.onUserCancel();
|
|
|
|
}
|
|
|
|
|
2019-04-17 14:21:30 +00:00
|
|
|
@Override
|
|
|
|
public void onStickerSuggestionSelected(@NonNull StickerRecord sticker) {
|
|
|
|
sendSticker(sticker, true);
|
|
|
|
}
|
|
|
|
|
2022-08-05 21:00:11 +00:00
|
|
|
@Override
|
|
|
|
public void onQuoteChanged(long id, @NonNull RecipientId author) {
|
|
|
|
draftViewModel.setQuoteDraft(id, author);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onQuoteCleared() {
|
|
|
|
draftViewModel.clearQuoteDraft();
|
|
|
|
}
|
|
|
|
|
2016-12-26 23:14:23 +00:00
|
|
|
@Override
|
|
|
|
public void onMediaSelected(@NonNull Uri uri, String contentType) {
|
2020-07-08 15:54:47 +00:00
|
|
|
if (MediaUtil.isGif(contentType) || MediaUtil.isImageType(contentType)) {
|
|
|
|
SimpleTask.run(getLifecycle(),
|
|
|
|
() -> getKeyboardImageDetails(uri),
|
|
|
|
details -> sendKeyboardImage(uri, contentType, details));
|
2017-05-08 22:32:59 +00:00
|
|
|
} else if (MediaUtil.isVideoType(contentType)) {
|
2022-01-14 13:06:28 +00:00
|
|
|
setMedia(uri, MediaType.VIDEO);
|
2017-05-08 22:32:59 +00:00
|
|
|
} else if (MediaUtil.isAudioType(contentType)) {
|
2022-01-14 13:06:28 +00:00
|
|
|
setMedia(uri, MediaType.AUDIO);
|
2016-12-26 23:14:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-14 21:55:48 +00:00
|
|
|
@Override
|
|
|
|
public void onCursorPositionChanged(int start, int end) {
|
2022-01-14 13:06:28 +00:00
|
|
|
linkPreviewViewModel.onTextChanged(requireContext(), composeText.getTextTrimmed().toString(), start, end);
|
2019-02-14 21:55:48 +00:00
|
|
|
}
|
|
|
|
|
2019-04-17 14:21:30 +00:00
|
|
|
@Override
|
|
|
|
public void onStickerSelected(@NonNull StickerRecord stickerRecord) {
|
|
|
|
sendSticker(stickerRecord, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onStickerManagementClicked() {
|
2022-01-14 13:06:28 +00:00
|
|
|
startActivity(StickerManagementActivity.getIntent(requireContext()));
|
2019-04-17 14:21:30 +00:00
|
|
|
container.hideAttachedInput(true);
|
|
|
|
}
|
|
|
|
|
2021-07-02 13:28:45 +00:00
|
|
|
private void sendVoiceNote(@NonNull Uri uri, long size) {
|
2022-08-05 21:00:11 +00:00
|
|
|
boolean initiating = threadId == -1;
|
|
|
|
long expiresIn = TimeUnit.SECONDS.toMillis(recipient.get().getExpiresInSeconds());
|
|
|
|
AudioSlide audioSlide = new AudioSlide(requireContext(), uri, size, MediaUtil.AUDIO_AAC, true);
|
|
|
|
SlideDeck slideDeck = new SlideDeck();
|
|
|
|
|
2021-07-02 13:28:45 +00:00
|
|
|
slideDeck.addSlide(audioSlide);
|
|
|
|
|
2022-08-05 21:00:11 +00:00
|
|
|
sendMediaMessage(recipient.getId(),
|
|
|
|
sendButton.getSelectedSendType(),
|
|
|
|
"",
|
|
|
|
slideDeck,
|
|
|
|
inputPanel.getQuote().orElse(null),
|
|
|
|
Collections.emptyList(),
|
|
|
|
Collections.emptyList(),
|
|
|
|
composeText.getMentions(),
|
|
|
|
expiresIn,
|
|
|
|
false,
|
|
|
|
initiating,
|
|
|
|
true,
|
|
|
|
null);
|
2021-07-02 13:28:45 +00:00
|
|
|
}
|
|
|
|
|
2019-04-17 14:21:30 +00:00
|
|
|
private void sendSticker(@NonNull StickerRecord stickerRecord, boolean clearCompose) {
|
2020-09-03 14:02:33 +00:00
|
|
|
sendSticker(new StickerLocator(stickerRecord.getPackId(), stickerRecord.getPackKey(), stickerRecord.getStickerId(), stickerRecord.getEmoji()), stickerRecord.getContentType(), stickerRecord.getUri(), stickerRecord.getSize(), clearCompose);
|
2019-04-17 14:21:30 +00:00
|
|
|
|
2019-08-30 21:45:35 +00:00
|
|
|
SignalExecutors.BOUNDED.execute(() ->
|
2021-11-18 17:36:52 +00:00
|
|
|
SignalDatabase.stickers()
|
2019-08-30 21:45:35 +00:00
|
|
|
.updateStickerLastUsedTime(stickerRecord.getRowId(), System.currentTimeMillis())
|
|
|
|
);
|
2019-04-17 14:21:30 +00:00
|
|
|
}
|
|
|
|
|
2020-09-02 16:46:58 +00:00
|
|
|
private void sendSticker(@NonNull StickerLocator stickerLocator, @NonNull String contentType, @NonNull Uri uri, long size, boolean clearCompose) {
|
2022-06-03 22:07:29 +00:00
|
|
|
if (sendButton.getSelectedSendType().usesSmsTransport()) {
|
2022-03-14 19:49:46 +00:00
|
|
|
Media media = new Media(uri, contentType, System.currentTimeMillis(), StickerSlide.WIDTH, StickerSlide.HEIGHT, size, 0, false, false, Optional.empty(), Optional.empty(), Optional.empty());
|
2022-06-03 22:07:29 +00:00
|
|
|
Intent intent = MediaSelectionActivity.editor(requireContext(), sendButton.getSelectedSendType(), Collections.singletonList(media), recipient.getId(), composeText.getTextTrimmed());
|
2019-04-17 14:21:30 +00:00
|
|
|
startActivityForResult(intent, MEDIA_SENDER);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-07-29 20:24:20 +00:00
|
|
|
long expiresIn = TimeUnit.SECONDS.toMillis(recipient.get().getExpiresInSeconds());
|
2019-04-17 14:21:30 +00:00
|
|
|
boolean initiating = threadId == -1;
|
2022-06-03 22:07:29 +00:00
|
|
|
MessageSendType sendType = sendButton.getSelectedSendType();
|
2019-04-17 14:21:30 +00:00
|
|
|
SlideDeck slideDeck = new SlideDeck();
|
2022-01-14 13:06:28 +00:00
|
|
|
Slide stickerSlide = new StickerSlide(requireContext(), uri, size, stickerLocator, contentType);
|
2019-04-17 14:21:30 +00:00
|
|
|
|
|
|
|
slideDeck.addSlide(stickerSlide);
|
|
|
|
|
2022-06-21 21:27:57 +00:00
|
|
|
sendMediaMessage(recipient.getId(), sendType, "", slideDeck, null, Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), expiresIn, false, initiating, clearCompose, null);
|
2019-04-17 14:21:30 +00:00
|
|
|
}
|
|
|
|
|
2018-10-29 22:14:31 +00:00
|
|
|
private void silentlySetComposeText(String text) {
|
2022-08-05 21:00:11 +00:00
|
|
|
typingTextWatcher.setTypingStatusEnabled(false);
|
2018-10-29 22:14:31 +00:00
|
|
|
composeText.setText(text);
|
2022-08-05 21:00:11 +00:00
|
|
|
typingTextWatcher.setTypingStatusEnabled(true);
|
2018-10-29 22:14:31 +00:00
|
|
|
}
|
2016-12-26 23:14:23 +00:00
|
|
|
|
2020-07-29 16:44:23 +00:00
|
|
|
@Override
|
|
|
|
public void onReactionsDialogDismissed() {
|
2021-09-29 16:38:34 +00:00
|
|
|
fragment.clearFocusedItem();
|
2020-07-29 16:44:23 +00:00
|
|
|
}
|
|
|
|
|
2021-05-26 13:47:14 +00:00
|
|
|
@Override
|
|
|
|
public void onShown() {
|
|
|
|
if (inputPanel != null) {
|
|
|
|
inputPanel.getMediaKeyboardListener().onShown();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onHidden() {
|
|
|
|
if (inputPanel != null) {
|
|
|
|
inputPanel.getMediaKeyboardListener().onHidden();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onKeyboardChanged(@NonNull KeyboardPage page) {
|
|
|
|
if (inputPanel != null) {
|
|
|
|
inputPanel.getMediaKeyboardListener().onKeyboardChanged(page);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onEmojiSelected(String emoji) {
|
|
|
|
if (inputPanel != null) {
|
|
|
|
inputPanel.onEmojiSelected(emoji);
|
2022-02-24 19:33:09 +00:00
|
|
|
if (recentEmojis == null) {
|
|
|
|
recentEmojis = new RecentEmojiPageModel(ApplicationDependencies.getApplication(), TextSecurePreferences.RECENT_STORAGE_KEY);
|
|
|
|
}
|
|
|
|
recentEmojis.onCodePointSelected(emoji);
|
2021-05-26 13:47:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onKeyEvent(KeyEvent keyEvent) {
|
|
|
|
if (keyEvent != null) {
|
|
|
|
inputPanel.onKeyEvent(keyEvent);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-25 17:34:32 +00:00
|
|
|
@Override
|
|
|
|
public void openGifSearch() {
|
2022-06-03 22:07:29 +00:00
|
|
|
AttachmentManager.selectGif(this, ConversationParentFragment.PICK_GIF, recipient.getId(), sendButton.getSelectedSendType(), isMms(), composeText.getTextTrimmed());
|
2022-01-25 17:34:32 +00:00
|
|
|
}
|
|
|
|
|
2021-05-26 13:47:14 +00:00
|
|
|
@Override
|
|
|
|
public void onGifSelectSuccess(@NonNull Uri blobUri, int width, int height) {
|
|
|
|
setMedia(blobUri,
|
|
|
|
Objects.requireNonNull(MediaType.from(BlobProvider.getMimeType(blobUri))),
|
|
|
|
width,
|
|
|
|
height,
|
|
|
|
false,
|
|
|
|
true);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean isMms() {
|
2022-07-22 13:47:40 +00:00
|
|
|
return !viewModel.isPushAvailable();
|
2021-05-26 13:47:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void openEmojiSearch() {
|
|
|
|
if (emojiDrawerStub.resolved()) {
|
|
|
|
emojiDrawerStub.get().onOpenEmojiSearch();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override public void closeEmojiSearch() {
|
|
|
|
if (emojiDrawerStub.resolved()) {
|
|
|
|
emojiDrawerStub.get().onCloseEmojiSearch();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-02 13:28:45 +00:00
|
|
|
@Override
|
|
|
|
public void onVoiceNoteDraftPlay(@NonNull Uri audioUri, double progress) {
|
|
|
|
voiceNoteMediaController.startSinglePlaybackForDraft(audioUri, threadId, progress);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onVoiceNoteDraftPause(@NonNull Uri audioUri) {
|
|
|
|
voiceNoteMediaController.pausePlayback(audioUri);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onVoiceNoteDraftSeekTo(@NonNull Uri audioUri, double progress) {
|
|
|
|
voiceNoteMediaController.seekToPosition(audioUri, progress);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onVoiceNoteDraftDelete(@NonNull Uri audioUri) {
|
|
|
|
voiceNoteMediaController.stopPlaybackAndReset(audioUri);
|
|
|
|
draftViewModel.deleteVoiceNoteDraft();
|
|
|
|
}
|
|
|
|
|
2021-07-09 12:46:00 +00:00
|
|
|
@Override
|
|
|
|
public @NonNull VoiceNoteMediaController getVoiceNoteMediaController() {
|
|
|
|
return voiceNoteMediaController;
|
|
|
|
}
|
|
|
|
|
2022-02-03 18:48:52 +00:00
|
|
|
@Override public void openStickerSearch() {
|
|
|
|
StickerSearchDialogFragment.show(getChildFragmentManager());
|
|
|
|
}
|
|
|
|
|
2022-05-26 20:32:52 +00:00
|
|
|
@Override
|
|
|
|
public void bindScrollHelper(@NonNull RecyclerView recyclerView) {
|
2022-06-10 19:20:02 +00:00
|
|
|
material3OnScrollHelper.attach(recyclerView);
|
2022-05-26 20:32:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onMessageDetailsFragmentDismissed() {
|
2022-06-10 19:20:02 +00:00
|
|
|
material3OnScrollHelper.setColorImmediate();
|
2022-05-26 20:32:52 +00:00
|
|
|
}
|
|
|
|
|
2022-07-11 15:54:30 +00:00
|
|
|
@Override
|
|
|
|
public void sendAnywayAfterSafetyNumberChangedInBottomSheet(@NonNull List<? extends ContactSearchKey.RecipientSearchKey> destinations) {
|
|
|
|
Log.d(TAG, "onSendAnywayAfterSafetyNumberChange");
|
|
|
|
initializeIdentityRecords().addListener(new AssertedSuccessListener<Boolean>() {
|
|
|
|
@Override
|
|
|
|
public void onSuccess(Boolean result) {
|
|
|
|
sendMessage(null);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2012-07-19 21:22:03 +00:00
|
|
|
// Listeners
|
|
|
|
|
2021-07-02 13:28:45 +00:00
|
|
|
private final class DeleteCanceledVoiceNoteListener implements ListenableFuture.Listener<VoiceNoteDraft> {
|
|
|
|
@Override
|
|
|
|
public void onSuccess(final VoiceNoteDraft result) {
|
2022-08-05 21:00:11 +00:00
|
|
|
draftViewModel.cancelEphemeralVoiceNoteDraft(result.asDraft());
|
2021-07-02 13:28:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onFailure(ExecutionException e) {}
|
|
|
|
}
|
|
|
|
|
2015-11-18 22:52:26 +00:00
|
|
|
private class QuickCameraToggleListener implements OnClickListener {
|
2015-04-16 05:38:33 +00:00
|
|
|
@Override
|
|
|
|
public void onClick(View v) {
|
2022-09-02 15:30:45 +00:00
|
|
|
Permissions.with(ConversationParentFragment.this)
|
2018-09-20 20:27:18 +00:00
|
|
|
.request(Manifest.permission.CAMERA)
|
|
|
|
.ifNecessary()
|
2020-11-10 15:20:54 +00:00
|
|
|
.withRationaleDialog(getString(R.string.ConversationActivity_to_capture_photos_and_video_allow_signal_access_to_the_camera), R.drawable.ic_camera_24)
|
2018-09-20 20:27:18 +00:00
|
|
|
.withPermanentDenialDialog(getString(R.string.ConversationActivity_signal_needs_the_camera_permission_to_take_photos_or_video))
|
|
|
|
.onAllGranted(() -> {
|
|
|
|
composeText.clearFocus();
|
2022-06-03 22:07:29 +00:00
|
|
|
startActivityForResult(MediaSelectionActivity.camera(requireActivity(), sendButton.getSelectedSendType(), recipient.getId(), inputPanel.getQuote().isPresent()), MEDIA_SENDER);
|
2022-01-14 13:06:28 +00:00
|
|
|
requireActivity().overridePendingTransition(R.anim.camera_slide_from_bottom, R.anim.stationary);
|
2018-09-20 20:27:18 +00:00
|
|
|
})
|
2022-01-14 13:06:28 +00:00
|
|
|
.onAnyDenied(() -> Toast.makeText(requireContext(), R.string.ConversationActivity_signal_needs_camera_permissions_to_take_photos_or_video, Toast.LENGTH_LONG).show())
|
2018-09-20 20:27:18 +00:00
|
|
|
.execute();
|
2015-04-16 05:38:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-19 21:22:03 +00:00
|
|
|
private class SendButtonListener implements OnClickListener, TextView.OnEditorActionListener {
|
2013-02-03 04:37:40 +00:00
|
|
|
@Override
|
2012-07-19 21:22:03 +00:00
|
|
|
public void onClick(View v) {
|
2021-08-23 14:05:48 +00:00
|
|
|
String metricId = recipient.get().isGroup() ? SignalLocalMetrics.GroupMessageSend.start()
|
|
|
|
: SignalLocalMetrics.IndividualMessageSend.start();
|
|
|
|
sendMessage(metricId);
|
2012-07-19 21:22:03 +00:00
|
|
|
}
|
|
|
|
|
2013-02-03 04:37:40 +00:00
|
|
|
@Override
|
2012-07-19 21:22:03 +00:00
|
|
|
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
|
|
|
|
if (actionId == EditorInfo.IME_ACTION_SEND) {
|
|
|
|
sendButton.performClick();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2013-04-26 01:59:49 +00:00
|
|
|
}
|
2012-07-19 21:22:03 +00:00
|
|
|
|
2015-05-18 17:26:32 +00:00
|
|
|
private class AttachButtonListener implements OnClickListener {
|
|
|
|
@Override
|
|
|
|
public void onClick(View v) {
|
|
|
|
handleAddAttachment();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-26 21:49:43 +00:00
|
|
|
private class AttachButtonLongClickListener implements View.OnLongClickListener {
|
|
|
|
@Override
|
|
|
|
public boolean onLongClick(View v) {
|
|
|
|
return sendButton.performLongClick();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-29 03:53:34 +00:00
|
|
|
private class ComposeKeyPressedListener implements OnKeyListener, OnClickListener, TextWatcher, OnFocusChangeListener {
|
2015-05-18 17:26:32 +00:00
|
|
|
|
|
|
|
int beforeLength;
|
|
|
|
|
2013-06-28 03:57:27 +00:00
|
|
|
@Override
|
|
|
|
public boolean onKey(View v, int keyCode, KeyEvent event) {
|
|
|
|
if (event.getAction() == KeyEvent.ACTION_DOWN) {
|
|
|
|
if (keyCode == KeyEvent.KEYCODE_ENTER) {
|
2021-02-03 11:26:14 +00:00
|
|
|
if (SignalStore.settings().isEnterKeySends() || event.isCtrlPressed()) {
|
2013-06-28 03:57:27 +00:00
|
|
|
sendButton.dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER));
|
|
|
|
sendButton.dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_ENTER));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onClick(View v) {
|
2015-07-24 20:22:28 +00:00
|
|
|
container.showSoftkey(composeText);
|
2013-06-28 03:57:27 +00:00
|
|
|
}
|
|
|
|
|
2015-05-18 17:26:32 +00:00
|
|
|
@Override
|
|
|
|
public void beforeTextChanged(CharSequence s, int start, int count,int after) {
|
2017-07-04 17:09:36 +00:00
|
|
|
beforeLength = composeText.getTextTrimmed().length();
|
2015-05-18 17:26:32 +00:00
|
|
|
}
|
|
|
|
|
2013-02-03 04:37:40 +00:00
|
|
|
@Override
|
2012-07-19 21:22:03 +00:00
|
|
|
public void afterTextChanged(Editable s) {
|
|
|
|
calculateCharactersRemaining();
|
2015-05-18 17:26:32 +00:00
|
|
|
|
2019-02-14 21:55:48 +00:00
|
|
|
if (composeText.getTextTrimmed().length() == 0 || beforeLength == 0) {
|
2022-01-14 13:06:28 +00:00
|
|
|
composeText.postDelayed(ConversationParentFragment.this::updateToggleButtonState, 50);
|
2015-05-18 17:26:32 +00:00
|
|
|
}
|
2019-04-17 14:21:30 +00:00
|
|
|
|
|
|
|
stickerViewModel.onInputTextUpdated(s.toString());
|
2012-07-19 21:22:03 +00:00
|
|
|
}
|
2015-05-18 17:26:32 +00:00
|
|
|
|
2013-02-03 04:37:40 +00:00
|
|
|
@Override
|
2012-07-19 21:22:03 +00:00
|
|
|
public void onTextChanged(CharSequence s, int start, int before,int count) {}
|
2014-05-29 03:53:34 +00:00
|
|
|
|
|
|
|
@Override
|
2021-05-26 13:47:14 +00:00
|
|
|
public void onFocusChange(View v, boolean hasFocus) {
|
|
|
|
if (hasFocus && container.getCurrentInput() == emojiDrawerStub.get()) {
|
|
|
|
container.showSoftkey(composeText);
|
|
|
|
}
|
|
|
|
}
|
2012-07-19 21:22:03 +00:00
|
|
|
}
|
2012-08-04 00:34:09 +00:00
|
|
|
|
2022-08-05 21:00:11 +00:00
|
|
|
private class ComposeTextWatcher extends SimpleTextWatcher {
|
2018-10-29 22:14:31 +00:00
|
|
|
|
2022-08-05 21:00:11 +00:00
|
|
|
private boolean typingStatusEnabled = true;
|
2018-10-29 22:14:31 +00:00
|
|
|
|
2020-11-11 19:14:54 +00:00
|
|
|
private String previousText = "";
|
|
|
|
|
2018-10-29 22:14:31 +00:00
|
|
|
@Override
|
2022-08-05 21:00:11 +00:00
|
|
|
public void onTextChanged(@NonNull CharSequence text) {
|
|
|
|
handleSaveDraftOnTextChange(text);
|
|
|
|
handleTypingIndicatorOnTextChange(text.toString());
|
|
|
|
}
|
|
|
|
|
|
|
|
private void handleSaveDraftOnTextChange(@NonNull CharSequence text) {
|
|
|
|
textDraftSaveDebouncer.publish(() -> draftViewModel.setTextDraft(StringUtil.trimSequence(text).toString(), MentionAnnotation.getMentionsFromAnnotations(text)));
|
|
|
|
}
|
|
|
|
|
|
|
|
private void handleTypingIndicatorOnTextChange(@NonNull String text) {
|
|
|
|
if (typingStatusEnabled && threadId > 0 && viewModel.isPushAvailable() && !isSmsForced() && !recipient.get().isBlocked() && !recipient.get().isSelf()) {
|
2020-11-11 19:14:54 +00:00
|
|
|
TypingStatusSender typingStatusSender = ApplicationDependencies.getTypingStatusSender();
|
|
|
|
|
|
|
|
if (text.length() == 0) {
|
|
|
|
typingStatusSender.onTypingStoppedWithNotify(threadId);
|
|
|
|
} else if (text.length() < previousText.length() && previousText.contains(text)) {
|
|
|
|
typingStatusSender.onTypingStopped(threadId);
|
|
|
|
} else {
|
|
|
|
typingStatusSender.onTypingStarted(threadId);
|
|
|
|
}
|
|
|
|
|
|
|
|
previousText = text;
|
2018-10-29 22:14:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-05 21:00:11 +00:00
|
|
|
public void setTypingStatusEnabled(boolean enabled) {
|
|
|
|
this.typingStatusEnabled = enabled;
|
2018-10-29 22:14:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-19 16:01:07 +00:00
|
|
|
@Override
|
2020-02-19 22:08:34 +00:00
|
|
|
public void onMessageRequest(@NonNull MessageRequestViewModel viewModel) {
|
2020-07-15 18:40:13 +00:00
|
|
|
messageRequestBottomView.setAcceptOnClickListener(v -> viewModel.onAccept());
|
2020-02-21 18:52:27 +00:00
|
|
|
messageRequestBottomView.setDeleteOnClickListener(v -> onMessageRequestDeleteClicked(viewModel));
|
|
|
|
messageRequestBottomView.setBlockOnClickListener(v -> onMessageRequestBlockClicked(viewModel));
|
|
|
|
messageRequestBottomView.setUnblockOnClickListener(v -> onMessageRequestUnblockClicked(viewModel));
|
2022-01-14 13:06:28 +00:00
|
|
|
messageRequestBottomView.setGroupV1MigrationContinueListener(v -> GroupsV1MigrationInitiationBottomSheetDialogFragment.showForInitiation(getChildFragmentManager(), recipient.getId()));
|
2019-11-19 16:01:07 +00:00
|
|
|
|
2022-01-14 13:06:28 +00:00
|
|
|
viewModel.getRequestReviewDisplayState().observe(getViewLifecycleOwner(), this::presentRequestReviewBanner);
|
|
|
|
viewModel.getMessageData().observe(getViewLifecycleOwner(), this::presentMessageRequestState);
|
|
|
|
viewModel.getFailures().observe(getViewLifecycleOwner(), this::showGroupChangeErrorToast);
|
|
|
|
viewModel.getMessageRequestStatus().observe(getViewLifecycleOwner(), status -> {
|
2020-02-19 22:08:34 +00:00
|
|
|
switch (status) {
|
2020-07-15 18:40:13 +00:00
|
|
|
case IDLE:
|
|
|
|
hideMessageRequestBusy();
|
|
|
|
break;
|
|
|
|
case ACCEPTING:
|
|
|
|
case BLOCKING:
|
|
|
|
case DELETING:
|
|
|
|
showMessageRequestBusy();
|
|
|
|
break;
|
2019-11-19 16:01:07 +00:00
|
|
|
case ACCEPTED:
|
2020-07-15 18:40:13 +00:00
|
|
|
hideMessageRequestBusy();
|
|
|
|
break;
|
2021-05-17 13:43:37 +00:00
|
|
|
case BLOCKED_AND_REPORTED:
|
|
|
|
hideMessageRequestBusy();
|
2022-01-14 13:06:28 +00:00
|
|
|
Toast.makeText(requireContext(), R.string.ConversationActivity__reported_as_spam_and_blocked, Toast.LENGTH_SHORT).show();
|
2021-05-17 13:43:37 +00:00
|
|
|
break;
|
2019-11-19 16:01:07 +00:00
|
|
|
case DELETED:
|
|
|
|
case BLOCKED:
|
2020-07-15 18:40:13 +00:00
|
|
|
hideMessageRequestBusy();
|
2022-01-14 13:06:28 +00:00
|
|
|
requireActivity().finish();
|
2019-11-19 16:01:07 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2020-11-04 20:00:12 +00:00
|
|
|
private void presentRequestReviewBanner(@NonNull MessageRequestViewModel.RequestReviewDisplayState state) {
|
|
|
|
switch (state) {
|
|
|
|
case SHOWN:
|
|
|
|
reviewBanner.get().setVisibility(View.VISIBLE);
|
|
|
|
|
|
|
|
CharSequence message = new SpannableStringBuilder().append(SpanUtil.bold(getString(R.string.ConversationFragment__review_requests_carefully)))
|
|
|
|
.append(" ")
|
|
|
|
.append(getString(R.string.ConversationFragment__signal_found_another_contact_with_the_same_name));
|
|
|
|
|
|
|
|
reviewBanner.get().setBannerMessage(message);
|
|
|
|
|
2022-01-14 13:06:28 +00:00
|
|
|
Drawable drawable = ContextUtil.requireDrawable(requireContext(), R.drawable.ic_info_white_24).mutate();
|
|
|
|
DrawableCompat.setTint(drawable, ContextCompat.getColor(requireContext(), R.color.signal_icon_tint_primary));
|
2020-11-04 20:00:12 +00:00
|
|
|
|
|
|
|
reviewBanner.get().setBannerIcon(drawable);
|
|
|
|
reviewBanner.get().setOnClickListener(unused -> handleReviewRequest(recipient.getId()));
|
|
|
|
break;
|
|
|
|
case HIDDEN:
|
|
|
|
reviewBanner.get().setVisibility(View.GONE);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void presentGroupReviewBanner(@NonNull ConversationGroupViewModel.ReviewState groupReviewState) {
|
|
|
|
if (groupReviewState.getCount() > 0) {
|
|
|
|
reviewBanner.get().setVisibility(View.VISIBLE);
|
|
|
|
reviewBanner.get().setBannerMessage(getString(R.string.ConversationFragment__d_group_members_have_the_same_name, groupReviewState.getCount()));
|
|
|
|
reviewBanner.get().setBannerRecipient(groupReviewState.getRecipient());
|
|
|
|
reviewBanner.get().setOnClickListener(unused -> handleReviewGroupMembers(groupReviewState.getGroupId()));
|
|
|
|
} else if (reviewBanner.resolved()) {
|
|
|
|
reviewBanner.get().setVisibility(View.GONE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-15 18:40:13 +00:00
|
|
|
private void showMessageRequestBusy() {
|
|
|
|
messageRequestBottomView.showBusy();
|
|
|
|
}
|
|
|
|
|
|
|
|
private void hideMessageRequestBusy() {
|
|
|
|
messageRequestBottomView.hideBusy();
|
|
|
|
}
|
|
|
|
|
2020-11-04 20:00:12 +00:00
|
|
|
private void handleReviewGroupMembers(@Nullable GroupId.V2 groupId) {
|
|
|
|
if (groupId == null) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ReviewCardDialogFragment.createForReviewMembers(groupId)
|
2022-01-14 13:06:28 +00:00
|
|
|
.show(getChildFragmentManager(), null);
|
2020-11-04 20:00:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private void handleReviewRequest(@NonNull RecipientId recipientId) {
|
|
|
|
if (recipientId == Recipient.UNKNOWN.getId()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ReviewCardDialogFragment.createForReviewRequest(recipientId)
|
2022-01-14 13:06:28 +00:00
|
|
|
.show(getChildFragmentManager(), null);
|
2020-11-04 20:00:12 +00:00
|
|
|
}
|
|
|
|
|
2020-05-12 18:09:47 +00:00
|
|
|
private void showGroupChangeErrorToast(@NonNull GroupChangeFailureReason e) {
|
2022-01-14 13:06:28 +00:00
|
|
|
Toast.makeText(requireContext(), GroupErrors.getUserDisplayMessage(e), Toast.LENGTH_LONG).show();
|
2020-05-12 18:09:47 +00:00
|
|
|
}
|
|
|
|
|
2020-02-19 22:08:34 +00:00
|
|
|
@Override
|
2021-09-29 16:38:34 +00:00
|
|
|
public void handleReaction(@NonNull ConversationMessage conversationMessage,
|
2022-01-28 20:12:35 +00:00
|
|
|
@NonNull ConversationReactionOverlay.OnActionSelectedListener onActionSelectedListener,
|
|
|
|
@NonNull SelectedConversationModel selectedConversationModel,
|
2019-12-03 21:57:21 +00:00
|
|
|
@NonNull ConversationReactionOverlay.OnHideListener onHideListener)
|
|
|
|
{
|
2022-01-28 20:12:35 +00:00
|
|
|
reactionDelegate.setOnActionSelectedListener(onActionSelectedListener);
|
2021-01-27 20:34:59 +00:00
|
|
|
reactionDelegate.setOnHideListener(onHideListener);
|
2022-01-28 20:12:35 +00:00
|
|
|
reactionDelegate.show(requireActivity(), recipient.get(), conversationMessage, groupViewModel.isNonAdminInAnnouncementGroup(), selectedConversationModel);
|
2022-08-01 14:55:40 +00:00
|
|
|
composeText.clearFocus();
|
2022-06-17 23:13:14 +00:00
|
|
|
if (attachmentKeyboardStub.resolved()) {
|
|
|
|
attachmentKeyboardStub.get().hide(true);
|
|
|
|
}
|
2019-12-03 21:57:21 +00:00
|
|
|
}
|
|
|
|
|
2020-06-26 15:10:54 +00:00
|
|
|
@Override
|
|
|
|
public void onMessageWithErrorClicked(@NonNull MessageRecord messageRecord) {
|
2022-01-21 01:39:49 +00:00
|
|
|
if (messageRecord.isIdentityMismatchFailure()) {
|
2022-07-11 15:54:30 +00:00
|
|
|
SafetyNumberBottomSheet
|
|
|
|
.forMessageRecord(requireContext(), messageRecord)
|
|
|
|
.show(getChildFragmentManager());
|
2022-01-21 01:39:49 +00:00
|
|
|
} else if (messageRecord.hasFailedWithNetworkFailures()) {
|
2022-04-27 18:24:50 +00:00
|
|
|
new MaterialAlertDialogBuilder(requireContext())
|
|
|
|
.setMessage(R.string.conversation_activity__message_could_not_be_sent)
|
|
|
|
.setNegativeButton(android.R.string.cancel, null)
|
|
|
|
.setPositiveButton(R.string.conversation_activity__send, (dialog, which) -> {
|
|
|
|
SignalExecutors.BOUNDED.execute(() -> {
|
|
|
|
MessageSender.resend(requireContext(), messageRecord);
|
|
|
|
});
|
|
|
|
})
|
|
|
|
.show();
|
2020-06-26 15:10:54 +00:00
|
|
|
} else {
|
2022-02-11 18:03:51 +00:00
|
|
|
MessageDetailsFragment.create(messageRecord, recipient.getId()).show(getChildFragmentManager(), null);
|
2020-06-26 15:10:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-02 13:28:45 +00:00
|
|
|
@Override
|
|
|
|
public void onVoiceNotePause(@NonNull Uri uri) {
|
|
|
|
voiceNoteMediaController.pausePlayback(uri);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onVoiceNotePlay(@NonNull Uri uri, long messageId, double progress) {
|
|
|
|
voiceNoteMediaController.startConsecutivePlayback(uri, messageId, progress);
|
|
|
|
}
|
|
|
|
|
2022-01-28 20:12:35 +00:00
|
|
|
@Override
|
|
|
|
public void onVoiceNoteResume(@NonNull Uri uri, long messageId) {
|
|
|
|
voiceNoteMediaController.resumePlayback(uri, messageId);
|
|
|
|
}
|
|
|
|
|
2021-07-02 13:28:45 +00:00
|
|
|
@Override
|
|
|
|
public void onVoiceNoteSeekTo(@NonNull Uri uri, double progress) {
|
|
|
|
voiceNoteMediaController.seekToPosition(uri, progress);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onVoiceNotePlaybackSpeedChanged(@NonNull Uri uri, float speed) {
|
|
|
|
voiceNoteMediaController.setPlaybackSpeed(uri, speed);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onRegisterVoiceNoteCallbacks(@NonNull Observer<VoiceNotePlaybackState> onPlaybackStartObserver) {
|
2022-01-14 13:06:28 +00:00
|
|
|
voiceNoteMediaController.getVoiceNotePlaybackState().observe(getViewLifecycleOwner(), onPlaybackStartObserver);
|
2021-07-02 13:28:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onUnregisterVoiceNoteCallbacks(@NonNull Observer<VoiceNotePlaybackState> onPlaybackStartObserver) {
|
|
|
|
voiceNoteMediaController.getVoiceNotePlaybackState().removeObserver(onPlaybackStartObserver);
|
|
|
|
}
|
|
|
|
|
2022-10-13 15:33:13 +00:00
|
|
|
@Override
|
|
|
|
public void onInviteToSignal() {
|
|
|
|
handleInviteLink();
|
|
|
|
}
|
|
|
|
|
2019-12-03 21:57:21 +00:00
|
|
|
@Override
|
|
|
|
public void onCursorChanged() {
|
2021-01-27 20:34:59 +00:00
|
|
|
if (!reactionDelegate.isShowing()) {
|
2019-12-03 21:57:21 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
SimpleTask.run(() -> {
|
|
|
|
//noinspection CodeBlock2Expr
|
2021-11-18 17:36:52 +00:00
|
|
|
return SignalDatabase.mmsSms().checkMessageExists(reactionDelegate.getMessageRecord());
|
2019-12-03 21:57:21 +00:00
|
|
|
}, messageExists -> {
|
|
|
|
if (!messageExists) {
|
2021-01-27 20:34:59 +00:00
|
|
|
reactionDelegate.hide();
|
2019-12-03 21:57:21 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2022-06-17 16:45:44 +00:00
|
|
|
@Override
|
|
|
|
public int getSendButtonTint() {
|
|
|
|
return getSendButtonColor(sendButton.getSelectedSendType());
|
|
|
|
}
|
|
|
|
|
2022-02-03 22:06:17 +00:00
|
|
|
@Override
|
|
|
|
public boolean isKeyboardOpen() {
|
|
|
|
return container.isKeyboardOpen();
|
|
|
|
}
|
|
|
|
|
2022-06-17 23:13:14 +00:00
|
|
|
@Override
|
|
|
|
public boolean isAttachmentKeyboardOpen() {
|
|
|
|
return attachmentKeyboardStub.resolved() && attachmentKeyboardStub.get().isShowing();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void openAttachmentKeyboard() {
|
|
|
|
attachmentKeyboardStub.get().show(container.getKeyboardHeight(), true);
|
|
|
|
}
|
|
|
|
|
2015-03-31 20:36:04 +00:00
|
|
|
@Override
|
|
|
|
public void setThreadId(long threadId) {
|
|
|
|
this.threadId = threadId;
|
2022-08-05 21:00:11 +00:00
|
|
|
draftViewModel.setThreadId(threadId);
|
2015-03-31 20:36:04 +00:00
|
|
|
}
|
|
|
|
|
2018-02-07 22:01:37 +00:00
|
|
|
@Override
|
2020-08-05 20:45:52 +00:00
|
|
|
public void handleReplyMessage(ConversationMessage conversationMessage) {
|
2022-03-11 11:44:07 +00:00
|
|
|
if (isSearchRequested) {
|
|
|
|
searchViewItem.collapseActionView();
|
|
|
|
}
|
|
|
|
|
2020-08-05 20:45:52 +00:00
|
|
|
MessageRecord messageRecord = conversationMessage.getMessageRecord();
|
|
|
|
|
2018-02-07 22:01:37 +00:00
|
|
|
Recipient author;
|
|
|
|
|
|
|
|
if (messageRecord.isOutgoing()) {
|
2019-08-07 18:22:51 +00:00
|
|
|
author = Recipient.self();
|
2018-02-07 22:01:37 +00:00
|
|
|
} else {
|
|
|
|
author = messageRecord.getIndividualRecipient();
|
|
|
|
}
|
|
|
|
|
2018-04-27 00:03:54 +00:00
|
|
|
if (messageRecord.isMms() && !((MmsMessageRecord) messageRecord).getSharedContacts().isEmpty()) {
|
|
|
|
Contact contact = ((MmsMessageRecord) messageRecord).getSharedContacts().get(0);
|
|
|
|
String displayName = ContactUtil.getDisplayName(contact);
|
|
|
|
String body = getString(R.string.ConversationActivity_quoted_contact_message, EmojiStrings.BUST_IN_SILHOUETTE, displayName);
|
|
|
|
SlideDeck slideDeck = new SlideDeck();
|
|
|
|
|
|
|
|
if (contact.getAvatarAttachment() != null) {
|
2022-01-14 13:06:28 +00:00
|
|
|
slideDeck.addSlide(MediaUtil.getSlideForAttachment(requireContext(), contact.getAvatarAttachment()));
|
2018-04-27 00:03:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
inputPanel.setQuote(GlideApp.with(this),
|
|
|
|
messageRecord.getDateSent(),
|
|
|
|
author,
|
|
|
|
body,
|
2022-05-10 13:10:35 +00:00
|
|
|
slideDeck,
|
|
|
|
MessageRecordUtil.getRecordQuoteType(messageRecord));
|
2019-01-15 08:41:05 +00:00
|
|
|
|
|
|
|
} else if (messageRecord.isMms() && !((MmsMessageRecord) messageRecord).getLinkPreviews().isEmpty()) {
|
|
|
|
LinkPreview linkPreview = ((MmsMessageRecord) messageRecord).getLinkPreviews().get(0);
|
|
|
|
SlideDeck slideDeck = new SlideDeck();
|
|
|
|
|
|
|
|
if (linkPreview.getThumbnail().isPresent()) {
|
2022-01-14 13:06:28 +00:00
|
|
|
slideDeck.addSlide(MediaUtil.getSlideForAttachment(requireContext(), linkPreview.getThumbnail().get()));
|
2019-01-15 08:41:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
inputPanel.setQuote(GlideApp.with(this),
|
|
|
|
messageRecord.getDateSent(),
|
|
|
|
author,
|
2022-01-14 13:06:28 +00:00
|
|
|
conversationMessage.getDisplayBody(requireContext()),
|
2022-05-10 13:10:35 +00:00
|
|
|
slideDeck,
|
|
|
|
MessageRecordUtil.getRecordQuoteType(messageRecord));
|
2018-04-27 00:03:54 +00:00
|
|
|
} else {
|
2019-06-11 06:18:45 +00:00
|
|
|
SlideDeck slideDeck = messageRecord.isMms() ? ((MmsMessageRecord) messageRecord).getSlideDeck() : new SlideDeck();
|
|
|
|
|
2020-01-10 20:34:38 +00:00
|
|
|
if (messageRecord.isMms() && ((MmsMessageRecord) messageRecord).isViewOnce()) {
|
|
|
|
Attachment attachment = new TombstoneAttachment(MediaUtil.VIEW_ONCE, true);
|
2019-06-11 06:18:45 +00:00
|
|
|
slideDeck = new SlideDeck();
|
2022-01-14 13:06:28 +00:00
|
|
|
slideDeck.addSlide(MediaUtil.getSlideForAttachment(requireContext(), attachment));
|
2019-06-11 06:18:45 +00:00
|
|
|
}
|
|
|
|
|
2018-04-27 00:03:54 +00:00
|
|
|
inputPanel.setQuote(GlideApp.with(this),
|
|
|
|
messageRecord.getDateSent(),
|
|
|
|
author,
|
2022-01-14 13:06:28 +00:00
|
|
|
conversationMessage.getDisplayBody(requireContext()),
|
2022-05-10 13:10:35 +00:00
|
|
|
slideDeck,
|
|
|
|
MessageRecordUtil.getRecordQuoteType(messageRecord));
|
2018-04-27 00:03:54 +00:00
|
|
|
}
|
2019-09-05 13:18:54 +00:00
|
|
|
|
|
|
|
inputPanel.clickOnComposeInput();
|
2018-02-07 22:01:37 +00:00
|
|
|
}
|
|
|
|
|
2019-02-01 17:06:59 +00:00
|
|
|
@Override
|
|
|
|
public void onMessageActionToolbarOpened() {
|
|
|
|
searchViewItem.collapseActionView();
|
2022-05-26 20:32:52 +00:00
|
|
|
toolbar.setVisibility(View.GONE);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onMessageActionToolbarClosed() {
|
|
|
|
toolbar.setVisibility(View.VISIBLE);
|
2019-02-01 17:06:59 +00:00
|
|
|
}
|
|
|
|
|
2022-01-11 14:36:21 +00:00
|
|
|
@Override
|
|
|
|
public void onBottomActionBarVisibilityChanged(int visibility) {
|
|
|
|
inputPanel.setHideForSelection(visibility == View.VISIBLE);
|
|
|
|
}
|
|
|
|
|
2019-04-09 13:35:47 +00:00
|
|
|
@Override
|
2020-02-19 22:08:34 +00:00
|
|
|
public void onForwardClicked() {
|
2019-04-09 13:35:47 +00:00
|
|
|
inputPanel.clearQuote();
|
|
|
|
}
|
|
|
|
|
2014-04-15 10:43:14 +00:00
|
|
|
@Override
|
|
|
|
public void onAttachmentChanged() {
|
2022-07-22 13:47:40 +00:00
|
|
|
handleSecurityChange(viewModel.getConversationStateSnapshot().getSecurityInfo());
|
2015-05-18 17:26:32 +00:00
|
|
|
updateToggleButtonState();
|
2019-01-15 08:41:05 +00:00
|
|
|
updateLinkPreviewState();
|
2014-04-15 10:43:14 +00:00
|
|
|
}
|
2015-09-05 00:33:22 +00:00
|
|
|
|
2022-08-05 21:00:11 +00:00
|
|
|
@Override
|
|
|
|
public void onLocationRemoved() {
|
|
|
|
draftViewModel.clearLocationDraft();
|
|
|
|
}
|
|
|
|
|
2020-02-21 18:52:27 +00:00
|
|
|
private void onMessageRequestDeleteClicked(@NonNull MessageRequestViewModel requestModel) {
|
|
|
|
Recipient recipient = requestModel.getRecipient().getValue();
|
|
|
|
if (recipient == null) {
|
|
|
|
Log.w(TAG, "[onMessageRequestDeleteClicked] No recipient!");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-06-23 13:18:16 +00:00
|
|
|
AlertDialog.Builder builder = new MaterialAlertDialogBuilder(requireContext())
|
2020-02-21 18:52:27 +00:00
|
|
|
.setNeutralButton(R.string.ConversationActivity_cancel, (d, w) -> d.dismiss());
|
|
|
|
|
|
|
|
if (recipient.isGroup() && recipient.isBlocked()) {
|
|
|
|
builder.setTitle(R.string.ConversationActivity_delete_conversation);
|
|
|
|
builder.setMessage(R.string.ConversationActivity_this_conversation_will_be_deleted_from_all_of_your_devices);
|
|
|
|
builder.setPositiveButton(R.string.ConversationActivity_delete, (d, w) -> requestModel.onDelete());
|
|
|
|
} else if (recipient.isGroup()) {
|
|
|
|
builder.setTitle(R.string.ConversationActivity_delete_and_leave_group);
|
|
|
|
builder.setMessage(R.string.ConversationActivity_you_will_leave_this_group_and_it_will_be_deleted_from_all_of_your_devices);
|
|
|
|
builder.setNegativeButton(R.string.ConversationActivity_delete_and_leave, (d, w) -> requestModel.onDelete());
|
|
|
|
} else {
|
|
|
|
builder.setTitle(R.string.ConversationActivity_delete_conversation);
|
|
|
|
builder.setMessage(R.string.ConversationActivity_this_conversation_will_be_deleted_from_all_of_your_devices);
|
|
|
|
builder.setNegativeButton(R.string.ConversationActivity_delete, (d, w) -> requestModel.onDelete());
|
|
|
|
}
|
|
|
|
|
|
|
|
builder.show();
|
|
|
|
}
|
|
|
|
|
|
|
|
private void onMessageRequestBlockClicked(@NonNull MessageRequestViewModel requestModel) {
|
|
|
|
Recipient recipient = requestModel.getRecipient().getValue();
|
|
|
|
if (recipient == null) {
|
|
|
|
Log.w(TAG, "[onMessageRequestBlockClicked] No recipient!");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-01-14 13:06:28 +00:00
|
|
|
BlockUnblockDialog.showBlockAndReportSpamFor(requireContext(), getLifecycle(), recipient, requestModel::onBlock, requestModel::onBlockAndReportSpam);
|
2020-02-21 18:52:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private void onMessageRequestUnblockClicked(@NonNull MessageRequestViewModel requestModel) {
|
|
|
|
Recipient recipient = requestModel.getRecipient().getValue();
|
|
|
|
if (recipient == null) {
|
|
|
|
Log.w(TAG, "[onMessageRequestUnblockClicked] No recipient!");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-01-14 13:06:28 +00:00
|
|
|
BlockUnblockDialog.showUnblockFor(requireContext(), getLifecycle(), recipient, requestModel::onUnblock);
|
2020-02-21 18:52:27 +00:00
|
|
|
}
|
|
|
|
|
2020-04-27 15:42:34 +00:00
|
|
|
private static void hideMenuItem(@NonNull Menu menu, @IdRes int menuItem) {
|
|
|
|
if (menu.findItem(menuItem) != null) {
|
|
|
|
menu.findItem(menuItem).setVisible(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-08 15:54:47 +00:00
|
|
|
@WorkerThread
|
|
|
|
private @Nullable KeyboardImageDetails getKeyboardImageDetails(@NonNull Uri uri) {
|
|
|
|
try {
|
|
|
|
Bitmap bitmap = glideRequests.asBitmap()
|
2020-07-10 13:30:00 +00:00
|
|
|
.load(new DecryptableStreamUriLoader.DecryptableUri(uri))
|
2020-07-08 15:54:47 +00:00
|
|
|
.skipMemoryCache(true)
|
|
|
|
.diskCacheStrategy(DiskCacheStrategy.NONE)
|
|
|
|
.submit()
|
|
|
|
.get(1000, TimeUnit.MILLISECONDS);
|
|
|
|
int topLeft = bitmap.getPixel(0, 0);
|
|
|
|
return new KeyboardImageDetails(bitmap.getWidth(), bitmap.getHeight(), Color.alpha(topLeft) < 255);
|
|
|
|
} catch (InterruptedException | ExecutionException | TimeoutException e) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void sendKeyboardImage(@NonNull Uri uri, @NonNull String contentType, @Nullable KeyboardImageDetails details) {
|
|
|
|
if (details == null || !details.hasTransparency) {
|
2022-01-14 13:06:28 +00:00
|
|
|
setMedia(uri, Objects.requireNonNull(MediaType.from(contentType)));
|
2020-07-08 15:54:47 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-07-29 20:24:20 +00:00
|
|
|
long expiresIn = TimeUnit.SECONDS.toMillis(recipient.get().getExpiresInSeconds());
|
2020-07-08 15:54:47 +00:00
|
|
|
boolean initiating = threadId == -1;
|
|
|
|
SlideDeck slideDeck = new SlideDeck();
|
|
|
|
|
|
|
|
if (MediaUtil.isGif(contentType)) {
|
2022-01-14 13:06:28 +00:00
|
|
|
slideDeck.addSlide(new GifSlide(requireContext(), uri, 0, details.width, details.height, details.hasTransparency, null));
|
2020-07-08 15:54:47 +00:00
|
|
|
} else if (MediaUtil.isImageType(contentType)) {
|
2022-01-14 13:06:28 +00:00
|
|
|
slideDeck.addSlide(new ImageSlide(requireContext(), uri, contentType, 0, details.width, details.height, details.hasTransparency, null, null));
|
2020-07-08 15:54:47 +00:00
|
|
|
} else {
|
|
|
|
throw new AssertionError("Only images are supported!");
|
|
|
|
}
|
|
|
|
|
2021-02-25 17:19:58 +00:00
|
|
|
sendMediaMessage(recipient.getId(),
|
2022-06-21 21:27:57 +00:00
|
|
|
sendButton.getSelectedSendType(),
|
2020-07-08 15:54:47 +00:00
|
|
|
"",
|
|
|
|
slideDeck,
|
2020-09-24 16:11:40 +00:00
|
|
|
null,
|
2020-07-08 15:54:47 +00:00
|
|
|
Collections.emptyList(),
|
|
|
|
Collections.emptyList(),
|
2020-08-05 20:45:52 +00:00
|
|
|
composeText.getMentions(),
|
2020-07-08 15:54:47 +00:00
|
|
|
expiresIn,
|
|
|
|
false,
|
|
|
|
initiating,
|
2021-08-23 14:05:48 +00:00
|
|
|
false,
|
|
|
|
null);
|
2020-07-08 15:54:47 +00:00
|
|
|
}
|
|
|
|
|
2017-06-07 01:03:09 +00:00
|
|
|
private class UnverifiedDismissedListener implements UnverifiedBannerView.DismissListener {
|
|
|
|
@Override
|
|
|
|
public void onDismissed(final List<IdentityRecord> unverifiedIdentities) {
|
2021-09-01 13:41:49 +00:00
|
|
|
SimpleTask.run(() -> {
|
|
|
|
try (SignalSessionLock.Lock unused = ReentrantSessionLock.INSTANCE.acquire()) {
|
|
|
|
for (IdentityRecord identityRecord : unverifiedIdentities) {
|
2022-01-26 21:22:19 +00:00
|
|
|
ApplicationDependencies.getProtocolStore().aci().identities().setVerified(identityRecord.getRecipientId(),
|
|
|
|
identityRecord.getIdentityKey(),
|
|
|
|
VerifiedStatus.DEFAULT);
|
2017-06-07 01:03:09 +00:00
|
|
|
}
|
|
|
|
}
|
2021-09-01 13:41:49 +00:00
|
|
|
return null;
|
|
|
|
}, nothing -> initializeIdentityRecords());
|
2017-06-07 01:03:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private class UnverifiedClickedListener implements UnverifiedBannerView.ClickListener {
|
|
|
|
@Override
|
|
|
|
public void onClicked(final List<IdentityRecord> unverifiedIdentities) {
|
2018-08-02 13:25:33 +00:00
|
|
|
Log.i(TAG, "onClicked: " + unverifiedIdentities.size());
|
2017-06-07 01:03:09 +00:00
|
|
|
if (unverifiedIdentities.size() == 1) {
|
2022-01-14 13:06:28 +00:00
|
|
|
startActivity(VerifyIdentityActivity.newIntent(requireContext(), unverifiedIdentities.get(0), false));
|
2017-06-07 01:03:09 +00:00
|
|
|
} else {
|
|
|
|
String[] unverifiedNames = new String[unverifiedIdentities.size()];
|
|
|
|
|
|
|
|
for (int i=0;i<unverifiedIdentities.size();i++) {
|
2022-01-14 13:06:28 +00:00
|
|
|
unverifiedNames[i] = Recipient.resolved(unverifiedIdentities.get(i).getRecipientId()).getDisplayName(requireContext());
|
2017-06-07 01:03:09 +00:00
|
|
|
}
|
|
|
|
|
2022-06-23 13:18:16 +00:00
|
|
|
AlertDialog.Builder builder = new MaterialAlertDialogBuilder(requireContext());
|
2020-11-10 15:20:54 +00:00
|
|
|
builder.setIcon(R.drawable.ic_warning);
|
2017-06-07 01:03:09 +00:00
|
|
|
builder.setTitle("No longer verified");
|
2017-12-05 19:52:03 +00:00
|
|
|
builder.setItems(unverifiedNames, (dialog, which) -> {
|
2022-01-14 13:06:28 +00:00
|
|
|
startActivity(VerifyIdentityActivity.newIntent(requireContext(), unverifiedIdentities.get(which), false));
|
2017-06-07 01:03:09 +00:00
|
|
|
});
|
|
|
|
builder.show();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-04-24 18:09:54 +00:00
|
|
|
|
2020-08-05 20:45:52 +00:00
|
|
|
private class QuoteRestorationTask extends AsyncTask<Void, Void, ConversationMessage> {
|
2018-04-24 18:09:54 +00:00
|
|
|
|
2018-07-25 15:30:48 +00:00
|
|
|
private final String serialized;
|
|
|
|
private final SettableFuture<Boolean> future;
|
2018-04-24 18:09:54 +00:00
|
|
|
|
2018-07-25 15:30:48 +00:00
|
|
|
QuoteRestorationTask(@NonNull String serialized, @NonNull SettableFuture<Boolean> future) {
|
2018-04-24 18:09:54 +00:00
|
|
|
this.serialized = serialized;
|
2018-07-25 15:30:48 +00:00
|
|
|
this.future = future;
|
2018-04-24 18:09:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-08-05 20:45:52 +00:00
|
|
|
protected ConversationMessage doInBackground(Void... voids) {
|
2022-01-14 13:06:28 +00:00
|
|
|
QuoteId quoteId = QuoteId.deserialize(ApplicationDependencies.getApplication(), serialized);
|
2018-04-24 18:09:54 +00:00
|
|
|
|
2020-08-05 20:45:52 +00:00
|
|
|
if (quoteId == null) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2022-01-14 13:06:28 +00:00
|
|
|
Context context = ApplicationDependencies.getApplication();
|
2020-08-05 20:45:52 +00:00
|
|
|
|
2021-11-18 17:36:52 +00:00
|
|
|
MessageRecord messageRecord = SignalDatabase.mmsSms().getMessageFor(quoteId.getId(), quoteId.getAuthor());
|
2020-08-05 20:45:52 +00:00
|
|
|
if (messageRecord == null) {
|
|
|
|
return null;
|
2018-04-24 18:09:54 +00:00
|
|
|
}
|
|
|
|
|
2020-08-05 20:45:52 +00:00
|
|
|
return ConversationMessageFactory.createWithUnresolvedData(context, messageRecord);
|
2018-04-24 18:09:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-08-05 20:45:52 +00:00
|
|
|
protected void onPostExecute(ConversationMessage conversationMessage) {
|
|
|
|
if (conversationMessage != null) {
|
|
|
|
handleReplyMessage(conversationMessage);
|
2018-07-25 15:30:48 +00:00
|
|
|
future.set(true);
|
2018-04-24 18:09:54 +00:00
|
|
|
} else {
|
|
|
|
Log.e(TAG, "Failed to restore a quote from a draft. No matching message record.");
|
2018-07-25 15:30:48 +00:00
|
|
|
future.set(false);
|
2018-04-24 18:09:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-02-19 22:08:34 +00:00
|
|
|
|
2021-07-07 17:23:37 +00:00
|
|
|
private final class VoiceNotePlayerViewListener implements VoiceNotePlayerView.Listener {
|
|
|
|
@Override
|
|
|
|
public void onCloseRequested(@NonNull Uri uri) {
|
|
|
|
voiceNoteMediaController.stopPlaybackAndReset(uri);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onSpeedChangeRequested(@NonNull Uri uri, float speed) {
|
|
|
|
voiceNoteMediaController.setPlaybackSpeed(uri, speed);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onPlay(@NonNull Uri uri, long messageId, double position) {
|
|
|
|
voiceNoteMediaController.startSinglePlayback(uri, messageId, position);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onPause(@NonNull Uri uri) {
|
|
|
|
voiceNoteMediaController.pausePlayback(uri);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onNavigateToMessage(long threadId, @NonNull RecipientId threadRecipientId, @NonNull RecipientId senderId, long messageTimestamp, long messagePositionInThread) {
|
2022-01-14 13:06:28 +00:00
|
|
|
if (threadId != ConversationParentFragment.this.threadId) {
|
|
|
|
startActivity(ConversationIntents.createBuilder(requireActivity(), threadRecipientId, threadId)
|
2021-07-07 17:23:37 +00:00
|
|
|
.withStartingPosition((int) messagePositionInThread)
|
|
|
|
.build());
|
|
|
|
} else {
|
|
|
|
fragment.jumpToMessage(senderId, messageTimestamp, () -> { });
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-23 18:10:35 +00:00
|
|
|
private void presentMessageRequestState(@Nullable MessageRequestViewModel.MessageData messageData) {
|
2020-11-25 15:36:33 +00:00
|
|
|
if (!Util.isEmpty(viewModel.getArgs().getDraftText()) ||
|
|
|
|
viewModel.getArgs().getMedia() != null ||
|
|
|
|
viewModel.getArgs().getStickerLocator() != null)
|
2020-11-23 18:10:35 +00:00
|
|
|
{
|
|
|
|
Log.d(TAG, "[presentMessageRequestState] Have extra, so ignoring provided state.");
|
|
|
|
messageRequestBottomView.setVisibility(View.GONE);
|
2022-06-15 13:01:41 +00:00
|
|
|
inputPanel.setHideForMessageRequestState(false);
|
2020-11-23 18:10:35 +00:00
|
|
|
} else if (isPushGroupV1Conversation() && !isActiveGroup()) {
|
|
|
|
Log.d(TAG, "[presentMessageRequestState] Inactive push group V1, so ignoring provided state.");
|
|
|
|
messageRequestBottomView.setVisibility(View.GONE);
|
2022-06-15 13:01:41 +00:00
|
|
|
inputPanel.setHideForMessageRequestState(false);
|
2020-11-23 18:10:35 +00:00
|
|
|
} else if (messageData == null) {
|
|
|
|
Log.d(TAG, "[presentMessageRequestState] Null messageData. Ignoring.");
|
|
|
|
} else if (messageData.getMessageState() == MessageRequestState.NONE) {
|
|
|
|
Log.d(TAG, "[presentMessageRequestState] No message request necessary.");
|
|
|
|
messageRequestBottomView.setVisibility(View.GONE);
|
2022-06-15 13:01:41 +00:00
|
|
|
inputPanel.setHideForMessageRequestState(false);
|
2020-11-23 18:10:35 +00:00
|
|
|
} else {
|
|
|
|
Log.d(TAG, "[presentMessageRequestState] " + messageData.getMessageState());
|
|
|
|
messageRequestBottomView.setMessageData(messageData);
|
|
|
|
messageRequestBottomView.setVisibility(View.VISIBLE);
|
2022-05-26 20:32:52 +00:00
|
|
|
noLongerMemberBanner.setVisibility(View.GONE);
|
2022-06-15 13:01:41 +00:00
|
|
|
inputPanel.setHideForMessageRequestState(true);
|
2020-11-23 18:10:35 +00:00
|
|
|
}
|
2020-02-19 22:08:34 +00:00
|
|
|
|
2020-11-23 18:10:35 +00:00
|
|
|
invalidateOptionsMenu();
|
2020-02-19 22:08:34 +00:00
|
|
|
}
|
2020-07-08 15:54:47 +00:00
|
|
|
|
|
|
|
private static class KeyboardImageDetails {
|
|
|
|
private final int width;
|
|
|
|
private final int height;
|
|
|
|
private final boolean hasTransparency;
|
|
|
|
|
|
|
|
private KeyboardImageDetails(int width, int height, boolean hasTransparency) {
|
|
|
|
this.width = width;
|
|
|
|
this.height = height;
|
|
|
|
this.hasTransparency = hasTransparency;
|
|
|
|
}
|
|
|
|
}
|
2022-01-14 13:06:28 +00:00
|
|
|
|
|
|
|
public interface Callback {
|
2022-07-29 18:55:05 +00:00
|
|
|
long getShareDataTimestamp();
|
|
|
|
|
|
|
|
void setShareDataTimestamp(long timestamp);
|
|
|
|
|
2022-01-14 13:06:28 +00:00
|
|
|
default void onInitializeToolbar(@NonNull Toolbar toolbar) {
|
|
|
|
}
|
|
|
|
|
|
|
|
default void onSendComplete(long threadId) {
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return true to skip built in, otherwise false.
|
|
|
|
*/
|
|
|
|
default boolean onUpdateReminders() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
default boolean isInBubble() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2012-07-19 21:22:03 +00:00
|
|
|
}
|