mobisocial.musubi.objects.PictureObj.java Source code

Java tutorial

Introduction

Here is the source code for mobisocial.musubi.objects.PictureObj.java

Source

/*
 * Copyright 2012 The Stanford MobiSocial Laboratory
 *
 * 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 mobisocial.musubi.objects;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.ref.SoftReference;

import mobisocial.musubi.App;
import mobisocial.musubi.ImageGalleryActivity;
import mobisocial.musubi.R;
import mobisocial.musubi.feed.iface.Activator;
import mobisocial.musubi.feed.iface.DbEntryHandler;
import mobisocial.musubi.feed.iface.FeedRenderer;
import mobisocial.musubi.model.DbContactAttributes;
import mobisocial.musubi.model.MFeed;
import mobisocial.musubi.model.MIdentity;
import mobisocial.musubi.model.MObject;
import mobisocial.musubi.ui.MusubiBaseActivity;
import mobisocial.musubi.ui.fragments.FeedListFragment.FeedSummary;
import mobisocial.musubi.ui.widget.DbObjCursorAdapter.DbObjCursor;
import mobisocial.musubi.util.CommonLayouts;
import mobisocial.musubi.util.UriImage;
import mobisocial.socialkit.musubi.DbObj;
import mobisocial.socialkit.obj.MemObj;

import org.apache.commons.io.IOUtils;
import org.json.JSONException;
import org.json.JSONObject;
import org.mobisocial.corral.ContentCorral;
import org.mobisocial.corral.CorralDownloadClient;

import android.app.Activity;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Typeface;
import android.graphics.drawable.BitmapDrawable;
import android.media.MediaScannerConnection;
import android.net.Uri;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

public class PictureObj extends DbEntryHandler implements FeedRenderer, Activator {
    public static final String TAG = "PictureObj";

    public static final String TYPE = "picture";
    public static final String DATA = "data";
    public static final String TEXT = "text";

    public static final int MAX_IMAGE_WIDTH = 1280;
    public static final int MAX_IMAGE_HEIGHT = 720;
    public static final int MAX_IMAGE_SIZE = 40 * 1024;

    @Override
    public String getType() {
        return TYPE;
    }

    public static MemObj from(byte[] data) {
        return from(data, "");
    }

    /** 
     * This does NOT do any SCALING!
     */
    public static MemObj from(byte[] data, String text) {
        JSONObject base = new JSONObject();
        try {
            base.put(TEXT, text);
        } catch (JSONException e) {
        }

        return new MemObj(TYPE, base, data);
    }

    public static MemObj from(JSONObject base, byte[] data) {
        return new MemObj(TYPE, base, data);
    }

    public static MemObj from(Context context, Uri imageUri, boolean referenceOrig) throws IOException {
        return from(context, imageUri, referenceOrig, null);
    }

    public static MemObj from(Context context, Uri imageUri, boolean referenceOrig, String text)
            throws IOException {
        // Query gallery for camera picture via
        // Android ContentResolver interface
        ContentResolver cr = context.getContentResolver();

        UriImage image = new UriImage(context, imageUri);
        byte[] data = image.getResizedImageData(MAX_IMAGE_WIDTH, MAX_IMAGE_HEIGHT, MAX_IMAGE_SIZE);

        JSONObject base = new JSONObject();
        // Maintain a reference to original file
        try {
            String type = cr.getType(imageUri);
            if (type == null) {
                type = "image/jpeg";
            }

            if (text != null && !text.isEmpty()) {
                base.put(TEXT, text);
            }
            base.put(CorralDownloadClient.OBJ_MIME_TYPE, type);
            if (referenceOrig) {
                base.put(CorralDownloadClient.OBJ_LOCAL_URI, imageUri.toString());
                String localIp = ContentCorral.getLocalIpAddress();
                // TODO: Share IP if allowed for the given feed
                if (localIp != null && MusubiBaseActivity.isDeveloperModeEnabled(context)) {
                    base.put(DbContactAttributes.ATTR_LAN_IP, localIp);
                }
            }
        } catch (JSONException e) {
            Log.e(TAG, "impossible json error possible!");
        }
        return new MemObj(TYPE, base, data);
    }

    @Override
    public View createView(Context context, ViewGroup parent) {
        LinearLayout frame = new LinearLayout(context);
        frame.setLayoutParams(CommonLayouts.FULL_WIDTH);
        frame.setOrientation(LinearLayout.VERTICAL);

        ImageView imageView = new ImageView(context);
        imageView.setBackgroundResource(android.R.drawable.picture_frame);
        imageView.setPadding(6, 4, 8, 9);
        frame.addView(imageView);

        TextView textView = new TextView(context);
        frame.addView(textView);

        return frame;
    }

    @Override
    public void render(Context context, View view, DbObjCursor obj, boolean allowInteractions) {
        LinearLayout frame = (LinearLayout) view;

        ImageView imageView = (ImageView) frame.getChildAt(0);
        FileDescriptor fd = obj.getFileDescriptorForRaw();
        byte[] raw = null;
        if (fd == null) {
            raw = obj.getRaw();
        }

        bindImageToView(context, imageView, raw, fd);

        String text = obj.getJson().optString(TEXT);
        TextView textView = (TextView) frame.getChildAt(1);
        textView.setText(text);
    }

    /**
     * Pass in one of raw or fd as the source of the image.
     * Not thread safe, only call on the ui thread.
     */
    protected static void bindImageToView(Context context, ImageView imageView, byte[] raw, FileDescriptor fd) {
        // recycle old images (vs. caching in ImageCache)
        if (imageView.getDrawable() != null) {
            BitmapDrawable d = (BitmapDrawable) imageView.getDrawable();
            if (d != null && d.getBitmap() != null) {
                d.getBitmap().recycle();
            }
        }

        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        if (fd != null) {
            BitmapFactory.decodeFileDescriptor(fd, null, options);
        } else {
            BitmapFactory.decodeByteArray(raw, 0, raw.length, options);
        }
        Resources res = context.getResources();

        float scaleFactor;
        if (res.getBoolean(R.bool.is_tablet)) {
            scaleFactor = 3.0f;
        } else {
            scaleFactor = 2.0f;
        }
        DisplayMetrics dm = context.getResources().getDisplayMetrics();
        int pixels = dm.widthPixels;
        if (dm.heightPixels < pixels) {
            pixels = dm.heightPixels;
        }
        int width = (int) (pixels / scaleFactor);
        int height = (int) ((float) width / options.outWidth * options.outHeight);
        int max_height = (int) (AppStateObj.MAX_HEIGHT * dm.density);
        if (height > max_height) {
            width = width * max_height / height;
            height = max_height;
        }

        options.inJustDecodeBounds = false;
        options.inTempStorage = getTempData();
        options.inSampleSize = 1;
        //TODO: lame, can just compute
        while (options.outWidth / (options.inSampleSize + 1) >= width
                && options.outHeight / (options.inSampleSize + 1) >= height) {
            options.inSampleSize++;
        }
        options.inPurgeable = true;
        options.inInputShareable = true;

        Bitmap bm;
        if (fd != null) {
            bm = BitmapFactory.decodeFileDescriptor(fd, null, options);
        } else {
            bm = BitmapFactory.decodeByteArray(raw, 0, raw.length, options);
        }
        imageView.getLayoutParams().width = width + 13;
        imageView.getLayoutParams().height = height + 14;
        imageView.setImageBitmap(bm);
    }

    @Override
    public void activate(Context context, DbObj obj) {
        // TODO: set data uri for obj
        Intent intent = new Intent(context, ImageGalleryActivity.class);
        intent.setData(obj.getContainingFeed().getUri());
        intent.putExtra(ImageGalleryActivity.EXTRA_DEFAULT_OBJECT_ID, obj.getLocalId());
        if (!(context instanceof Activity)) {
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        }
        context.startActivity(intent);
    }

    @Override
    public boolean processObject(Context context, MFeed feed, MIdentity sender, MObject object) {
        DbObj obj = App.getMusubi(context).objForId(object.id_);
        File thumbFile = CorralDownloadClient.localFileForContent(obj, true);
        try {
            FileOutputStream fout = new FileOutputStream(thumbFile);
            ByteArrayInputStream fin = new ByteArrayInputStream(object.raw_);
            IOUtils.copy(fin, fout);
            String[] paths = new String[] { thumbFile.getAbsolutePath() };
            MediaScannerConnection.scanFile(context, paths, null, null);
        } catch (IOException e) {
            Log.e(TAG, "Error saving thumbnail", e);
            thumbFile.delete();
        }
        return true;
    }

    static byte[] mTempData;

    static byte[] getTempData() {
        if (mTempData == null) {
            mTempData = new byte[16 * 1024];
        }
        return mTempData;
    }

    @Override
    public void getSummaryText(Context context, TextView view, FeedSummary summary) {
        view.setTypeface(null, Typeface.ITALIC);

        JSONObject json = summary.getJson();
        if (json != null && json.optString(PictureObj.TEXT).length() > 0) {
            StringBuilder summaryText = new StringBuilder(50).append(summary.getSender())
                    .append(" shared a picture with the caption \"" + json.optString(StatusObj.TEXT) + "\"");
            view.setText(summaryText.toString());
        } else {
            StringBuilder summaryText = new StringBuilder(50).append(summary.getSender())
                    .append(" shared a picture.");
            view.setText(summaryText.toString());
        }
    }
}