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); }
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); }
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); } }
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); }
private TransferControlView getTransferControls() { if (!transferControls.isPresent()) { transferControls = Optional.of( (TransferControlView) ViewUtil.inflateStub(this, R.id.transfer_controls_stub)); } return transferControls.get(); }
@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); }
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()); } }
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()); } }
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)); }
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); } }
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); }
@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..."); } }
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(); } }
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); }
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); } }
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); }
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); }
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); }
@Override public void setClickable(boolean clickable) { super.setClickable(clickable); if (transferControls.isPresent()) transferControls.get().setClickable(clickable); }
@Override public void setFocusable(boolean focusable) { super.setFocusable(focusable); if (transferControls.isPresent()) transferControls.get().setFocusable(focusable); }
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; } } }
public void hideControls(boolean hideControls) { this.hideControls = hideControls; if (hideControls && transferControls.isPresent()) getTransferControls().setVisibility(View.GONE); }
private TransportOptionsPopup getTransportOptionsPopup() { if (!transportOptionsPopup.isPresent()) { transportOptionsPopup = Optional.of(new TransportOptionsPopup(getContext(), this, this)); } return transportOptionsPopup.get(); }
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; } }
@Override @NonNull public Optional<String> getBody() { return Optional.of(place.getDescription()); }