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;
|
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-08-05 20:45:52 +00:00
|
|
|
import android.text.Spannable;
|
|
|
|
import android.text.SpannableString;
|
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;
|
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-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;
|
2019-08-30 21:45:35 +00:00
|
|
|
|
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;
|
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;
|
|
|
|
import org.signal.core.util.logging.Log;
|
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;
|
|
|
|
import org.thoughtcrime.securesms.TransportOption;
|
2022-03-16 14:10:01 +00:00
|
|
|
import org.thoughtcrime.securesms.components.emoji.RecentEmojiPageModel;
|
2022-03-17 13:00:10 +00:00
|
|
|
import org.thoughtcrime.securesms.util.Debouncer;
|
2022-03-16 14:10:01 +00:00
|
|
|
import org.thoughtcrime.securesms.util.LifecycleDisposable;
|
|
|
|
import org.thoughtcrime.securesms.verify.VerifyIdentityActivity;
|
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;
|
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-03-14 19:49:46 +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;
|
2019-11-12 14:18:57 +00:00
|
|
|
import org.thoughtcrime.securesms.contacts.sync.DirectoryHelper;
|
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.DraftRepository;
|
|
|
|
import org.thoughtcrime.securesms.conversation.drafts.DraftViewModel;
|
2020-06-26 15:10:54 +00:00
|
|
|
import org.thoughtcrime.securesms.conversation.ui.error.SafetyNumberChangeDialog;
|
2020-12-02 18:20:38 +00:00
|
|
|
import org.thoughtcrime.securesms.conversation.ui.groupcall.GroupCallViewModel;
|
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;
|
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.database.DraftDatabase;
|
|
|
|
import org.thoughtcrime.securesms.database.DraftDatabase.Draft;
|
2014-12-12 01:13:01 +00:00
|
|
|
import org.thoughtcrime.securesms.database.DraftDatabase.Drafts;
|
2020-03-27 18:55:44 +00:00
|
|
|
import org.thoughtcrime.securesms.database.GroupDatabase;
|
2017-06-07 01:03:09 +00:00
|
|
|
import org.thoughtcrime.securesms.database.IdentityDatabase.VerifiedStatus;
|
2020-08-05 20:45:52 +00:00
|
|
|
import org.thoughtcrime.securesms.database.MentionUtil;
|
|
|
|
import org.thoughtcrime.securesms.database.MentionUtil.UpdatedBodyAndMentions;
|
2014-12-12 01:13:01 +00:00
|
|
|
import org.thoughtcrime.securesms.database.MmsSmsColumns.Types;
|
2019-04-12 19:22:38 +00:00
|
|
|
import org.thoughtcrime.securesms.database.RecipientDatabase;
|
2017-08-22 17:44:04 +00:00
|
|
|
import org.thoughtcrime.securesms.database.RecipientDatabase.RegisteredState;
|
2021-11-18 17:36:52 +00:00
|
|
|
import org.thoughtcrime.securesms.database.SignalDatabase;
|
2013-04-26 01:59:49 +00:00
|
|
|
import org.thoughtcrime.securesms.database.ThreadDatabase;
|
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;
|
2018-03-20 18:27:11 +00:00
|
|
|
import org.thoughtcrime.securesms.giph.ui.GiphyActivity;
|
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;
|
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;
|
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;
|
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;
|
2016-01-04 21:02:22 +00:00
|
|
|
import org.thoughtcrime.securesms.mms.LocationSlide;
|
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;
|
|
|
|
import org.thoughtcrime.securesms.mms.OutgoingSecureMediaMessage;
|
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;
|
2021-04-06 16:03:33 +00:00
|
|
|
import org.thoughtcrime.securesms.payments.CanNotSendPaymentDialog;
|
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;
|
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;
|
2020-08-26 15:51:25 +00:00
|
|
|
import org.thoughtcrime.securesms.util.AsynchronousCallback;
|
2020-08-05 20:45:52 +00:00
|
|
|
import org.thoughtcrime.securesms.util.Base64;
|
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;
|
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;
|
2015-09-05 00:33:22 +00:00
|
|
|
import org.thoughtcrime.securesms.util.MediaUtil;
|
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;
|
2019-11-19 16:01:07 +00:00
|
|
|
import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
|
2017-01-19 02:46:40 +00:00
|
|
|
import org.thoughtcrime.securesms.util.views.Stub;
|
2022-03-14 19:49:46 +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;
|
2016-03-23 17:34:41 +00:00
|
|
|
import org.whispersystems.libsignal.InvalidMessageException;
|
2020-01-08 20:56:51 +00:00
|
|
|
import org.whispersystems.libsignal.util.Pair;
|
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
|
|
|
|
2015-03-11 21:23:45 +00:00
|
|
|
import static org.thoughtcrime.securesms.TransportOption.Type;
|
2014-02-22 18:54:43 +00:00
|
|
|
import static org.thoughtcrime.securesms.database.GroupDatabase.GroupRecord;
|
|
|
|
|
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,
|
2020-07-29 16:44:23 +00:00
|
|
|
SafetyNumberChangeDialog.Callback,
|
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,
|
|
|
|
StickerKeyboardPageFragment.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
|
|
|
|
|
|
|
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;
|
|
|
|
private Button makeDefaultSmsButton;
|
|
|
|
private Button registerButton;
|
|
|
|
private InputAwareLayout container;
|
|
|
|
protected Stub<ReminderView> reminderView;
|
|
|
|
private Stub<UnverifiedBannerView> unverifiedBannerView;
|
|
|
|
private Stub<ReviewBannerView> reviewBanner;
|
|
|
|
private TypingStatusTextWatcher typingTextWatcher;
|
|
|
|
private ConversationSearchBottomBar searchNav;
|
|
|
|
private MenuItem searchViewItem;
|
|
|
|
private MessageRequestsBottomView messageRequestBottomView;
|
|
|
|
private ConversationReactionDelegate reactionDelegate;
|
2021-07-22 14:10:57 +00:00
|
|
|
private Stub<FrameLayout> voiceNotePlayerViewStub;
|
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-02-19 22:08:34 +00:00
|
|
|
private View panelParent;
|
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-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;
|
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;
|
2021-07-02 13:28:45 +00:00
|
|
|
|
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;
|
|
|
|
private boolean isSecureText;
|
2021-07-23 20:22:08 +00:00
|
|
|
private boolean isDefaultSms;
|
2021-01-21 17:35:00 +00:00
|
|
|
private int reactWithAnyEmojiStartPage = -1;
|
2020-02-19 22:08:34 +00:00
|
|
|
private boolean isMmsEnabled = true;
|
|
|
|
private boolean isSecurityInitialized = false;
|
2021-06-25 12:28:55 +00:00
|
|
|
private boolean isSearchRequested = false;
|
2012-07-19 21:22:03 +00:00
|
|
|
|
2022-03-17 13:00:10 +00:00
|
|
|
private final LifecycleDisposable disposables = new LifecycleDisposable();
|
|
|
|
private final Debouncer optionsMenuDebouncer = new Debouncer(50);
|
2022-03-16 14:10:01 +00:00
|
|
|
|
2021-03-16 14:37:40 +00:00
|
|
|
private volatile boolean screenInitialized = false;
|
|
|
|
|
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
|
|
|
|
|
|
|
@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
|
|
|
|
if (ConversationIntents.isInvalid(requireActivity().getIntent())) {
|
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
|
|
|
isDefaultSms = Util.isDefaultSmsProvider(requireContext());
|
|
|
|
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-01-14 13:06:28 +00:00
|
|
|
// TODO [alex] LargeScreenSupport -- This will need to be built from requireArguments()
|
|
|
|
ConversationIntents.Args args = ConversationIntents.Args.from(requireActivity().getIntent());
|
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
|
|
|
|
2022-01-14 13:06:28 +00:00
|
|
|
final boolean typingIndicatorsEnabled = TextSecurePreferences.isTypingIndicatorsEnabled(requireContext());
|
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();
|
2019-10-17 13:04:37 +00:00
|
|
|
initializeSecurity(recipient.get().isRegistered(), isDefaultSms).addListener(new AssertedSuccessListener<Boolean>() {
|
2015-10-02 00:46:47 +00:00
|
|
|
@Override
|
|
|
|
public void onSuccess(Boolean result) {
|
2022-01-14 13:06:28 +00:00
|
|
|
if (getActivity() == null) {
|
|
|
|
Log.w(TAG, "Activity is not attached. Not proceeding with initialization.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (requireActivity().isFinishing()) {
|
2021-03-16 14:37:40 +00:00
|
|
|
Log.w(TAG, "Activity is finishing. Not proceeding with initialization.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-06-14 16:53:22 +00:00
|
|
|
initializeProfiles();
|
2020-10-15 19:49:09 +00:00
|
|
|
initializeGv1Migration();
|
2020-11-25 15:36:33 +00:00
|
|
|
initializeDraft(args).addListener(new AssertedSuccessListener<Boolean>() {
|
2018-07-25 15:30:48 +00:00
|
|
|
@Override
|
2018-10-29 22:14:31 +00:00
|
|
|
public void onSuccess(Boolean loadedDraft) {
|
|
|
|
if (loadedDraft != null && loadedDraft) {
|
2018-08-02 15:57:10 +00:00
|
|
|
Log.i(TAG, "Finished loading draft");
|
2021-03-01 20:44:33 +00:00
|
|
|
ThreadUtil.runOnMain(() -> {
|
2018-07-25 15:30:48 +00:00
|
|
|
if (fragment != null && fragment.isResumed()) {
|
|
|
|
fragment.moveToLastSeen();
|
2018-08-02 15:57:10 +00:00
|
|
|
} else {
|
|
|
|
Log.w(TAG, "Wanted to move to the last seen position, but the fragment was in an invalid state");
|
2018-07-25 15:30:48 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
2018-10-29 22:14:31 +00:00
|
|
|
|
2022-01-14 13:06:28 +00:00
|
|
|
if (typingIndicatorsEnabled) {
|
2018-10-29 22:14:31 +00:00
|
|
|
composeText.addTextChangedListener(typingTextWatcher);
|
|
|
|
}
|
2019-02-14 21:55:48 +00:00
|
|
|
composeText.setSelection(composeText.length(), composeText.length());
|
2021-03-16 14:37:40 +00:00
|
|
|
|
|
|
|
screenInitialized = true;
|
2018-07-25 15:30:48 +00:00
|
|
|
}
|
|
|
|
});
|
2015-10-02 00:46:47 +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-01-28 17:24:44 +00:00
|
|
|
requireActivity().getOnBackPressedDispatcher().addCallback(getViewLifecycleOwner(), new OnBackPressedCallback(true) {
|
|
|
|
@Override
|
|
|
|
public void handleOnBackPressed() {
|
|
|
|
onBackPressed();
|
|
|
|
}
|
|
|
|
});
|
2012-07-19 21:22:03 +00:00
|
|
|
}
|
|
|
|
|
2022-01-14 13:06:28 +00:00
|
|
|
// TODO [alex] LargeScreenSupport -- This needs to be fed a stream of intents
|
2014-12-25 02:32:51 +00:00
|
|
|
protected void onNewIntent(Intent intent) {
|
2018-08-02 13:25:33 +00:00
|
|
|
Log.i(TAG, "onNewIntent()");
|
2021-06-24 16:52:54 +00:00
|
|
|
|
2022-01-14 13:06:28 +00:00
|
|
|
if (requireActivity().isFinishing()) {
|
2016-01-30 23:33:47 +00:00
|
|
|
Log.w(TAG, "Activity is finishing...");
|
|
|
|
return;
|
|
|
|
}
|
2014-12-15 20:25:55 +00:00
|
|
|
|
2021-03-16 14:37:40 +00:00
|
|
|
if (!screenInitialized) {
|
|
|
|
Log.w(TAG, "Activity is in the middle of initialization. Restarting.");
|
2022-01-14 13:06:28 +00:00
|
|
|
requireActivity().finish();
|
2021-03-16 14:37:40 +00:00
|
|
|
startActivity(intent);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-01-21 17:35:00 +00:00
|
|
|
reactWithAnyEmojiStartPage = -1;
|
2021-07-02 13:28:45 +00:00
|
|
|
if (!Util.isEmpty(composeText) || attachmentManager.isAttachmentPresent() || inputPanel.hasSaveableContent()) {
|
2014-12-25 02:32:51 +00:00
|
|
|
saveDraft();
|
2017-10-16 20:11:42 +00:00
|
|
|
attachmentManager.clear(glideRequests, false);
|
2020-03-19 13:10:16 +00:00
|
|
|
inputPanel.clearQuote();
|
2018-10-29 22:14:31 +00:00
|
|
|
silentlySetComposeText("");
|
2014-12-25 02:32:51 +00:00
|
|
|
}
|
|
|
|
|
2020-11-25 15:36:33 +00:00
|
|
|
if (ConversationIntents.isInvalid(intent)) {
|
2019-10-01 12:17:25 +00:00
|
|
|
Log.w(TAG, "[onNewIntent] 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;
|
|
|
|
}
|
|
|
|
|
2022-01-14 13:06:28 +00:00
|
|
|
requireActivity().setIntent(intent);
|
2020-11-25 15:36:33 +00:00
|
|
|
|
2021-06-25 12:28:55 +00:00
|
|
|
ConversationIntents.Args args = ConversationIntents.Args.from(intent);
|
2022-01-14 13:06:28 +00:00
|
|
|
// TODO [alex] LargeScreenSupport - Set arguments
|
2021-06-25 12:28:55 +00:00
|
|
|
isSearchRequested = args.isWithSearchOpen();
|
|
|
|
|
|
|
|
viewModel.setArgs(args);
|
2022-01-14 13:06:28 +00:00
|
|
|
setVisibleThread(args.getThreadId());
|
2020-11-25 15:36:33 +00:00
|
|
|
|
|
|
|
reportShortcutLaunch(viewModel.getArgs().getRecipientId());
|
|
|
|
initializeResources(viewModel.getArgs());
|
2019-10-17 13:04:37 +00:00
|
|
|
initializeSecurity(recipient.get().isRegistered(), isDefaultSms).addListener(new AssertedSuccessListener<Boolean>() {
|
2015-10-02 00:46:47 +00:00
|
|
|
@Override
|
|
|
|
public void onSuccess(Boolean result) {
|
2022-01-14 13:06:28 +00:00
|
|
|
if (getContext() != null) {
|
|
|
|
initializeDraft(viewModel.getArgs());
|
|
|
|
}
|
2015-10-02 00:46:47 +00:00
|
|
|
}
|
|
|
|
});
|
2014-10-08 18:11:02 +00:00
|
|
|
|
2014-12-25 02:32:51 +00:00
|
|
|
if (fragment != null) {
|
|
|
|
fragment.onNewIntent();
|
|
|
|
}
|
2019-03-01 00:51:10 +00:00
|
|
|
|
|
|
|
searchNav.setVisibility(View.GONE);
|
2021-06-24 16:52:54 +00:00
|
|
|
|
2021-06-25 12:28:55 +00:00
|
|
|
if (args.isWithSearchOpen()) {
|
|
|
|
if (searchViewItem != null && searchViewItem.expandActionView()) {
|
|
|
|
searchViewModel.onSearchOpened();
|
|
|
|
}
|
2022-02-07 16:31:04 +00:00
|
|
|
} else {
|
|
|
|
searchViewModel.onSearchClosed();
|
|
|
|
viewModel.setSearchQuery(null);
|
|
|
|
inputPanel.setHideForSearch(false);
|
2021-06-25 12:28:55 +00:00
|
|
|
}
|
2013-02-04 02:41:34 +00:00
|
|
|
}
|
|
|
|
|
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);
|
2013-03-05 01:43:04 +00:00
|
|
|
initializeMmsEnabledCheck();
|
2017-06-07 01:03:09 +00:00
|
|
|
initializeIdentityRecords();
|
2015-07-21 02:25:54 +00:00
|
|
|
composeText.setTransport(sendButton.getSelectedTransport());
|
2015-06-09 14:37:20 +00:00
|
|
|
|
2019-08-07 18:22:51 +00:00
|
|
|
Recipient recipientSnapshot = recipient.get();
|
|
|
|
|
|
|
|
titleView.setTitle(glideRequests, recipientSnapshot);
|
|
|
|
setBlockedUserState(recipientSnapshot, isSecureText, isDefaultSms);
|
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
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2022-01-14 13:06:28 +00:00
|
|
|
public void onStop() {
|
2017-02-18 04:43:24 +00:00
|
|
|
super.onStop();
|
2021-07-02 13:28:45 +00:00
|
|
|
saveDraft();
|
2017-02-18 04:43:24 +00:00
|
|
|
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);
|
2015-07-21 02:25:54 +00:00
|
|
|
composeText.setTransport(sendButton.getSelectedTransport());
|
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
|
|
|
}
|
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:
|
2018-06-29 18:08:13 +00:00
|
|
|
if (isSecureText && !isSmsForced()) {
|
|
|
|
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-01-14 13:06:28 +00:00
|
|
|
NotificationChannels.updateContactChannelName(requireContext(), recipientSnapshot);
|
2019-08-07 18:22:51 +00:00
|
|
|
setBlockedUserState(recipientSnapshot, isSecureText, isDefaultSms);
|
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-01-14 13:06:28 +00:00
|
|
|
DirectoryHelper.refreshDirectoryFor(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());
|
2015-12-18 22:37:11 +00:00
|
|
|
break;
|
2016-10-17 02:05:07 +00:00
|
|
|
case PICK_GIF:
|
2021-05-26 13:47:14 +00:00
|
|
|
onGifSelectSuccess(data.getData(),
|
|
|
|
data.getIntExtra(GiphyActivity.EXTRA_WIDTH, 0),
|
|
|
|
data.getIntExtra(GiphyActivity.EXTRA_HEIGHT, 0));
|
2016-10-17 02:05:07 +00:00
|
|
|
break;
|
2017-01-18 19:01:13 +00:00
|
|
|
case SMS_DEFAULT:
|
2017-03-14 20:24:24 +00:00
|
|
|
initializeSecurity(isSecureText, isDefaultSms);
|
2017-01-18 19:01:13 +00:00
|
|
|
break;
|
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;
|
|
|
|
}
|
|
|
|
|
2020-01-08 20:56:51 +00:00
|
|
|
sendButton.setTransport(result.getTransport());
|
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());
|
2022-03-14 19:49:46 +00:00
|
|
|
int subscriptionId = sendButton.getSelectedTransport().getSimSubscriptionId().orElse(-1);
|
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(),
|
|
|
|
result.getTransport().isSms(),
|
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
|
|
|
subscriptionId,
|
|
|
|
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
|
|
|
}
|
|
|
|
|
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.
|
2020-11-25 18:11:17 +00:00
|
|
|
ApplicationDependencies.getMessageNotifier().setVisibleThread(threadId);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2016-09-26 03:04:13 +00:00
|
|
|
if (isSecureText) {
|
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-01-31 17:46:44 +00:00
|
|
|
if (isSecureText) inflater.inflate(R.menu.conversation_callable_secure, menu);
|
|
|
|
else if (!recipient.get().isReleaseNotes()) 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);
|
|
|
|
if (distributionType == ThreadDatabase.DistributionTypes.BROADCAST) {
|
|
|
|
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-01-31 17:46:44 +00:00
|
|
|
if (isSingleConversation() && !isSecureText && !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-01-31 17:46:44 +00:00
|
|
|
if (isSingleConversation() && getRecipient().getContactUri() == null && !recipient.get().isReleaseNotes()) {
|
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()) {
|
2019-12-03 20:26:05 +00:00
|
|
|
if (isSecureText) {
|
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()) {
|
|
|
|
if (isSecureText) {
|
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);
|
2020-04-22 15:12:08 +00:00
|
|
|
setBlockedUserState(recipient.get(), isSecureText, isDefaultSms);
|
2019-02-01 17:06:59 +00:00
|
|
|
invalidateOptionsMenu();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
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);
|
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
|
|
|
|
public boolean onOptionsItemSelected(MenuItem item) {
|
|
|
|
super.onOptionsItemSelected(item);
|
|
|
|
switch (item.getItemId()) {
|
2018-09-27 18:45:56 +00:00
|
|
|
case R.id.menu_call_secure: handleDial(getRecipient(), true); return true;
|
2019-12-03 20:26:05 +00:00
|
|
|
case R.id.menu_video_secure: handleVideo(getRecipient()); return true;
|
2018-09-27 18:45:56 +00:00
|
|
|
case R.id.menu_call_insecure: handleDial(getRecipient(), false); return true;
|
2015-01-19 02:11:30 +00:00
|
|
|
case R.id.menu_view_media: handleViewMedia(); return true;
|
2018-04-08 10:55:30 +00:00
|
|
|
case R.id.menu_add_shortcut: handleAddShortcut(); return true;
|
2019-02-01 17:06:59 +00:00
|
|
|
case R.id.menu_search: handleSearch(); return true;
|
2014-06-03 23:24:44 +00:00
|
|
|
case R.id.menu_add_to_contacts: handleAddToContacts(); return true;
|
2013-04-26 01:59:49 +00:00
|
|
|
case R.id.menu_group_recipients: handleDisplayGroupRecipients(); return true;
|
|
|
|
case R.id.menu_distribution_broadcast: handleDistributionBroadcastEnabled(item); return true;
|
|
|
|
case R.id.menu_distribution_conversation: handleDistributionConversationEnabled(item); return true;
|
2020-06-16 17:07:25 +00:00
|
|
|
case R.id.menu_group_settings: handleManageGroup(); return true;
|
2014-02-20 23:41:52 +00:00
|
|
|
case R.id.menu_leave: handleLeavePushGroup(); return true;
|
2014-12-13 02:31:20 +00:00
|
|
|
case R.id.menu_invite: handleInviteLink(); return true;
|
2015-06-09 14:37:20 +00:00
|
|
|
case R.id.menu_mute_notifications: handleMuteNotifications(); return true;
|
|
|
|
case R.id.menu_unmute_notifications: handleUnmuteNotifications(); return true;
|
2015-07-08 19:22:51 +00:00
|
|
|
case R.id.menu_conversation_settings: handleConversationSettings(); return true;
|
2016-08-16 03:23:56 +00:00
|
|
|
case R.id.menu_expiring_messages_off:
|
|
|
|
case R.id.menu_expiring_messages: handleSelectMessageExpiration(); return true;
|
2020-11-25 18:11:17 +00:00
|
|
|
case R.id.menu_create_bubble: handleCreateBubble(); return true;
|
2022-01-28 17:24:44 +00:00
|
|
|
case android.R.id.home: requireActivity().finish(); return true;
|
2012-07-19 21:22:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
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-03-11 11:44:07 +00:00
|
|
|
} else if (isSearchRequested) {
|
|
|
|
searchViewItem.collapseActionView();
|
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();
|
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-01-14 13:06:28 +00:00
|
|
|
startActivityForResult(MediaSelectionActivity.editor(requireActivity(), sendButton.getSelectedTransport(), 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-01-25 13:58:52 +00:00
|
|
|
AttachmentManager.selectGallery(this, MEDIA_SENDER, recipient.get(), composeText.getTextTrimmed(), sendButton.getSelectedTransport(), 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-01-25 13:58:52 +00:00
|
|
|
AttachmentManager.selectLocation(this, PICK_LOCATION);
|
2020-01-30 03:13:44 +00:00
|
|
|
break;
|
2021-04-06 16:03:33 +00:00
|
|
|
case PAYMENT:
|
|
|
|
if (recipient.get().hasProfileKeyCredential()) {
|
2022-01-25 13:58:52 +00:00
|
|
|
AttachmentManager.selectPayment(this, recipient.getId());
|
2021-04-06 16:03:33 +00:00
|
|
|
} else {
|
2022-01-14 13:06:28 +00:00
|
|
|
CanNotSendPaymentDialog.show(requireActivity());
|
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
|
|
|
});
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2020-02-19 22:08:34 +00:00
|
|
|
if (isInMessageRequest()) return;
|
|
|
|
|
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-01-14 13:06:28 +00:00
|
|
|
RecipientUtil.unblock(context, 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
|
|
|
|
|
|
|
if (isDefaultSms) {
|
|
|
|
composeText.appendInvite(inviteText);
|
|
|
|
} else {
|
|
|
|
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);
|
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);
|
|
|
|
PendingIntent shortcutPinnedCallback = PendingIntent.getBroadcast(context, REQUEST_CODE_PIN_SHORTCUT, callbackIntent, 0);
|
|
|
|
|
|
|
|
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) {
|
|
|
|
distributionType = ThreadDatabase.DistributionTypes.BROADCAST;
|
|
|
|
item.setChecked(true);
|
|
|
|
|
|
|
|
if (threadId != -1) {
|
|
|
|
new AsyncTask<Void, Void, Void>() {
|
|
|
|
@Override
|
|
|
|
protected Void doInBackground(Void... params) {
|
2021-11-18 17:36:52 +00:00
|
|
|
SignalDatabase.threads().setDistributionType(threadId, ThreadDatabase.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) {
|
|
|
|
distributionType = ThreadDatabase.DistributionTypes.CONVERSATION;
|
|
|
|
item.setChecked(true);
|
|
|
|
|
|
|
|
if (threadId != -1) {
|
|
|
|
new AsyncTask<Void, Void, Void>() {
|
|
|
|
@Override
|
|
|
|
protected Void doInBackground(Void... params) {
|
2021-11-18 17:36:52 +00:00
|
|
|
SignalDatabase.threads().setDistributionType(threadId, ThreadDatabase.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-01-14 13:06:28 +00:00
|
|
|
CommunicationActions.startVoiceCall(requireActivity(), recipient);
|
2015-09-22 00:41:27 +00:00
|
|
|
} else {
|
2022-01-14 13:06:28 +00:00
|
|
|
CommunicationActions.startInsecureCall(requireActivity(), 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-01-14 13:06:28 +00:00
|
|
|
CommunicationActions.startVideoCall(requireActivity(), 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() {
|
2015-09-29 21:26:37 +00:00
|
|
|
if (this.isMmsEnabled || isSecureText) {
|
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());
|
|
|
|
|
|
|
|
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-01-14 13:06:28 +00:00
|
|
|
Bundle extras = requireActivity().getIntent().getExtras();
|
|
|
|
Intent intent = new Intent(requireContext(), PromptMmsActivity.class);
|
2017-12-05 19:52:03 +00:00
|
|
|
if (extras != null) 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-01-14 13:06:28 +00:00
|
|
|
SafetyNumberChangeDialog.show(getChildFragmentManager(), records);
|
2017-06-07 01:03:09 +00:00
|
|
|
}
|
|
|
|
|
2020-06-26 15:10:54 +00:00
|
|
|
@Override
|
2020-12-04 20:24:18 +00:00
|
|
|
public void onSendAnywayAfterSafetyNumberChange(@NonNull List<RecipientId> changedRecipients) {
|
2021-06-10 20:06:32 +00:00
|
|
|
Log.d(TAG, "onSendAnywayAfterSafetyNumberChange");
|
2020-06-26 15:10:54 +00:00
|
|
|
initializeIdentityRecords().addListener(new AssertedSuccessListener<Boolean>() {
|
|
|
|
@Override
|
|
|
|
public void onSuccess(Boolean result) {
|
2021-08-23 14:05:48 +00:00
|
|
|
sendMessage(null);
|
2020-06-26 15:10:54 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
2017-06-07 01:03:09 +00:00
|
|
|
|
2020-06-26 15:10:54 +00:00
|
|
|
@Override
|
|
|
|
public void onMessageResentAfterSafetyNumberChange() {
|
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() { }
|
|
|
|
|
2017-03-14 20:24:24 +00:00
|
|
|
private void handleSecurityChange(boolean isSecureText, boolean isDefaultSms) {
|
2018-08-02 13:25:33 +00:00
|
|
|
Log.i(TAG, "handleSecurityChange(" + isSecureText + ", " + isDefaultSms + ")");
|
2017-09-07 00:54:32 +00:00
|
|
|
|
|
|
|
this.isSecureText = isSecureText;
|
|
|
|
this.isDefaultSms = isDefaultSms;
|
|
|
|
this.isSecurityInitialized = true;
|
2015-09-29 21:26:37 +00:00
|
|
|
|
2019-08-07 18:22:51 +00:00
|
|
|
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())) {
|
|
|
|
sendButton.disableTransport(Type.SMS);
|
2022-02-04 17:01:31 +00:00
|
|
|
smsEnabled = false;
|
|
|
|
}
|
|
|
|
|
2022-02-17 20:55:54 +00:00
|
|
|
if (!isSecureText && !isPushGroupConversation() && !recipient.get().isServiceIdOnly() && !recipient.get().isReleaseNotes() && smsEnabled) {
|
2022-02-04 17:01:31 +00:00
|
|
|
sendButton.disableTransport(Type.TEXTSECURE);
|
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) {
|
2019-04-12 19:22:38 +00:00
|
|
|
sendButton.setDefaultTransport(Type.SMS);
|
|
|
|
} else {
|
2022-02-17 20:55:54 +00:00
|
|
|
if (isSecureText || isPushGroupConversation() || recipient.get().isServiceIdOnly() || recipient.get().isReleaseNotes() || !smsEnabled) {
|
2021-05-03 17:45:53 +00:00
|
|
|
sendButton.setDefaultTransport(Type.TEXTSECURE);
|
|
|
|
} else {
|
|
|
|
sendButton.setDefaultTransport(Type.SMS);
|
|
|
|
}
|
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();
|
2019-08-07 18:22:51 +00:00
|
|
|
setBlockedUserState(recipient.get(), isSecureText, isDefaultSms);
|
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<>();
|
|
|
|
|
2020-11-25 15:36:33 +00:00
|
|
|
final CharSequence draftText = args.getDraftText();
|
2022-01-14 13:06:28 +00:00
|
|
|
final Uri draftMedia = requireActivity().getIntent().getData();
|
|
|
|
final String draftContentType = requireActivity().getIntent().getType();
|
|
|
|
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) {
|
|
|
|
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-01-14 13:06:28 +00:00
|
|
|
Intent sendIntent = MediaSelectionActivity.editor(requireContext(), sendButton.getSelectedTransport(), 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) {
|
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
|
|
|
|
2015-11-18 20:54:40 +00:00
|
|
|
if (draftText == null && draftMedia == null && draftMediaType == null) {
|
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
|
|
|
|
2021-08-27 17:30:30 +00:00
|
|
|
if (!leftGroup && !canCancelRequest && selfMembership.isAnnouncementGroup() && selfMembership.getMemberLevel() != GroupDatabase.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
|
|
|
}
|
|
|
|
|
|
|
|
noLongerMemberBanner.setVisibility(leftGroup ? View.VISIBLE : View.GONE);
|
|
|
|
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-01-14 13:06:28 +00:00
|
|
|
final Context context = requireContext().getApplicationContext();
|
|
|
|
|
2020-08-05 20:45:52 +00:00
|
|
|
new AsyncTask<Void, Void, Pair<Drafts, CharSequence>>() {
|
2013-02-04 08:13:07 +00:00
|
|
|
@Override
|
2020-08-05 20:45:52 +00:00
|
|
|
protected Pair<Drafts, CharSequence> doInBackground(Void... params) {
|
2021-11-18 17:36:52 +00:00
|
|
|
DraftDatabase draftDatabase = SignalDatabase.drafts();
|
2020-08-05 20:45:52 +00:00
|
|
|
Drafts results = draftDatabase.getDrafts(threadId);
|
|
|
|
Draft mentionsDraft = results.getDraftOfType(Draft.MENTION);
|
|
|
|
Spannable updatedText = null;
|
|
|
|
|
|
|
|
if (mentionsDraft != null) {
|
|
|
|
String text = results.getDraftOfType(Draft.TEXT).getValue();
|
|
|
|
List<Mention> mentions = MentionUtil.bodyRangeListToMentions(context, Base64.decodeOrThrow(mentionsDraft.getValue()));
|
|
|
|
UpdatedBodyAndMentions updated = MentionUtil.updateBodyAndMentionsWithDisplayNames(context, text, mentions);
|
|
|
|
|
|
|
|
updatedText = new SpannableString(updated.getBody());
|
|
|
|
MentionAnnotation.setMentionAnnotations(updatedText, updated.getMentions());
|
|
|
|
}
|
2013-02-04 08:13:07 +00:00
|
|
|
|
|
|
|
draftDatabase.clearDrafts(threadId);
|
|
|
|
|
2020-08-05 20:45:52 +00:00
|
|
|
return new Pair<>(results, updatedText);
|
2013-02-04 08:13:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-08-05 20:45:52 +00:00
|
|
|
protected void onPostExecute(Pair<Drafts, CharSequence> draftsWithUpdatedMentions) {
|
|
|
|
Drafts drafts = Objects.requireNonNull(draftsWithUpdatedMentions.first());
|
|
|
|
CharSequence updatedText = draftsWithUpdatedMentions.second();
|
|
|
|
|
2018-10-29 22:14:31 +00:00
|
|
|
if (drafts.isEmpty()) {
|
|
|
|
future.set(false);
|
|
|
|
updateToggleButtonState();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-07-25 15:30:48 +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);
|
|
|
|
|
|
|
|
if (draftsRemaining.decrementAndGet() <= 0) {
|
|
|
|
future.set(success.get());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2013-02-04 08:13:07 +00:00
|
|
|
for (Draft draft : drafts) {
|
2016-01-04 21:02:22 +00:00
|
|
|
try {
|
2017-12-05 19:52:03 +00:00
|
|
|
switch (draft.getType()) {
|
|
|
|
case Draft.TEXT:
|
2020-08-05 20:45:52 +00:00
|
|
|
composeText.setText(updatedText == null ? draft.getValue() : updatedText);
|
2018-07-25 15:30:48 +00:00
|
|
|
listener.onSuccess(true);
|
2017-12-05 19:52:03 +00:00
|
|
|
break;
|
|
|
|
case Draft.LOCATION:
|
2018-07-25 15:30:48 +00:00
|
|
|
attachmentManager.setLocation(SignalPlace.deserialize(draft.getValue()), getCurrentMediaConstraints()).addListener(listener);
|
2017-12-05 19:52:03 +00:00
|
|
|
break;
|
|
|
|
case Draft.IMAGE:
|
2022-01-14 13:06:28 +00:00
|
|
|
setMedia(Uri.parse(draft.getValue()), MediaType.IMAGE).addListener(listener);
|
2017-12-05 19:52:03 +00:00
|
|
|
break;
|
|
|
|
case Draft.AUDIO:
|
2022-01-14 13:06:28 +00:00
|
|
|
setMedia(Uri.parse(draft.getValue()), MediaType.AUDIO).addListener(listener);
|
2017-12-05 19:52:03 +00:00
|
|
|
break;
|
|
|
|
case Draft.VIDEO:
|
2022-01-14 13:06:28 +00:00
|
|
|
setMedia(Uri.parse(draft.getValue()), MediaType.VIDEO).addListener(listener);
|
2017-12-05 19:52:03 +00:00
|
|
|
break;
|
2018-04-24 18:09:54 +00:00
|
|
|
case Draft.QUOTE:
|
2018-07-25 15:30:48 +00:00
|
|
|
SettableFuture<Boolean> quoteResult = new SettableFuture<>();
|
|
|
|
new QuoteRestorationTask(draft.getValue(), quoteResult).execute();
|
|
|
|
quoteResult.addListener(listener);
|
2021-07-09 16:03:20 +00:00
|
|
|
break;
|
2021-07-02 13:28:45 +00:00
|
|
|
case Draft.VOICE_NOTE:
|
|
|
|
draftViewModel.setVoiceNoteDraft(recipient.getId(), draft);
|
2018-04-24 18:09:54 +00:00
|
|
|
break;
|
2016-01-04 21:02:22 +00:00
|
|
|
}
|
|
|
|
} catch (IOException e) {
|
|
|
|
Log.w(TAG, e);
|
2014-05-22 21:00:53 +00:00
|
|
|
}
|
2013-02-04 08:13:07 +00:00
|
|
|
}
|
2015-05-18 17:26:32 +00:00
|
|
|
|
|
|
|
updateToggleButtonState();
|
2013-02-04 08:13:07 +00:00
|
|
|
}
|
2017-10-23 20:03:32 +00:00
|
|
|
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
2018-07-25 15:30:48 +00:00
|
|
|
|
|
|
|
return future;
|
2013-02-03 04:37:40 +00:00
|
|
|
}
|
|
|
|
|
2015-10-02 00:46:47 +00:00
|
|
|
private ListenableFuture<Boolean> initializeSecurity(final boolean currentSecureText,
|
2017-01-18 19:01:13 +00:00
|
|
|
final boolean currentIsDefaultSms)
|
2015-09-29 21:26:37 +00:00
|
|
|
{
|
2022-01-14 13:06:28 +00:00
|
|
|
final SettableFuture<Boolean> future = new SettableFuture<>();
|
|
|
|
final Context context = requireContext().getApplicationContext();
|
2015-10-02 00:46:47 +00:00
|
|
|
|
2017-03-14 20:24:24 +00:00
|
|
|
handleSecurityChange(currentSecureText || isPushGroupConversation(), currentIsDefaultSms);
|
2015-09-22 00:41:27 +00:00
|
|
|
|
2017-08-01 15:56:00 +00:00
|
|
|
new AsyncTask<Recipient, Void, boolean[]>() {
|
2015-09-22 00:41:27 +00:00
|
|
|
@Override
|
2017-08-01 15:56:00 +00:00
|
|
|
protected boolean[] doInBackground(Recipient... params) {
|
2019-08-07 18:22:51 +00:00
|
|
|
Recipient recipient = params[0].resolve();
|
2018-08-02 13:25:33 +00:00
|
|
|
Log.i(TAG, "Resolving registered state...");
|
2017-11-25 17:50:36 +00:00
|
|
|
RegisteredState registeredState;
|
|
|
|
|
2019-08-07 18:22:51 +00:00
|
|
|
if (recipient.isPushGroup()) {
|
2018-08-02 13:25:33 +00:00
|
|
|
Log.i(TAG, "Push group recipient...");
|
2017-11-27 17:44:50 +00:00
|
|
|
registeredState = RegisteredState.REGISTERED;
|
2017-11-25 17:50:36 +00:00
|
|
|
} else {
|
2018-08-02 13:25:33 +00:00
|
|
|
Log.i(TAG, "Checking through resolved recipient");
|
2017-11-25 17:50:36 +00:00
|
|
|
registeredState = recipient.resolve().getRegistered();
|
|
|
|
}
|
|
|
|
|
2018-08-02 13:25:33 +00:00
|
|
|
Log.i(TAG, "Resolved registered state: " + registeredState);
|
2021-05-26 16:02:19 +00:00
|
|
|
boolean signalEnabled = Recipient.self().isRegistered();
|
2015-09-29 21:26:37 +00:00
|
|
|
|
2017-08-22 17:44:04 +00:00
|
|
|
if (registeredState == RegisteredState.UNKNOWN) {
|
2017-02-01 05:46:20 +00:00
|
|
|
try {
|
2019-09-07 03:40:06 +00:00
|
|
|
Log.i(TAG, "Refreshing directory for user: " + recipient.getId().serialize());
|
|
|
|
registeredState = DirectoryHelper.refreshDirectoryFor(context, recipient, false);
|
2017-02-01 05:46:20 +00:00
|
|
|
} catch (IOException e) {
|
|
|
|
Log.w(TAG, e);
|
2015-09-29 21:26:37 +00:00
|
|
|
}
|
2015-09-22 00:41:27 +00:00
|
|
|
}
|
2017-02-01 05:46:20 +00:00
|
|
|
|
2018-08-02 13:25:33 +00:00
|
|
|
Log.i(TAG, "Returning registered state...");
|
2017-09-14 23:46:12 +00:00
|
|
|
return new boolean[] {registeredState == RegisteredState.REGISTERED && signalEnabled,
|
|
|
|
Util.isDefaultSmsProvider(context)};
|
2015-09-22 00:41:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2017-01-18 19:01:13 +00:00
|
|
|
protected void onPostExecute(boolean[] result) {
|
2017-03-14 20:24:24 +00:00
|
|
|
if (result[0] != currentSecureText || result[1] != currentIsDefaultSms) {
|
2018-08-02 13:25:33 +00:00
|
|
|
Log.i(TAG, "onPostExecute() handleSecurityChange: " + result[0] + " , " + result[1]);
|
2017-03-14 20:24:24 +00:00
|
|
|
handleSecurityChange(result[0], result[1]);
|
2015-09-22 00:41:27 +00:00
|
|
|
}
|
2015-10-02 00:46:47 +00:00
|
|
|
future.set(true);
|
2015-10-14 04:44:01 +00:00
|
|
|
onSecurityUpdated();
|
2015-09-22 00:41:27 +00:00
|
|
|
}
|
2019-08-07 18:22:51 +00:00
|
|
|
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, recipient.get());
|
2015-10-02 00:46:47 +00:00
|
|
|
|
|
|
|
return future;
|
2015-09-22 00:41:27 +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) &&
|
|
|
|
!isSecureText &&
|
|
|
|
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) {
|
|
|
|
groupViewModel.onSuggestedMembersBannerDismissed(recipient.get().requireGroupId(), gv1MigrationSuggestions);
|
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) + ")");
|
2016-02-06 00:10:33 +00:00
|
|
|
sendButton.setDefaultSubscriptionId(defaultSubscriptionId);
|
|
|
|
}
|
|
|
|
|
2013-03-05 01:43:04 +00:00
|
|
|
private void initializeMmsEnabledCheck() {
|
2022-01-14 13:06:28 +00:00
|
|
|
final Context context = requireContext().getApplicationContext();
|
|
|
|
|
2013-03-05 01:43:04 +00:00
|
|
|
new AsyncTask<Void, Void, Boolean>() {
|
|
|
|
@Override
|
|
|
|
protected Boolean doInBackground(Void... params) {
|
2022-01-14 13:06:28 +00:00
|
|
|
return Util.isMmsCapable(context);
|
2013-03-05 01:43:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
protected void onPostExecute(Boolean isMmsEnabled) {
|
2022-01-14 13:06:28 +00:00
|
|
|
ConversationParentFragment.this.isMmsEnabled = isMmsEnabled;
|
2013-03-05 01:43:04 +00:00
|
|
|
}
|
2017-10-23 20:03:32 +00:00
|
|
|
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
2013-03-05 01:43:04 +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()) {
|
2021-11-18 17:36:52 +00:00
|
|
|
recipients = SignalDatabase.groups().getGroupMembers(params[0].requireGroupId(), GroupDatabase.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();
|
|
|
|
}
|
|
|
|
|
2017-06-22 17:37:26 +00:00
|
|
|
titleView.setVerified(isSecureText && identityRecords.isVerified());
|
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);
|
|
|
|
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);
|
|
|
|
makeDefaultSmsButton = view.findViewById(R.id.make_default_sms_button);
|
|
|
|
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);
|
|
|
|
panelParent = view.findViewById(R.id.conversation_activity_panel_parent);
|
|
|
|
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);
|
|
|
|
|
|
|
|
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
|
|
|
|
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-01-14 13:06:28 +00:00
|
|
|
attachmentManager = new AttachmentManager(requireActivity(), this);
|
|
|
|
audioRecorder = new AudioRecorder(requireContext());
|
2020-01-30 03:13:44 +00:00
|
|
|
typingTextWatcher = new TypingStatusTextWatcher();
|
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);
|
2017-12-05 19:52:03 +00:00
|
|
|
sendButton.addOnTransportChangedListener((newTransport, manuallySelected) -> {
|
|
|
|
calculateCharactersRemaining();
|
2019-01-15 08:41:05 +00:00
|
|
|
updateLinkPreviewState();
|
2020-08-27 14:52:47 +00:00
|
|
|
linkPreviewViewModel.onTransportChanged(newTransport.isSms());
|
2017-12-05 19:52:03 +00:00
|
|
|
composeText.setTransport(newTransport);
|
2019-10-07 18:43:36 +00:00
|
|
|
|
|
|
|
buttonToggle.getBackground().setColorFilter(newTransport.getBackgroundColor(), PorterDuff.Mode.MULTIPLY);
|
2017-12-05 19:52:03 +00:00
|
|
|
buttonToggle.getBackground().invalidateSelf();
|
2019-10-07 18:43:36 +00:00
|
|
|
|
2019-04-12 19:22:38 +00:00
|
|
|
if (manuallySelected) recordTransportPreference(newTransport);
|
2015-02-16 10:38:09 +00:00
|
|
|
});
|
|
|
|
|
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());
|
|
|
|
makeDefaultSmsButton.setOnClickListener(v -> handleMakeDefaultSms());
|
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());
|
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
|
|
|
|
|
|
|
int toolbarColor = getResources().getColor(R.color.conversation_toolbar_color_wallpaper);
|
|
|
|
toolbar.setBackgroundColor(toolbarColor);
|
2022-01-14 13:06:28 +00:00
|
|
|
// TODO [alex] LargeScreenSupport -- statusBarBox
|
2022-02-02 14:52:51 +00:00
|
|
|
if (Build.VERSION.SDK_INT > 23) {
|
2022-01-14 13:06:28 +00:00
|
|
|
WindowUtil.setStatusBarColor(requireActivity().getWindow(), toolbarColor);
|
2021-02-12 19:16:21 +00:00
|
|
|
}
|
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
|
|
|
|
|
|
|
int toolbarColor = getResources().getColor(R.color.conversation_toolbar_color);
|
|
|
|
toolbar.setBackgroundColor(toolbarColor);
|
2022-01-14 13:06:28 +00:00
|
|
|
// TODO [alex] LargeScreenSupport -- statusBarBox
|
2022-02-02 14:52:51 +00:00
|
|
|
if (Build.VERSION.SDK_INT > 23) {
|
2022-01-14 13:06:28 +00:00
|
|
|
WindowUtil.setStatusBarColor(requireActivity().getWindow(), toolbarColor);
|
2021-02-12 19:16:21 +00:00
|
|
|
}
|
2021-01-20 02:54:10 +00:00
|
|
|
}
|
2021-01-20 21:09:36 +00:00
|
|
|
fragment.onWallpaperChanged(chatWallpaper);
|
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-01-14 13:06:28 +00:00
|
|
|
linkPreviewViewModel = new ViewModelProvider(this, 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));
|
|
|
|
|
|
|
|
searchViewModel = new ViewModelProvider(this, 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-01-14 13:06:28 +00:00
|
|
|
stickerViewModel = new ViewModelProvider(this, 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-01-14 13:06:28 +00:00
|
|
|
this.viewModel = new ViewModelProvider(this, 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-01-14 13:06:28 +00:00
|
|
|
groupViewModel = new ViewModelProvider(this, 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-01-14 13:06:28 +00:00
|
|
|
mentionsViewModel = new ViewModelProvider(requireActivity(), new MentionsPickerViewModel.Factory()).get(MentionsPickerViewModel.class);
|
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
|
|
|
|
2020-07-27 13:58:58 +00:00
|
|
|
composeText.setMentionQueryChangedListener(query -> {
|
2020-09-25 16:13:18 +00:00
|
|
|
if (getRecipient().isPushV2Group() && getRecipient().isActiveGroup()) {
|
2020-07-27 13:58:58 +00:00
|
|
|
if (!mentionsSuggestions.resolved()) {
|
|
|
|
mentionsSuggestions.get();
|
|
|
|
}
|
|
|
|
mentionsViewModel.onQueryChange(query);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
Set<String> validRecipientIds = Stream.of(getRecipient().getParticipants())
|
|
|
|
.map(r -> MentionAnnotation.idToMentionAnnotationValue(r.getId()))
|
|
|
|
.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
|
|
|
});
|
|
|
|
}
|
|
|
|
|
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-01-14 13:06:28 +00:00
|
|
|
draftViewModel = new ViewModelProvider(this, new DraftViewModel.Factory(new DraftRepository(requireContext().getApplicationContext()))).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-01-14 13:06:28 +00:00
|
|
|
draftViewModel.getState().observe(getViewLifecycleOwner(),
|
2021-07-02 13:28:45 +00:00
|
|
|
state -> {
|
|
|
|
inputPanel.setVoiceNoteDraft(state.getVoiceNoteDraft());
|
|
|
|
updateToggleButtonState();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
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() {
|
2017-06-14 16:53:22 +00:00
|
|
|
if (!isSecureText) {
|
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);
|
|
|
|
titleView.setVerified(identityRecords.isVerified());
|
|
|
|
setBlockedUserState(recipient, isSecureText, isDefaultSms);
|
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();
|
2019-08-07 18:22:51 +00:00
|
|
|
initializeSecurity(isSecureText, isDefaultSms);
|
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);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
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) {
|
2017-03-14 20:24:24 +00:00
|
|
|
initializeSecurity(isSecureText, isDefaultSms);
|
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-01-14 13:06:28 +00:00
|
|
|
if (MediaType.VCARD.equals(mediaType) && isSecureText) {
|
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-01-14 13:06:28 +00:00
|
|
|
startActivityForResult(MediaSelectionActivity.editor(requireContext(), sendButton.getSelectedTransport(), 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-01-14 13:06:28 +00:00
|
|
|
Intent intent = ContactShareEditActivity.getIntent(requireContext(), Collections.singletonList(contactUri));
|
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) {
|
2022-03-14 19:49:46 +00:00
|
|
|
int subscriptionId = sendButton.getSelectedTransport().getSimSubscriptionId().orElse(-1);
|
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;
|
|
|
|
|
2021-08-23 14:05:48 +00:00
|
|
|
sendMediaMessage(recipient.getId(), isSmsForced(), "", attachmentManager.buildSlideDeck(), null, contacts, Collections.emptyList(), Collections.emptyList(), expiresIn, false, subscriptionId, 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-01-14 13:06:28 +00:00
|
|
|
AlertDialog.Builder builder = new AlertDialog.Builder(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();
|
|
|
|
}
|
|
|
|
|
2014-12-12 01:13:01 +00:00
|
|
|
private Drafts getDraftsForCurrentState() {
|
|
|
|
Drafts drafts = new Drafts();
|
2013-02-04 08:13:07 +00:00
|
|
|
|
2020-10-05 16:59:00 +00:00
|
|
|
if (recipient.get().isGroup() && !recipient.get().isActiveGroup()) {
|
|
|
|
return drafts;
|
|
|
|
}
|
|
|
|
|
2013-02-04 08:13:07 +00:00
|
|
|
if (!Util.isEmpty(composeText)) {
|
2020-08-05 20:45:52 +00:00
|
|
|
drafts.add(new Draft(Draft.TEXT, composeText.getTextTrimmed().toString()));
|
|
|
|
List<Mention> draftMentions = composeText.getMentions();
|
|
|
|
if (!draftMentions.isEmpty()) {
|
|
|
|
drafts.add(new Draft(Draft.MENTION, Base64.encodeBytes(MentionUtil.mentionsToBodyRangeList(draftMentions).toByteArray())));
|
|
|
|
}
|
2013-02-04 08:13:07 +00:00
|
|
|
}
|
|
|
|
|
2015-10-15 21:40:45 +00:00
|
|
|
for (Slide slide : attachmentManager.buildSlideDeck().getSlides()) {
|
2016-12-11 21:37:27 +00:00
|
|
|
if (slide.hasAudio() && slide.getUri() != null) drafts.add(new Draft(Draft.AUDIO, slide.getUri().toString()));
|
|
|
|
else if (slide.hasVideo() && slide.getUri() != null) drafts.add(new Draft(Draft.VIDEO, slide.getUri().toString()));
|
|
|
|
else if (slide.hasLocation()) drafts.add(new Draft(Draft.LOCATION, ((LocationSlide)slide).getPlace().serialize()));
|
|
|
|
else if (slide.hasImage() && slide.getUri() != null) drafts.add(new Draft(Draft.IMAGE, slide.getUri().toString()));
|
2013-02-04 08:13:07 +00:00
|
|
|
}
|
|
|
|
|
2018-04-24 18:09:54 +00:00
|
|
|
Optional<QuoteModel> quote = inputPanel.getQuote();
|
|
|
|
|
|
|
|
if (quote.isPresent()) {
|
|
|
|
drafts.add(new Draft(Draft.QUOTE, new QuoteId(quote.get().getId(), quote.get().getAuthor()).serialize()));
|
|
|
|
}
|
|
|
|
|
2022-01-14 13:06:28 +00:00
|
|
|
Draft voiceNoteDraft = draftViewModel.getVoiceNoteDraft();
|
2021-07-02 13:28:45 +00:00
|
|
|
if (voiceNoteDraft != null) {
|
|
|
|
drafts.add(voiceNoteDraft);
|
|
|
|
}
|
|
|
|
|
2013-02-04 08:13:07 +00:00
|
|
|
return drafts;
|
|
|
|
}
|
|
|
|
|
2015-06-22 15:46:43 +00:00
|
|
|
protected ListenableFuture<Long> saveDraft() {
|
|
|
|
final SettableFuture<Long> future = new SettableFuture<>();
|
|
|
|
|
2017-08-01 15:56:00 +00:00
|
|
|
if (this.recipient == null) {
|
2015-06-22 15:46:43 +00:00
|
|
|
future.set(threadId);
|
|
|
|
return future;
|
|
|
|
}
|
2013-02-04 08:13:07 +00:00
|
|
|
|
2022-01-14 13:06:28 +00:00
|
|
|
final Context context = requireContext().getApplicationContext();
|
2021-07-02 13:28:45 +00:00
|
|
|
final Drafts drafts = getDraftsForCurrentState();
|
|
|
|
final long thisThreadId = this.threadId;
|
|
|
|
final RecipientId recipientId = this.recipient.getId();
|
|
|
|
final int thisDistributionType = this.distributionType;
|
|
|
|
final ListenableFuture<VoiceNoteDraft> voiceNoteDraftFuture = draftViewModel.consumeVoiceNoteDraftFuture();
|
2013-02-04 08:13:07 +00:00
|
|
|
|
2015-06-22 15:46:43 +00:00
|
|
|
new AsyncTask<Long, Void, Long>() {
|
2013-02-04 08:13:07 +00:00
|
|
|
@Override
|
2015-06-22 15:46:43 +00:00
|
|
|
protected Long doInBackground(Long... params) {
|
2021-07-02 13:28:45 +00:00
|
|
|
if (voiceNoteDraftFuture != null) {
|
|
|
|
try {
|
|
|
|
Draft voiceNoteDraft = voiceNoteDraftFuture.get().asDraft();
|
|
|
|
draftViewModel.setVoiceNoteDraft(recipientId, voiceNoteDraft);
|
|
|
|
drafts.add(voiceNoteDraft);
|
|
|
|
} catch (ExecutionException | InterruptedException e) {
|
|
|
|
Log.w(TAG, "Could not extract voice note draft data.", e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-18 17:36:52 +00:00
|
|
|
ThreadDatabase threadDatabase = SignalDatabase.threads();
|
|
|
|
DraftDatabase draftDatabase = SignalDatabase.drafts();
|
2015-01-03 23:25:35 +00:00
|
|
|
long threadId = params[0];
|
|
|
|
|
2014-12-12 01:13:01 +00:00
|
|
|
if (drafts.size() > 0) {
|
2021-07-27 17:52:49 +00:00
|
|
|
if (threadId == -1) threadId = threadDatabase.getOrCreateThreadIdFor(getRecipient(), thisDistributionType);
|
2015-01-03 23:25:35 +00:00
|
|
|
|
2021-07-02 13:28:45 +00:00
|
|
|
draftDatabase.replaceDrafts(threadId, drafts);
|
2022-01-14 13:06:28 +00:00
|
|
|
threadDatabase.updateSnippet(threadId, drafts.getSnippet(context),
|
2018-01-25 03:17:44 +00:00
|
|
|
drafts.getUriSnippet(),
|
2015-11-23 23:07:41 +00:00
|
|
|
System.currentTimeMillis(), Types.BASE_DRAFT_TYPE, true);
|
2015-01-03 23:25:35 +00:00
|
|
|
} else if (threadId > 0) {
|
2015-11-23 23:07:41 +00:00
|
|
|
threadDatabase.update(threadId, false);
|
2014-12-12 01:13:01 +00:00
|
|
|
}
|
2015-06-22 15:46:43 +00:00
|
|
|
|
2021-07-07 19:43:24 +00:00
|
|
|
if (drafts.isEmpty()) {
|
|
|
|
draftDatabase.clearDrafts(threadId);
|
|
|
|
}
|
|
|
|
|
2015-06-22 15:46:43 +00:00
|
|
|
return threadId;
|
2013-02-04 08:13:07 +00:00
|
|
|
}
|
2015-06-22 15:46:43 +00:00
|
|
|
|
|
|
|
@Override
|
|
|
|
protected void onPostExecute(Long result) {
|
|
|
|
future.set(result);
|
|
|
|
}
|
|
|
|
|
2017-10-23 20:03:32 +00:00
|
|
|
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, thisThreadId);
|
2015-06-22 15:46:43 +00:00
|
|
|
|
|
|
|
return future;
|
2013-02-04 08:13:07 +00:00
|
|
|
}
|
|
|
|
|
2017-08-01 15:56:00 +00:00
|
|
|
private void setBlockedUserState(Recipient recipient, boolean isSecureText, boolean isDefaultSms) {
|
2020-06-16 14:37:27 +00:00
|
|
|
if (!isSecureText && isPushGroupConversation()) {
|
2017-12-25 23:57:33 +00:00
|
|
|
unblockButton.setVisibility(View.GONE);
|
2021-07-23 20:22:08 +00:00
|
|
|
inputPanel.setHideForBlockedState(true);
|
2017-12-25 23:57:33 +00:00
|
|
|
makeDefaultSmsButton.setVisibility(View.GONE);
|
|
|
|
registerButton.setVisibility(View.VISIBLE);
|
2021-05-03 17:45:53 +00:00
|
|
|
} else if (!isSecureText && !isDefaultSms && recipient.hasSmsAddress()) {
|
2016-11-20 23:56:47 +00:00
|
|
|
unblockButton.setVisibility(View.GONE);
|
2021-07-23 20:22:08 +00:00
|
|
|
inputPanel.setHideForBlockedState(true);
|
2016-11-20 23:56:47 +00:00
|
|
|
makeDefaultSmsButton.setVisibility(View.VISIBLE);
|
2017-12-25 23:57:33 +00:00
|
|
|
registerButton.setVisibility(View.GONE);
|
2022-01-31 17:46:44 +00:00
|
|
|
} else if (recipient.isReleaseNotes() && !recipient.isBlocked()) {
|
|
|
|
unblockButton.setVisibility(View.GONE);
|
|
|
|
inputPanel.setHideForBlockedState(true);
|
|
|
|
makeDefaultSmsButton.setVisibility(View.GONE);
|
|
|
|
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());
|
|
|
|
} else if (releaseChannelUnmute.resolved()) {
|
|
|
|
releaseChannelUnmute.get().setVisibility(View.GONE);
|
|
|
|
}
|
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);
|
2016-11-20 23:56:47 +00:00
|
|
|
makeDefaultSmsButton.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();
|
2015-03-07 17:02:10 +00:00
|
|
|
TransportOption transportOption = sendButton.getSelectedTransport();
|
2016-04-17 16:09:31 +00:00
|
|
|
CharacterState characterState = transportOption.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() {
|
|
|
|
return sendButton.isManualSelection() && sendButton.getSelectedTransport().isSms();
|
|
|
|
}
|
|
|
|
|
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() {
|
|
|
|
return sendButton.getSelectedTransport().getType() == Type.TEXTSECURE
|
2017-05-08 22:32:59 +00:00
|
|
|
? MediaConstraints.getPushMediaConstraints()
|
2022-03-14 19:49:46 +00:00
|
|
|
: MediaConstraints.getMmsMediaConstraints(sendButton.getSelectedTransport().getSimSubscriptionId().orElse(-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);
|
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());
|
|
|
|
draftViewModel.clearVoiceNoteDraft();
|
|
|
|
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();
|
|
|
|
TransportOption transport = sendButton.getSelectedTransport();
|
2019-04-28 18:34:56 +00:00
|
|
|
boolean forceSms = (recipient.isForceSmsSelection() || sendButton.isManualSelection()) && transport.isSms();
|
2022-03-14 19:49:46 +00:00
|
|
|
int subscriptionId = sendButton.getSelectedTransport().getSimSubscriptionId().orElse(-1);
|
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;
|
|
|
|
boolean needsSplit = !transport.isSms() && message.length() > transport.calculateCharacters(message).maxPrimaryMessageSize;
|
|
|
|
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
|
|
|
|
2021-03-08 20:27:10 +00:00
|
|
|
Log.i(TAG, "[sendMessage] recipient: " + recipient.getId() + ", threadId: " + threadId + ", forceSms: " + forceSms + ", isManual: " + sendButton.isManualSelection());
|
2012-08-02 00:39:36 +00:00
|
|
|
|
2019-09-07 03:40:06 +00:00
|
|
|
if ((recipient.isMmsGroup() || recipient.getEmail().isPresent()) && !isMmsEnabled) {
|
2013-09-16 07:55:01 +00:00
|
|
|
handleManualMmsRequired();
|
2020-08-12 15:18:14 +00:00
|
|
|
} else if (!forceSms && (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) {
|
2021-08-23 14:05:48 +00:00
|
|
|
sendMediaMessage(forceSms, expiresIn, false, subscriptionId, initiating, metricId);
|
2012-07-19 21:22:03 +00:00
|
|
|
} else {
|
2021-08-23 14:05:48 +00:00
|
|
|
sendTextMessage(forceSms, expiresIn, subscriptionId, 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) {
|
2021-01-15 17:15:07 +00:00
|
|
|
long thread = this.threadId;
|
2021-07-29 20:24:20 +00:00
|
|
|
long expiresIn = TimeUnit.SECONDS.toMillis(recipient.get().getExpiresInSeconds());
|
2022-03-14 19:49:46 +00:00
|
|
|
QuoteModel quote = result.isViewOnce() ? null : inputPanel.getQuote().orElse(null);
|
2020-08-05 20:45:52 +00:00
|
|
|
List<Mention> mentions = new ArrayList<>(result.getMentions());
|
2022-03-16 16:44:54 +00:00
|
|
|
OutgoingMediaMessage message = new OutgoingMediaMessage(recipient.get(), new SlideDeck(), result.getBody(), System.currentTimeMillis(), -1, expiresIn, result.isViewOnce(), distributionType, result.getStoryType(), null, false, quote, Collections.emptyList(), Collections.emptyList(), mentions);
|
2020-08-05 20:45:52 +00:00
|
|
|
OutgoingMediaMessage secureMessage = new OutgoingSecureMediaMessage(message);
|
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("");
|
|
|
|
|
2021-08-05 14:05:54 +00:00
|
|
|
long id = fragment.stageOutgoingMessage(secureMessage);
|
2020-01-08 20:56:51 +00:00
|
|
|
|
|
|
|
SimpleTask.run(() -> {
|
2022-01-14 13:06:28 +00:00
|
|
|
long resultId = MessageSender.sendPushWithPreUploadedMedia(context, secureMessage, 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);
|
|
|
|
}
|
|
|
|
|
2021-08-23 14:05:48 +00:00
|
|
|
private void sendMediaMessage(final boolean forceSms, final long expiresIn, final boolean viewOnce, final int subscriptionId, 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(),
|
|
|
|
forceSms,
|
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,
|
|
|
|
subscriptionId,
|
|
|
|
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,
|
|
|
|
final boolean forceSms,
|
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-01-15 08:41:05 +00:00
|
|
|
final int subscriptionId,
|
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
|
|
|
{
|
2021-05-03 17:45:53 +00:00
|
|
|
if (!isDefaultSms && (!isSecureText || forceSms) && 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-02-17 20:55:54 +00:00
|
|
|
final boolean sendPush = (isSecureText && !forceSms) || recipient.get().isServiceIdOnly();
|
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-01-14 13:06:28 +00:00
|
|
|
MessageUtil.SplitResult splitMessage = MessageUtil.getSplitMessage(requireContext(), body, sendButton.getSelectedTransport().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-03-16 16:44:54 +00:00
|
|
|
OutgoingMediaMessage outgoingMessageCandidate = new OutgoingMediaMessage(Recipient.resolved(recipientId), slideDeck, body, System.currentTimeMillis(), subscriptionId, expiresIn, viewOnce, distributionType, StoryType.NONE, null, false, quote, contacts, previews, mentions);
|
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) {
|
2017-12-05 19:35:15 +00:00
|
|
|
outgoingMessage = new OutgoingSecureMediaMessage(outgoingMessageCandidate);
|
2021-01-15 17:15:07 +00:00
|
|
|
ApplicationDependencies.getTypingStatusSender().onTypingStopped(thread);
|
2017-12-05 19:35:15 +00:00
|
|
|
} else {
|
|
|
|
outgoingMessage = outgoingMessageCandidate;
|
|
|
|
}
|
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(() -> {
|
2021-08-30 19:08:38 +00:00
|
|
|
return MessageSender.send(context, outgoingMessage, thread, forceSms, 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
|
|
|
}
|
|
|
|
|
2021-08-23 14:05:48 +00:00
|
|
|
private void sendTextMessage(final boolean forceSms, final long expiresIn, final int subscriptionId, final boolean initiating, final @Nullable String metricId)
|
2014-06-11 22:31:59 +00:00
|
|
|
throws InvalidMessageException
|
|
|
|
{
|
2021-05-03 17:45:53 +00:00
|
|
|
if (!isDefaultSms && (!isSecureText || forceSms) && 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-02-17 20:55:54 +00:00
|
|
|
final boolean sendPush = (isSecureText && !forceSms) || recipient.get().isServiceIdOnly();
|
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 {
|
2019-08-07 18:22:51 +00:00
|
|
|
message = new OutgoingTextMessage(recipient.get(), messageBody, expiresIn, subscriptionId);
|
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(() -> {
|
2021-08-30 19:08:38 +00:00
|
|
|
return MessageSender.send(context, message, thread, forceSms, 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-01-14 13:06:28 +00:00
|
|
|
new AlertDialog.Builder(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;
|
|
|
|
}
|
|
|
|
|
2021-07-02 13:28:45 +00:00
|
|
|
if (draftViewModel.hasVoiceNoteDraft()) {
|
|
|
|
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-02-04 14:38:30 +00:00
|
|
|
if (SignalStore.settings().isLinkPreviewsEnabled() && isSecureText && !sendButton.getSelectedTransport().isSms() && !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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-12 19:22:38 +00:00
|
|
|
private void recordTransportPreference(TransportOption transportOption) {
|
2016-02-06 00:10:33 +00:00
|
|
|
new AsyncTask<Void, Void, Void>() {
|
|
|
|
@Override
|
|
|
|
protected Void doInBackground(Void... params) {
|
2021-11-18 17:36:52 +00:00
|
|
|
RecipientDatabase recipientDatabase = SignalDatabase.recipients();
|
2019-04-12 19:22:38 +00:00
|
|
|
|
2022-03-14 19:49:46 +00:00
|
|
|
recipientDatabase.setDefaultSubscriptionId(recipient.getId(), transportOption.getSimSubscriptionId().orElse(-1));
|
2019-04-12 19:22:38 +00:00
|
|
|
|
2019-08-07 18:22:51 +00:00
|
|
|
if (!recipient.resolve().isPushGroup()) {
|
|
|
|
recipientDatabase.setForceSmsSelection(recipient.getId(), recipient.get().getRegistered() == RegisteredState.REGISTERED && transportOption.isSms());
|
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
|
|
|
|
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 {
|
|
|
|
draftViewModel.setVoiceNoteDraftFuture(future);
|
|
|
|
}
|
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()) {
|
2019-04-17 14:21:30 +00:00
|
|
|
Boolean stickersAvailable = stickerViewModel.getStickersAvailability().getValue();
|
|
|
|
|
2021-05-26 13:47:14 +00:00
|
|
|
initializeMediaKeyboardProviders();
|
2019-04-17 14:21:30 +00:00
|
|
|
|
|
|
|
inputPanel.setMediaKeyboard(emojiDrawerStub.get());
|
2017-01-19 19:31:41 +00:00
|
|
|
}
|
|
|
|
|
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-12 23:13:58 +00:00
|
|
|
container.showSoftkey(composeText, true);
|
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);
|
|
|
|
}
|
|
|
|
|
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) {
|
|
|
|
boolean forceSms = sendButton.isManualSelection() && sendButton.getSelectedTransport().isSms();
|
|
|
|
boolean initiating = threadId == -1;
|
2022-03-14 19:49:46 +00:00
|
|
|
int subscriptionId = sendButton.getSelectedTransport().getSimSubscriptionId().orElse(-1);
|
2021-07-29 20:24:20 +00:00
|
|
|
long expiresIn = TimeUnit.SECONDS.toMillis(recipient.get().getExpiresInSeconds());
|
2022-01-14 13:06:28 +00:00
|
|
|
AudioSlide audioSlide = new AudioSlide(requireContext(), uri, size, MediaUtil.AUDIO_AAC, true);
|
2021-07-02 13:28:45 +00:00
|
|
|
SlideDeck slideDeck = new SlideDeck();
|
|
|
|
slideDeck.addSlide(audioSlide);
|
|
|
|
|
|
|
|
ListenableFuture<Void> sendResult = sendMediaMessage(recipient.getId(),
|
|
|
|
forceSms,
|
|
|
|
"",
|
|
|
|
slideDeck,
|
2022-03-14 19:49:46 +00:00
|
|
|
inputPanel.getQuote().orElse(null),
|
2021-07-02 13:28:45 +00:00
|
|
|
Collections.emptyList(),
|
|
|
|
Collections.emptyList(),
|
|
|
|
composeText.getMentions(),
|
|
|
|
expiresIn,
|
|
|
|
false,
|
|
|
|
subscriptionId,
|
|
|
|
initiating,
|
2021-08-23 14:05:48 +00:00
|
|
|
true,
|
|
|
|
null);
|
2021-07-02 13:28:45 +00:00
|
|
|
|
|
|
|
sendResult.addListener(new AssertedSuccessListener<Void>() {
|
|
|
|
@Override
|
|
|
|
public void onSuccess(Void nothing) {
|
|
|
|
draftViewModel.deleteBlob(uri);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
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) {
|
2019-04-17 14:21:30 +00:00
|
|
|
if (sendButton.getSelectedTransport().isSms()) {
|
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-01-14 13:06:28 +00:00
|
|
|
Intent intent = MediaSelectionActivity.editor(requireContext(), sendButton.getSelectedTransport(), 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());
|
2022-03-14 19:49:46 +00:00
|
|
|
int subscriptionId = sendButton.getSelectedTransport().getSimSubscriptionId().orElse(-1);
|
2019-04-17 14:21:30 +00:00
|
|
|
boolean initiating = threadId == -1;
|
|
|
|
TransportOption transport = sendButton.getSelectedTransport();
|
|
|
|
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);
|
|
|
|
|
2021-08-23 14:05:48 +00:00
|
|
|
sendMediaMessage(recipient.getId(), transport.isSms(), "", slideDeck, null, Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), expiresIn, false, subscriptionId, initiating, clearCompose, null);
|
2019-04-17 14:21:30 +00:00
|
|
|
}
|
|
|
|
|
2018-10-29 22:14:31 +00:00
|
|
|
private void silentlySetComposeText(String text) {
|
|
|
|
typingTextWatcher.setEnabled(false);
|
|
|
|
composeText.setText(text);
|
|
|
|
typingTextWatcher.setEnabled(true);
|
|
|
|
}
|
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() {
|
|
|
|
AttachmentManager.selectGif(this, ConversationParentFragment.PICK_GIF, isMms());
|
|
|
|
}
|
|
|
|
|
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() {
|
|
|
|
return !isSecureText;
|
|
|
|
}
|
|
|
|
|
|
|
|
@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());
|
|
|
|
}
|
|
|
|
|
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) {
|
|
|
|
draftViewModel.deleteBlob(result.getUri());
|
|
|
|
}
|
|
|
|
|
|
|
|
@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-01-14 13:06:28 +00:00
|
|
|
Permissions.with(requireActivity())
|
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-01-14 13:06:28 +00:00
|
|
|
startActivityForResult(MediaSelectionActivity.camera(requireActivity(), sendButton.getSelectedTransport(), recipient.getId(), inputPanel.getQuote().isPresent()), MEDIA_SENDER);
|
|
|
|
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
|
|
|
|
2018-10-29 22:14:31 +00:00
|
|
|
private class TypingStatusTextWatcher extends SimpleTextWatcher {
|
|
|
|
|
|
|
|
private boolean enabled = true;
|
|
|
|
|
2020-11-11 19:14:54 +00:00
|
|
|
private String previousText = "";
|
|
|
|
|
2018-10-29 22:14:31 +00:00
|
|
|
@Override
|
|
|
|
public void onTextChanged(String text) {
|
2021-02-18 15:16:36 +00:00
|
|
|
if (enabled && threadId > 0 && isSecureText && !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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setEnabled(boolean enabled) {
|
|
|
|
this.enabled = enabled;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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);
|
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-02-11 18:03:51 +00:00
|
|
|
SafetyNumberChangeDialog.show(requireContext(), getChildFragmentManager(), messageRecord);
|
2022-01-21 01:39:49 +00:00
|
|
|
} else if (messageRecord.hasFailedWithNetworkFailures()) {
|
2022-01-14 13:06:28 +00:00
|
|
|
new AlertDialog.Builder(requireContext())
|
2020-06-26 15:10:54 +00:00
|
|
|
.setMessage(R.string.conversation_activity__message_could_not_be_sent)
|
|
|
|
.setNegativeButton(android.R.string.cancel, null)
|
2022-01-14 13:06:28 +00:00
|
|
|
.setPositiveButton(R.string.conversation_activity__send, (dialog, which) -> MessageSender.resend(requireContext(), messageRecord))
|
2020-06-26 15:10:54 +00:00
|
|
|
.show();
|
|
|
|
} 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);
|
|
|
|
}
|
|
|
|
|
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-02-03 22:06:17 +00:00
|
|
|
@Override
|
|
|
|
public boolean isKeyboardOpen() {
|
|
|
|
return container.isKeyboardOpen();
|
|
|
|
}
|
|
|
|
|
2015-03-31 20:36:04 +00:00
|
|
|
@Override
|
|
|
|
public void setThreadId(long threadId) {
|
|
|
|
this.threadId = threadId;
|
|
|
|
}
|
|
|
|
|
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,
|
2021-05-26 22:52:56 +00:00
|
|
|
slideDeck);
|
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()),
|
2021-05-26 22:52:56 +00:00
|
|
|
slideDeck);
|
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()),
|
2021-05-26 22:52:56 +00:00
|
|
|
slideDeck);
|
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-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() {
|
2017-03-14 20:24:24 +00:00
|
|
|
handleSecurityChange(isSecureText, isDefaultSms);
|
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
|
|
|
|
2020-07-31 14:34:46 +00:00
|
|
|
private int inputAreaHeight() {
|
|
|
|
int height = panelParent.getMeasuredHeight();
|
|
|
|
|
|
|
|
if (attachmentKeyboardStub.resolved()) {
|
|
|
|
View keyboard = attachmentKeyboardStub.get();
|
|
|
|
if (keyboard.getVisibility() == View.VISIBLE) {
|
|
|
|
return height + keyboard.getMeasuredHeight();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return height;
|
|
|
|
}
|
|
|
|
|
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-01-14 13:06:28 +00:00
|
|
|
AlertDialog.Builder builder = new AlertDialog.Builder(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());
|
2022-03-14 19:49:46 +00:00
|
|
|
int subscriptionId = sendButton.getSelectedTransport().getSimSubscriptionId().orElse(-1);
|
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(),
|
|
|
|
isSmsForced(),
|
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,
|
|
|
|
subscriptionId,
|
|
|
|
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-01-14 13:06:28 +00:00
|
|
|
AlertDialog.Builder builder = new AlertDialog.Builder(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);
|
|
|
|
} else if (isPushGroupV1Conversation() && !isActiveGroup()) {
|
|
|
|
Log.d(TAG, "[presentMessageRequestState] Inactive push group V1, so ignoring provided state.");
|
|
|
|
messageRequestBottomView.setVisibility(View.GONE);
|
|
|
|
} 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);
|
|
|
|
} else {
|
|
|
|
Log.d(TAG, "[presentMessageRequestState] " + messageData.getMessageState());
|
|
|
|
messageRequestBottomView.setMessageData(messageData);
|
|
|
|
messageRequestBottomView.setVisibility(View.VISIBLE);
|
|
|
|
}
|
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 {
|
|
|
|
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
|
|
|
}
|