Пример #1
0
  private void handleEndSessionMessage(
      MasterSecret masterSecret,
      TextSecureEnvelope envelope,
      TextSecureMessage message,
      Optional<Long> smsMessageId) {
    EncryptingSmsDatabase smsDatabase = DatabaseFactory.getEncryptingSmsDatabase(context);
    IncomingTextMessage incomingTextMessage =
        new IncomingTextMessage(
            envelope.getSource(),
            envelope.getSourceDevice(),
            message.getTimestamp(),
            "",
            Optional.<TextSecureGroup>absent());

    long threadId;

    if (!smsMessageId.isPresent()) {
      IncomingEndSessionMessage incomingEndSessionMessage =
          new IncomingEndSessionMessage(incomingTextMessage);
      Pair<Long, Long> messageAndThreadId =
          smsDatabase.insertMessageInbox(masterSecret, incomingEndSessionMessage);
      threadId = messageAndThreadId.second;
    } else {
      smsDatabase.markAsEndSession(smsMessageId.get());
      threadId = smsDatabase.getThreadIdForMessage(smsMessageId.get());
    }

    SessionStore sessionStore = new TextSecureSessionStore(context, masterSecret);
    sessionStore.deleteAllSessions(envelope.getSource());

    SecurityEvent.broadcastSecurityUpdateEvent(context, threadId);
    MessageNotifier.updateNotification(context, masterSecret, threadId);
  }
Пример #2
0
  private Pair<Long, Long> insertSyncTextMessage(
      MasterSecret masterSecret,
      TextSecureEnvelope envelope,
      TextSecureMessage message,
      Optional<Long> smsMessageId) {
    EncryptingSmsDatabase database = DatabaseFactory.getEncryptingSmsDatabase(context);
    Recipients recipients = getSyncMessageDestination(message);
    String body = message.getBody().or("");
    OutgoingTextMessage outgoingTextMessage = new OutgoingTextMessage(recipients, body);

    long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipients);
    long messageId =
        database.insertMessageOutbox(
            masterSecret,
            threadId,
            outgoingTextMessage,
            false,
            message.getSyncContext().get().getTimestamp());

    database.markAsSent(messageId);
    database.markAsPush(messageId);
    database.markAsSecure(messageId);

    if (smsMessageId.isPresent()) {
      database.deleteMessage(smsMessageId.get());
    }

    return new Pair<>(messageId, threadId);
  }
Пример #3
0
  private void handleUntrustedIdentityMessage(
      MasterSecret masterSecret, TextSecureEnvelope envelope, Optional<Long> smsMessageId) {
    try {
      EncryptingSmsDatabase database = DatabaseFactory.getEncryptingSmsDatabase(context);
      Recipients recipients =
          RecipientFactory.getRecipientsFromString(context, envelope.getSource(), false);
      long recipientId = recipients.getPrimaryRecipient().getRecipientId();
      PreKeyWhisperMessage whisperMessage = new PreKeyWhisperMessage(envelope.getMessage());
      IdentityKey identityKey = whisperMessage.getIdentityKey();
      String encoded = Base64.encodeBytes(envelope.getMessage());
      IncomingTextMessage textMessage =
          new IncomingTextMessage(
              envelope.getSource(),
              envelope.getSourceDevice(),
              envelope.getTimestamp(),
              encoded,
              Optional.<TextSecureGroup>absent());

      if (!smsMessageId.isPresent()) {
        IncomingPreKeyBundleMessage bundleMessage =
            new IncomingPreKeyBundleMessage(textMessage, encoded);
        Pair<Long, Long> messageAndThreadId =
            database.insertMessageInbox(masterSecret, bundleMessage);

        database.setMismatchedIdentity(messageAndThreadId.first, recipientId, identityKey);
        MessageNotifier.updateNotification(context, masterSecret, messageAndThreadId.second);
      } else {
        database.updateMessageBody(masterSecret, smsMessageId.get(), encoded);
        database.markAsPreKeyBundle(smsMessageId.get());
        database.setMismatchedIdentity(smsMessageId.get(), recipientId, identityKey);
      }
    } catch (InvalidMessageException | InvalidVersionException e) {
      throw new AssertionError(e);
    }
  }
Пример #4
0
  private @NonNull RecipientDetails getIndividualRecipientDetails(
      Context context, long recipientId, String number) {
    Optional<RecipientsPreferences> preferences =
        DatabaseFactory.getRecipientPreferenceDatabase(context)
            .getRecipientsPreferences(new long[] {recipientId});
    MaterialColor color = preferences.isPresent() ? preferences.get().getColor() : null;
    Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number));
    Cursor cursor = context.getContentResolver().query(uri, CALLER_ID_PROJECTION, null, null, null);

    try {
      if (cursor != null && cursor.moveToFirst()) {
        Uri contactUri = Contacts.getLookupUri(cursor.getLong(2), cursor.getString(1));
        String name = cursor.getString(3).equals(cursor.getString(0)) ? null : cursor.getString(0);
        ContactPhoto contactPhoto =
            ContactPhotoFactory.getContactPhoto(
                context, Uri.withAppendedPath(Contacts.CONTENT_URI, cursor.getLong(2) + ""), name);

        return new RecipientDetails(
            cursor.getString(0), cursor.getString(3), contactUri, contactPhoto, color);
      }
    } finally {
      if (cursor != null) cursor.close();
    }

    return new RecipientDetails(
        null, number, null, ContactPhotoFactory.getDefaultContactPhoto(null), color);
  }
Пример #5
0
 private TransferControlView getTransferControls() {
   if (!transferControls.isPresent()) {
     transferControls =
         Optional.of(
             (TransferControlView) ViewUtil.inflateStub(this, R.id.transfer_controls_stub));
   }
   return transferControls.get();
 }
Пример #6
0
  @Override
  public void onRun(MasterSecret masterSecret) throws NoSuchMessageException {
    PushDatabase database = DatabaseFactory.getPushDatabase(context);
    TextSecureEnvelope envelope = database.get(messageId);
    Optional<Long> optionalSmsMessageId =
        smsMessageId > 0 ? Optional.of(smsMessageId) : Optional.<Long>absent();

    handleMessage(masterSecret, envelope, optionalSmsMessageId);
    database.delete(messageId);
  }
Пример #7
0
  private void handleGroupMessage(
      MasterSecret masterSecret,
      TextSecureEnvelope envelope,
      TextSecureMessage message,
      Optional<Long> smsMessageId) {
    GroupMessageProcessor.process(context, masterSecret, envelope, message);

    if (smsMessageId.isPresent()) {
      DatabaseFactory.getSmsDatabase(context).deleteMessage(smsMessageId.get());
    }
  }
Пример #8
0
  private void handleLegacyMessage(
      MasterSecret masterSecret, TextSecureEnvelope envelope, Optional<Long> smsMessageId) {
    EncryptingSmsDatabase smsDatabase = DatabaseFactory.getEncryptingSmsDatabase(context);

    if (!smsMessageId.isPresent()) {
      Pair<Long, Long> messageAndThreadId = insertPlaceholder(masterSecret, envelope);
      smsDatabase.markAsLegacyVersion(messageAndThreadId.first);
      MessageNotifier.updateNotification(context, masterSecret, messageAndThreadId.second);
    } else {
      smsDatabase.markAsLegacyVersion(smsMessageId.get());
    }
  }
Пример #9
0
  private Optional<IncomingTextMessage> assembleMessageFragments(
      Object[] pdus, int subscriptionId) {
    List<IncomingTextMessage> messages = new LinkedList<>();

    for (Object pdu : pdus) {
      messages.add(new IncomingTextMessage(SmsMessage.createFromPdu((byte[]) pdu), subscriptionId));
    }

    if (messages.isEmpty()) {
      return Optional.absent();
    }

    return Optional.of(new IncomingTextMessage(messages));
  }
Пример #10
0
  private void handleCommonRegistration(
      MasterSecret masterSecret, TextSecureAccountManager accountManager, String number)
      throws IOException {
    setState(new RegistrationState(RegistrationState.STATE_GENERATING_KEYS, number));
    Recipient self =
        RecipientFactory.getRecipientsFromString(this, number, false).getPrimaryRecipient();
    IdentityKeyPair identityKey = IdentityKeyUtil.getIdentityKeyPair(this, masterSecret);
    List<PreKeyRecord> records = PreKeyUtil.generatePreKeys(this, masterSecret);
    PreKeyRecord lastResort = PreKeyUtil.generateLastResortKey(this, masterSecret);
    SignedPreKeyRecord signedPreKey =
        PreKeyUtil.generateSignedPreKey(this, masterSecret, identityKey);
    accountManager.setPreKeys(identityKey.getPublicKey(), lastResort, signedPreKey, records);

    setState(new RegistrationState(RegistrationState.STATE_GCM_REGISTERING, number));

    String gcmRegistrationId = "";
    accountManager.setGcmId(Optional.of(gcmRegistrationId));

    TextSecurePreferences.setGcmRegistrationId(this, gcmRegistrationId);
    TextSecurePreferences.setWebsocketRegistered(this, true);

    DatabaseFactory.getIdentityDatabase(this)
        .saveIdentity(masterSecret, self.getRecipientId(), identityKey.getPublicKey());
    DirectoryHelper.refreshDirectory(this, accountManager, number);

    DirectoryRefreshListener.schedule(this);
  }
  public static Apn getApn(Context context) throws ApnUnavailableException {

    try {
      Optional<Apn> params =
          ApnDatabase.getInstance(context)
              .getMmsConnectionParameters(
                  TelephonyUtil.getMccMnc(context), TelephonyUtil.getApn(context));

      if (!params.isPresent()) {
        throw new ApnUnavailableException("No parameters available from ApnDefaults.");
      }

      return params.get();
    } catch (IOException ioe) {
      throw new ApnUnavailableException("ApnDatabase threw an IOException", ioe);
    }
  }
Пример #12
0
 public void clear() {
   if (isContextValid()) Glide.clear(image);
   if (slideDeckFuture != null) slideDeckFuture.removeListener(slideDeckListener);
   if (transferControls.isPresent()) getTransferControls().clear();
   slide = null;
   slideId = null;
   slideDeckFuture = null;
   slideDeckListener = null;
 }
  private void initializeSessionsV3(SessionState aliceSessionState, SessionState bobSessionState)
      throws InvalidKeyException {
    ECKeyPair aliceIdentityKeyPair = Curve.generateKeyPair();
    IdentityKeyPair aliceIdentityKey =
        new IdentityKeyPair(
            new IdentityKey(aliceIdentityKeyPair.getPublicKey()),
            aliceIdentityKeyPair.getPrivateKey());
    ECKeyPair aliceBaseKey = Curve.generateKeyPair();
    ECKeyPair aliceEphemeralKey = Curve.generateKeyPair();

    ECKeyPair alicePreKey = aliceBaseKey;

    ECKeyPair bobIdentityKeyPair = Curve.generateKeyPair();
    IdentityKeyPair bobIdentityKey =
        new IdentityKeyPair(
            new IdentityKey(bobIdentityKeyPair.getPublicKey()), bobIdentityKeyPair.getPrivateKey());
    ECKeyPair bobBaseKey = Curve.generateKeyPair();
    ECKeyPair bobEphemeralKey = bobBaseKey;

    ECKeyPair bobPreKey = Curve.generateKeyPair();

    AliceAxolotlParameters aliceParameters =
        AliceAxolotlParameters.newBuilder()
            .setOurBaseKey(aliceBaseKey)
            .setOurIdentityKey(aliceIdentityKey)
            .setTheirOneTimePreKey(Optional.<ECPublicKey>absent())
            .setTheirRatchetKey(bobEphemeralKey.getPublicKey())
            .setTheirSignedPreKey(bobBaseKey.getPublicKey())
            .setTheirIdentityKey(bobIdentityKey.getPublicKey())
            .create();

    BobAxolotlParameters bobParameters =
        BobAxolotlParameters.newBuilder()
            .setOurRatchetKey(bobEphemeralKey)
            .setOurSignedPreKey(bobBaseKey)
            .setOurOneTimePreKey(Optional.<ECKeyPair>absent())
            .setOurIdentityKey(bobIdentityKey)
            .setTheirIdentityKey(aliceIdentityKey.getPublicKey())
            .setTheirBaseKey(aliceBaseKey.getPublicKey())
            .create();

    RatchetingSession.initializeSession(aliceSessionState, 3, aliceParameters);
    RatchetingSession.initializeSession(bobSessionState, 3, bobParameters);
  }
Пример #14
0
  @Override
  public void onRun() {
    Optional<IncomingTextMessage> message = assembleMessageFragments(pdus, subscriptionId);
    MasterSecret masterSecret = KeyCachingService.getMasterSecret(context);

    MasterSecretUnion masterSecretUnion;

    if (masterSecret == null) {
      masterSecretUnion =
          new MasterSecretUnion(MasterSecretUtil.getAsymmetricMasterSecret(context, null));
    } else {
      masterSecretUnion = new MasterSecretUnion(masterSecret);
    }

    if (message.isPresent() && !isBlocked(message.get())) {
      Pair<Long, Long> messageAndThreadId = storeMessage(masterSecretUnion, message.get());
      MessageNotifier.updateNotification(context, masterSecret, messageAndThreadId.second);
    } else if (message.isPresent()) {
      Log.w(TAG, "*** Received blocked SMS, ignoring...");
    }
  }
Пример #15
0
  public Optional<NotificationInd> getNotification(long messageId) {
    Cursor cursor = null;

    try {
      cursor = rawQuery(RAW_ID_WHERE, new String[] {String.valueOf(messageId)});

      if (cursor != null && cursor.moveToNext()) {
        PduHeaders headers = new PduHeaders();
        PduHeadersBuilder builder = new PduHeadersBuilder(headers, cursor);
        builder.addText(CONTENT_LOCATION, PduHeaders.CONTENT_LOCATION);
        builder.addLong(NORMALIZED_DATE_SENT, PduHeaders.DATE);
        builder.addLong(EXPIRY, PduHeaders.EXPIRY);
        builder.addLong(MESSAGE_SIZE, PduHeaders.MESSAGE_SIZE);
        builder.addText(TRANSACTION_ID, PduHeaders.TRANSACTION_ID);

        return Optional.of(new NotificationInd(headers));
      } else {
        return Optional.absent();
      }
    } finally {
      if (cursor != null) cursor.close();
    }
  }
Пример #16
0
  private void handleMediaMessage(
      MasterSecret masterSecret,
      TextSecureEnvelope envelope,
      TextSecureMessage message,
      Optional<Long> smsMessageId)
      throws MmsException {
    Pair<Long, Long> messageAndThreadId;

    if (message.getSyncContext().isPresent()) {
      messageAndThreadId = insertSyncMediaMessage(masterSecret, envelope, message);
    } else {
      messageAndThreadId = insertStandardMediaMessage(masterSecret, envelope, message);
    }

    ApplicationContext.getInstance(context)
        .getJobManager()
        .add(new AttachmentDownloadJob(context, messageAndThreadId.first));

    if (smsMessageId.isPresent()) {
      DatabaseFactory.getSmsDatabase(context).deleteMessage(smsMessageId.get());
    }

    MessageNotifier.updateNotification(context, masterSecret, messageAndThreadId.second);
  }
Пример #17
0
  private Pair<Long, Long> insertStandardTextMessage(
      MasterSecret masterSecret,
      TextSecureEnvelope envelope,
      TextSecureMessage message,
      Optional<Long> smsMessageId) {
    EncryptingSmsDatabase database = DatabaseFactory.getEncryptingSmsDatabase(context);
    String body = message.getBody().isPresent() ? message.getBody().get() : "";

    if (smsMessageId.isPresent()) {
      return database.updateBundleMessageBody(masterSecret, smsMessageId.get(), body);
    } else {
      IncomingTextMessage textMessage =
          new IncomingTextMessage(
              envelope.getSource(),
              envelope.getSourceDevice(),
              message.getTimestamp(),
              body,
              message.getGroupInfo());

      textMessage = new IncomingEncryptedMessage(textMessage, body);

      return database.insertMessageInbox(masterSecret, textMessage);
    }
  }
Пример #18
0
  private Pair<Long, Long> insertPlaceholder(
      MasterSecret masterSecret, TextSecureEnvelope envelope) {
    EncryptingSmsDatabase database = DatabaseFactory.getEncryptingSmsDatabase(context);

    IncomingTextMessage textMessage =
        new IncomingTextMessage(
            envelope.getSource(),
            envelope.getSourceDevice(),
            envelope.getTimestamp(),
            "",
            Optional.<TextSecureGroup>absent());

    textMessage = new IncomingEncryptedMessage(textMessage, "");

    return database.insertMessageInbox(masterSecret, textMessage);
  }
Пример #19
0
  private Pair<Long, Long> insertStandardMediaMessage(
      MasterSecret masterSecret, TextSecureEnvelope envelope, TextSecureMessage message)
      throws MmsException {
    MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
    String localNumber = TextSecurePreferences.getLocalNumber(context);
    IncomingMediaMessage mediaMessage =
        new IncomingMediaMessage(
            masterSecret,
            envelope.getSource(),
            localNumber,
            message.getTimestamp(),
            Optional.fromNullable(envelope.getRelay()),
            message.getBody(),
            message.getGroupInfo(),
            message.getAttachments());

    return database.insertSecureDecryptedMessageInbox(masterSecret, mediaMessage, -1);
  }
Пример #20
0
  public void setImageResource(
      @Nullable MasterSecret masterSecret,
      long id,
      long timestamp,
      @NonNull ListenableFutureTask<SlideDeck> slideDeckFuture) {
    if (this.slideDeckFuture != null && this.slideDeckListener != null) {
      this.slideDeckFuture.removeListener(this.slideDeckListener);
    }

    String slideId = id + "::" + timestamp;

    if (!slideId.equals(this.slideId)) {
      if (transferControls.isPresent()) getTransferControls().clear();
      image.setImageDrawable(null);
      this.slide = null;
      this.slideId = slideId;
    }

    this.slideDeckListener = new SlideDeckListener(masterSecret);
    this.slideDeckFuture = slideDeckFuture;
    this.slideDeckFuture.addListener(this.slideDeckListener);
  }
Пример #21
0
 @Override
 public void setClickable(boolean clickable) {
   super.setClickable(clickable);
   if (transferControls.isPresent()) transferControls.get().setClickable(clickable);
 }
Пример #22
0
 @Override
 public void setFocusable(boolean focusable) {
   super.setFocusable(focusable);
   if (transferControls.isPresent()) transferControls.get().setFocusable(focusable);
 }
Пример #23
0
public class ThumbnailView extends FrameLayout {
  private static final String TAG = ThumbnailView.class.getSimpleName();

  private boolean hideControls;
  private ImageView image;
  private ImageView removeButton;
  private int backgroundColorHint;
  private int radius;
  private OnClickListener parentClickListener;

  private Optional<TransferControlView> transferControls = Optional.absent();
  private ListenableFutureTask<SlideDeck> slideDeckFuture = null;
  private SlideDeckListener slideDeckListener = null;
  private ThumbnailClickListener thumbnailClickListener = null;
  private ThumbnailClickListener downloadClickListener = null;
  private String slideId = null;
  private Slide slide = null;

  public ThumbnailView(Context context) {
    this(context, null);
  }

  public ThumbnailView(Context context, AttributeSet attrs) {
    this(context, attrs, 0);
  }

  public ThumbnailView(final Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    inflate(context, R.layout.thumbnail_view, this);
    radius = getResources().getDimensionPixelSize(R.dimen.message_bubble_corner_radius);
    image = (ImageView) findViewById(R.id.thumbnail_image);
    super.setOnClickListener(new ThumbnailClickDispatcher());

    if (attrs != null) {
      TypedArray typedArray =
          context.getTheme().obtainStyledAttributes(attrs, R.styleable.ThumbnailView, 0, 0);
      backgroundColorHint = typedArray.getColor(0, Color.BLACK);
      typedArray.recycle();
    }
  }

  @Override
  public void setOnClickListener(OnClickListener l) {
    parentClickListener = l;
  }

  @Override
  public void setFocusable(boolean focusable) {
    super.setFocusable(focusable);
    if (transferControls.isPresent()) transferControls.get().setFocusable(focusable);
  }

  @Override
  public void setClickable(boolean clickable) {
    super.setClickable(clickable);
    if (transferControls.isPresent()) transferControls.get().setClickable(clickable);
  }

  @Override
  protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
    super.onLayout(changed, left, top, right, bottom);
    if (removeButton != null) {
      final int paddingHorizontal = removeButton.getWidth() / 2;
      final int paddingVertical = removeButton.getHeight() / 2;
      image.setPadding(paddingHorizontal, paddingVertical, paddingHorizontal, 0);
    }
  }

  private ImageView getRemoveButton() {
    if (removeButton == null) removeButton = ViewUtil.inflateStub(this, R.id.remove_button_stub);
    return removeButton;
  }

  private TransferControlView getTransferControls() {
    if (!transferControls.isPresent()) {
      transferControls =
          Optional.of(
              (TransferControlView) ViewUtil.inflateStub(this, R.id.transfer_controls_stub));
    }
    return transferControls.get();
  }

  public void setBackgroundColorHint(int color) {
    this.backgroundColorHint = color;
  }

  public void setImageResource(
      @Nullable MasterSecret masterSecret,
      long id,
      long timestamp,
      @NonNull ListenableFutureTask<SlideDeck> slideDeckFuture) {
    if (this.slideDeckFuture != null && this.slideDeckListener != null) {
      this.slideDeckFuture.removeListener(this.slideDeckListener);
    }

    String slideId = id + "::" + timestamp;

    if (!slideId.equals(this.slideId)) {
      if (transferControls.isPresent()) getTransferControls().clear();
      image.setImageDrawable(null);
      this.slide = null;
      this.slideId = slideId;
    }

    this.slideDeckListener = new SlideDeckListener(masterSecret);
    this.slideDeckFuture = slideDeckFuture;
    this.slideDeckFuture.addListener(this.slideDeckListener);
  }

  public void setImageResource(@NonNull Slide slide, @Nullable MasterSecret masterSecret) {
    if (Util.equals(slide, this.slide)) {
      Log.w(TAG, "Not re-loading slide " + slide.getPart().getPartId());
      return;
    }

    if (!isContextValid()) {
      Log.w(TAG, "Not loading slide, context is invalid");
      return;
    }

    Log.w(
        TAG,
        "loading part with id "
            + slide.getPart().getPartId()
            + ", progress "
            + slide.getTransferProgress());

    this.slide = slide;
    loadInto(slide, masterSecret, image);

    if (!hideControls) {
      getTransferControls().setSlide(slide);
      getTransferControls().setDownloadClickListener(new DownloadClickDispatcher());
    }
  }

  public void setThumbnailClickListener(ThumbnailClickListener listener) {
    this.thumbnailClickListener = listener;
  }

  public void setRemoveClickListener(OnClickListener listener) {
    getRemoveButton().setOnClickListener(listener);
    final int pad = getResources().getDimensionPixelSize(R.dimen.media_bubble_remove_button_size);
    image.setPadding(pad, pad, pad, 0);
  }

  public void setDownloadClickListener(ThumbnailClickListener listener) {
    this.downloadClickListener = listener;
  }

  public void clear() {
    if (isContextValid()) Glide.clear(image);
    if (slideDeckFuture != null) slideDeckFuture.removeListener(slideDeckListener);
    if (transferControls.isPresent()) getTransferControls().clear();
    slide = null;
    slideId = null;
    slideDeckFuture = null;
    slideDeckListener = null;
  }

  public void hideControls(boolean hideControls) {
    this.hideControls = hideControls;
    if (hideControls && transferControls.isPresent())
      getTransferControls().setVisibility(View.GONE);
  }

  public void showProgressSpinner() {
    getTransferControls().showProgressSpinner();
  }

  @TargetApi(VERSION_CODES.JELLY_BEAN_MR1)
  private boolean isContextValid() {
    return !(getContext() instanceof Activity)
        || VERSION.SDK_INT < VERSION_CODES.JELLY_BEAN_MR1
        || !((Activity) getContext()).isDestroyed();
  }

  private void loadInto(
      @NonNull Slide slide, @Nullable MasterSecret masterSecret, @NonNull ImageView view) {
    if (slide.getThumbnailUri() != null) {
      buildThumbnailGlideRequest(slide, masterSecret).into(view);
    } else if (!slide.isInProgress()) {
      buildPlaceholderGlideRequest(slide).into(view);
    } else {
      Glide.clear(view);
    }
  }

  private GenericRequestBuilder buildThumbnailGlideRequest(Slide slide, MasterSecret masterSecret) {
    final GenericRequestBuilder builder;

    if (slide.isDraft()) builder = buildDraftGlideRequest(slide, masterSecret);
    else builder = buildPartGlideRequest(slide, masterSecret);

    if (slide.isInProgress()) return builder;
    else return builder.error(R.drawable.ic_missing_thumbnail_picture);
  }

  private GenericRequestBuilder buildDraftGlideRequest(Slide slide, MasterSecret masterSecret) {
    final DrawableTypeRequest<?> request;
    if (masterSecret == null) request = Glide.with(getContext()).load(slide.getThumbnailUri());
    else
      request =
          Glide.with(getContext()).load(new DecryptableUri(masterSecret, slide.getThumbnailUri()));

    return request
        .transform(new RoundedCorners(getContext(), false, radius, backgroundColorHint))
        .listener(new PduThumbnailSetListener(slide.getPart()));
  }

  private GenericRequestBuilder buildPartGlideRequest(Slide slide, MasterSecret masterSecret) {
    if (masterSecret == null) {
      throw new IllegalStateException("null MasterSecret when loading non-draft thumbnail");
    }

    return Glide.with(getContext())
        .load(new DecryptableUri(masterSecret, slide.getThumbnailUri()))
        .crossFade()
        .transform(new RoundedCorners(getContext(), true, radius, backgroundColorHint));
  }

  private GenericRequestBuilder buildPlaceholderGlideRequest(Slide slide) {
    return Glide.with(getContext())
        .load(slide.getPlaceholderRes(getContext().getTheme()))
        .asBitmap()
        .fitCenter();
  }

  private class SlideDeckListener implements FutureTaskListener<SlideDeck> {
    private final MasterSecret masterSecret;

    public SlideDeckListener(MasterSecret masterSecret) {
      this.masterSecret = masterSecret;
    }

    @Override
    public void onSuccess(final SlideDeck slideDeck) {
      if (slideDeck == null) return;

      final Slide slide = slideDeck.getThumbnailSlide();

      if (slide != null) {
        Util.runOnMain(
            new Runnable() {
              @Override
              public void run() {
                setImageResource(slide, masterSecret);
              }
            });
      } else {
        Util.runOnMain(
            new Runnable() {
              @Override
              public void run() {
                Log.w(TAG, "Resolved slide was null!");
                setVisibility(View.GONE);
              }
            });
      }
    }

    @Override
    public void onFailure(Throwable error) {
      Log.w(TAG, error);
      Util.runOnMain(
          new Runnable() {
            @Override
            public void run() {
              Log.w(TAG, "onFailure!");
              setVisibility(View.GONE);
            }
          });
    }
  }

  public interface ThumbnailClickListener {
    void onClick(View v, Slide slide);
  }

  private class ThumbnailClickDispatcher implements View.OnClickListener {
    @Override
    public void onClick(View view) {
      if (thumbnailClickListener != null
          && slide != null
          && slide.getPart().getDataUri() != null
          && slide.getTransferProgress() == PartDatabase.TRANSFER_PROGRESS_DONE) {
        thumbnailClickListener.onClick(view, slide);
      } else if (parentClickListener != null) {
        parentClickListener.onClick(view);
      }
    }
  }

  private class DownloadClickDispatcher implements View.OnClickListener {
    @Override
    public void onClick(View view) {
      if (downloadClickListener != null && slide != null) {
        downloadClickListener.onClick(view, slide);
      }
    }
  }

  private class PduThumbnailSetListener implements RequestListener<Object, GlideDrawable> {
    private PduPart part;

    public PduThumbnailSetListener(@NonNull PduPart part) {
      this.part = part;
    }

    @Override
    public boolean onException(
        Exception e, Object model, Target<GlideDrawable> target, boolean isFirstResource) {
      return false;
    }

    @Override
    public boolean onResourceReady(
        GlideDrawable resource,
        Object model,
        Target<GlideDrawable> target,
        boolean isFromMemoryCache,
        boolean isFirstResource) {
      if (resource instanceof GlideBitmapDrawable) {
        Log.w(TAG, "onResourceReady() for a Bitmap. Saving.");
        part.setThumbnail(((GlideBitmapDrawable) resource).getBitmap());
      }
      LayoutParams layoutParams = (LayoutParams) getRemoveButton().getLayoutParams();
      if (resource.getIntrinsicWidth() < getWidth()) {
        layoutParams.topMargin = 0;
        layoutParams.rightMargin =
            Math.max(0, (getWidth() - image.getPaddingRight() - resource.getIntrinsicWidth()) / 2);
      } else {
        layoutParams.topMargin =
            Math.max(0, (getHeight() - image.getPaddingTop() - resource.getIntrinsicHeight()) / 2);
        layoutParams.rightMargin = 0;
      }
      getRemoveButton().setLayoutParams(layoutParams);
      return false;
    }
  }
}
Пример #24
0
 public void hideControls(boolean hideControls) {
   this.hideControls = hideControls;
   if (hideControls && transferControls.isPresent())
     getTransferControls().setVisibility(View.GONE);
 }
Пример #25
0
 private TransportOptionsPopup getTransportOptionsPopup() {
   if (!transportOptionsPopup.isPresent()) {
     transportOptionsPopup = Optional.of(new TransportOptionsPopup(getContext(), this, this));
   }
   return transportOptionsPopup.get();
 }
Пример #26
0
public class SendButton extends ImageButton
    implements TransportOptions.OnTransportChangedListener,
        TransportOptionsPopup.SelectedListener,
        View.OnLongClickListener {

  private final TransportOptions transportOptions;

  private Optional<TransportOptionsPopup> transportOptionsPopup = Optional.absent();

  @SuppressWarnings("unused")
  public SendButton(Context context) {
    super(context);
    this.transportOptions = initializeTransportOptions(false);
    ViewUtil.mirrorIfRtl(this, getContext());
  }

  @SuppressWarnings("unused")
  public SendButton(Context context, AttributeSet attrs) {
    super(context, attrs);
    this.transportOptions = initializeTransportOptions(false);
    ViewUtil.mirrorIfRtl(this, getContext());
  }

  @SuppressWarnings("unused")
  public SendButton(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    this.transportOptions = initializeTransportOptions(false);
    ViewUtil.mirrorIfRtl(this, getContext());
  }

  private TransportOptions initializeTransportOptions(boolean media) {
    TransportOptions transportOptions = new TransportOptions(getContext(), media);
    transportOptions.addOnTransportChangedListener(this);

    setOnLongClickListener(this);

    return transportOptions;
  }

  private TransportOptionsPopup getTransportOptionsPopup() {
    if (!transportOptionsPopup.isPresent()) {
      transportOptionsPopup = Optional.of(new TransportOptionsPopup(getContext(), this, this));
    }
    return transportOptionsPopup.get();
  }

  public boolean isManualSelection() {
    return transportOptions.isManualSelection();
  }

  public void addOnTransportChangedListener(OnTransportChangedListener listener) {
    transportOptions.addOnTransportChangedListener(listener);
  }

  public TransportOption getSelectedTransport() {
    return transportOptions.getSelectedTransport();
  }

  public void resetAvailableTransports(boolean isMediaMessage) {
    transportOptions.reset(isMediaMessage);
  }

  public void disableTransport(TransportOption.Type type) {
    transportOptions.disableTransport(type);
  }

  public void setDefaultTransport(TransportOption.Type type) {
    transportOptions.setDefaultTransport(type);
  }

  @Override
  public void onSelected(TransportOption option) {
    transportOptions.setSelectedTransport(option.getType());
    getTransportOptionsPopup().dismiss();
  }

  @Override
  public void onChange(TransportOption newTransport) {
    setImageResource(newTransport.getDrawable());
    setContentDescription(newTransport.getDescription());
  }

  @Override
  public boolean onLongClick(View v) {
    if (transportOptions.getEnabledTransports().size() > 1) {
      getTransportOptionsPopup().display(transportOptions.getEnabledTransports());
      return true;
    }

    return false;
  }
}
Пример #27
0
 @Override
 @NonNull
 public Optional<String> getBody() {
   return Optional.of(place.getDescription());
 }