/*
* Copyright (C) 2016 eschao <esc.chao@gmail.com>
*
* 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 com.eschao.android.widget.sample.pageflip;
import android.content.Context;
import android.content.SharedPreferences;
import android.opengl.GLSurfaceView;
import android.opengl.GLSurfaceView.Renderer;
import android.os.Handler;
import android.os.Message;
import android.preference.PreferenceManager;
import android.util.Log;
import com.eschao.android.widget.pageflip.PageFlip;
import com.eschao.android.widget.pageflip.PageFlipException;
import java.util.concurrent.locks.ReentrantLock;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
/**
* Page flip view
*
* @author eschao
*/
public class PageFlipView extends GLSurfaceView implements Renderer {
private final static String TAG = "PageFlipView";
int mPageNo;
int mDuration;
Handler mHandler;
PageFlip mPageFlip;
PageRender mPageRender;
ReentrantLock mDrawLock;
public PageFlipView(Context context) {
super(context);
// create handler to tackle message
newHandler();
// load preferences
SharedPreferences pref = PreferenceManager
.getDefaultSharedPreferences(context);
mDuration = pref.getInt(Constants.PREF_DURATION, 1000);
int pixelsOfMesh = pref.getInt(Constants.PREF_MESH_PIXELS, 10);
boolean isAuto = pref.getBoolean(Constants.PREF_PAGE_MODE, true);
// create PageFlip
mPageFlip = new PageFlip(context);
mPageFlip.setSemiPerimeterRatio(0.8f)
.setShadowWidthOfFoldEdges(5, 60, 0.3f)
.setShadowWidthOfFoldBase(5, 80, 0.4f)
.setPixelsOfMesh(pixelsOfMesh)
.enableAutoPage(isAuto);
setEGLContextClientVersion(2);
// init others
mPageNo = 1;
mDrawLock = new ReentrantLock();
mPageRender = new SinglePageRender(context, mPageFlip,
mHandler, mPageNo);
// configure render
setRenderer(this);
setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
}
/**
* Is auto page mode enabled?
*
* @return true if auto page mode enabled
*/
public boolean isAutoPageEnabled() {
return mPageFlip.isAutoPageEnabled();
}
/**
* Enable/Disable auto page mode
*
* @param enable true is enable
*/
public void enableAutoPage(boolean enable) {
if (mPageFlip.enableAutoPage(enable)) {
try {
mDrawLock.lock();
if (mPageFlip.getSecondPage() != null &&
mPageRender instanceof SinglePageRender) {
mPageRender = new DoublePagesRender(getContext(),
mPageFlip,
mHandler,
mPageNo);
mPageRender.onSurfaceChanged(mPageFlip.getSurfaceWidth(),
mPageFlip.getSurfaceHeight());
}
else if (mPageFlip.getSecondPage() == null &&
mPageRender instanceof DoublePagesRender) {
mPageRender = new SinglePageRender(getContext(),
mPageFlip,
mHandler,
mPageNo);
mPageRender.onSurfaceChanged(mPageFlip.getSurfaceWidth(),
mPageFlip.getSurfaceHeight());
}
requestRender();
}
finally {
mDrawLock.unlock();
}
}
}
/**
* Get duration of animating
*
* @return duration of animating
*/
public int getAnimateDuration() {
return mDuration;
}
/**
* Set animate duration
*
* @param duration duration of animating
*/
public void setAnimateDuration(int duration) {
mDuration = duration;
}
/**
* Get pixels of mesh
*
* @return pixels of mesh
*/
public int getPixelsOfMesh() {
return mPageFlip.getPixelsOfMesh();
}
/**
* Handle finger down event
*
* @param x finger x coordinate
* @param y finger y coordinate
*/
public void onFingerDown(float x, float y) {
// if the animation is going, we should ignore this event to avoid
// mess drawing on screen
if (!mPageFlip.isAnimating() &&
mPageFlip.getFirstPage() != null) {
mPageFlip.onFingerDown(x, y);
}
}
/**
* Handle finger moving event
*
* @param x finger x coordinate
* @param y finger y coordinate
*/
public void onFingerMove(float x, float y) {
if (mPageFlip.isAnimating()) {
// nothing to do during animating
}
else if (mPageFlip.canAnimate(x, y)) {
// if the point is out of current page, try to start animating
onFingerUp(x, y);
}
// move page by finger
else if (mPageFlip.onFingerMove(x, y)) {
try {
mDrawLock.lock();
if (mPageRender != null &&
mPageRender.onFingerMove(x, y)) {
requestRender();
}
}
finally {
mDrawLock.unlock();
}
}
}
/**
* Handle finger up event and start animating if need
*
* @param x finger x coordinate
* @param y finger y coordinate
*/
public void onFingerUp(float x, float y) {
if (!mPageFlip.isAnimating()) {
mPageFlip.onFingerUp(x, y, mDuration);
try {
mDrawLock.lock();
if (mPageRender != null &&
mPageRender.onFingerUp(x, y)) {
requestRender();
}
}
finally {
mDrawLock.unlock();
}
}
}
/**
* Draw frame
*
* @param gl OpenGL handle
*/
@Override
public void onDrawFrame(GL10 gl) {
try {
mDrawLock.lock();
if (mPageRender != null) {
mPageRender.onDrawFrame();
}
}
finally {
mDrawLock.unlock();
}
}
/**
* Handle surface is changed
*
* @param gl OpenGL handle
* @param width new width of surface
* @param height new height of surface
*/
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
try {
mPageFlip.onSurfaceChanged(width, height);
// if there is the second page, create double page render when need
int pageNo = mPageRender.getPageNo();
if (mPageFlip.getSecondPage() != null && width > height) {
if (!(mPageRender instanceof DoublePagesRender)) {
mPageRender.release();
mPageRender = new DoublePagesRender(getContext(),
mPageFlip,
mHandler,
pageNo);
}
}
// if there is only one page, create single page render when need
else if(!(mPageRender instanceof SinglePageRender)) {
mPageRender.release();
mPageRender = new SinglePageRender(getContext(),
mPageFlip,
mHandler,
pageNo);
}
// let page render handle surface change
mPageRender.onSurfaceChanged(width, height);
}
catch (PageFlipException e) {
Log.e(TAG, "Failed to run PageFlipFlipRender:onSurfaceChanged");
}
}
/**
* Handle surface is created
*
* @param gl OpenGL handle
* @param config EGLConfig object
*/
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
try {
mPageFlip.onSurfaceCreated();
}
catch (PageFlipException e) {
Log.e(TAG, "Failed to run PageFlipFlipRender:onSurfaceCreated");
}
}
/**
* Create message handler to cope with messages from page render,
* Page render will send message in GL thread, but we want to handle those
* messages in main thread that why we need handler here
*/
private void newHandler() {
mHandler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case PageRender.MSG_ENDED_DRAWING_FRAME:
try {
mDrawLock.lock();
// notify page render to handle ended drawing
// message
if (mPageRender != null &&
mPageRender.onEndedDrawing(msg.arg1)) {
requestRender();
}
}
finally {
mDrawLock.unlock();
}
break;
default:
break;
}
}
};
}
}