Search in sources :

Example 36 with GroupId

use of org.thoughtcrime.securesms.groups.GroupId in project Signal-Android by WhisperSystems.

the class TypingSendJob method onRun.

@Override
public void onRun() throws Exception {
    if (!Recipient.self().isRegistered()) {
        throw new NotPushRegisteredException();
    }
    if (!TextSecurePreferences.isTypingIndicatorsEnabled(context)) {
        return;
    }
    Log.d(TAG, "Sending typing " + (typing ? "started" : "stopped") + " for thread " + threadId);
    Recipient recipient = SignalDatabase.threads().getRecipientForThreadId(threadId);
    if (recipient == null) {
        Log.w(TAG, "Tried to send a typing indicator to a non-existent thread.");
        return;
    }
    if (recipient.isBlocked()) {
        Log.w(TAG, "Not sending typing indicators to blocked recipients.");
        return;
    }
    if (recipient.isSelf()) {
        Log.w(TAG, "Not sending typing indicators to self.");
        return;
    }
    if (recipient.isPushV1Group() || recipient.isMmsGroup()) {
        Log.w(TAG, "Not sending typing indicators to unsupported groups.");
        return;
    }
    if (!recipient.isRegistered() || recipient.isForceSmsSelection()) {
        Log.w(TAG, "Not sending typing indicators to non-Signal recipients.");
        return;
    }
    List<Recipient> recipients = Collections.singletonList(recipient);
    Optional<byte[]> groupId = Optional.absent();
    if (recipient.isGroup()) {
        recipients = SignalDatabase.groups().getGroupMembers(recipient.requireGroupId(), GroupDatabase.MemberSet.FULL_MEMBERS_EXCLUDING_SELF);
        groupId = Optional.of(recipient.requireGroupId().getDecodedId());
    }
    recipients = RecipientUtil.getEligibleForSending(Stream.of(recipients).map(Recipient::resolve).filter(r -> !r.isBlocked()).toList());
    SignalServiceTypingMessage typingMessage = new SignalServiceTypingMessage(typing ? Action.STARTED : Action.STOPPED, System.currentTimeMillis(), groupId);
    try {
        GroupSendUtil.sendTypingMessage(context, recipient.getGroupId().transform(GroupId::requireV2).orNull(), recipients, typingMessage, this::isCanceled);
    } catch (CancelationException e) {
        Log.w(TAG, "Canceled during send!");
    }
}
Also used : SignalDatabase(org.thoughtcrime.securesms.database.SignalDatabase) SignalServiceTypingMessage(org.whispersystems.signalservice.api.messages.SignalServiceTypingMessage) Stream(com.annimon.stream.Stream) NonNull(androidx.annotation.NonNull) Data(org.thoughtcrime.securesms.jobmanager.Data) RecipientUtil(org.thoughtcrime.securesms.recipients.RecipientUtil) NetworkConstraint(org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint) NotPushRegisteredException(org.thoughtcrime.securesms.net.NotPushRegisteredException) GroupDatabase(org.thoughtcrime.securesms.database.GroupDatabase) Optional(org.whispersystems.libsignal.util.guava.Optional) TextSecurePreferences(org.thoughtcrime.securesms.util.TextSecurePreferences) TimeUnit(java.util.concurrent.TimeUnit) Log(org.signal.core.util.logging.Log) List(java.util.List) GroupId(org.thoughtcrime.securesms.groups.GroupId) Job(org.thoughtcrime.securesms.jobmanager.Job) Action(org.whispersystems.signalservice.api.messages.SignalServiceTypingMessage.Action) Recipient(org.thoughtcrime.securesms.recipients.Recipient) GroupSendUtil(org.thoughtcrime.securesms.messages.GroupSendUtil) Collections(java.util.Collections) CancelationException(org.whispersystems.signalservice.api.CancelationException) SignalServiceTypingMessage(org.whispersystems.signalservice.api.messages.SignalServiceTypingMessage) CancelationException(org.whispersystems.signalservice.api.CancelationException) NotPushRegisteredException(org.thoughtcrime.securesms.net.NotPushRegisteredException) Recipient(org.thoughtcrime.securesms.recipients.Recipient) GroupId(org.thoughtcrime.securesms.groups.GroupId)

Example 37 with GroupId

use of org.thoughtcrime.securesms.groups.GroupId in project Signal-Android by WhisperSystems.

the class EditProfileFragment method initializeResources.

private void initializeResources(@NonNull View view, @Nullable GroupId groupId) {
    Bundle arguments = requireArguments();
    boolean isEditingGroup = groupId != null;
    this.toolbar = view.findViewById(R.id.toolbar);
    this.title = view.findViewById(R.id.title);
    this.avatar = view.findViewById(R.id.avatar);
    this.givenName = view.findViewById(R.id.given_name);
    this.familyName = view.findViewById(R.id.family_name);
    this.finishButton = view.findViewById(R.id.finish_button);
    this.reveal = view.findViewById(R.id.reveal);
    this.preview = view.findViewById(R.id.name_preview);
    this.avatarPreviewBackground = view.findViewById(R.id.avatar_background);
    this.avatarPreview = view.findViewById(R.id.avatar_placeholder);
    this.nextIntent = arguments.getParcelable(NEXT_INTENT);
    this.avatar.setOnClickListener(v -> startAvatarSelection());
    view.findViewById(R.id.mms_group_hint).setVisibility(isEditingGroup && groupId.isMms() ? View.VISIBLE : View.GONE);
    if (isEditingGroup) {
        EditTextUtil.addGraphemeClusterLimitFilter(givenName, FeatureFlags.getMaxGroupNameGraphemeLength());
        givenName.addTextChangedListener(new AfterTextChanged(s -> viewModel.setGivenName(s.toString())));
        givenName.setHint(R.string.EditProfileFragment__group_name);
        givenName.requestFocus();
        toolbar.setTitle(R.string.EditProfileFragment__edit_group);
        preview.setVisibility(View.GONE);
        if (groupId.isV2()) {
            EditTextUtil.addGraphemeClusterLimitFilter(familyName, MAX_DESCRIPTION_GLYPHS);
            familyName.addTextChangedListener(new AfterTextChanged(s -> {
                EditProfileNameFragment.trimFieldToMaxByteLength(s, MAX_DESCRIPTION_BYTES);
                viewModel.setFamilyName(s.toString());
            }));
            familyName.setHint(R.string.EditProfileFragment__group_description);
            familyName.setSingleLine(false);
            familyName.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_MULTI_LINE | InputType.TYPE_TEXT_FLAG_CAP_SENTENCES);
            LearnMoreTextView descriptionText = view.findViewById(R.id.description_text);
            descriptionText.setLearnMoreVisible(false);
            descriptionText.setText(R.string.CreateProfileActivity_group_descriptions_will_be_visible_to_members_of_this_group_and_people_who_have_been_invited);
        } else {
            familyName.setVisibility(View.GONE);
            familyName.setEnabled(false);
            view.findViewById(R.id.description_text).setVisibility(View.GONE);
        }
        view.<ImageView>findViewById(R.id.avatar_placeholder).setImageResource(R.drawable.ic_group_outline_40);
    } else {
        EditTextUtil.addGraphemeClusterLimitFilter(givenName, EditProfileNameFragment.NAME_MAX_GLYPHS);
        EditTextUtil.addGraphemeClusterLimitFilter(familyName, EditProfileNameFragment.NAME_MAX_GLYPHS);
        this.givenName.addTextChangedListener(new AfterTextChanged(s -> {
            EditProfileNameFragment.trimFieldToMaxByteLength(s);
            viewModel.setGivenName(s.toString());
        }));
        this.familyName.addTextChangedListener(new AfterTextChanged(s -> {
            EditProfileNameFragment.trimFieldToMaxByteLength(s);
            viewModel.setFamilyName(s.toString());
        }));
        LearnMoreTextView descriptionText = view.findViewById(R.id.description_text);
        descriptionText.setLearnMoreVisible(true);
        descriptionText.setOnLinkClickListener(v -> CommunicationActions.openBrowserLink(requireContext(), getString(R.string.EditProfileFragment__support_link)));
    }
    this.finishButton.setOnClickListener(v -> {
        this.finishButton.setIndeterminateProgressMode(true);
        this.finishButton.setProgress(50);
        handleUpload();
    });
    this.finishButton.setText(arguments.getInt(NEXT_BUTTON_TEXT, R.string.CreateProfileActivity_next));
    if (arguments.getBoolean(SHOW_TOOLBAR, true)) {
        this.toolbar.setVisibility(View.VISIBLE);
        this.toolbar.setNavigationOnClickListener(v -> requireActivity().finish());
        this.title.setVisibility(View.GONE);
    }
}
Also used : RequiresApi(androidx.annotation.RequiresApi) AvatarColor(org.thoughtcrime.securesms.conversation.colors.AvatarColor) Bundle(android.os.Bundle) EditTextUtil(org.signal.core.util.EditTextUtil) NonNull(androidx.annotation.NonNull) AvatarPickerFragment(org.thoughtcrime.securesms.avatar.picker.AvatarPickerFragment) ImageView(android.widget.ImageView) SHOW_TOOLBAR(org.thoughtcrime.securesms.profiles.edit.EditProfileActivity.SHOW_TOOLBAR) Animator(android.animation.Animator) R(org.thoughtcrime.securesms.R) SafeNavigation(org.thoughtcrime.securesms.util.navigation.SafeNavigation) Media(org.thoughtcrime.securesms.mediasend.Media) View(android.view.View) ViewModelProviders(androidx.lifecycle.ViewModelProviders) SimpleColorFilter(com.airbnb.lottie.SimpleColorFilter) Avatars(org.thoughtcrime.securesms.avatar.Avatars) ParcelableGroupId(org.thoughtcrime.securesms.groups.ParcelableGroupId) InputType(android.text.InputType) ViewAnimationUtils(android.view.ViewAnimationUtils) ViewGroup(android.view.ViewGroup) Log(org.signal.core.util.logging.Log) FeatureFlags(org.thoughtcrime.securesms.util.FeatureFlags) TextView(android.widget.TextView) Nullable(androidx.annotation.Nullable) ResourceContactPhoto(org.thoughtcrime.securesms.contacts.avatars.ResourceContactPhoto) EXCLUDE_SYSTEM(org.thoughtcrime.securesms.profiles.edit.EditProfileActivity.EXCLUDE_SYSTEM) GroupId(org.thoughtcrime.securesms.groups.GroupId) Toolbar(androidx.appcompat.widget.Toolbar) GROUP_ID(org.thoughtcrime.securesms.profiles.edit.EditProfileActivity.GROUP_ID) GlideApp(org.thoughtcrime.securesms.mms.GlideApp) Context(android.content.Context) NEXT_BUTTON_TEXT(org.thoughtcrime.securesms.profiles.edit.EditProfileActivity.NEXT_BUTTON_TEXT) Intent(android.content.Intent) Toast(android.widget.Toast) DiskCacheStrategy(com.bumptech.glide.load.engine.DiskCacheStrategy) Build(android.os.Build) NEXT_INTENT(org.thoughtcrime.securesms.profiles.edit.EditProfileActivity.NEXT_INTENT) SimpleTask(org.thoughtcrime.securesms.util.concurrent.SimpleTask) CircularProgressButton(com.dd.CircularProgressButton) Parcelable(android.os.Parcelable) LayoutInflater(android.view.LayoutInflater) AfterTextChanged(org.thoughtcrime.securesms.util.text.AfterTextChanged) StreamUtil(org.signal.core.util.StreamUtil) BlobProvider(org.thoughtcrime.securesms.providers.BlobProvider) IOException(java.io.IOException) CommunicationActions(org.thoughtcrime.securesms.util.CommunicationActions) LearnMoreTextView(org.thoughtcrime.securesms.util.views.LearnMoreTextView) Navigation(androidx.navigation.Navigation) LoggingFragment(org.thoughtcrime.securesms.LoggingFragment) EditText(android.widget.EditText) EditProfileNameFragment(org.thoughtcrime.securesms.profiles.manage.EditProfileNameFragment) InputStream(java.io.InputStream) Bundle(android.os.Bundle) LearnMoreTextView(org.thoughtcrime.securesms.util.views.LearnMoreTextView) AfterTextChanged(org.thoughtcrime.securesms.util.text.AfterTextChanged)

Example 38 with GroupId

use of org.thoughtcrime.securesms.groups.GroupId in project Signal-Android by WhisperSystems.

the class EditProfileFragment method onViewCreated.

@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
    GroupId groupId = GroupId.parseNullableOrThrow(requireArguments().getString(GROUP_ID, null));
    initializeViewModel(requireArguments().getBoolean(EXCLUDE_SYSTEM, false), groupId, savedInstanceState != null);
    initializeResources(view, groupId);
    initializeProfileAvatar();
    initializeProfileName();
    getParentFragmentManager().setFragmentResultListener(AvatarPickerFragment.REQUEST_KEY_SELECT_AVATAR, getViewLifecycleOwner(), (key, bundle) -> {
        if (bundle.getBoolean(AvatarPickerFragment.SELECT_AVATAR_CLEAR)) {
            viewModel.setAvatarMedia(null);
            viewModel.setAvatar(null);
            avatar.setImageDrawable(null);
        } else {
            Media media = bundle.getParcelable(AvatarPickerFragment.SELECT_AVATAR_MEDIA);
            handleMediaFromResult(media);
        }
    });
}
Also used : Media(org.thoughtcrime.securesms.mediasend.Media) ParcelableGroupId(org.thoughtcrime.securesms.groups.ParcelableGroupId) GroupId(org.thoughtcrime.securesms.groups.GroupId)

Example 39 with GroupId

use of org.thoughtcrime.securesms.groups.GroupId in project Signal-Android by WhisperSystems.

the class GroupDatabase method fixMissingMasterKey.

/**
 * There was a point in time where we weren't properly responding to group creates on linked devices. This would result in us having a Recipient entry for the
 * group, but we'd either be missing the group entry, or that entry would be missing a master key. This method fixes this scenario.
 */
public void fixMissingMasterKey(@NonNull GroupMasterKey groupMasterKey) {
    GroupId.V2 groupId = GroupId.v2(groupMasterKey);
    if (getGroupV1ByExpectedV2(groupId).isPresent()) {
        Log.w(TAG, "There already exists a V1 group that should be migrated into this group. But if the recipient already exists, there's not much we can do here.");
    }
    SQLiteDatabase db = databaseHelper.getSignalWritableDatabase();
    db.beginTransaction();
    try {
        String query = GROUP_ID + " = ?";
        String[] args = SqlUtil.buildArgs(groupId);
        ContentValues values = new ContentValues();
        values.put(V2_MASTER_KEY, groupMasterKey.serialize());
        int updated = db.update(TABLE_NAME, values, query, args);
        if (updated < 1) {
            Log.w(TAG, "No group entry. Creating restore placeholder for " + groupId);
            create(groupMasterKey, DecryptedGroup.newBuilder().setRevision(GroupsV2StateProcessor.RESTORE_PLACEHOLDER_REVISION).build(), true);
        } else {
            Log.w(TAG, "Had a group entry, but it was missing a master key. Updated.");
        }
        db.setTransactionSuccessful();
    } finally {
        db.endTransaction();
    }
    Log.w(TAG, "Scheduling request for latest group info for " + groupId);
    ApplicationDependencies.getJobManager().add(new RequestGroupV2InfoJob(groupId));
}
Also used : ContentValues(android.content.ContentValues) RequestGroupV2InfoJob(org.thoughtcrime.securesms.jobs.RequestGroupV2InfoJob) SuppressLint(android.annotation.SuppressLint) GroupId(org.thoughtcrime.securesms.groups.GroupId)

Example 40 with GroupId

use of org.thoughtcrime.securesms.groups.GroupId in project Signal-Android by WhisperSystems.

the class PushProcessMessageQueueJobMigration method migratePushProcessMessageJob.

@NonNull
private static JobData migratePushProcessMessageJob(@NonNull Context context, @NonNull JobData jobData) throws IOException {
    Data data = jobData.getData();
    String suffix = "";
    if (data.getInt("message_state") == 0) {
        SignalServiceContent content = SignalServiceContent.deserialize(Base64.decode(data.getString("message_content")));
        if (content != null && content.getDataMessage().isPresent() && content.getDataMessage().get().getGroupContext().isPresent()) {
            Log.i(TAG, "Migrating a group message.");
            try {
                GroupId groupId = GroupUtil.idFromGroupContext(content.getDataMessage().get().getGroupContext().get());
                Recipient recipient = Recipient.externalGroupExact(context, groupId);
                suffix = recipient.getId().toQueueKey();
            } catch (BadGroupIdException e) {
                Log.w(TAG, "Bad groupId! Using default queue.");
            }
        } else if (content != null) {
            Log.i(TAG, "Migrating an individual message.");
            suffix = RecipientId.from(content.getSender()).toQueueKey();
        }
    } else {
        Log.i(TAG, "Migrating an exception message.");
        String exceptionSender = data.getString("exception_sender");
        GroupId exceptionGroup = GroupId.parseNullableOrThrow(data.getStringOrDefault("exception_groupId", null));
        if (exceptionGroup != null) {
            suffix = Recipient.externalGroupExact(context, exceptionGroup).getId().toQueueKey();
        } else if (exceptionSender != null) {
            suffix = Recipient.external(context, exceptionSender).getId().toQueueKey();
        }
    }
    return jobData.withQueueKey("__PUSH_PROCESS_JOB__" + suffix);
}
Also used : SignalServiceContent(org.whispersystems.signalservice.api.messages.SignalServiceContent) Data(org.thoughtcrime.securesms.jobmanager.Data) Recipient(org.thoughtcrime.securesms.recipients.Recipient) BadGroupIdException(org.thoughtcrime.securesms.groups.BadGroupIdException) GroupId(org.thoughtcrime.securesms.groups.GroupId) NonNull(androidx.annotation.NonNull)

Aggregations

GroupId (org.thoughtcrime.securesms.groups.GroupId)41 Recipient (org.thoughtcrime.securesms.recipients.Recipient)26 NonNull (androidx.annotation.NonNull)22 RecipientId (org.thoughtcrime.securesms.recipients.RecipientId)13 Context (android.content.Context)12 List (java.util.List)11 Log (org.signal.core.util.logging.Log)11 GroupDatabase (org.thoughtcrime.securesms.database.GroupDatabase)11 Collections (java.util.Collections)10 SignalDatabase (org.thoughtcrime.securesms.database.SignalDatabase)10 ApplicationDependencies (org.thoughtcrime.securesms.dependencies.ApplicationDependencies)10 Optional (org.whispersystems.libsignal.util.guava.Optional)10 Nullable (androidx.annotation.Nullable)9 IOException (java.io.IOException)9 LinkedList (java.util.LinkedList)8 Collectors (java.util.stream.Collectors)8 SignalStore (org.thoughtcrime.securesms.keyvalue.SignalStore)8 SendMessageResult (org.whispersystems.signalservice.api.messages.SendMessageResult)8 Intent (android.content.Intent)7 Stream (com.annimon.stream.Stream)7