/* * Copyright (C) 2007-2008 Esmertec AG. Copyright (C) 2007-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 android.annotation.TargetApi; import android.app.Activity; import android.content.ContentResolver; import android.content.ContentUris; import android.content.Context; import android.content.SharedPreferences; import android.content.res.AssetFileDescriptor; import android.content.res.AssetManager; import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Color; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.AsyncTask; import android.os.Build; import android.preference.PreferenceManager; import android.support.v4.util.LruCache; import android.text.Spannable; import android.text.SpannableString; import android.text.TextUtils; import android.text.style.UnderlineSpan; import android.util.AttributeSet; import android.util.Log; import android.view.View; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.TextView; import com.bumptech.glide.Glide; import com.bumptech.glide.load.engine.DiskCacheStrategy; import net.java.otr4j.session.SessionStatus; import org.awesomeapp.messenger.ImApp; import org.awesomeapp.messenger.crypto.IOtrChatSession; import org.awesomeapp.messenger.model.Presence; import org.awesomeapp.messenger.provider.Imps; import org.awesomeapp.messenger.service.IChatSession; import org.awesomeapp.messenger.service.IImConnection; import org.awesomeapp.messenger.ui.legacy.DatabaseUtils; import org.awesomeapp.messenger.ui.widgets.ConversationViewHolder; import org.awesomeapp.messenger.ui.widgets.LetterAvatar; import org.awesomeapp.messenger.ui.widgets.RoundedAvatarDrawable; import org.awesomeapp.messenger.util.SecureMediaStore; import org.awesomeapp.messenger.util.SystemServices; import org.awesomeapp.messenger.util.SystemServices.FileInfo; import org.ocpsoft.prettytime.PrettyTime; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.util.Date; import java.util.Locale; import im.zom.messenger.R; public class ConversationListItem extends FrameLayout { public static final String[] CONTACT_PROJECTION = { Imps.Contacts._ID, Imps.Contacts.PROVIDER, Imps.Contacts.ACCOUNT, Imps.Contacts.USERNAME, Imps.Contacts.NICKNAME, Imps.Contacts.TYPE, Imps.Contacts.SUBSCRIPTION_TYPE, Imps.Contacts.SUBSCRIPTION_STATUS, Imps.Presence.PRESENCE_STATUS, Imps.Presence.PRESENCE_CUSTOM_STATUS, Imps.Chats.LAST_MESSAGE_DATE, Imps.Chats.LAST_UNREAD_MESSAGE, }; public static final int COLUMN_CONTACT_ID = 0; public static final int COLUMN_CONTACT_PROVIDER = 1; public static final int COLUMN_CONTACT_ACCOUNT = 2; public static final int COLUMN_CONTACT_USERNAME = 3; public static final int COLUMN_CONTACT_NICKNAME = 4; public static final int COLUMN_CONTACT_TYPE = 5; public static final int COLUMN_SUBSCRIPTION_TYPE = 6; public static final int COLUMN_SUBSCRIPTION_STATUS = 7; public static final int COLUMN_CONTACT_PRESENCE_STATUS = 8; public static final int COLUMN_CONTACT_CUSTOM_STATUS = 9; public static final int COLUMN_LAST_MESSAGE_DATE = 10; public static final int COLUMN_LAST_MESSAGE = 11; static Drawable AVATAR_DEFAULT_GROUP = null; private PrettyTime sPrettyTime = null; public ConversationListItem(Context context, AttributeSet attrs) { super(context, attrs); sPrettyTime = new PrettyTime(getCurrentLocale()); } /** public void bind(ConversationViewHolder holder, Cursor cursor, String underLineText, boolean scrolling) { bind(holder, cursor, underLineText, true, scrolling); } */ public void bind(ConversationViewHolder holder, long contactId, long providerId, long accountId, String address, String nickname, int contactType, String message, long messageDate, int presence, String underLineText, boolean showChatMsg, boolean scrolling) { //applyStyleColors(holder); if (nickname == null) { nickname = address.split("@")[0].split("\\.")[0]; } else { nickname = nickname.split("@")[0].split("\\.")[0]; } if (Imps.Contacts.TYPE_GROUP == contactType) { String groupCountString = getGroupCount(getContext().getContentResolver(), contactId); nickname += groupCountString; } if (!TextUtils.isEmpty(underLineText)) { // highlight/underline the word being searched String lowercase = nickname.toLowerCase(); int start = lowercase.indexOf(underLineText.toLowerCase()); if (start >= 0) { int end = start + underLineText.length(); SpannableString str = new SpannableString(nickname); str.setSpan(new UnderlineSpan(), start, end, Spannable.SPAN_INCLUSIVE_INCLUSIVE); holder.mLine1.setText(str); } else holder.mLine1.setText(nickname); } else holder.mLine1.setText(nickname); holder.mStatusIcon.setVisibility(View.GONE); if (holder.mAvatar != null) { if (Imps.Contacts.TYPE_GROUP == contactType) { holder.mAvatar.setVisibility(View.VISIBLE); if (AVATAR_DEFAULT_GROUP == null) AVATAR_DEFAULT_GROUP = new RoundedAvatarDrawable(BitmapFactory.decodeResource(getResources(), R.drawable.group_chat)); holder.mAvatar.setImageDrawable(AVATAR_DEFAULT_GROUP); } // else if (cursor.getColumnIndex(Imps.Contacts.AVATAR_DATA)!=-1) else { // holder.mAvatar.setVisibility(View.GONE); Drawable avatar = null; try { avatar = DatabaseUtils.getAvatarFromAddress(this.getContext().getContentResolver(), address, ImApp.SMALL_AVATAR_WIDTH, ImApp.SMALL_AVATAR_HEIGHT); // avatar = DatabaseUtils.getAvatarFromCursor(cursor, COLUMN_AVATAR_DATA, ImApp.SMALL_AVATAR_WIDTH, ImApp.SMALL_AVATAR_HEIGHT); } catch (Exception e) { //problem decoding avatar Log.e(ImApp.LOG_TAG,"error decoding avatar",e); } try { if (avatar != null) { //if (avatar instanceof RoundedAvatarDrawable) // setAvatarBorder(presence,(RoundedAvatarDrawable)avatar); holder.mAvatar.setImageDrawable(avatar); } else { // int color = getAvatarBorder(presence); int padding = 24; LetterAvatar lavatar = new LetterAvatar(getContext(), nickname, padding); holder.mAvatar.setImageDrawable(lavatar); } holder.mAvatar.setVisibility(View.VISIBLE); } catch (OutOfMemoryError ome) { //this seems to happen now and then even on tiny images; let's catch it and just not set an avatar } } } if (showChatMsg && message != null) { if (holder.mLine2 != null) { if (SecureMediaStore.isVfsUri(message)) { FileInfo fInfo = SystemServices.getFileInfoFromURI(getContext(), Uri.parse(message)); if (fInfo.type == null || fInfo.type.startsWith("image")) { if (holder.mMediaThumb != null) { holder.mMediaThumb.setVisibility(View.VISIBLE); if (fInfo.type != null && fInfo.type.equals("image/png")) { holder.mMediaThumb.setScaleType(ImageView.ScaleType.FIT_CENTER); } else { holder.mMediaThumb.setScaleType(ImageView.ScaleType.CENTER_CROP); } setThumbnail(getContext().getContentResolver(), holder, Uri.parse(message)); holder.mLine2.setVisibility(View.GONE); } } else { holder.mLine2.setText(""); } } else if ((!TextUtils.isEmpty(message)) && message.startsWith("/")) { String cmd = message.toString().substring(1); if (cmd.startsWith("sticker")) { String[] cmds = cmd.split(":"); String mimeTypeSticker = "image/png"; Uri mediaUri = Uri.parse("asset://"+cmds[1]); setThumbnail(getContext().getContentResolver(), holder, mediaUri); holder.mLine2.setVisibility(View.GONE); holder.mMediaThumb.setScaleType(ImageView.ScaleType.FIT_CENTER); } } else if ((!TextUtils.isEmpty(message)) && message.startsWith(":")) { String[] cmds = message.split(":"); 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); setThumbnail(getContext().getContentResolver(), holder, mediaUri); holder.mLine2.setVisibility(View.GONE); holder.mMediaThumb.setScaleType(ImageView.ScaleType.FIT_CENTER); } catch (Exception e) { } } else { if (holder.mMediaThumb != null) holder.mMediaThumb.setVisibility(View.GONE); holder.mLine2.setVisibility(View.VISIBLE); try { holder.mLine2.setText(android.text.Html.fromHtml(message).toString()); } catch (RuntimeException re){} } } if (messageDate != -1) { Date dateLast = new Date(messageDate); holder.mStatusText.setText(sPrettyTime.format(dateLast)); } else { holder.mStatusText.setText(""); } } else if (holder.mLine2 != null) { holder.mLine2.setText(address); if (holder.mMediaThumb != null) holder.mMediaThumb.setVisibility(View.GONE); } holder.mLine1.setVisibility(View.VISIBLE); if (providerId != -1) getEncryptionState (providerId, accountId, address, holder); } private void getEncryptionState (long providerId, long accountId, String address, ConversationViewHolder holder) { try { ImApp app = ((ImApp)((Activity) getContext()).getApplication()); IImConnection conn = app.getConnection(providerId,accountId); if (conn == null || conn.getChatSessionManager() == null) return; IChatSession chatSession = conn.getChatSessionManager().getChatSession(address); if (chatSession != null) { if (chatSession.isEncrypted()) { holder.mStatusIcon.setImageDrawable(getResources().getDrawable(R.drawable.ic_encrypted_grey)); holder.mStatusIcon.setVisibility(View.VISIBLE); } } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } //mCurrentChatSession.getOtrChatSession(); } /** 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(android.R.color.transparent)); break; default: } }**/ 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; } private Uri mLastMediaUri = null; /** * @param contentResolver * @param aHolder * @param mediaUri */ private void setThumbnail(final ContentResolver contentResolver, final ConversationViewHolder aHolder, final Uri mediaUri) { if (mLastMediaUri != null && mLastMediaUri.getPath().equals(mediaUri.getPath())) return; mLastMediaUri = mediaUri; Glide.clear(aHolder.mMediaThumb); if(SecureMediaStore.isVfsUri(mediaUri)) { info.guardianproject.iocipher.File fileMedia = new info.guardianproject.iocipher.File(mediaUri.getPath()); if (fileMedia.exists()) { try { Glide.with(getContext()) .load(new info.guardianproject.iocipher.FileInputStream(fileMedia)) .diskCacheStrategy(DiskCacheStrategy.NONE) .into(aHolder.mMediaThumb); } catch (Exception e) { Log.e(ImApp.LOG_TAG,"unable to load thumbnail",e); } } } else if (mediaUri.getScheme().equals("asset")) { String assetPath = "file:///android_asset/" + mediaUri.getPath().substring(1); Glide.with(getContext()) .load(assetPath) .diskCacheStrategy(DiskCacheStrategy.NONE) .into(aHolder.mMediaThumb); } else { Glide.with(getContext()) .load(mediaUri) .into(aHolder.mMediaThumb); } } private String getGroupCount(ContentResolver resolver, long groupId) { String[] projection = { Imps.GroupMembers.NICKNAME }; Uri uri = ContentUris.withAppendedId(Imps.GroupMembers.CONTENT_URI, groupId); Cursor c = resolver.query(uri, projection, null, null, null); StringBuilder buf = new StringBuilder(); if (c != null) { buf.append(" ("); buf.append(c.getCount()); buf.append(")"); c.close(); } return buf.toString(); } /** public void applyStyleColors (ConversationViewHolder holder) { //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 (themeColorText != -1) { if (holder.mLine1 != null) holder.mLine1.setTextColor(themeColorText); if (holder.mLine2 != null) holder.mLine2.setTextColor(themeColorText); //holder.mLine2.setTextColor(darker(themeColorText,2.0f)); } }*/ /** * Returns darker version of specified <code>color</code>. */ public static int darker (int color, float factor) { int a = Color.alpha( color ); int r = Color.red( color ); int g = Color.green( color ); int b = Color.blue( color ); return Color.argb( a, Math.max( (int)(r * factor), 0 ), Math.max( (int)(g * factor), 0 ), Math.max( (int)(b * factor), 0 ) ); } @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; } } }