/* * Copyright (C) 2008 Esmertec AG. Copyright (C) 2008 The Android Open Source * Project * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.awesomeapp.messenger.ui; import im.zom.messenger.R; import org.awesomeapp.messenger.ImUrlActivity; import org.awesomeapp.messenger.ui.widgets.MessageViewHolder; import org.awesomeapp.messenger.util.SecureMediaStore; import org.awesomeapp.messenger.ui.legacy.DatabaseUtils; import org.awesomeapp.messenger.ImApp; import org.awesomeapp.messenger.ui.legacy.Markup; import org.awesomeapp.messenger.plugin.xmpp.XmppAddress; import org.awesomeapp.messenger.provider.Imps; import org.awesomeapp.messenger.ui.widgets.ImageViewActivity; import org.awesomeapp.messenger.ui.widgets.LetterAvatar; import org.awesomeapp.messenger.ui.widgets.RoundedAvatarDrawable; import org.awesomeapp.messenger.util.LinkifyHelper; import org.ocpsoft.prettytime.PrettyTime; import java.net.URLConnection; import java.util.Date; import java.util.List; import java.util.Locale; import android.annotation.TargetApi; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.res.AssetFileDescriptor; import android.content.res.Resources; import android.database.Cursor; import android.graphics.Color; import android.graphics.Typeface; import android.net.Uri; import android.os.Build; import android.preference.PreferenceManager; import android.provider.Browser; import android.provider.MediaStore; import android.text.Spannable; import android.text.SpannableString; import android.text.TextUtils; import android.text.style.ClickableSpan; import android.text.style.ImageSpan; import android.text.style.RelativeSizeSpan; import android.text.style.StyleSpan; import android.text.style.URLSpan; import android.util.AttributeSet; import android.util.Log; import android.view.View; import android.widget.FrameLayout; import android.widget.Toast; import com.bumptech.glide.Glide; import com.bumptech.glide.load.engine.DiskCacheStrategy; public class MessageListItem extends FrameLayout { public enum DeliveryState { NEUTRAL, DELIVERED, UNDELIVERED } public enum EncryptionState { NONE, ENCRYPTED, ENCRYPTED_AND_VERIFIED } private String lastMessage = null; private Uri mediaUri = null; private String mimeType = null; private Context context; private boolean linkify = false; private MessageViewHolder mHolder = null; private static PrettyTime sPrettyTime = null; public MessageListItem(Context context, AttributeSet attrs) { super(context, attrs); this.context = context; sPrettyTime = new PrettyTime(getCurrentLocale()); } /** * This trickery is needed in order to have clickable links that open things * in a new {@code Task} rather than in ChatSecure's {@code Task.} Thanks to @commonsware * https://stackoverflow.com/a/11417498 * */ class NewTaskUrlSpan extends ClickableSpan { private String urlString; NewTaskUrlSpan(String urlString) { this.urlString = urlString; } @Override public void onClick(View widget) { Uri uri = Uri.parse(urlString); Context context = widget.getContext(); Intent intent = new Intent(Intent.ACTION_VIEW, uri); intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName()); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(intent); } } class URLSpanConverter implements LinkifyHelper.SpanConverter<URLSpan, ClickableSpan> { @Override public NewTaskUrlSpan convert(URLSpan span) { return (new NewTaskUrlSpan(span.getURL())); } } @Override protected void onFinishInflate() { super.onFinishInflate(); } public void setLinkify(boolean linkify) { this.linkify = linkify; } public URLSpan[] getMessageLinks() { return mHolder.mTextViewForMessages.getUrls(); } public String getLastMessage () { return lastMessage; } public void bindIncomingMessage(MessageViewHolder holder, int id, int messageType, String address, String nickname, final String mimeType, final String body, Date date, Markup smileyRes, boolean scrolling, EncryptionState encryption, boolean showContact, int presenceStatus) { mHolder = holder; applyStyleColors(); mHolder.mTextViewForMessages.setVisibility(View.VISIBLE); mHolder.mAudioContainer.setVisibility(View.GONE); mHolder.mMediaContainer.setVisibility(View.GONE); if (nickname == null) nickname = address; lastMessage = formatMessage(body); showAvatar(address, nickname, true, presenceStatus); mHolder.resetOnClickListenerMediaThumbnail(); if( mimeType != null ) { Uri mediaUri = Uri.parse(body); lastMessage = ""; if (mimeType.startsWith("audio")) { mHolder.mAudioButton.setImageResource(R.drawable.media_audio_play); try { mHolder.mAudioContainer.setVisibility(View.VISIBLE); showAudioPlayer(mimeType, mediaUri, id, mHolder); } catch (Exception e) { mHolder.mAudioContainer.setVisibility(View.GONE); } } else { mHolder.mTextViewForMessages.setVisibility(View.GONE); showMediaThumbnail(mimeType, mediaUri, id, mHolder); mHolder.mMediaContainer.setVisibility(View.VISIBLE); } } else if ((!TextUtils.isEmpty(lastMessage)) && (lastMessage.charAt(0) == '/'||lastMessage.charAt(0) == ':')) { boolean cmdSuccess = false; if (lastMessage.startsWith("/sticker:")) { String[] cmds = lastMessage.split(":"); String mimeTypeSticker = "image/png"; try { String assetPath = cmds[1].split(" ")[0].toLowerCase();//just get up to any whitespace; //make sure sticker exists AssetFileDescriptor afd = getContext().getAssets().openFd(assetPath); afd.getLength(); afd.close(); //now setup the new URI for loading local sticker asset Uri mediaUri = Uri.parse("asset://localhost/" + assetPath); //now load the thumbnail cmdSuccess = showMediaThumbnail(mimeTypeSticker, mediaUri, id, mHolder); } catch (Exception e) { Log.e(ImApp.LOG_TAG, "error loading sticker bitmap: " + cmds[1],e); cmdSuccess = false; } } else if (lastMessage.startsWith(":")) { String[] cmds = lastMessage.split(":"); String mimeTypeSticker = "image/png"; try { String[] stickerParts = cmds[1].split("-"); String stickerPath = "stickers/" + stickerParts[0].toLowerCase() + "/" + stickerParts[1].toLowerCase() + ".png"; //make sure sticker exists AssetFileDescriptor afd = getContext().getAssets().openFd(stickerPath); afd.getLength(); afd.close(); //now setup the new URI for loading local sticker asset Uri mediaUri = Uri.parse("asset://localhost/" + stickerPath); //now load the thumbnail cmdSuccess = showMediaThumbnail(mimeTypeSticker, mediaUri, id, mHolder); } catch (Exception e) { cmdSuccess = false; } } if (!cmdSuccess) { mHolder.mTextViewForMessages.setText(new SpannableString(lastMessage)); } else { mHolder.mContainer.setBackgroundResource(android.R.color.transparent); lastMessage = ""; } } // if (isSelected()) // mHolder.mContainer.setBackgroundColor(getResources().getColor(R.color.holo_blue_bright)); if (lastMessage.length() > 0) { mHolder.mTextViewForMessages.setText(new SpannableString(lastMessage)); } else { mHolder.mTextViewForMessages.setText(lastMessage); } if (date != null) { String contact = null; if (showContact) { String[] nickParts = nickname.split("/"); contact = nickParts[nickParts.length-1]; } CharSequence tsText = formatTimeStamp(date,messageType, null, encryption, contact); mHolder.mTextViewForTimestamp.setText(tsText); mHolder.mTextViewForTimestamp.setVisibility(View.VISIBLE); } else { mHolder.mTextViewForTimestamp.setText(""); //mHolder.mTextViewForTimestamp.setVisibility(View.GONE); } if (linkify) LinkifyHelper.addLinks(mHolder.mTextViewForMessages, new URLSpanConverter()); LinkifyHelper.addTorSafeLinks(mHolder.mTextViewForMessages); } private boolean showMediaThumbnail (String mimeType, Uri mediaUri, int id, MessageViewHolder holder) { this.mediaUri = mediaUri; this.mimeType = mimeType; /* Guess the MIME type in case we received a file that we can display or play*/ if (TextUtils.isEmpty(mimeType) || mimeType.startsWith("application")) { String guessed = URLConnection.guessContentTypeFromName(mediaUri.toString()); if (!TextUtils.isEmpty(guessed)) { if (TextUtils.equals(guessed, "video/3gpp")) mimeType = "audio/3gpp"; else mimeType = guessed; } } holder.setOnClickListenerMediaThumbnail(mimeType, mediaUri); holder.mTextViewForMessages.setText(lastMessage); holder.mTextViewForMessages.setVisibility(View.GONE); if( mimeType.startsWith("image/") ) { setImageThumbnail( getContext().getContentResolver(), id, holder, mediaUri ); holder.mMediaThumbnail.setBackgroundResource(android.R.color.transparent); } else { Glide.clear(holder.mMediaThumbnail); try { Glide.with(context) .load(R.drawable.ic_file) .diskCacheStrategy(DiskCacheStrategy.NONE) .into(holder.mMediaThumbnail); } catch (Exception e) { Log.e(ImApp.LOG_TAG,"unable to load thumbnail",e); } holder.mMediaThumbnail.setImageResource(R.drawable.ic_file); // generic file icon holder.mTextViewForMessages.setText(mediaUri.getLastPathSegment()); holder.mTextViewForMessages.setVisibility(View.VISIBLE); } holder.mMediaContainer.setVisibility(View.VISIBLE); holder.mContainer.setBackgroundResource(android.R.color.transparent); return true; } private void showAudioPlayer (String mimeType, Uri mediaUri, int id, MessageViewHolder holder) throws Exception { /* Guess the MIME type in case we received a file that we can display or play*/ if (TextUtils.isEmpty(mimeType) || mimeType.startsWith("application")) { String guessed = URLConnection.guessContentTypeFromName(mediaUri.toString()); if (!TextUtils.isEmpty(guessed)) { if (TextUtils.equals(guessed, "video/3gpp")) mimeType = "audio/3gpp"; else mimeType = guessed; } } holder.setOnClickListenerMediaThumbnail(mimeType, mediaUri); mHolder.mTextViewForMessages.setText(""); mAudioPlayer = new AudioPlayer(getContext(), mediaUri.getPath(), mimeType, mHolder.mVisualizerView,mHolder.mTextViewForMessages); holder.mContainer.setBackgroundResource(android.R.color.transparent); } protected String convertMediaUriToPath(Uri uri) { String path = null; String [] proj={MediaStore.Images.Media.DATA}; Cursor cursor = getContext().getContentResolver().query(uri, proj, null, null, null); if (cursor != null && (!cursor.isClosed())) { if (cursor.isBeforeFirst()) { int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); cursor.moveToFirst(); path = cursor.getString(column_index); } cursor.close(); } return path; } private AudioPlayer mAudioPlayer; public void onClickMediaIcon(String mimeType, Uri mediaUri) { if (mimeType.startsWith("image")) { if (mimeType.equals("image/jpeg")) { Intent intent = new Intent(context, ImageViewActivity.class); intent.putExtra(ImageViewActivity.URI, mediaUri.toString()); intent.putExtra(ImageViewActivity.MIMETYPE, mimeType); intent.putExtra(ImageViewActivity.MIMETYPE, mimeType); context.startActivity(intent); } } else if (mimeType.startsWith("audio")) { if (mAudioPlayer.getDuration() != -1) mHolder.mTextViewForMessages.setText((mAudioPlayer.getDuration()/1000) + "secs"); if (mAudioPlayer.isPlaying()) { mHolder.mAudioButton.setImageResource(R.drawable.media_audio_play); mAudioPlayer.pause(); } else { mHolder.mAudioButton.setImageResource(R.drawable.media_audio_pause); mAudioPlayer.play(); } } else { exportMediaFile(); /** String body = convertMediaUriToPath(mediaUri); if (body == null) body = new File(mediaUri.getPath()).getAbsolutePath(); Intent intent = new Intent(Intent.ACTION_VIEW); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); if (Build.VERSION.SDK_INT >= 11) intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); //set a general mime type not specific intent.setDataAndType(Uri.parse(body), mimeType); Context context = getContext().getApplicationContext(); if (isIntentAvailable(context, intent)) { context.startActivity(intent); } else { intent = new Intent(Intent.ACTION_SEND); intent.setDataAndType(Uri.parse(body), mimeType); if (isIntentAvailable(context, intent)) { context.startActivity(intent); } else { Toast.makeText(getContext(), R.string.there_is_no_viewer_available_for_this_file_format, Toast.LENGTH_LONG).show(); } }**/ } } /** protected void onLongClickMediaIcon(final String mimeType, final Uri mediaUri) { final java.io.File exportPath = SecureMediaStore.exportPath(mimeType, mediaUri); new AlertDialog.Builder(context) .setTitle(context.getString(R.string.export_media)) .setMessage(context.getString(R.string.export_media_file_to, exportPath.getAbsolutePath())) .setNeutralButton("Share on Zom", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { reshareMediaFile(mimeType, mediaUri); } }) .setPositiveButton(R.string.export, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int whichButton) { exportMediaFile(mimeType, mediaUri, exportPath); return; } }) .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int whichButton) { return; } }) .create().show(); }*/ private void forwardMediaFile (String mimeType, Uri mediaUri) { String resharePath = "vfs:/" + mediaUri.getPath(); Intent shareIntent = new Intent(context, ImUrlActivity.class); shareIntent.setAction(Intent.ACTION_SEND); shareIntent.setDataAndType(Uri.parse(resharePath), mimeType); context.startActivity(shareIntent); } public void forwardMediaFile () { if (mimeType != null && mediaUri != null) { forwardMediaFile(mimeType, mediaUri); } else { Intent shareIntent = new Intent(context, ImUrlActivity.class); shareIntent.setAction(Intent.ACTION_SEND); shareIntent.putExtra(Intent.EXTRA_TEXT, lastMessage); shareIntent.setType("text/plain"); context.startActivity(shareIntent); } } public void exportMediaFile () { if (mimeType != null && mediaUri != null) { java.io.File exportPath = SecureMediaStore.exportPath(mimeType, mediaUri); exportMediaFile(mimeType, mediaUri, exportPath); } else { Intent shareIntent = new Intent(); shareIntent.setAction(Intent.ACTION_SEND); shareIntent.putExtra(Intent.EXTRA_TEXT,lastMessage); shareIntent.setType("text/plain"); context.startActivity(Intent.createChooser(shareIntent, getResources().getText(R.string.export_media))); } }; private void exportMediaFile (String mimeType, Uri mediaUri, java.io.File exportPath) { try { SecureMediaStore.exportContent(mimeType, mediaUri, exportPath); Intent shareIntent = new Intent(); shareIntent.setAction(Intent.ACTION_SEND); shareIntent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(exportPath)); shareIntent.setType(mimeType); context.startActivity(Intent.createChooser(shareIntent, getResources().getText(R.string.export_media))); } catch (Exception e) { Toast.makeText(getContext(), "Export Failed " + e.getMessage(), Toast.LENGTH_LONG).show(); e.printStackTrace(); } } public static boolean isIntentAvailable(Context context, Intent intent) { final PackageManager packageManager = context.getPackageManager(); List<ResolveInfo> list = packageManager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY); return list.size() > 0; } /** * @param contentResolver * @param id * @param aHolder * @param mediaUri */ private void setImageThumbnail(final ContentResolver contentResolver, final int id, final MessageViewHolder aHolder, final Uri mediaUri) { //if the same URI, we don't need to reload if (aHolder.mMediaUri != null && aHolder.mMediaUri.getPath().equals(mediaUri.getPath())) return; // pair this holder to the uri. if the holder is recycled, the pairing is broken aHolder.mMediaUri = mediaUri; // if a content uri - already scanned Glide.clear(aHolder.mMediaThumbnail); if(SecureMediaStore.isVfsUri(mediaUri)) { try { info.guardianproject.iocipher.File fileImage = new info.guardianproject.iocipher.File(mediaUri.getPath()); if (fileImage.exists()) { Glide.with(context) .load(new info.guardianproject.iocipher.FileInputStream(fileImage)) .diskCacheStrategy(DiskCacheStrategy.NONE) .into(aHolder.mMediaThumbnail); } } catch (Exception e) { Log.w(ImApp.LOG_TAG,"unable to load thumbnail: " + mediaUri.toString()); } } else if (mediaUri.getScheme().equals("asset")) { String assetPath = "file:///android_asset/" + mediaUri.getPath().substring(1); Glide.with(context) .load(assetPath) .diskCacheStrategy(DiskCacheStrategy.NONE) .into(aHolder.mMediaThumbnail); } else { Glide.with(context) .load(mediaUri) .into(aHolder.mMediaThumbnail); } } private String formatMessage (String body) { if (body != null) try { return (android.text.Html.fromHtml(body).toString()); //this happens on Xiaomi sometimes } catch (RuntimeException re){ return ""; } else return ""; } public void bindOutgoingMessage(MessageViewHolder holder, int id, int messageType, String address, final String mimeType, final String body, Date date, Markup smileyRes, boolean scrolling, DeliveryState delivery, EncryptionState encryption) { mHolder = holder; applyStyleColors(); mHolder.mTextViewForMessages.setVisibility(View.VISIBLE); mHolder.mAudioContainer.setVisibility(View.GONE); mHolder.mMediaContainer.setVisibility(View.GONE); mHolder.mAudioButton.setImageResource(R.drawable.media_audio_play); mHolder.resetOnClickListenerMediaThumbnail(); lastMessage = body; if( mimeType != null ) { lastMessage = ""; Uri mediaUri = Uri.parse( body ) ; if (mimeType.startsWith("audio")) { try { mHolder.mAudioContainer.setVisibility(View.VISIBLE); showAudioPlayer(mimeType, mediaUri, id, mHolder); } catch (Exception e) { mHolder.mAudioContainer.setVisibility(View.GONE); } } else { mHolder.mTextViewForMessages.setVisibility(View.GONE); mHolder.mMediaContainer.setVisibility(View.VISIBLE); showMediaThumbnail(mimeType, mediaUri, id, mHolder); } } else if ((!TextUtils.isEmpty(lastMessage)) && (lastMessage.charAt(0) == '/'||lastMessage.charAt(0) == ':')) { // String cmd = lastMessage.toString().substring(1); boolean cmdSuccess = false; if (lastMessage.startsWith("/sticker:")) { String[] cmds = lastMessage.split(":"); String mimeTypeSticker = "image/png"; try { //make sure sticker exists AssetFileDescriptor afd = getContext().getAssets().openFd(cmds[1]); afd.getLength(); afd.close(); //now setup the new URI for loading local sticker asset Uri mediaUri = Uri.parse("asset://localhost/" + cmds[1].toLowerCase()); //now load the thumbnail cmdSuccess = showMediaThumbnail(mimeTypeSticker, mediaUri, id, mHolder); } catch (Exception e) { cmdSuccess = false; } } else if (lastMessage.startsWith(":")) { String[] cmds = lastMessage.split(":"); String mimeTypeSticker = "image/png"; try { String[] stickerParts = cmds[1].split("-"); String stickerPath = "stickers/" + stickerParts[0].toLowerCase() + "/" + stickerParts[1].toLowerCase() + ".png"; //make sure sticker exists AssetFileDescriptor afd = getContext().getAssets().openFd(stickerPath); afd.getLength(); afd.close(); //now setup the new URI for loading local sticker asset Uri mediaUri = Uri.parse("asset://localhost/" + stickerPath); //now load the thumbnail cmdSuccess = showMediaThumbnail(mimeTypeSticker, mediaUri, id, mHolder); } catch (Exception e) { cmdSuccess = false; } } if (!cmdSuccess) { mHolder.mTextViewForMessages.setText(new SpannableString(lastMessage)); } else { holder.mContainer.setBackgroundResource(android.R.color.transparent); lastMessage = ""; } } else { mHolder.mTextViewForMessages.setText(new SpannableString(lastMessage)); } //if (isSelected()) // mHolder.mContainer.setBackgroundColor(getResources().getColor(R.color.holo_blue_bright)); if (date != null) { CharSequence tsText = formatTimeStamp(date,messageType, delivery, encryption, null); mHolder.mTextViewForTimestamp.setText(tsText); mHolder.mTextViewForTimestamp.setVisibility(View.VISIBLE); } else { mHolder.mTextViewForTimestamp.setText(""); } if (linkify) LinkifyHelper.addLinks(mHolder.mTextViewForMessages, new URLSpanConverter()); LinkifyHelper.addTorSafeLinks(mHolder.mTextViewForMessages); } private void showAvatar (String address, String nickname, boolean isLeft, int presenceStatus) { if (mHolder.mAvatar == null) return; mHolder.mAvatar.setVisibility(View.GONE); if (address != null && isLeft) { RoundedAvatarDrawable avatar = null; try { avatar = (RoundedAvatarDrawable)DatabaseUtils.getAvatarFromAddress(this.getContext().getContentResolver(), XmppAddress.stripResource(address), ImApp.SMALL_AVATAR_WIDTH, ImApp.SMALL_AVATAR_HEIGHT);} catch (Exception e){} if (avatar != null) { mHolder.mAvatar.setVisibility(View.VISIBLE); mHolder.mAvatar.setImageDrawable(avatar); //setAvatarBorder(presenceStatus, avatar); } else { // int color = getAvatarBorder(presenceStatus); int padding = 24; if (nickname.length() > 0) { LetterAvatar lavatar = new LetterAvatar(getContext(), nickname, padding); mHolder.mAvatar.setVisibility(View.VISIBLE); mHolder.mAvatar.setImageDrawable(lavatar); } } } } /** public int getAvatarBorder(int status) { switch (status) { case Presence.AVAILABLE: return (getResources().getColor(R.color.holo_green_light)); case Presence.IDLE: return (getResources().getColor(R.color.holo_green_dark)); case Presence.AWAY: return (getResources().getColor(R.color.holo_orange_light)); case Presence.DO_NOT_DISTURB: return(getResources().getColor(R.color.holo_red_dark)); case Presence.OFFLINE: return(getResources().getColor(R.color.holo_grey_dark)); default: } return Color.TRANSPARENT; }**/ public void bindPresenceMessage(MessageViewHolder holder, String contact, int type, Date date, boolean isGroupChat, boolean scrolling) { mHolder = holder; mHolder.mContainer.setBackgroundResource(android.R.color.transparent); mHolder.mTextViewForMessages.setVisibility(View.GONE); mHolder.mTextViewForTimestamp.setVisibility(View.VISIBLE); CharSequence message = formatPresenceUpdates(contact, type, date, isGroupChat, scrolling); mHolder.mTextViewForTimestamp.setText(message); } public void bindErrorMessage(int errCode) { mHolder = (MessageViewHolder)getTag(); mHolder.mTextViewForMessages.setText(R.string.msg_sent_failed); mHolder.mTextViewForMessages.setTextColor(getResources().getColor(R.color.error)); } private SpannableString formatTimeStamp(Date date, int messageType, MessageListItem.DeliveryState delivery, EncryptionState encryptionState, String nickname) { StringBuilder deliveryText = new StringBuilder(); if (nickname != null) { deliveryText.append(nickname); deliveryText.append(' '); } deliveryText.append(sPrettyTime.format(date)); SpannableString spanText = null; spanText = new SpannableString(deliveryText.toString()); if (delivery != null) { deliveryText.append(' '); //this is for delivery if (messageType == Imps.MessageType.QUEUED) { //do nothing deliveryText.append("X"); spanText = new SpannableString(deliveryText.toString()); int len = spanText.length(); spanText.setSpan(new ImageSpan(getContext(), R.drawable.ic_message_wait_grey), len-1, len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } else if (delivery == DeliveryState.DELIVERED) { if (encryptionState == EncryptionState.ENCRYPTED || encryptionState == EncryptionState.ENCRYPTED_AND_VERIFIED) { deliveryText.append("XX"); spanText = new SpannableString(deliveryText.toString()); int len = spanText.length(); spanText.setSpan(new ImageSpan(getContext(), R.drawable.ic_delivered_grey), len - 2, len - 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); spanText.setSpan(new ImageSpan(getContext(), R.drawable.ic_encrypted_grey), len - 1, len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } else{ deliveryText.append("X"); spanText = new SpannableString(deliveryText.toString()); int len = spanText.length(); spanText.setSpan(new ImageSpan(getContext(), R.drawable.ic_delivered_grey), len-1, len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } } else if (delivery == DeliveryState.UNDELIVERED) { if (encryptionState == EncryptionState.ENCRYPTED||encryptionState == EncryptionState.ENCRYPTED_AND_VERIFIED) { deliveryText.append("XX"); spanText = new SpannableString(deliveryText.toString()); int len = spanText.length(); spanText.setSpan(new ImageSpan(getContext(), R.drawable.ic_sent_grey),len-2,len-1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); spanText.setSpan(new ImageSpan(getContext(), R.drawable.ic_encrypted_grey), len - 1, len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } else { deliveryText.append("XX"); spanText = new SpannableString(deliveryText.toString()); int len = spanText.length(); spanText.setSpan(new ImageSpan(getContext(), R.drawable.ic_sent_grey),len-1,len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } } else if (delivery == DeliveryState.NEUTRAL) { if (encryptionState == EncryptionState.ENCRYPTED||encryptionState == EncryptionState.ENCRYPTED_AND_VERIFIED) { deliveryText.append("XX"); spanText = new SpannableString(deliveryText.toString()); int len = spanText.length(); spanText.setSpan(new ImageSpan(getContext(), R.drawable.ic_sent_grey),len-2,len-1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); spanText.setSpan(new ImageSpan(getContext(), R.drawable.ic_encrypted_grey), len - 1, len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } else { deliveryText.append("X"); spanText = new SpannableString(deliveryText.toString()); int len = spanText.length(); spanText.setSpan(new ImageSpan(getContext(), R.drawable.ic_sent_grey),len-1,len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } } } else { if (encryptionState == EncryptionState.ENCRYPTED||encryptionState == EncryptionState.ENCRYPTED_AND_VERIFIED) { deliveryText.append('X'); spanText = new SpannableString(deliveryText.toString()); int len = spanText.length(); if (encryptionState == EncryptionState.ENCRYPTED||encryptionState == EncryptionState.ENCRYPTED_AND_VERIFIED) spanText.setSpan(new ImageSpan(getContext(), R.drawable.ic_encrypted_grey), len-1, len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } else if (messageType == Imps.MessageType.OUTGOING) { //do nothing deliveryText.append("X"); spanText = new SpannableString(deliveryText.toString()); int len = spanText.length(); spanText.setSpan(new ImageSpan(getContext(), R.drawable.ic_message_wait_grey), len-1, len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } } return spanText; } private CharSequence formatPresenceUpdates(String contact, int type, Date date, boolean isGroupChat, boolean scrolling) { String body; Resources resources =getResources(); switch (type) { case Imps.MessageType.PRESENCE_AVAILABLE: body = resources.getString(isGroupChat ? R.string.contact_joined : R.string.contact_online, contact); break; case Imps.MessageType.PRESENCE_AWAY: body = resources.getString(R.string.contact_away, contact); break; case Imps.MessageType.PRESENCE_DND: body = resources.getString(R.string.contact_busy, contact); break; case Imps.MessageType.PRESENCE_UNAVAILABLE: body = resources.getString(isGroupChat ? R.string.contact_left : R.string.contact_offline, contact); break; default: return null; } body += " - "; body += formatTimeStamp(date,type, null, EncryptionState.NONE, null); if (scrolling) { return body; } else { SpannableString spanText = new SpannableString(body); int len = spanText.length(); spanText.setSpan(new StyleSpan(Typeface.ITALIC), 0, len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); spanText.setSpan(new RelativeSizeSpan((float) 0.8), 0, len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); return spanText; } } /** public void setAvatarBorder(int status, RoundedAvatarDrawable avatar) { switch (status) { case Presence.AVAILABLE: avatar.setBorderColor(getResources().getColor(R.color.holo_green_light)); break; case Presence.IDLE: avatar.setBorderColor(getResources().getColor(R.color.holo_green_dark)); break; case Presence.AWAY: avatar.setBorderColor(getResources().getColor(R.color.holo_orange_light)); break; case Presence.DO_NOT_DISTURB: avatar.setBorderColor(getResources().getColor(R.color.holo_red_dark)); break; case Presence.OFFLINE: avatar.setBorderColor(getResources().getColor(R.color.holo_grey_light)); break; default: } }**/ public void applyStyleColors () { //not set color final SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(getContext()); int themeColorHeader = settings.getInt("themeColor",-1); int themeColorText = settings.getInt("themeColorText",-1); int themeColorBg = settings.getInt("themeColorBg",-1); if (mHolder != null) { if (themeColorText != -1) { if (mHolder.mTextViewForMessages != null) mHolder.mTextViewForMessages.setTextColor(themeColorText); if (mHolder.mTextViewForTimestamp != null) mHolder.mTextViewForTimestamp.setTextColor(themeColorText); } if (themeColorBg != -1) { int textBubbleBg = getContrastColor(themeColorText); if (textBubbleBg == Color.BLACK) mHolder.mContainer.setBackgroundResource(R.drawable.message_view_rounded_dark); else mHolder.mContainer.setBackgroundResource(R.drawable.message_view_rounded_light); //mHolder.mContainer.setBackgroundResource(android.R.color.transparent); //mHolder.mContainer.setBackgroundColor(themeColorBg); } else { mHolder.mContainer.setBackgroundResource(R.drawable.message_view_rounded_light); } } } public static int getContrastColor(int colorIn) { double y = (299 * Color.red(colorIn) + 587 * Color.green(colorIn) + 114 * Color.blue(colorIn)) / 1000; return y >= 128 ? Color.BLACK : Color.WHITE; } @TargetApi(Build.VERSION_CODES.N) public Locale getCurrentLocale(){ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){ return getResources().getConfiguration().getLocales().get(0); } else{ //noinspection deprecation return getResources().getConfiguration().locale; } } }