Android Open Source - matrix-android-sdk Adapter Utils






From Project

Back to project page matrix-android-sdk.

License

The source code is released under:

Apache License

If you think the Android project matrix-android-sdk listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package org.matrix.matrixandroidsdk.adapters;
/*w  w w. j a v  a2 s.  co  m*/
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.support.v4.util.LruCache;
import android.text.Html;
import android.util.Log;
import android.widget.ImageView;

import com.google.gson.JsonNull;
import com.google.gson.JsonObject;

import org.matrix.androidsdk.data.RoomState;
import org.matrix.androidsdk.rest.model.Event;
import org.matrix.androidsdk.rest.model.Message;
import org.matrix.androidsdk.rest.model.RoomMember;
import org.matrix.androidsdk.util.ContentManager;
import org.matrix.matrixandroidsdk.Matrix;
import org.matrix.matrixandroidsdk.R;

import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.WeakReference;
import java.net.URL;

/**
 * Contains useful functions for adapters.
 */
public class AdapterUtils {
    private static final String LOG_TAG = "AdapterUtils";

    public static class EventDisplay {
        private Event mEvent;
        private Context mContext;
        private boolean mPrependAuthor;
        private RoomState mRoomState;

        public EventDisplay(Context context, Event event, RoomState roomState) {
            mContext = context.getApplicationContext();
            mEvent = event;
            mRoomState = roomState;
        }

        /**
         * <p>Prepend the text with the author's name if they have not been mentioned in the text.</p>
         * This will prepend text messages with the author's name. This will NOT prepend things like
         * emote, room topic changes, etc which already mention the author's name in the message.
         * @param prepend
         */
        public void setPrependMessagesWithAuthor(boolean prepend) {
            mPrependAuthor = prepend;
        }

        private String getUserDisplayName(String userId) {
            RoomMember roomMember = mRoomState.getMember(userId);
            return (roomMember != null) ? roomMember.getName() : userId;
        }

        /**
         * Get the textual body for this event.
         * @return The text or null if it isn't possible.
         */
        public CharSequence getTextualDisplay() {
            CharSequence text = null;
            try {
                String userDisplayName = getUserDisplayName(mEvent.userId);
                if (Event.EVENT_TYPE_MESSAGE.equals(mEvent.type)) {
                    // all m.room.message events should support the 'body' key fallback, so use it.
                    text = mEvent.content.get("body") == null ? null : mEvent.content.get("body").getAsString();

                    // check for more specific formatting.
                    String msgType = mEvent.content.getAsJsonPrimitive("msgtype").getAsString();
                    if (msgType.equals(Message.MSGTYPE_TEXT)) {
                        // check for html formatting
                        if (mEvent.content.has("formatted_body") && mEvent.content.has("format")) {
                            String format = mEvent.content.getAsJsonPrimitive("format").getAsString();
                            if ("org.matrix.custom.html".equals(format)) {
                                text = Html.fromHtml(mEvent.content.getAsJsonPrimitive("formatted_body").getAsString());
                            }
                        }
                    }

                    if (mPrependAuthor) {
                        text = mContext.getString(R.string.summary_message, userDisplayName, text);
                    }
                }
                else if (Event.EVENT_TYPE_STATE_ROOM_TOPIC.equals(mEvent.type)) {
                    // pretty print 'XXX changed the topic to YYYY'
                    text = mContext.getString(R.string.notice_topic_changed,
                            userDisplayName, mEvent.content.getAsJsonPrimitive("topic").getAsString());
                }
                else if (Event.EVENT_TYPE_STATE_ROOM_NAME.equals(mEvent.type)) {
                    // pretty print 'XXX changed the room name to YYYY'
                    text = mContext.getString(R.string.notice_room_name_changed,
                            userDisplayName, mEvent.content.getAsJsonPrimitive("name").getAsString());
                }
                else if (Event.EVENT_TYPE_STATE_ROOM_MEMBER.equals(mEvent.type)) {
                    // m.room.member is used to represent at least 3 different changes in state: membership,
                    // avatar pic url and display name. We need to figure out which thing changed to display
                    // the right text.
                    JsonObject prevState = mEvent.prevContent;
                    if (prevState == null) {
                        // if there is no previous state, it has to be an invite or a join as they are the first
                        // m.room.member events for a user.
                        text = getMembershipNotice(mEvent);
                    }
                    else {
                        // check if the membership changed
                        if (hasStringValueChanged(mEvent, "membership")) {
                            text = getMembershipNotice(mEvent);
                        }
                        // check if avatar url changed
                        else if (hasStringValueChanged(mEvent, "avatar_url")) {
                            text = getAvatarChangeNotice(mEvent);
                        }
                        // check if the display name changed.
                        else if (hasStringValueChanged(mEvent, "displayname")) {
                            text = getDisplayNameChangeNotice(mEvent);
                        }
                        else {
                            // well shucks, I'm all out of ideas, let's whine.
                            Log.e(LOG_TAG, "Redundant membership event. PREV=>"+prevState+" NOW=>"+mEvent.content);
                        }
                    }
                }
            }
            catch (Exception e) {
                Log.e(LOG_TAG, "getTextualDisplay() "+e);
            }

            return text;
        }

        private String getMembershipNotice(Event msg) {
            String membership = msg.content.getAsJsonPrimitive("membership").getAsString();
            String userDisplayName = getUserDisplayName(msg.userId);
            if (RoomMember.MEMBERSHIP_INVITE.equals(membership)) {
                return mContext.getString(R.string.notice_room_invite, userDisplayName, getUserDisplayName(msg.stateKey));
            }
            else if (RoomMember.MEMBERSHIP_JOIN.equals(membership)) {
                return mContext.getString(R.string.notice_room_join, userDisplayName);
            }
            else if (RoomMember.MEMBERSHIP_LEAVE.equals(membership)) {
                // 2 cases here: this member may have left voluntarily or they may have been "left" by someone else ie. kicked
                if (msg.userId.equals(msg.stateKey)) {
                    return mContext.getString(R.string.notice_room_leave, userDisplayName);
                }
                else {
                    return mContext.getString(R.string.notice_room_kick, userDisplayName, getUserDisplayName(msg.stateKey));
                }
            }
            else if (RoomMember.MEMBERSHIP_BAN.equals(membership)) {
                return mContext.getString(R.string.notice_room_ban, userDisplayName, getUserDisplayName(msg.stateKey));
            }
            else {
                // eh?
                Log.e(LOG_TAG, "Unknown membership: "+membership);
            }
            return null;
        }

        private String getAvatarChangeNotice(Event msg) {
            // TODO: Pictures!
            return mContext.getString(R.string.notice_avatar_url_changed, getUserDisplayName(msg.userId));
        }

        private String getDisplayNameChangeNotice(Event msg) {
            return mContext.getString(R.string.notice_display_name_changed,
                    getUserDisplayName(msg.userId),
                    msg.content.getAsJsonPrimitive("displayname").getAsString()
            );
        }

        private boolean hasStringValueChanged(Event msg, String key) {
            JsonObject prevContent = msg.prevContent;
            if (prevContent.has(key) && msg.content.has(key)) {
                String old = prevContent.get(key) == JsonNull.INSTANCE ? null : prevContent.get(key).getAsString();
                String current = msg.content.get(key) == JsonNull.INSTANCE ? null : msg.content.get(key).getAsString();
                if (old == null && current == null) {
                    return false;
                }
                else if (old != null) {
                    return !old.equals(current);
                }
                else {
                    return !current.equals(old);
                }
            }
            else if (!prevContent.has(key) && !msg.content.has(key)) {
                return false; // this key isn't in either prev or current
            }
            else {
                return true; // this key is in one but not the other.
            }
        }
    }


    // Bitmap loading and storage


    public static void loadBitmap(ImageView imageView, String url) {
        ContentManager contentManager = Matrix.getInstance(imageView.getContext()).getDefaultSession().getContentManager();
        String downloadableUrl = contentManager.getDownloadableUrl(url);
        imageView.setTag(downloadableUrl);
        BitmapWorkerTask task = new BitmapWorkerTask(imageView, downloadableUrl);
        task.execute();
    }

    public static void loadThumbnailBitmap(ImageView imageView, String url, int width, int height) {
        ContentManager contentManager = Matrix.getInstance(imageView.getContext()).getDefaultSession().getContentManager();
        String downloadableUrl = contentManager.getDownloadableThumbnailUrl(url, width, height, ContentManager.METHOD_CROP);
        imageView.setTag(downloadableUrl);
        BitmapWorkerTask task = new BitmapWorkerTask(imageView, downloadableUrl);
        task.execute(width, height);
    }

    static class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {

        private static final int MEMORY_CACHE_MB = 6;

        private static LruCache<String, Bitmap> sMemoryCache = new LruCache<String, Bitmap>(1024 * 1024 * MEMORY_CACHE_MB){
            @Override
            protected int sizeOf(String key, Bitmap bitmap) {
                return bitmap.getRowBytes() * bitmap.getHeight(); // size in bytes
            }
        };

        private final WeakReference<ImageView> mImageViewReference;
        private String mUrl;

        public BitmapWorkerTask(ImageView imageView, String url) {
            mImageViewReference = new WeakReference<ImageView>(imageView);
            mUrl = url;
        }

        // Decode image in background.
        @Override
        protected Bitmap doInBackground(Integer... params) {
            try {
                // check the in-memory cache
                String key = mUrl;
                Bitmap bm = sMemoryCache.get(key);
                if (bm != null) {
                    return bm;
                }

                URL url = new URL(mUrl);
                Log.d(LOG_TAG, "BitmapWorkerTask open >>>>> " + mUrl);
                InputStream stream = url.openConnection().getInputStream();
//                BitmapFactory.Options o = decodeBitmapDimensions(stream);
//                int sampleSize = getSampleSize(o.outWidth, o.outHeight, mMaxPx);
//                close(stream); // checking the sample size processed the stream so it's useless now.
//                stream = url.openConnection().getInputStream();
                // decode within the limits specified.
                BitmapFactory.Options bitmapOptions = new BitmapFactory.Options();
//                bitmapOptions.inSampleSize = sampleSize;
                bitmapOptions.inDither = true;
                bitmapOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;
                Bitmap bitmap = BitmapFactory.decodeStream(stream, null, bitmapOptions);
                close(stream);
                if (bitmap != null) {
                    cacheBitmap(key, bitmap);
                }
                return bitmap;
            }
            catch (Exception e) {
                Log.e(LOG_TAG, "Unable to load bitmap: "+e);
                return null;
            }
        }

        // Once complete, see if ImageView is still around and set bitmap.
        @Override
        protected void onPostExecute(Bitmap bitmap) {
            if (mImageViewReference != null && bitmap != null) {
                final ImageView imageView = mImageViewReference.get();
                if (imageView != null && mUrl.equals(imageView.getTag())) {
                    imageView.setImageBitmap(bitmap);
                }
            }
        }

        /**
         * Get the width/height of the image at the end of this InputStream without dumping it all
         * in memory or disk. Note that this action processes the stream entirely, so a new stream
         * will be required (or this stream has to be rewindable) if the image is to be loaded from
         * it.
         * @param stream The input stream representing an image.
         * @return The bitmap info
         * @throws IOException If there isn't a decodable width and height for this image.
         */
        private BitmapFactory.Options decodeBitmapDimensions(InputStream stream) throws IOException {
            BitmapFactory.Options o = new BitmapFactory.Options();
            o.inJustDecodeBounds = true;
            BitmapFactory.decodeStream(stream, null, o);
            if (o.outHeight == -1 || o.outWidth == -1) {
                // this doesn't look like an image...
                throw new IOException("Cannot resize input stream, failed to get w/h.");
            }
            return o;
        }

        /**
         * Get the inSampleSize required to decode this image to the 'right' size.
         * @param w The width of the image in px
         * @param h The height of the image in px
         * @param maxSizePx The max dimension allowed in px
         * @return The sample size to use.
         */
        private int getSampleSize(int w, int h, int maxSizePx) {
            int highestDimensionSize = (h > w) ? h : w;
            double ratio = (highestDimensionSize > maxSizePx) ? (highestDimensionSize / maxSizePx) : 1.0;
            int sampleSize = Integer.highestOneBit((int)Math.floor(ratio));
            if (sampleSize == 0) {
                sampleSize = 1;
            }
            return sampleSize;
        }

        private void cacheBitmap(String key, Bitmap bitmap) {
            // for now we'll just in-memory cache this. In future, they should be written to the
            // cache directory as well.
            sMemoryCache.put(key, bitmap);
        }

        private void close(InputStream stream) {
            try {
                stream.close();
            }
            catch (Exception e) {} // don't care, it's being closed!
        }
    }
}




Java Source Code List

org.matrix.androidsdk.MXDataHandler.java
org.matrix.androidsdk.MXSession.java
org.matrix.androidsdk.RestClient.java
org.matrix.androidsdk.data.DataRetriever.java
org.matrix.androidsdk.data.IMXStore.java
org.matrix.androidsdk.data.MXMemoryStore.java
org.matrix.androidsdk.data.MyUser.java
org.matrix.androidsdk.data.RoomState.java
org.matrix.androidsdk.data.RoomSummary.java
org.matrix.androidsdk.data.Room.java
org.matrix.androidsdk.listeners.IMXEventListener.java
org.matrix.androidsdk.listeners.MXEventListener.java
org.matrix.androidsdk.rest.api.EventsApi.java
org.matrix.androidsdk.rest.api.LoginApi.java
org.matrix.androidsdk.rest.api.PresenceApi.java
org.matrix.androidsdk.rest.api.ProfileApi.java
org.matrix.androidsdk.rest.api.RegistrationApi.java
org.matrix.androidsdk.rest.api.RoomsApi.java
org.matrix.androidsdk.rest.callback.ApiCallback.java
org.matrix.androidsdk.rest.callback.ApiFailureCallback.java
org.matrix.androidsdk.rest.callback.RestAdapterCallback.java
org.matrix.androidsdk.rest.callback.SimpleApiCallback.java
org.matrix.androidsdk.rest.client.EventsRestClient.java
org.matrix.androidsdk.rest.client.LoginRestClient.java
org.matrix.androidsdk.rest.client.PresenceRestClient.java
org.matrix.androidsdk.rest.client.ProfileRestClient.java
org.matrix.androidsdk.rest.client.RegistrationRestClient.java
org.matrix.androidsdk.rest.client.RestClientTest.java
org.matrix.androidsdk.rest.client.RoomsRestClient.java
org.matrix.androidsdk.rest.model.BannedUser.java
org.matrix.androidsdk.rest.model.ContentResponse.java
org.matrix.androidsdk.rest.model.CreateRoomResponse.java
org.matrix.androidsdk.rest.model.Event.java
org.matrix.androidsdk.rest.model.ImageInfo.java
org.matrix.androidsdk.rest.model.ImageMessage.java
org.matrix.androidsdk.rest.model.InitialSyncResponse.java
org.matrix.androidsdk.rest.model.MatrixError.java
org.matrix.androidsdk.rest.model.MessageFeedback.java
org.matrix.androidsdk.rest.model.Message.java
org.matrix.androidsdk.rest.model.PowerLevels.java
org.matrix.androidsdk.rest.model.PublicRoom.java
org.matrix.androidsdk.rest.model.RoomMember.java
org.matrix.androidsdk.rest.model.RoomResponse.java
org.matrix.androidsdk.rest.model.TextMessage.java
org.matrix.androidsdk.rest.model.TokensChunkResponse.java
org.matrix.androidsdk.rest.model.User.java
org.matrix.androidsdk.rest.model.login.Credentials.java
org.matrix.androidsdk.rest.model.login.LoginFlowResponse.java
org.matrix.androidsdk.rest.model.login.LoginFlow.java
org.matrix.androidsdk.rest.model.login.LoginParams.java
org.matrix.androidsdk.rest.model.login.PasswordLoginParams.java
org.matrix.androidsdk.sync.DefaultEventsThreadListener.java
org.matrix.androidsdk.sync.EventsThreadListener.java
org.matrix.androidsdk.sync.EventsThreadTest.java
org.matrix.androidsdk.sync.EventsThread.java
org.matrix.androidsdk.util.ContentManager.java
org.matrix.androidsdk.util.ContentUtils.java
org.matrix.androidsdk.util.JsonUtils.java
org.matrix.matrixandroidsdk.ApplicationTest.java
org.matrix.matrixandroidsdk.ErrorListener.java
org.matrix.matrixandroidsdk.Matrix.java
org.matrix.matrixandroidsdk.ViewedRoomTracker.java
org.matrix.matrixandroidsdk.activity.CommonActivityUtils.java
org.matrix.matrixandroidsdk.activity.HomeActivity.java
org.matrix.matrixandroidsdk.activity.LoginActivity.java
org.matrix.matrixandroidsdk.activity.PublicRoomsActivity.java
org.matrix.matrixandroidsdk.activity.RoomActivity.java
org.matrix.matrixandroidsdk.activity.RoomInfoActivity.java
org.matrix.matrixandroidsdk.activity.SettingsActivity.java
org.matrix.matrixandroidsdk.activity.SplashActivity.java
org.matrix.matrixandroidsdk.adapters.AdapterUtils.java
org.matrix.matrixandroidsdk.adapters.MessageRow.java
org.matrix.matrixandroidsdk.adapters.MessagesAdapter.java
org.matrix.matrixandroidsdk.adapters.RoomMembersAdapter.java
org.matrix.matrixandroidsdk.adapters.RoomSummaryAdapter.java
org.matrix.matrixandroidsdk.adapters.RoomsAdapter.java
org.matrix.matrixandroidsdk.fragments.MatrixMessageListFragment.java
org.matrix.matrixandroidsdk.fragments.MatrixMessagesFragment.java
org.matrix.matrixandroidsdk.fragments.RoomMembersDialogFragment.java
org.matrix.matrixandroidsdk.services.EventStreamService.java
org.matrix.matrixandroidsdk.store.LoginStorage.java
org.matrix.matrixandroidsdk.util.EventUtils.java
org.matrix.matrixandroidsdk.util.ResourceUtils.java
org.matrix.matrixandroidsdk.util.UIUtils.java
org.matrix.matrixandroidsdk.view.PieFractionView.java