org.quantumbadger.redreader.activities.ImageViewActivity.java Source code

Java tutorial

Introduction

Here is the source code for org.quantumbadger.redreader.activities.ImageViewActivity.java

Source

/*******************************************************************************
 * This file is part of RedReader.
 *
 * RedReader is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * RedReader is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with RedReader.  If not, see <http://www.gnu.org/licenses/>.
 ******************************************************************************/

package org.quantumbadger.redreader.activities;

import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.media.MediaPlayer;
import android.net.Uri;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.*;
import org.apache.http.StatusLine;
import org.quantumbadger.redreader.R;
import org.quantumbadger.redreader.account.RedditAccountManager;
import org.quantumbadger.redreader.cache.CacheManager;
import org.quantumbadger.redreader.cache.CacheRequest;
import org.quantumbadger.redreader.cache.RequestFailureType;
import org.quantumbadger.redreader.common.*;
import org.quantumbadger.redreader.image.GifDecoderThread;
import org.quantumbadger.redreader.reddit.prepared.RedditPreparedPost;
import org.quantumbadger.redreader.reddit.things.RedditPost;
import org.quantumbadger.redreader.reddit.url.PostCommentListingURL;
import org.quantumbadger.redreader.views.GIFView;
import org.quantumbadger.redreader.views.RedditPostView;
import org.quantumbadger.redreader.views.bezelmenu.BezelSwipeOverlay;
import org.quantumbadger.redreader.views.bezelmenu.SideToolbarOverlay;
import org.quantumbadger.redreader.views.glview.RRGLSurfaceView;
import org.quantumbadger.redreader.views.imageview.ImageTileSource;
import org.quantumbadger.redreader.views.imageview.ImageTileSourceWholeBitmap;
import org.quantumbadger.redreader.views.imageview.ImageViewDisplayListManager;
import org.quantumbadger.redreader.views.liststatus.ErrorView;

import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.util.UUID;

public class ImageViewActivity extends BaseActivity
        implements RedditPostView.PostSelectionListener, ImageViewDisplayListManager.Listener {

    GLSurfaceView surfaceView;
    private ImageView imageView;
    private GifDecoderThread gifThread;

    private URI mUrl;

    private boolean mIsPaused = true, mIsDestroyed = false;
    private CacheRequest mRequest;

    private boolean mHaveReverted = false;

    private ImageViewDisplayListManager mImageViewDisplayerManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        final SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
        final boolean solidblack = PrefsUtility.appearance_solidblack(this, sharedPreferences);

        if (solidblack)
            getWindow().setBackgroundDrawable(new ColorDrawable(Color.BLACK));

        final Intent intent = getIntent();

        mUrl = General.uriFromString(intent.getDataString());
        final RedditPost src_post = intent.getParcelableExtra("post");

        if (mUrl == null) {
            General.quickToast(this, "Invalid URL. Trying web browser.");
            revertToWeb();
            return;
        }

        Log.i("ImageViewActivity", "Loading URL " + mUrl.toString());

        final ProgressBar progressBar = new ProgressBar(this, null, android.R.attr.progressBarStyleHorizontal);

        final LinearLayout layout = new LinearLayout(this);
        layout.setOrientation(LinearLayout.VERTICAL);
        layout.addView(progressBar);

        CacheManager.getInstance(this)
                .makeRequest(mRequest = new CacheRequest(mUrl, RedditAccountManager.getAnon(), null,
                        Constants.Priority.IMAGE_VIEW, 0, CacheRequest.DownloadType.IF_NECESSARY,
                        Constants.FileType.IMAGE, false, false, false, this) {

                    private void setContentView(View v) {
                        layout.removeAllViews();
                        layout.addView(v);
                        v.getLayoutParams().width = ViewGroup.LayoutParams.MATCH_PARENT;
                        v.getLayoutParams().height = ViewGroup.LayoutParams.MATCH_PARENT;
                    }

                    @Override
                    protected void onCallbackException(Throwable t) {
                        BugReportActivity.handleGlobalError(context.getApplicationContext(),
                                new RRError(null, null, t));
                    }

                    @Override
                    protected void onDownloadNecessary() {
                        AndroidApi.UI_THREAD_HANDLER.post(new Runnable() {
                            @Override
                            public void run() {
                                progressBar.setVisibility(View.VISIBLE);
                                progressBar.setIndeterminate(true);
                            }
                        });
                    }

                    @Override
                    protected void onDownloadStarted() {
                    }

                    @Override
                    protected void onFailure(final RequestFailureType type, Throwable t, StatusLine status,
                            final String readableMessage) {

                        final RRError error = General.getGeneralErrorForFailure(context, type, t, status,
                                url.toString());

                        AndroidApi.UI_THREAD_HANDLER.post(new Runnable() {
                            public void run() {
                                // TODO handle properly
                                mRequest = null;
                                progressBar.setVisibility(View.GONE);
                                layout.addView(new ErrorView(ImageViewActivity.this, error));
                            }
                        });
                    }

                    @Override
                    protected void onProgress(final boolean authorizationInProgress, final long bytesRead,
                            final long totalBytes) {
                        AndroidApi.UI_THREAD_HANDLER.post(new Runnable() {
                            @Override
                            public void run() {
                                progressBar.setVisibility(View.VISIBLE);
                                progressBar.setIndeterminate(authorizationInProgress);
                                progressBar.setProgress((int) ((100 * bytesRead) / totalBytes));
                            }
                        });
                    }

                    @Override
                    protected void onSuccess(final CacheManager.ReadableCacheFile cacheFile, long timestamp,
                            UUID session, boolean fromCache, final String mimetype) {

                        if (mimetype == null
                                || (!Constants.Mime.isImage(mimetype) && !Constants.Mime.isVideo(mimetype))) {
                            revertToWeb();
                            return;
                        }

                        final InputStream cacheFileInputStream;
                        try {
                            cacheFileInputStream = cacheFile.getInputStream();
                        } catch (IOException e) {
                            notifyFailure(RequestFailureType.PARSE, e, null,
                                    "Could not read existing cached image.");
                            return;
                        }

                        if (cacheFileInputStream == null) {
                            notifyFailure(RequestFailureType.CACHE_MISS, null, null, "Could not find cached image");
                            return;
                        }

                        if (Constants.Mime.isVideo(mimetype)) {

                            AndroidApi.UI_THREAD_HANDLER.post(new Runnable() {
                                public void run() {

                                    if (mIsDestroyed)
                                        return;
                                    mRequest = null;

                                    try {
                                        final RelativeLayout layout = new RelativeLayout(context);
                                        layout.setGravity(Gravity.CENTER);

                                        final VideoView videoView = new VideoView(ImageViewActivity.this);

                                        videoView.setVideoURI(cacheFile.getUri());
                                        layout.addView(videoView);
                                        setContentView(layout);

                                        layout.getLayoutParams().width = ViewGroup.LayoutParams.MATCH_PARENT;
                                        layout.getLayoutParams().height = ViewGroup.LayoutParams.MATCH_PARENT;
                                        videoView.setLayoutParams(
                                                new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                                                        ViewGroup.LayoutParams.MATCH_PARENT));

                                        videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
                                            @Override
                                            public void onPrepared(MediaPlayer mp) {
                                                mp.setLooping(true);
                                                videoView.start();
                                            }
                                        });

                                        videoView.setOnErrorListener(new MediaPlayer.OnErrorListener() {
                                            @Override
                                            public boolean onError(final MediaPlayer mediaPlayer, final int i,
                                                    final int i1) {
                                                revertToWeb();
                                                return true;
                                            }
                                        });

                                        videoView.setOnTouchListener(new View.OnTouchListener() {
                                            @Override
                                            public boolean onTouch(final View view, final MotionEvent motionEvent) {
                                                finish();
                                                return true;
                                            }
                                        });

                                    } catch (OutOfMemoryError e) {
                                        General.quickToast(context, R.string.imageview_oom);
                                        revertToWeb();

                                    } catch (Throwable e) {
                                        General.quickToast(context, R.string.imageview_invalid_video);
                                        revertToWeb();
                                    }
                                }
                            });

                        } else if (Constants.Mime.isImageGif(mimetype)) {

                            final PrefsUtility.GifViewMode gifViewMode = PrefsUtility
                                    .pref_behaviour_gifview_mode(context, sharedPreferences);

                            if (gifViewMode == PrefsUtility.GifViewMode.INTERNAL_BROWSER) {
                                revertToWeb();
                                return;

                            } else if (gifViewMode == PrefsUtility.GifViewMode.EXTERNAL_BROWSER) {
                                AndroidApi.UI_THREAD_HANDLER.post(new Runnable() {
                                    @Override
                                    public void run() {
                                        LinkHandler.openWebBrowser(ImageViewActivity.this,
                                                Uri.parse(mUrl.toString()));
                                        finish();
                                    }
                                });

                                return;
                            }

                            if (AndroidApi.isIceCreamSandwichOrLater()
                                    && gifViewMode == PrefsUtility.GifViewMode.INTERNAL_MOVIE) {

                                AndroidApi.UI_THREAD_HANDLER.post(new Runnable() {
                                    public void run() {

                                        if (mIsDestroyed)
                                            return;
                                        mRequest = null;

                                        try {
                                            final GIFView gifView = new GIFView(ImageViewActivity.this,
                                                    cacheFileInputStream);
                                            setContentView(gifView);
                                            gifView.setOnClickListener(new View.OnClickListener() {
                                                public void onClick(View v) {
                                                    finish();
                                                }
                                            });

                                        } catch (OutOfMemoryError e) {
                                            General.quickToast(context, R.string.imageview_oom);
                                            revertToWeb();

                                        } catch (Throwable e) {
                                            General.quickToast(context, R.string.imageview_invalid_gif);
                                            revertToWeb();
                                        }
                                    }
                                });

                            } else {

                                gifThread = new GifDecoderThread(cacheFileInputStream,
                                        new GifDecoderThread.OnGifLoadedListener() {

                                            public void onGifLoaded() {
                                                AndroidApi.UI_THREAD_HANDLER.post(new Runnable() {
                                                    public void run() {

                                                        if (mIsDestroyed)
                                                            return;
                                                        mRequest = null;

                                                        imageView = new ImageView(context);
                                                        imageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
                                                        setContentView(imageView);
                                                        gifThread.setView(imageView);

                                                        imageView.setOnClickListener(new View.OnClickListener() {
                                                            public void onClick(View v) {
                                                                finish();
                                                            }
                                                        });
                                                    }
                                                });
                                            }

                                            public void onOutOfMemory() {
                                                General.quickToast(context, R.string.imageview_oom);
                                                revertToWeb();
                                            }

                                            public void onGifInvalid() {
                                                General.quickToast(context, R.string.imageview_invalid_gif);
                                                revertToWeb();
                                            }
                                        });

                                gifThread.start();

                            }

                        } else {

                            final ImageTileSource imageTileSource;
                            try {

                                final long bytes = cacheFile.getSize();
                                final byte[] buf = new byte[(int) bytes];

                                try {
                                    new DataInputStream(cacheFileInputStream).readFully(buf);
                                } catch (IOException e) {
                                    throw new RuntimeException(e);
                                }

                                try {
                                    imageTileSource = new ImageTileSourceWholeBitmap(buf);

                                } catch (Throwable t) {
                                    Log.e("ImageViewActivity", "Exception when creating ImageTileSource", t);
                                    General.quickToast(context, R.string.imageview_decode_failed);
                                    revertToWeb();
                                    return;
                                }

                            } catch (OutOfMemoryError e) {
                                General.quickToast(context, R.string.imageview_oom);
                                revertToWeb();
                                return;
                            }

                            AndroidApi.UI_THREAD_HANDLER.post(new Runnable() {
                                public void run() {

                                    if (mIsDestroyed)
                                        return;
                                    mRequest = null;
                                    mImageViewDisplayerManager = new ImageViewDisplayListManager(imageTileSource,
                                            ImageViewActivity.this);
                                    surfaceView = new RRGLSurfaceView(ImageViewActivity.this,
                                            mImageViewDisplayerManager);
                                    setContentView(surfaceView);

                                    surfaceView.setOnClickListener(new View.OnClickListener() {
                                        public void onClick(View v) {
                                            finish();
                                        }
                                    });

                                    if (mIsPaused) {
                                        surfaceView.onPause();
                                    } else {
                                        surfaceView.onResume();
                                    }
                                }
                            });
                        }
                    }
                });

        final RedditPreparedPost post = src_post == null ? null
                : new RedditPreparedPost(this, CacheManager.getInstance(this), 0, src_post, -1, false, false, false,
                        false, RedditAccountManager.getInstance(this).getDefaultAccount(), false);

        final FrameLayout outerFrame = new FrameLayout(this);
        outerFrame.addView(layout);

        if (post != null) {

            final SideToolbarOverlay toolbarOverlay = new SideToolbarOverlay(this);

            final BezelSwipeOverlay bezelOverlay = new BezelSwipeOverlay(this,
                    new BezelSwipeOverlay.BezelSwipeListener() {

                        public boolean onSwipe(BezelSwipeOverlay.SwipeEdge edge) {

                            toolbarOverlay.setContents(
                                    post.generateToolbar(ImageViewActivity.this, false, toolbarOverlay));
                            toolbarOverlay.show(edge == BezelSwipeOverlay.SwipeEdge.LEFT
                                    ? SideToolbarOverlay.SideToolbarPosition.LEFT
                                    : SideToolbarOverlay.SideToolbarPosition.RIGHT);
                            return true;
                        }

                        public boolean onTap() {

                            if (toolbarOverlay.isShown()) {
                                toolbarOverlay.hide();
                                return true;
                            }

                            return false;
                        }
                    });

            outerFrame.addView(bezelOverlay);
            outerFrame.addView(toolbarOverlay);

            bezelOverlay.getLayoutParams().width = android.widget.FrameLayout.LayoutParams.MATCH_PARENT;
            bezelOverlay.getLayoutParams().height = android.widget.FrameLayout.LayoutParams.MATCH_PARENT;

            toolbarOverlay.getLayoutParams().width = android.widget.FrameLayout.LayoutParams.MATCH_PARENT;
            toolbarOverlay.getLayoutParams().height = android.widget.FrameLayout.LayoutParams.MATCH_PARENT;

        }

        setContentView(outerFrame);
    }

    public void onPostSelected(final RedditPreparedPost post) {
        LinkHandler.onLinkClicked(this, post.url, false, post.src);
    }

    public void onPostCommentsSelected(final RedditPreparedPost post) {
        LinkHandler.onLinkClicked(this, PostCommentListingURL.forPostId(post.idAlone).generateJsonUri().toString(),
                false);
    }

    @Override
    public void onBackPressed() {
        if (General.onBackPressed())
            super.onBackPressed();
    }

    private void revertToWeb() {

        final Runnable r = new Runnable() {
            public void run() {
                if (!mHaveReverted) {
                    mHaveReverted = true;
                    LinkHandler.onLinkClicked(ImageViewActivity.this, mUrl.toString(), true);
                    finish();
                }
            }
        };

        if (General.isThisUIThread()) {
            r.run();
        } else {
            AndroidApi.UI_THREAD_HANDLER.post(r);
        }
    }

    @Override
    public void onPause() {

        if (mIsPaused)
            throw new RuntimeException();

        mIsPaused = true;

        Log.i("DEBUG", "ImageViewActivity.onPause()");
        super.onPause();
        if (surfaceView != null) {
            Log.i("DEBUG", "surfaceView.onPause()");
            surfaceView.onPause();
        }
    }

    @Override
    public void onResume() {

        if (!mIsPaused)
            throw new RuntimeException();

        mIsPaused = false;

        Log.i("DEBUG", "ImageViewActivity.onResume()");
        super.onResume();
        if (surfaceView != null) {
            Log.i("DEBUG", "surfaceView.onResume()");
            surfaceView.onResume();
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        mIsDestroyed = true;
        if (mRequest != null)
            mRequest.cancel();
        if (gifThread != null)
            gifThread.stopPlaying();
    }

    @Override
    public void onSingleTap() {
        finish();
    }

    @Override
    public void onImageViewDLMOutOfMemory() {
        if (!mHaveReverted) {
            General.quickToast(this, R.string.imageview_oom);
            revertToWeb();
        }
    }

    @Override
    public void onImageViewDLMException(Throwable t) {
        if (!mHaveReverted) {
            General.quickToast(this, R.string.imageview_decode_failed);
            revertToWeb();
        }
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        if (mImageViewDisplayerManager != null) {
            mImageViewDisplayerManager.resetTouchState();
        }
    }
}