package com.novelbook.android.utils; import android.app.ProgressDialog; import android.content.ContentValues; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.SyncAdapterType; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Region; import android.graphics.Typeface; import android.opengl.Visibility; import android.os.AsyncTask; import android.os.Handler; import android.os.Message; import android.text.Layout; import android.text.StaticLayout; import android.text.TextPaint; import android.text.TextUtils; import android.util.DisplayMetrics; import android.util.Log; import android.view.View; import android.view.WindowManager; import android.widget.Toast; import com.novelbook.android.MyApp; import com.novelbook.android.R; import com.novelbook.android.bean.AdSetting; import com.novelbook.android.bean.NovelSites; import com.novelbook.android.bean.Site; import com.novelbook.android.db.Chapter; import com.novelbook.android.db.Novel; import com.novelbook.android.netutils.NetUtil; import com.novelbook.android.view.PageWidget; import com.umeng.analytics.MobclickAgent; import org.litepal.LitePal; import org.litepal.util.Const; import java.io.File; import java.io.IOException; import java.text.DecimalFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Random; import java.util.concurrent.ConcurrentHashMap; import static com.novelbook.android.utils.Constants.AD_BANNER_TOP; //import static com.baidu.tts.loopj.AsyncHttpClient.log; public class PageFactory implements ChangeSource{ private static final String TAG = "PageFactory"; private static PageFactory pageFactory; private float mBannerNaviHeight; private float mBannerTopHeight; private Context mContext; private Config config; //当前的书本 // private File book_file = null; // 默认背景颜色 private int m_backColor = 0xffff9e85; //页面宽 private int mWidth; //页面高 private int mHeight; //文字字体大小 private float m_fontSize ; //时间格式 private SimpleDateFormat sdf; //时间 private String date; //进度格式 private DecimalFormat df ; //电池边界宽度 private float mBorderWidth; // 上下与边缘的距离 private float marginHeight ; //满屏 差异 private float screenHeihtDiff ; // 左右与边缘的距离 private float measureMarginWidth ; // 左右与边缘的距离 private float marginWidth ; //状态栏距离底部高度 private float statusMarginBottom; //行间距 private float lineSpace; //段间距 private float paragraphSpace; //段间距相对行间距的倍数 private final float prate = 1.8f; //字高度 private float fontHeight; //字体 private Typeface typeface; //文字画笔 private Paint mPaint; //加载画笔 private Paint waitPaint; //文字颜色 private int m_textColor = Color.rgb(50, 65, 78); // 绘制内容的宽 private float mVisibleHeight; // 绘制内容的宽 private float mVisibleWidth; // 每页可以显示的行数 private int mLineCount; //电池画笔 private Paint mBatterryPaint ; //电池字体大小 private float mBatterryFontSize; //背景图片 private Bitmap m_book_bg = null; //当前显示的文字 // private StringBuilder word = new StringBuilder(); //当前总共的行 // private Vector m_lines = new Vector<>(); // // 当前页起始位置 // private long m_mbBufBegin = 0; // // 当前页终点位置 // private long m_mbBufEnd = 0; // // 之前页起始位置 // private long m_preBegin = 0; // // 之前页终点位置 // private long m_preEnd = 0; // 图书总长度 // private long m_mbBufLen = 0; private Intent batteryInfoIntent; //电池电量百分比 private float mBatteryPercentage; //电池外边框 private RectF rect1 = new RectF(); //电池内边框 private RectF rect2 = new RectF(); //文件编码 // private String m_strCharsetName = "GBK"; //当前是否为第一页 private boolean m_isfirstPage; //当前是否为最后一页 private boolean m_islastPage; //书本widget private PageWidget mBookPageWidget; // //书本所有段 // List allParagraph; // //书本所有行 // List allLines = new ArrayList<>(); //现在的进度 private float currentProgress; //目录 // private List directoryList = new ArrayList<>(); //书本路径 private String bookPath = ""; //书本名字 private String bookName = ""; // private Novel mBook; //书的目录列表 private List mChapters; //当前章节 // private Chapter mCurrentChapter; //书本章节 private int currentChapter = 0; //当前电量 private int level = 0; private BookUtil mBookUtil; private PageEvent mPageEvent; private TRPage currentPage; private TRPage prePage; private TRPage cancelPage; ContentValues values = new ContentValues(); ConcurrentHashMap> chaptMap; private List currentChaptPages; private List nextChaptPages; private List preChaptPages; private AdInterface mAd; private BookTask bookTask; private final int MSG_CHANGECHAPTER =1; private final int MSG_NEXTPAGE=2; private final int MSG_HIDEPROGRESS=3; private final int MSG_NEXTPAGE_FAIL=4; private final int MSG_HID_AD=5; private final int MSG_SHOW_LOADING=5; private int mLoadingChaptNo; public AdInterface getmAd() { return mAd; } private static int mNavtiveBannerPlusCnt =0; private int mSmallBannerPlusCnt =0; private int mSmallBannerMinusCnt =0; //页面宽 private int mAdHeight; //页面高 private int mAdY; private enum AdTpye {BANNER,NATIVEINLINES,CHAPTEREND;}; private AdTpye mAdType = AdTpye.BANNER; public void setAd(AdInterface ad){ mAd =ad; } Handler handler = new Handler() { @Override public void handleMessage(Message msg) { // Log.d(TAG, "prepare book get handler msg:" +msg); handlerMsg(msg); // dismissProgressDialog(); } }; void handlerMsg(Message msg) { if (msg.what == 1) { Log.d(TAG, String.format("prepare book handler get notic to download chapter %s , getNovel() is null? %s", currentChapter, getNovel() == null)); if (getNovel() != null) { changeChapter(currentChapter); } else { /* mStatus = Status.FAIL; // unknow error null Attempt to invoke virtual method 'android.graphics.Bitmap com.novelbook.android.view.PageWidget.getCurPage()' on a null object reference drawStatus(); */ } } else if (msg.what == MSG_NEXTPAGE) { mStatus =Status.FINISH; // drawStatus(); Log.d(TAG, "prepare book to load next page"); nextPage(); } else if (msg.what == MSG_NEXTPAGE_FAIL) { mStatus =Status.FAIL; drawStatus(); } else if (msg.what == MSG_HIDEPROGRESS) { // dismissProgressDialog(); if(mAd!=null) { mAd.showRefresh(View.GONE); // mAd.hideProgressbar(); mAd.showLoading(false); // Log.d(TAG, "showloading: case MSG_HIDEPROGRESS: false" ); } }else if (msg.what == MSG_HID_AD) { // Log.d(TAG, "loadBannerAd: set banner gone 0, showingStatusAd " +showingStatusAd); if(showingStatusAd) { if (mAd != null) { mAd.hideStatusAds(); // Log.d(TAG, "loadBannerAd: set banner gone 1"); } } }else if (msg.what == MSG_SHOW_LOADING) { if(mAd!=null) { mAd.showLoading(true); Log.d(TAG, "showloading: case MSG_SHOW_LOADING: true" ); } } } Map fileRetryCnt = new HashMap(); private List loadCurrentChapt(int chaptId){ Log.d(TAG, String.format("prepare book, loadCurrentChapt chaptId %s, getChapters().size() %s ,currentChapter %s",chaptId,getChapters().size() ,currentChapter) ); if ( getChapters().size()>0) { //待下载 chaptId = chaptId > getChapters().size() ? getChapters().size() : chaptId; chaptId = chaptId > 0 ? chaptId : 1; } List chaptPages = new ArrayList(); chaptPages.add(new TRPage()); long starttime = new Date().getTime(); if(chaptMap==null) { chaptMap = new ConcurrentHashMap>(); } if(chaptMap.containsKey(chaptId)){ chaptPages =chaptMap.get(chaptId); mBookUtil.setChapterLen( chaptPages.get(chaptPages.size()-1).getEnd()); mBookUtil.setChapterNo(chaptId); Log.d(TAG, String.format("prepare book to load chapt %s, cost %s ",chaptId ,new Date().getTime() -starttime) ); return chaptMap.get(chaptId); } chaptId = chaptId > 0 ? chaptId : 1; File file = new File(getChapterFileName(chaptId)); if (!file.exists() && getChapters().size()>0) { //待下载 chaptId = chaptId > getChapters().size() ? getChapters().size() : chaptId; chaptId = chaptId > 0 ? chaptId : 1; file = new File(getChapterFileName(chaptId)); } if(!getNovel().isLocalBook()) { mStatus = Status.OPENING; final int maxSleep = Constants.MAX_SLEEP_4_CHAPT_DOWNLOAD+1000; // final File file = new File(getChapterFileName(chaptId)); Log.d(TAG, String.format("prepare book to open chapter %s ,file is exist ? %s",chaptId,file.exists() ) ); if (!file.exists()) { if (fileRetryCnt.containsKey(chaptId)) { fileRetryCnt.put(chaptId, fileRetryCnt.get(chaptId) + 1); loadingTxt+="."; } else { fileRetryCnt.clear();//只保留一个章节数据 fileRetryCnt.put(chaptId, 1); loadingTxt=""; mBookUtil.fileRetryCnt.clear(); } Log.d(TAG, String.format("prepare book loadCurrentChapt %s, rertying count %s ",chaptId, fileRetryCnt.get(chaptId))); if(fileRetryCnt.get(chaptId) > Constants.retryCnt){ mStatus = Status.FAIL; drawStatus(); return chaptPages; } drawStatus(); if( !NetUtil.isNetworkConnected()){ //TODO: 500错误处理 mStatus = Status.NETWORKFAILE; drawStatus(); return chaptPages; } if(getChapters().size()==0 && mBookUtil.muluRetryCount>=Constants.retryCnt) { Log.d(TAG, String.format("prepare book download mulu 失败,重试次数: %s ,thread.name %s",mBookUtil.muluRetryCount,Thread.currentThread().getName() ) ); mBookUtil.muluRetryCount=0; mStatus = Status.FAIL; drawStatus(); return chaptPages; } // showProgressDialog(); final int chid = chaptId; new Thread() { @Override public void run() { Log.d(TAG, String.format("prepare book to download chapter %s ,thread.name %s",chid,Thread.currentThread().getName() ) ); mBookUtil.chaptChars(chid); super.run(); }}.start(); new Thread() { @Override public void run() { int slepttime =0; File file = new File(getChapterFileName(chid)); while( slepttime =Constants.retryCnt){ mStatus = Status.FAIL; } Log.d(TAG, String.format("prepare book to download chapter %s ,handler notice changeChapter %s",chid, currentChapter ) ); //notice file done handler.sendEmptyMessage(MSG_CHANGECHAPTER); super.run(); }}.start(); drawStatus(); return chaptPages; } } chaptPages =readChaptCache(chaptId); if(chaptPages.size()>0) { chaptMap.put(chaptId, chaptPages); mBookUtil.setChapterLen(chaptPages.get(chaptPages.size() - 1).getEnd()); mBookUtil.setChapterNo(chaptId); Log.d(TAG, String.format("prepare book to load chapt %s, cost %s ",chaptId ,new Date().getTime() -starttime) ); mStatus = Status.FINISH; Log.d(TAG, String.format("changing Source prepare book to draw chapter %s, currentChapter %s ",chaptId ,currentChapter ) ); // drawStatus(); }else{ mStatus = Status.FAIL; if(getNovle().isLocalBook()){ mStatus=Status.LOCALFAIL; } drawStatus(); } return chaptPages; } void preReadChaptCache(final int chaptId){ if(!Constants.PRE_LOAD_CHAPT){ return; } if(chaptMap==null) { chaptMap = new ConcurrentHashMap>(); } if(chaptMap.containsKey(chaptId)){ return; } Log.d(TAG, String.format("prepare book to preLoad chapt %s, current chapt %s --->",chaptId ,currentChapter) ); new Thread() { @Override public void run() { super.run(); Log.d(TAG, String.format("prepare book to preRead chapter %s ,thread.name %s",chaptId,Thread.currentThread().getName() ) ); File file = new File(getChapterFileName(chaptId)); if(file.exists()) { chaptMap.put(chaptId, readChaptCache(chaptId)); Log.d(TAG, String.format("prepare book to preLoad %s done <-----",chaptId ) ); }else{ Log.d(TAG, String.format("prepare book to trying download the chapt %s again........... ",chaptId ) ); mBookUtil.retryDownLoadContent(chaptId) ; } }}.start(); } /** * only read chapt that cached already * @param chaptId * @return */ List readChaptCache(int chaptId){ List chaptPages = new ArrayList(); Log.d(TAG, String.format("prepare book to open chapter %s, currentChapter %s ",chaptId ,currentChapter ) ); char[] chars = mBookUtil.chaptChars(chaptId); mBookUtil.setTmpChaptLen(chars.length); // mBookUtil.setChapterNo(chaptId); // TRPage page = new TRPage(); long length =0; int pageNo =0; long starttime = new Date().getTime(); while(length =chars.length ){ if(page.getLines().size()< mLineCount/2) page.setBannerHeight(0); }*/ chaptPages.add(page); // Log.d(TAG, String.format("prepare book build page %s ready for chapter %s,cost %s",pageNo, chaptId,new Date().getTime()-starttime1)); } // Log.d(TAG, String.format(" prepare book build pages ready for chapter %s,cost %s", chaptId,new Date().getTime()-starttime)); return chaptPages; } public TRPage getNextChapterPage(int chaptId,long position,int pageNo) { mBookUtil.setPostition(chaptId, position); TRPage trPage = new TRPage(); // Constants.AD_CHAPT_NATIVE_BANNER_PER_PAGE_COUNT = 20; if (Constants.AD_SETTING.isShowAdsense() && pageNo > 1) { mNavtiveBannerPlusCnt++; // Constants.AD_CHAPT_TOP_BANNER_PER_PAGE_COUNT = 1; int bannerPagecnt = Constants.AD_SETTING.getChapterBanner().getPageCount4Display(); int nativeBannerPageCnt = Constants.AD_SETTING.getChapterContentBanner().getPageCount4Display(); if (Constants.AD_SETTING.getChapterContentBanner().isShow() && nativeBannerPageCnt > 0 && mNavtiveBannerPlusCnt >= nativeBannerPageCnt) { mNavtiveBannerPlusCnt = 0; calculateLineCount(); int adLines = (int) (mBannerNaviHeight / ((m_fontSize + lineSpace))); if(mLineCount - adLines - 1>0) { int adLine = new Random().nextInt(mLineCount - adLines - 1); adLine = adLine < mLineCount ? adLine : mLineCount - 2; if (adLine > 0) { trPage.setNativeBannerStartLine(adLine); //trPage.setNativeBannerHeight(Constants.AD_CHAPT_NATIVE_BANNER_HEIGHT); trPage.setNativeBannerHeight((int) mBannerNaviHeight); } Log.d(TAG, String.format("getNextChapterPage: pageNo %s, adLines %s,adLine %s, nativeBannerHeight %s", pageNo, adLines, adLine, trPage.getNativeBannerHeight())); } } if(trPage.getNativeBannerHeight()==0) if (Constants.AD_SETTING.getChapterBanner().isShow()) { if (bannerPagecnt <=0 || mSmallBannerPlusCnt < bannerPagecnt) { mSmallBannerPlusCnt++; trPage.setBannerHeight((int) mBannerTopHeight); } else { mSmallBannerMinusCnt--; if (mSmallBannerMinusCnt < 0) { mSmallBannerMinusCnt = bannerPagecnt; } if (mSmallBannerMinusCnt == 0) { mSmallBannerPlusCnt = 0; } } Log.d(TAG, String.format("getNextChapterPage: pageNo %s, topBannerHeight %s,bannerPagecnt %s,mSmallBannerPlusCnt %s,mSmallBannerMinusCnt %s ", pageNo, trPage.getBannerHeight() , bannerPagecnt ,mSmallBannerPlusCnt ,mSmallBannerMinusCnt )); } } trPage.setPageNo(pageNo); trPage.setBegin(position + 1); // Log.d(TAG,"page postion next begin:" + (position + 1) + ""); trPage.setLines(getNextLines(chaptId, trPage)); if (trPage.getNativeBannerStartLine() > 0 && trPage.getNativeBannerStartLine() >= trPage.getLines().size()) { trPage.setNativeBannerStartLine(trPage.getLines().size() - 1); } // Log.d(TAG,"page postion next end:" +mBookUtil.getPosition() + ""); trPage.setEnd(mBookUtil.getPosition(chaptId)); return trPage; } private static Status mStatus = Status.OPENING; public NovelSites getNovelSites() { return mBookUtil.getmNovelSites(); } /* private ProgressDialog progressDialog; private void showProgressDialog() { if ( null == progressDialog) { progressDialog =new ProgressDialog(mContext); progressDialog.setMessage("正在努力加载..."); } try { progressDialog.show(); }catch (Exception e) { Log.e(TAG, "prepare book: ", e); } // progressDialog.show(mContext,"网络不给力","正努力加载",false,true); } private void dismissProgressDialog() { if ( null != progressDialog) { // progressDialog.dismiss(); } }*/ public void changeSource(String domainName,String domain,int chapId,String chapTitle) { hideSysUI(); fileRetryCnt.clear(); if(TextUtils.isEmpty(getSite().getDomain()) || TextUtils.isEmpty(domain)|| getSite().getDomain().equals(domain)){ //当前源 Log.d(TAG, "prepare book changing Source: same site with original " + domain); return; } if(chaptMap!=null){ chaptMap.clear(); } Log.d(TAG, String.format("prepare book changing Source:target site received: name %s, site domain %s ,chapterId %s " ,domainName, domain,chapId)); mStatus= Status.CHANGESOURCE; statusChangeSource="正在换源..."; if(!TextUtils.isEmpty(domainName)) { statusChangeSource = "前往 " + domainName.substring(0,domainName.length()>5?5:domainName.length()) + "..."; } // drawChangeSourceStatus(); drawStatus(); mBookUtil.pagefactory=this; mBookUtil.changeSource(domain, chapId, chapTitle); } @Override public void drawStatus(Status status) { mStatus =status; drawStatus(); } /* public String getChapterName() { return getChapters().get(currentChapter-1).getChapterName(); }*/ public Chapter getChapter(){ return mBookUtil.getChapter(mBookUtil.getChapterNo()); } private static boolean isBusy =false; public void setBusy(boolean isBusy) { this.isBusy = isBusy; } public static boolean busy(){ return isBusy; } public static boolean canTouch(){ switch (mStatus){ case FAIL: return true; case FINISH:return true; case OPENING:return false; case SERVERERROR:return true; case CHANGESOURCE:return false; case NETWORKFAILE:return true; case LASTPAGE:return true; } return false; } public void refreshChapter() { fileRetryCnt.clear(); mBookUtil.fileRetryCnt.clear(); if( chaptMap.containsKey(getCurrentChapter())){ chaptMap.remove(getCurrentChapter()); } mBookUtil.refreshChapter(); } public void changeSourceForCate(String name, String domain) { if(getSite().getDomain().equals(domain)){ //当前源 Log.d(TAG, "prepare book changing Source: same site with original " + domain); return; } mBookUtil.changeSite(domain); } public enum Status { OPENING, FINISH, FAIL, NETWORKFAILE, SERVERERROR, CHANGESOURCE , LOCALFAIL, LASTPAGE, CONTENTPARESERROR; } private void hideSysUI(){ if(mAd!=null){ mAd.hideSystemUI(); // mAd.showRefresh(View.GONE); } } public static synchronized PageFactory getInstance(Context context){ if(pageFactory==null){ createPageFactory(context); } return pageFactory; } public static synchronized PageFactory createPageFactory(Context context){ if (pageFactory == null){ pageFactory = new PageFactory(context); } return pageFactory; } private PageFactory(Context context) { mBookUtil = new BookUtil(); mContext = context.getApplicationContext(); config = Config.getInstance(); //获取屏幕宽高 WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); DisplayMetrics metric = new DisplayMetrics(); wm.getDefaultDisplay().getMetrics(metric); mWidth = metric.widthPixels; // mHeight = metric.heightPixels; // mHeight = CommonUtil.getDpi(context); mHeight = CommonUtil.getScreenHeight(context) - CommonUtil.statusBarDiff(context); sdf = new SimpleDateFormat("HH:mm");//HH:mm为24小时制,hh:mm为12小时制 date = sdf.format(new java.util.Date()); df = new DecimalFormat("#0.0"); mBannerNaviHeight = mContext.getResources().getDimension(R.dimen.nativeBannerHeight) + 4 * Constants.ONE_DP_SIZE; mBannerTopHeight = mContext.getResources().getDimension(R.dimen.topBannerHeight) + 0 * Constants.ONE_DP_SIZE; marginWidth = mContext.getResources().getDimension(R.dimen.readingMarginWidth); marginHeight = mContext.getResources().getDimension(R.dimen.readingMarginHeight); // Log.d(TAG, "getNavigationBarSize: orignal marginHeight +" +marginHeight); // marginHeight = CommonUtil. getStatusBarHeight(mContext); statusMarginBottom = mContext.getResources().getDimension(R.dimen.reading_status_margin_bottom); screenHeihtDiff =CommonUtil.statusBarDiff(mContext); Log.d(TAG, "getNavigationBarSize: screenHeihtDiff " +screenHeihtDiff); lineSpace = context.getResources().getDimension(R.dimen.reading_line_spacing); paragraphSpace = context.getResources().getDimension(R.dimen.reading_paragraph_spacing); mVisibleWidth = mWidth - marginWidth * 2; mVisibleHeight = mHeight - marginHeight * 2 - CommonUtil.convertDpToPixel(mContext,10);; mHeight +=screenHeihtDiff; typeface = config.getTypeface(); m_fontSize = config.getFontSize(); lineSpace =config.getLineSpace(); paragraphSpace = prate * lineSpace ; mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);// 画笔 mPaint.setTextAlign(Paint.Align.LEFT);// 左对齐 mPaint.setTextSize(m_fontSize);// 字体大小 mPaint.setColor(m_textColor);// 字体颜色 mPaint.setTypeface(typeface); mPaint.setSubpixelText(true);// 设置该项为true,将有助于文本在LCD屏幕上的显示效果 waitPaint = new Paint(Paint.ANTI_ALIAS_FLAG);// 画笔 waitPaint.setTextAlign(Paint.Align.LEFT);// 左对齐 waitPaint.setTextSize(mContext.getResources().getDimension(R.dimen.reading_max_text_size));// 字体大小 waitPaint.setColor(m_textColor);// 字体颜色 waitPaint.setTypeface(typeface); waitPaint.setSubpixelText(true);// 设置该项为true,将有助于文本在LCD屏幕上的显示效果 calculateLineCount(); mBorderWidth = mContext.getResources().getDimension(R.dimen.reading_board_battery_border_width); mBatterryPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mBatterryFontSize = CommonUtil.sp2px(context, 12); mBatterryPaint.setTextSize(mBatterryFontSize); mBatterryPaint.setTypeface(typeface); mBatterryPaint.setTextAlign(Paint.Align.LEFT); mBatterryPaint.setColor(m_textColor); batteryInfoIntent = context.getApplicationContext().registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)) ;//注册广播,随时获取到电池电量信息 level = batteryInfoIntent.getIntExtra( "level" , 0 ); initBg(config.getDayOrNight()); measureMarginWidth(); } private void measureMarginWidth(){ float wordWidth =mPaint.measureText("\u3000"); float width = mVisibleWidth % wordWidth; measureMarginWidth = marginWidth + width / 2; // Rect rect = new Rect(); // mPaint.getTextBounds("好", 0, 1, rect); // float wordHeight = rect.height(); // float wordW = rect.width(); // Paint.FontMetrics fm = mPaint.getFontMetrics(); // float wrodH = (float) (Math.ceil(fm.top + fm.bottom + fm.leading)); // String a = ""; } //初始化背景 private void initBg(Boolean isNight){ if (isNight) { //设置背景 // setBgBitmap(BitmapUtil.decodeSampledBitmapFromResource( // mContext.getResources(), R.drawable.main_bg, mWidth, mHeight)); Bitmap bitmap = Bitmap.createBitmap(mWidth,mHeight, Bitmap.Config.RGB_565); Canvas canvas = new Canvas(bitmap); canvas.drawColor(Color.BLACK); setBgBitmap(bitmap); //设置字体颜色 setM_textColor(Color.rgb(128, 128, 128)); setBookPageBg(Color.BLACK); } else { //设置背景 setBookBg(config.getBookBgType()); } } private void calculateLineCount(){ mLineCount = (int) (mVisibleHeight / (m_fontSize + lineSpace));// 可显示的行数 } private void calculateLineCount(float paragrapheight){ mLineCount = (int) ((mVisibleHeight - paragrapheight ) / (m_fontSize + lineSpace));// 可显示的行数 // Log.d(TAG,"line count is " + mLineCount +" paragrapheight is " +paragrapheight); } private void drawStatus(){ if(mBookPageWidget!=null) { // drawStatus(mBookPageWidget.getCurPage()); drawStatus(mBookPageWidget.getNextPage()); } } public boolean isChangingSource(){ return mStatus == Status.CHANGESOURCE; } private String loadingTxt =""; private String statusChangeSource ="正在换源..."; private boolean showingStatusAd =false; private long showStatusAdTime =0; private void drawStatus(Bitmap bitmap){ hideSysUI(); mAd.showRefresh(View.VISIBLE); // mAd.hideProgressbar(); // mAd.showLoading(false); String status = ""; boolean showAd =false; switch (mStatus){ case OPENING: status = "正在拼命加载" + loadingTxt; mAd.showRefresh(View.GONE); // mAd.showProgressbar(false,status); mAd.showLoading(true); Log.d(TAG, "showloading: case OPENING: true" ); //handler.sendEmptyMessage(MSG_SHOW_LOADING); // showProgressDialog(); break; case CONTENTPARESERROR: status = "内容解析错误,请稍后再试"; mAd.showRefresh(View.VISIBLE); mAd.showReadSetting(); mAd.showLoading(false); break; case FAIL: status = "读取错误,请稍后重试"; mAd.showRefresh(View.VISIBLE); mAd.showReadSetting(); mAd.showLoading(false); /* try { throw new Exception("error on reading"); } catch (Exception e) { e.printStackTrace(); Log.d(TAG, "prepare book: why fail ",e); }*/ break; case NETWORKFAILE: mAd.showLoading(false); Log.d(TAG, "showloading: case NETWORKFAILE: false" ); showAd =false; status = "请开启网络"; break; case SERVERERROR: mAd.showLoading(false); Log.d(TAG, "showloading: case SERVERERROR: false" ); status = "服务器故障"; break; case FINISH: mAd.showLoading(false); Log.d(TAG, "showloading: case FINISH: false" ); status = "加载成功"; mAd.showRefresh(View.GONE); mAd.hideProgressbar(); showAd =false; break; case CHANGESOURCE: mAd.showLoading(true); Log.d(TAG, "showloading: case CHANGESOURCE: true" ); status = statusChangeSource; mAd.showRefresh(View.GONE); break; case LOCALFAIL: mAd.showLoading(false); Log.d(TAG, "showloading: case LOCALFAIL: false" ); status = "本地缓存加载错误"; mAd.showRefresh(View.GONE); break; case LASTPAGE: status = "看完了,没有了"; mAd.showRefresh(View.GONE); mAd.showLoading(false); Log.d(TAG, "showloading: case LASTPAGE: false" ); break; } Canvas c = new Canvas(bitmap); c.drawBitmap(getBgBitmap(), 0, 0, null); waitPaint.setTextSize(mContext.getResources().getDimension(R.dimen.reading_max_text_size));// 字体大小 waitPaint.setColor(getTextColor()); waitPaint.setTextAlign(Paint.Align.CENTER); Rect targetRect = new Rect(0, 0, mWidth, mHeight); // c.drawRect(targetRect, waitPaint); Paint.FontMetricsInt fontMetrics = waitPaint.getFontMetricsInt(); // 转载请注明出处:http://blog.csdn.net/hursing int baseline = (targetRect.bottom + targetRect.top - fontMetrics.bottom - fontMetrics.top) *4/5; // 下面这行是实现水平居中,drawText对应改为传入targetRect.centerX() waitPaint.setTextAlign(Paint.Align.CENTER); c.drawText(status, targetRect.centerX(), baseline, waitPaint); Log.d(TAG, "changing Source showloading: drawing status :" +status ); // c.drawText("正在打开书本...", mHeight / 2, 0, waitPaint); /* TextPaint tp = new TextPaint(); tp.setColor(getTextColor()); tp.setStyle(Paint.Style.FILL); tp.setTextSize(50); StaticLayout myStaticLayout = new StaticLayout(status, tp, c.getWidth(), Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false); myStaticLayout.draw(c);*/ // hideSysUI(); /* float adHeight = mHeight - baseline -marginHeight-statusMarginBottom-30; float adY =targetRect.top +10;*/ float adHeight = baseline -100; float adY =targetRect.top +250; if(showAd) while(!showingStatusAd /*|| new Date().getTime() - showStatusAdTime > 2000*/) { showingStatusAd =true; showStatusAdTime = new Date().getTime(); // showStatusAd((int) adHeight, (int) adY); // Log.d(TAG, "loadBannerAd: draw status, AD is requested, mStatus:" +mStatus); } Log.d(TAG, "drawStatus: mStatus is " +mStatus); if (mStatus==Status.OPENING ) { mLoadingChaptNo =mLoadingChaptNo >0?mLoadingChaptNo: getNovel().getLastReadChapt(); String url = mBookUtil.getChapter(mLoadingChaptNo).getChapterUrl(); Log.d(TAG, "drawStatus: url is " +url); if(!TextUtils.isEmpty(url)) { if(url.length()>100) url =url.substring(0,100); waitPaint.setTextSize(mContext.getResources().getDimension(R.dimen.reading_medu_text_size));// 字体大小 waitPaint.setColor(getTextColor()); waitPaint.setTextAlign(Paint.Align.CENTER); targetRect = new Rect(0, 0, mWidth, mHeight); fontMetrics = waitPaint.getFontMetricsInt(); baseline = baseline +150; // 下面这行是实现水平居中,drawText对应改为传入targetRect.centerX() String site = getSite().getName() ==null ? "":getSite().getName(); waitPaint.setTextAlign(Paint.Align.CENTER); c.drawText("正加载第三方网站 " +site, targetRect.centerX(), baseline, waitPaint); baseline+=40; if(Constants.SHOW_NOVEL_CHAPTER_URL) { c.drawText(url, targetRect.centerX(), baseline, waitPaint); } String chaptName= mBookUtil.getChapter(mLoadingChaptNo).getChapterName(); if(!TextUtils.isEmpty(chaptName)) { if(chaptName.length()>100) chaptName =chaptName.substring(0,100); chaptName ="正为您搜索加载 " +chaptName +" ..."; baseline = 80; // 下面这行是实现水平居中,drawText对应改为传入targetRect.centerX() waitPaint.setTextAlign(Paint.Align.CENTER); c.drawText(chaptName, targetRect.centerX(), baseline, waitPaint); } } } mBookPageWidget.postInvalidate(); } //上次翻书时间 private long lastPageTime; public void onDraw(Bitmap bitmap,TRPage trPage,Boolean updateChapter,Boolean showAd) { hideSysUI(); List m_lines = trPage.getLines(); // mAd.showRefresh(View.GONE); Log.d(TAG, String.format("onDraw: trPage pageno %s,showAd %s",trPage.getPageNo(),showAd)); // Log.d(TAG, "changing Source onDraw showloading: drawing status :" ); if(m_lines.size()==0 ){ return; } if(trPage.getChapterNo() >0 && trPage.getChapterNo() !=mBookUtil.getChapterNo()){ mBookUtil.setChapterNo(trPage.getChapterNo()); } /* try { throw new Exception("who's ad"); }catch (Exception e){ Log.e(TAG, "onDraw:changing Source ",e ); }*/ /* Log.d(TAG, "showloading: ondraw showAd: " +showAd ); try{ throw new Exception("showloading: ondraw mStatus: " +mStatus ); }catch (Exception e){ Log.e(TAG, "showloading: ", e); }*/ if(showAd && mAd!=null){ handler.sendEmptyMessage(MSG_HID_AD); //handler.sendEmptyMessage(MSG_HID_AD); handler.sendEmptyMessage(MSG_HIDEPROGRESS); mAdHeight=0; mAdY=0; } mStatus =Status.FINISH; // Log.d(TAG, String.format(" prepare book onDraw chapter %s, getChapters().size() %s ",currentChapter ,getChapters().size() ) ); if (getChapters().size() > 0 && updateChapter) { // Log.d(TAG, String.format(" prepare book onDraw chapter to getCurrentChapter(),currentChapter %s ",currentChapter ) ); currentChapter = getCurrentChapter(); // Log.d(TAG, String.format(" prepare book onDraw chapter after getCurrentChapter(),currentChapter %s ",currentChapter ) ); } // Log.d(TAG, String.format(" prepare book onDraw chapter _____________ %s ",currentChapter ) ); String chapterName =CommonUtil.subString(mBookUtil.getChapter(mBookUtil.getChapterNo()).getChapterName(),16); // CommonUtil.subString(getChapterName(),16); Log.d(TAG, String.format(" prepare book reading chapter %s ",chapterName ) ); //更新数据库进度 if ( mStatus ==Status.FINISH && currentPage != null && getNovel() != null) { new Thread() { @Override public void run() { super.run(); if (getNovel().getLastReadChapt() != currentChapter || getNovel().getLastReadPos() != currentPage.getBegin()) { if(!TextUtils.isEmpty(chapterName)) { getNovel().setLastReadChaptName(chapterName); } if (currentChapter > 1) { getNovel().setLastReadChapt(currentChapter); } else { getNovel().setToDefault("lastReadChapt"); } if(lastPageTime>0) { long time = new Date().getTime() - lastPageTime; // Log.d(TAG, String.format("prepare book read time last %s,current %s,spent %s",lastPageTime,new Date().getTime(), time)); if (time > 1000) { getNovel().setReadtime(getNovel().getReadtime() + time); } } getNovel().setToDefault("isUpdated"); //去除更新标志 getNovel().setLastReadPos(currentPage.getBegin()); getNovel().update(getNovel().getId()); //If you set a default value to a field, the corresponding // * column won't be updated. // getNovel().save(); /* Novel nv = LitePal.find(Novel.class,getNovel().getId()); Log.d(TAG,String.format("prepare book %s ,%s isUpdated %s,saved isUpdated %s, saved lastchapt %s,lastpos %s, db lastchapt %s last pos %s", getNovel().getId(), getNovel().getName(),getNovel().isUpdated(),nv.isUpdated(), currentChapter,currentPage.getBegin(),nv.getLastReadChapt(),nv.getLastReadPos()));*/ lastPageTime = new Date().getTime(); } /* values.put("lastReadPos",currentPage.getBegin()); values.put("lastReadChapt",currentChapter); Log.d(TAG,String.format("begin to update book %s chapter%s bigin %s ",getNovel().getName(),currentChapter, currentPage.getBegin() ) ); int rows = LitePal.update(Novel.class,values,getNovel().getId()); Log.d(TAG,String.format("update book %s chapter%s bigin %s, result %s",getNovel().getName(),currentChapter, currentPage.getBegin(),rows) ); */ } }.start(); } Canvas c = new Canvas(bitmap); c.drawBitmap(getBgBitmap(), 0, 0, null); // word.setLength(0); mPaint.setTextSize(getFontSize()); mPaint.setColor(getTextColor()); mBatterryPaint.setColor(getTextColor()); if (m_lines.size() == 0) { return; } float space =m_fontSize + lineSpace; paragraphSpace = prate * lineSpace; // if(showAd && mAd!=null){ mAdHeight= Constants.AD_SETTING.getChapterBanner().getDisplayPosition() ==AD_BANNER_TOP ? trPage.getBannerHeight() :0; mAdY=(int)marginHeight; mAdType =AdTpye.BANNER; if(trPage.getBannerHeight()==0) { mAd.showTopBanner(0,0);//hide banner container } // } /* if(trPage.getPageNo()>1 && m_lines.size() <= mLineCount/2+1){ if(trPage.getTopBannerHeight() + trPage.getNativeBannerHeight() ==0){ mAdHeight=(int)mBannerNaviHeight; mAdY=(int)marginHeight; mAdType =AdTpye.NATIVEINLINES; } }*/ float y = marginHeight +mAdHeight; String lastLine =""; int lineNo =0; for (String strLine : m_lines) { lineNo++; // if(strLine.endsWith("\n")) { // if(strLine.charAt(strLine.length()-1) == ('\n' )) { // Log.d(TAG, strLine); // Log.d(TAG,"最后字符 。。。" +strLine.charAt(strLine.length()-1) + ""); lastLine =strLine; // strLine = strLine.replace("�",""); if(lineNo==trPage.getNativeBannerStartLine()){ if(showAd && mAd!=null){ mAdHeight=trPage.getNativeBannerHeight(); mAdY=(int)y +(int)( +lineSpace*0.5); mAdType =AdTpye.NATIVEINLINES; // mAd.showNativeBannerInLines(trPage.getNativeBannerHeight(),(int)y); } y+=trPage.getNativeBannerHeight() +m_fontSize +lineSpace ; // Log.d(TAG, String.format("onDraw showNativeBannerInLines : lineno %s,strline %s ",lineNo,strLine)); space = m_fontSize + lineSpace; // y-=lineSpace; if (strLine.length() > 0 && (strLine.charAt(strLine.length() - 1) + "").equals("\n")) { space = m_fontSize + paragraphSpace; } }else { if (strLine.length() > 0 && (strLine.charAt(strLine.length() - 1) + "").equals("\n")) { strLine = strLine.replace("\n", ""); y += space; space = m_fontSize + paragraphSpace; // Log.d( TAG ,String.format("prepare book 开始新段落 %s, y plus is %s" ,strLine, m_fontSize + paragraphSpace)); } else { y += space; space = m_fontSize + lineSpace; // Log.d(TAG,String.format("prepare book %s,y plus is %s" ,strLine, m_fontSize + lineSpace)); } } c.drawText(strLine, measureMarginWidth, y, mPaint); // word.append(strLine); } // Log.d(TAG,String.format("getNavigationBarSize mHeight is %s ,last line height %s, power %s, %s", // // mHeight,y,mHeight - CommonUtil.convertDpToPixel(mContext,10) + mBorderWidth - statusMarginBottom, lastLine)); // lastLine =lastLine.trim().replace(Constants.BAD_CHAR,""); // Log.d(TAG, String.format("onDraw: last line lenth %s,%s, ",lastLine.length() ,lastLine)); float adHeight = mHeight -y - space -marginHeight-statusMarginBottom; float adY =y ;//+space; adY= lastLine.length()==0 ?adY-m_fontSize - lineSpace :adY; if(mAdHeight ==0 && showAd ) { if(trPage.getBannerHeight()>0){ mAdY=(int) (mHeight - statusMarginBottom - trPage.getBannerHeight()); mAdHeight = trPage.getBannerHeight(); mAdType =AdTpye.BANNER; }else if(trPage.getPageNo()>1 && trPage.isLastPage() && Constants.AD_SETTING.getChapterEndBanner().isShow()) { mAdY=(int)adY; mAdHeight = (int) adHeight; mAdType = AdTpye.CHAPTEREND; }else{ mAd.showNativeBannerInLines(0, 0);//清除内容广告 } // showAd((int) adHeight, (int) adY); // Log.d(TAG, String.format("loadBannerAd: AD is requested, adtype %s, adHeight %s, ady %s",mAdType,adHeight,adY)); } // Log.d(TAG,String.format("ad + statusMarginBottom %s ",200+ statusMarginBottom)); // Log.d(TAG,String.format("adHeight %s, adY %s",adHeight,adY)); if(trPage.getBannerHeight()==0 ){ mAd.showTopBanner(0, 0);//清除 banner广告 } if(trPage.getNativeBannerHeight()==0 && mAdType != AdTpye.CHAPTEREND){ mAd.showNativeBannerInLines(0,0);//hide content banner container } //画进度及时间 int dateWith = (int) (mBatterryPaint.measureText(date)+mBorderWidth);//时间宽度 // float fPercent = (float) (currentPage.getBegin() * 1.0 / mBookUtil.getChapterLen());//进度 float fPercent = (float) (currentPage.getPageNo() * 1.0 /currentChaptPages.size());//进度 currentProgress = fPercent; if (mPageEvent != null){ mPageEvent.changeProgress(fPercent); } // String strPercent = df.format(fPercent * 100) + "%";//进度文字 String strPercent = String.format("%s/%s",currentPage.getPageNo(),currentChaptPages.size()) + "页";//进度文字 int nPercentWidth = (int) mBatterryPaint.measureText("10/25页") + 50; //Paint.measureText直接返回參數字串所佔用的寬度 float botoomY =mHeight - statusMarginBottom;// +screenHeihtDiff; c.drawText(strPercent, mWidth - nPercentWidth, botoomY, mBatterryPaint);//x y为坐标值 c.drawText(date, marginWidth ,botoomY, mBatterryPaint); // 画电池 // Log.d(TAG, String.format("updateBattery to draw: level1 %s ",level)); // level = batteryInfoIntent.getIntExtra( "level" , 0 ); int scale = batteryInfoIntent.getIntExtra("scale", 100); mBatteryPercentage = (float) level / scale; // Log.d(TAG, String.format("updateBattery to draw: level2 %s ",level)); float rect1Left = marginWidth + dateWith + statusMarginBottom;//电池外框left位置 //画电池外框 float width = CommonUtil.convertDpToPixel(mContext,20) - mBorderWidth; float height = CommonUtil.convertDpToPixel(mContext,10); rect1.set(rect1Left, botoomY - height ,rect1Left + width, botoomY); rect2.set(rect1Left + mBorderWidth, botoomY - height + mBorderWidth , rect1Left + width - mBorderWidth, botoomY - mBorderWidth ); // c.save(Canvas.CLIP_SAVE_FLAG); c.save(); c.clipRect(rect2, Region.Op.DIFFERENCE); c.drawRect(rect1, mBatterryPaint); c.restore(); //画电量部分 rect2.left += mBorderWidth; rect2.right -= mBorderWidth; rect2.right = rect2.left + rect2.width() * mBatteryPercentage; rect2.top += mBorderWidth; rect2.bottom -= mBorderWidth; c.drawRect(rect2, mBatterryPaint); //画电池头 int poleHeight = (int) CommonUtil.convertDpToPixel(mContext,10) / 2; rect2.left = rect1.right; rect2.top = rect2.top + poleHeight / 4; rect2.right = rect1.right + mBorderWidth; rect2.bottom = rect2.bottom - poleHeight/4; c.drawRect(rect2, mBatterryPaint); //画书名 c.drawText(CommonUtil.subString(bookName,12), marginWidth ,statusMarginBottom + mBatterryFontSize, mBatterryPaint); //画章 /* String chapterName =""; if(mCurrentChapter!=null){ chapterName = mCurrentChapter.getChapterName(); }else*/ // if (getChapters().size() > 0) { int nChaterWidth = (int) mBatterryPaint.measureText(chapterName) + 1; c.drawText(chapterName, mWidth - marginWidth - nChaterWidth, statusMarginBottom + mBatterryFontSize, mBatterryPaint); } if(currentPage!=null && currentPage.getPageNo()==1){ String sn = getNovel().getDomainName(); if(TextUtils.isEmpty(sn)){ if(getSite()!=null &&getSite().getName() !=null ){ sn =getSite().getName(); } } String source =String.format("本章节内容来自网络"); if(!TextUtils.isEmpty(sn)){ source =String.format("本章节内容来自第三方网站:%s",sn); } int anny= (int) CommonUtil.convertDpToPixel(mContext,25); c.drawText(source, marginWidth, statusMarginBottom + mBatterryFontSize+anny, mBatterryPaint); anny= (int) CommonUtil.convertDpToPixel(mContext,45); c.drawText( Constants.announcement, marginWidth, statusMarginBottom + mBatterryFontSize+anny, mBatterryPaint); } if(mBookPageWidget!=null) { mBookPageWidget.postInvalidate(); /* if(mAd!=null) new Handler().postDelayed(new Runnable() { @Override public void run() { mBookPageWidget.setetCurPage(mAd.getBitmapWithAd()); mBookPageWidget.setPageMode(config.getPageMode()); } }, 1000);*/ } } public void showAd(){ // Log.d(TAG, String.format("loadBannerAd showAd: mAdType %s ",mAdType )); if(mStatus == Status.LASTPAGE || mAd==null ||currentPage==null || !Constants.AD_SETTING.isShowAdsense()){ return; } // Log.d(TAG, String.format("loadBannerAd showAd: mAdType %s, pageNo %s",mAdType, currentPage.getPageNo())); if(mAdType ==AdTpye.BANNER){ mAd.showTopBanner(mAdHeight,mAdY); }else if(mAdType == AdTpye.NATIVEINLINES){ // mAd.showNativeBannerInLines(0,0); mAd.showNativeBannerInLines(mAdHeight,mAdY); }else if(mAdType == AdTpye.CHAPTEREND){ // mAd.showNativeBannerInLines(0,0); mAd.showNativeBannerInLines(mAdHeight,mAdY); }else{ mAd.showNativeBannerInLines(0,0); } } private void showStatusAd(int adHeight,int adY) { boolean showAd = showingStatusAd /*|| getCurrentPage()==null || getCurrentPage().getPageNo() > 1*/; //Log.d(TAG, String.format("loadBannerAd showStatusAd: mAdType %s",mAdType)); // boolean showAd =true; if (showAd && mAd != null) { // mAd.showStatusAd(adHeight, adY); } } //向前翻页 public void prePage(){ if(null == currentPage){ return; } if(mBookUtil.isBusy()){ return; } m_isfirstPage = false; if (currentPage.getBegin() <= 1) { Log.d(TAG,"当前是本章第一页"); m_isfirstPage =currentChapter ==1; if ( m_isfirstPage){ Toast.makeText(mContext, "当前是第一页", Toast.LENGTH_SHORT).show(); return; } } // Log.d(TAG, "prepare book prePage: to open prepage: "); cancelPage = currentPage; if(mBookPageWidget==null){ return; } if(mStatus ==Status.LASTPAGE) { // onDraw(mBookPageWidget.getCurPage(),currentPage ,true,false); if(mBookPageWidget==null){ return; } // Log.d(TAG, " prePage() onDraw: mBookPageWidget.getNextPage() "); onDraw(mBookPageWidget.getNextPage(),currentPage ,true,true); }else{ if(mBookPageWidget==null){ return; } // Log.d(TAG, " prePage() onDraw: mBookPageWidget.getNextPage() "); currentPage = getPrePage(); onDraw(mBookPageWidget.getNextPage(),currentPage ,true,true); } } //向后翻页 public void nextPage(){ m_islastPage = false; if(null == currentPage){ changeChapter(mBookUtil.getChapterNo()); return; } if(mBookUtil.isBusy()){ return; } if(currentPage.getChapterNo()>0 && currentPage.getChapterNo() != currentChapter) { currentChapter = currentPage.getChapterNo(); Log.d(TAG, "getNextPage: prepare book correct current chapterno to " +currentChapter); } Log.d(TAG, "prepare book nextPage:chaptid " +mBookUtil.getChapterNo()); if (currentPage.getEnd() >= mBookUtil.getChapterLen()) { Log.d(TAG,"已经是本章最后一页了"); File file =new File( mBookUtil.fileChapterName(currentChapter+1)); if(!file.exists()) if(mBookUtil.getChapters().size()==0 &&NetUtil.isNetworkConnected()){ mBookUtil.setChapterNo(currentChapter+1); mStatus = Status.OPENING; drawStatus(); new Thread() { @Override public void run() { int slepttime = 0; mBookUtil.muluRetryCount=0; while (slepttime<300 && mBookUtil.getChapters().size()==0 && (mBookUtil.mMuluStatus == BookUtil.MuluStatus.isDownloading || mBookUtil.muluRetryCount < Constants.retryCnt)) { try { sleep(50); slepttime++; } catch (InterruptedException e) { e.printStackTrace(); } } Log.d(TAG, String.format("prepare book waiting for chapters slept %s, chapt size %s, MuluStatus %s, muluRetryCount %s ,mStatus %s" , slepttime *50,mBookUtil.getChapters().size(),mBookUtil.mMuluStatus,mBookUtil.muluRetryCount,mStatus)); if(mBookUtil.getChapters().size()>0){ if( mBookUtil.getChapterNo() == mBookUtil.getChapters().size()+1){ mBookUtil.setChapterNo(mBookUtil.getChapterNo()-1); } currentChapter=mBookUtil.getChapterNo(); handler.sendEmptyMessage(MSG_NEXTPAGE) ; }else if(mBookUtil.mMuluStatus == BookUtil.MuluStatus.failed || mStatus !=Status.OPENING){ mBookUtil.setChapterNo(mBookUtil.getChapterNo()-1); currentChapter=mBookUtil.getChapterNo(); handler.sendEmptyMessage(MSG_NEXTPAGE_FAIL) ; } mLoadingChaptNo=currentChapter; }}.start(); return; } mLoadingChaptNo =currentChapter+1; m_islastPage =currentChapter == mBookUtil.getChapters().size();// ||mBookUtil.getChapters().size()==0; if ( m_islastPage){ Toast.makeText(mContext, "已经是最后一页了", Toast.LENGTH_SHORT).show(); mStatus = Status.LASTPAGE; drawStatus(); // currentPage(false); return; } else if(mBookUtil.getChapters().size()==0){ return; } } // Log.d(TAG, "prepare book nextPage: to open next page: "); cancelPage = currentPage; if(mBookPageWidget==null){ return; } // Log.d(TAG, "nextPage() onDraw: mBookPageWidget.getCurPage() "); // onDraw(mBookPageWidget.getCurPage(),currentPage ,true,false); // Log.d(TAG, "nextpage:set current bitmap ..ondraw"); prePage = currentPage; currentPage = getNextPage(); mLoadingChaptNo=0; // currentPage = currentChaptPages.get(currentPage.getPageNo()-1); if(mBookPageWidget==null){ return; } // Log.d(TAG, "nextPage() onDraw: mBookPageWidget.getNextPage() "); onDraw(mBookPageWidget.getNextPage(),currentPage ,true,true); // Log.d("nextPage","nextPagenext"); HashMap map = new HashMap(); map.put("novel",bookName); map.put("chapt",getChapter().getChapterName()); map.put("page",currentPage.getPageNo()+""); MobclickAgent.onEvent(MyApp.applicationContext, "page_reading", map); } //取消翻页 public void cancelPage(){ if(cancelPage !=null && (cancelPage.isLastPage() || cancelPage.isFirstPage())){ mBookUtil.setChapterNo(cancelPage.getChapterNo()); currentChaptPages = loadCurrentChapt(cancelPage.getChapterNo()); currentPage = getPageForBegin(cancelPage.getBegin()) ;// currentChaptPages.get(0); // currentPage = getPageForBegin(begin); /* if (mBookPageWidget != null) { currentPage(true); }*/ } currentPage = cancelPage; if (mBookPageWidget != null) { currentPage(true); } } public void prepareBook(Novel book){ Log.d(TAG, "prepare book: start prepare book " + book.getName()); if(getNovel()!=null) { if (getNovel().getNovelId() != book.getNovelId()) { //取消未上本书完成的web请求,待验证效果 try { NetUtil.cancelRequest(getNovel().getNovelId()); } catch (Exception e) { // Log.e(TAG, "prepare book: error on canceling request " + e.getMessage()); e.printStackTrace(); } }else{ // Log.d(TAG, "prepare book: has been prepared, return.... " + book.getName()); if(mBookUtil!=null) { return; } } } if(mBookUtil!=null){ mBookUtil. clear(); mBookUtil=null; } mBookUtil = new BookUtil(); mBookUtil.pagefactory=this; //this.mBookUtil.setContext(context); this.mBookUtil.setNovel(book); this.mBookUtil.getTargetSites(); } public void initBookUtil() { mBookUtil = new BookUtil(); } /** * 打开书本 * @throws IOException */ public void openBook(Novel book ,Context context) throws IOException { if(book==null){ return; } if(book.isLocalBook()){ //离线书籍重新初始化加载mBookUtil mBookUtil = new BookUtil(); mBookUtil.setNovel(book); }else if(mBookUtil ==null || getNovle()==null){ Log.d(TAG, "prepare book: preparing in openBook method" + book.getName()); prepareBook(book); } mBookUtil.setContext(context); mContext =context; mBookUtil.pagefactory=this; //清空数据 currentChapter = 0; // m_mbBufLen = 0; initBg(config.getDayOrNight()); if(getNovel()!=null &&getNovel().getNovelId() !=book.getNovelId()){ //取消未上本书完成的web请求 NetUtil.cancelRequest(getNovel().getNovelId() ); } bookPath = book.getNovelPath(); bookName =book.getName();// FileUtils.getFileName(bookPath); // this.mCurrentChapter = chapter; mStatus = Status.OPENING; if (bookTask != null && bookTask.getStatus() != AsyncTask.Status.FINISHED){ bookTask.cancel(true); } bookTask = new BookTask(); Log.d(TAG, String.format("prepare book 1 to open chapter %s ,position %s,source %s",book.getLastReadChapt() ,book.getLastReadPos(),book.getDomain()+book.getDomainName() ) ); bookTask.execute((long)book.getLastReadChapt(),book .getLastReadPos()); drawStatus(); } private class BookTask extends AsyncTask{ private long chapter=0; private long begin = 0; @Override protected void onPostExecute(Boolean result) { super.onPostExecute(result); Log.d("onPostExecute",isCancelled() + ""); if (isCancelled()){ return; } if (result) { Log.d(TAG, String.format("prepare book ready, to open chapter %s ",chapter ) ); // m_mbBufLen = mBookUtil.getChapterLen(); currentChapter =(int)chapter; mBookUtil.setChapterNo((int)chapter); Log.d(TAG, String.format("prepare book ready, to open chapter, loadCurrentChapt %s ",chapter ) ); currentChaptPages = loadCurrentChapt((int)chapter); currentPage = getPageForBegin(begin) ;// currentChaptPages.get(0); // currentPage = getPageForBegin(begin); if (mBookPageWidget != null) { currentPage(true); showAd(); } // Log.d(TAG, String.format("prepare book set PageFactory.mStatus %s .",PageFactory.Status.FINISH ) ); // PageFactory.mStatus = PageFactory.Status.FINISH; }else{ PageFactory.mStatus = PageFactory.Status.FAIL; drawStatus(); Toast.makeText(mContext,"打开书本失败!",Toast.LENGTH_SHORT).show(); } } @Override protected void onPreExecute() { super.onPreExecute(); } @Override protected void onProgressUpdate(Void... values) { super.onProgressUpdate(values); } @Override protected Boolean doInBackground(Long... params) { chapter = params[0]; begin = params[1]; currentChapter = (int) chapter; try { int slept=0; while(getNovel() ==null){ // Log.d(TAG, "prepare book:waiting for bookutil book:" + getNovel()); Thread.sleep(10); slept++; if(slept>500){ return false; } } Log.d(TAG, "prepare book:waiting for bookutil book slept "+slept*10); mBookUtil.openBook(getNovel(),chapter); } catch (Exception e) { Log.e(TAG, "prepare book: backgroud error", e); e.printStackTrace(); return false; } return true; } } public TRPage getNextPage(){ int nextPageNo =currentPage.getPageNo(); Log.e(TAG,String.format("prepare book getNextPage() currentChapter %s, chapters().size() %s,currentChaptPages .size() is %s, currentpage pageno is %s ,currentpage chaptNo %s" ,currentChapter, getChapters().size(), currentChaptPages.size() , nextPageNo,currentPage.getChapterNo())); if(currentPage.getChapterNo()>0 && currentPage.getChapterNo() < currentChapter) { currentChapter = currentPage.getChapterNo(); Log.d(TAG, "getNextPage: prepare book correct current chapterno to " +currentChapter); } if(nextPageNo==0){ drawStatus(); } if(nextPageNo >= currentChaptPages.size() && (getChapters().size()==0 || getChapters().size()>currentChapter)){ preChaptPages =currentChaptPages; currentChapter++; mBookUtil.setChapterNo(currentChapter); currentChaptPages = loadCurrentChapt(currentChapter ) ; nextPageNo =0; }else { if(getChapters().size()>currentChapter) { preReadChaptCache(currentChapter + 1); } } if(currentChaptPages.size()>nextPageNo) return currentChaptPages.get(nextPageNo); else{ return new TRPage(""); } } public TRPage getPrePage(){ int prePageNo =currentPage.getPageNo()-1; Log.d(TAG,String.format("prepare book currentPageno %s,total pagno %s",currentPage.getPageNo(),currentChaptPages.size())); Log.e(TAG,String.format("prepare book getPrePage() currentChapter %s, chapters().size() %s,currentChaptPages .size() is %s,currentpage pageno is %s" ,currentChapter, getChapters().size(), currentChaptPages.size() , prePageNo)); if(prePageNo <=0){ nextChaptPages =currentChaptPages; currentChapter--; mLoadingChaptNo =currentChapter; if(currentChapter ==0) { return new TRPage("没有内容了"); } mBookUtil.setChapterNo(currentChapter); currentChaptPages = loadCurrentChapt(currentChapter ) ; prePageNo = currentChaptPages.size(); }else{ if(currentChapter-1>0) { preReadChaptCache(currentChapter - 1); } } mLoadingChaptNo =0; return currentChaptPages.get(prePageNo-1); } public TRPage getPageForBegin(long begin){ /* TRPage trPage = new TRPage(); trPage.setBegin(begin); mBookUtil.setPostition(begin - 1); trPage.setLines(getNextLines()); trPage.setEnd(mBookUtil.getPosition()); return trPage; */ if(currentChaptPages.size()==0){ return new TRPage(); } // Log.d(TAG, String.format("prepare book getPageForBegin: currentChaptPages count %s, chaptid %s, begin %s ",currentChaptPages.size(),currentChapter,begin)); for(TRPage page : currentChaptPages) { if(page.getEnd() >=begin){ return page; } } //return new TRPage();// currentChaptPages.get(currentChaptPages.size()-1); return currentChaptPages.get(currentChaptPages.size()-1); } boolean showChapTitleOnTopWhenNextPage =false; public List getNextLines(int chaptId,TRPage trpage){ List lines = new ArrayList<>(); float width = 0; float height = 0; String line = ""; // boolean isFirstPage =false; int firstPageLine =0; if(mBookUtil.getPosition(chaptId)==0) { lines.add("\n");//lines.add("\n"); } int adHeight = trpage.getNativeBannerHeight()+trpage.getBannerHeight(); calculateLineCount(adHeight ); // Log.d(TAG, String.format("getNextChapterPage getNextLines: pageNo %s, adHeight %s, totalLines %s",trpage.getPageNo(),adHeight,mLineCount)); boolean newParagraph =false; while (mBookUtil.next(true,chaptId) != -1){ char word = (char) mBookUtil.next(false,chaptId); // Log.d(TAG, String.format(" loadchapt getNextLines(), chaptId %s, word '%s'", chaptId,word )); if((word+"").equals(Constants.BAD_CHAR)){ // continue; } //判断是否换行 if ((word + "" ).equals("\n") ){// if ((word + "" ).equals("\r") && (((char) mBookUtil.next(true)) + "").equals("\n")){ // mBookUtil.next(false); newParagraph =true; if ( !line.isEmpty()){ if (showChapTitleOnTopWhenNextPage && lines.size() >0 && mBookUtil.isChapterTitle(line)) { // Log.d(TAG,String.format("title is %s\n,size is %s ,position is %s" ,line,line.length(),mBookUtil.getPosition(chaptId) )); //isFirstPage =true; firstPageLine=1; break; } // Log.d(TAG, String.format(" loadchapt getNextLines(),chaptId %s, new line with enter '%s' ", chaptId, line+word )); lines.add(line+word); // lines.add("\n"); line = ""; width = 0; height += paragraphSpace - lineSpace; calculateLineCount(adHeight+height); if (lines.size()>= mLineCount +firstPageLine){ // Log.d(TAG,String.format("lines count limit a %s,lines size %s",mLineCount,lines.size())); line =""; break; } } }else { float widthChar = mPaint.measureText(word + ""); if(widthChar==0){ continue; } if(newParagraph && line.length()==0) { newParagraph = false; if(!(word+"").equals(Constants.BAD_CHAR)){ line += Constants.BAD_CHAR + Constants.BAD_CHAR; widthChar += 2* mPaint.measureText( Constants.BAD_CHAR + ""); } } width += widthChar; // Log.d(TAG, String.format(" loadchapt getNextLines(),widthChar %s ,width %s,mVisibleWidth %s",widthChar, width ,mVisibleWidth )); if (width > mVisibleWidth) { width = widthChar; lines.add(line); // Log.d(TAG, String.format(" loadchapt getNextLines(),chaptId %s,new line '%s' ",chaptId , line )); /* if (lines.size() == mLineCount){ Log.d(TAG,String.format("lines count limit b %s,lines size %s",mLineCount,lines.size())); line =""; break; } */ line = word + ""; } else { line += word; // Log.d(TAG, String.format(" loadchapt getNextLines(),chaptId %s,growing line '%s' ",chaptId , line )); } } if (lines.size() == mLineCount +firstPageLine){ // Log.d(TAG,String.format("loadchapt lines count ,chaptId %s limit c %s,lines size %s",chaptId ,mLineCount,lines.size())); if (!line.isEmpty()){ // mBookUtil.setPostition(mBookUtil.getPosition() - line.length()-2);// mBookUtil.setPostition(mBookUtil.getPosition() - 1); mBookUtil.setPostition(chaptId,mBookUtil.getPosition(chaptId) - 1); } break; } } /* if (lines.size() == mLineCount) { Log.d(TAG, String.format("lines count limit d %s,lines size %s", mLineCount, lines.size())); Log.d(TAG, String.format("lines count limit d %s,line is \n %s", mLineCount, line)); if (!line.isEmpty()) { mBookUtil.setPostition(mBookUtil.getPosition() - line.length() - 2);// mBookUtil.setPostition(mBookUtil.getPosition() - 1); } }*/ if (!line.isEmpty() && lines.size() < mLineCount +firstPageLine){ if (!(showChapTitleOnTopWhenNextPage && mBookUtil.isChapterTitle(line) ) ) { lines.add(line); }else { // mBookUtil.setPostition(mBookUtil.getPosition() - line.length()-2); } // lines.add(line); } /*for (String str : lines){ Log.d(TAG,str + " "); }*/ return lines; } /*public List getPreLines(){ List lines = new ArrayList<>(); float width = 0; String line = ""; char[] par = mBookUtil.preLine(); while (par != null){ List preLines = new ArrayList<>(); for (int i = 0 ; i < par.length ; i++){ char word = par[i]; float widthChar = mPaint.measureText(word + ""); width += widthChar; if (width > mVisibleWidth) { width = widthChar; preLines.add(line); line = word + ""; } else { line += word; } // Log.d(TAG,"preLine is \n" + line); } *//* if ( mBookUtil.isChapterTitle(line)) { mBookUtil.setPostition(mBookUtil.getPosition() - line.length()-2); break; }*//* // lines.add(line); // Log.d(TAG,"preLine is \n" + line); if (!line.isEmpty()){ preLines.add(line); } lines.addAll(0,preLines); if (lines.size() >= mLineCount){ break; } width = 0; line = ""; par = mBookUtil.preLine(); } List reLines = new ArrayList<>(); int num = 0; for (int i = lines.size() -1;i >= 0;i --){ if (reLines.size() < mLineCount) { reLines.add(0,lines.get(i)); }else{ num = num + lines.get(i).length(); } Log.d(TAG,lines.get(i) + " "); } if (num > 0){ if ( mBookUtil.getPosition() > 0) { mBookUtil.setPostition(mBookUtil.getPosition() + num + 1);//mBookUtil.setPostition(mBookUtil.getPosition() + num + 2); // /r/n -> /n,只需要回退1个字符 }else{ mBookUtil.setPostition(mBookUtil.getPosition() + num ); } } return reLines; }*/ //上一章 public void preChapter(){ fileRetryCnt.clear(); mBookUtil.fileRetryCnt.clear(); if(currentChapter==1){ Toast.makeText(mContext,"到头了",Toast.LENGTH_SHORT).show(); } // if (mBookUtil.getChapters().size() > 0 ){ int num = currentChapter; if (num ==1){ num = getCurrentChapter(); } num --; if (num >= 1){ nextChaptPages =currentChaptPages; currentChapter = num; mBookUtil.setChapterNo(currentChapter); currentChaptPages = loadCurrentChapt(currentChapter ) ; currentPage = getPageForBegin(0); currentPage(true); } } //} //下一章 public void nextChapter(){ fileRetryCnt.clear(); mBookUtil.fileRetryCnt.clear(); int num = currentChapter; if (num == 0){ num = getCurrentChapter(); } if(num==getChapters().size()){ Toast.makeText(mContext,"没有了",Toast.LENGTH_SHORT).show(); } num ++; if (num <= getChapters().size() || mBookUtil.chaptCached(num)){ preChaptPages =currentChaptPages; currentChapter = num; mBookUtil.setChapterNo(currentChapter); currentChaptPages = loadCurrentChapt(currentChapter ) ; currentPage = getPageForBegin(0); currentPage(true); } } //获取现在的章 public int getCurrentChapter(){ /*int num = 0; for (int i = 0;getDirectoryList().size() > i;i++){ Chapter bookCatalogue = getDirectoryList().get(i); if (currentPage.getEnd() >= bookCatalogue.getBookChapterStartPos()){ num = i; }else{ break; } } return num; */ currentChapter = mBookUtil.getChapterNo(); Log.d(TAG, String.format(" prepare book onDraw chapter after mBookUtil.getChapterNo(),currentChapter %s ",currentChapter ) ); return currentChapter ; } //绘制当前页面 public void currentPage(Boolean updateChapter){ // Log.d(TAG, "prepare book currentPage: to open current Page : "); if(mBookPageWidget==null){ return; } // Log.d(TAG, "currentPage onDraw: mBookPageWidget.getCurPage() "); onDraw(mBookPageWidget.getCurPage(),currentPage ,updateChapter,false); // Log.d(TAG, "currentPage onDraw: mBookPageWidget.getNextPage() "); onDraw(mBookPageWidget.getNextPage(),currentPage ,updateChapter,true); } //更新电量 public void updateBattery(int mLevel){ hideSysUI(); if (currentPage != null && mBookPageWidget != null && !mBookPageWidget.isRunning()) { // Log.d(TAG, String.format("updateBattery: level old %s, new %s",level,mLevel)); if (level != mLevel) { level = mLevel; currentPage(false); } } } public void updateTime(){ hideSysUI(); if (currentPage != null && mBookPageWidget != null && !mBookPageWidget.isRunning()) { String mDate = sdf.format(new java.util.Date()); if (date != mDate) { date = mDate; currentPage(false); } } } //改变进度 public void changeProgress(float progress){ long begin = (long) (mBookUtil.getChapterLen() * progress); currentPage = getPageForBegin(begin); currentPage(true); } //改变章节 public void changeChapter(int chapNum){ if (getNovel() == null) { return; } long position =0; if(currentChapter == chapNum){ if( currentPage!=null){ position =currentPage.getBegin(); Log.d(TAG, "prepare book changeChapter: to position " + position); } } if(position==0){ if( !getNovle().isLocalBook() && getNovle().getDomain()!=null && getSite().getDomain()!=null && getNovle().getDomain().equals(getSite().getDomain()) && getNovle().getLastReadChapt() == chapNum ){ position =getNovel().getLastReadPos(); } } preChaptPages =currentChaptPages; currentChapter = chapNum; mBookUtil.setChapterNo(currentChapter); currentChaptPages = loadCurrentChapt(currentChapter ) ; currentPage = getPageForBegin(position); currentPage(true); hideSysUI(); if(position>0){ showAd(); } } public void retryChapt(int chapNum){ fileRetryCnt.clear(); mBookUtil.fileRetryCnt.clear(); mBookUtil.chaptDownStatus.clear(); changeChapter(chapNum); } public void openBookmark(int chapNum,long position){ //preChaptPages =currentChaptPages; currentChapter = chapNum; mBookUtil.setChapterNo(currentChapter); currentChaptPages = loadCurrentChapt(currentChapter ) ; currentPage = getPageForBegin(position); currentPage(true); } //改变行间距 public void changeLineHight(int lineSpace) { this.lineSpace = lineSpace; mPaint.setTextSize(m_fontSize); calculateLineCount(); measureMarginWidth(); chaptMap.clear(); currentChaptPages = loadCurrentChapt(currentChapter ); currentPage = getPageForBegin(currentPage.getBegin()); currentPage(true); showAd(); } //改变字体大小 public void changeFontSize(int fontSize){ this.m_fontSize = fontSize; mPaint.setTextSize(m_fontSize); calculateLineCount(); measureMarginWidth(); chaptMap.clear(); currentChaptPages = loadCurrentChapt(currentChapter ); currentPage = getPageForBegin(currentPage.getBegin()); currentPage(true); showAd(); } //改变字体 public void changeTypeface(Typeface typeface){ this.typeface = typeface; mPaint.setTypeface(typeface); mBatterryPaint.setTypeface(typeface); calculateLineCount(); measureMarginWidth(); chaptMap.clear(); currentPage = getPageForBegin(currentPage.getBegin()); currentPage(true); } //改变背景 public void changeBookBg(int type){ setBookBg(type); currentPage(false); } //设置页面的背景 public void setBookBg(int type){ Bitmap bitmap = Bitmap.createBitmap(mWidth,mHeight, Bitmap.Config.RGB_565); Canvas canvas = new Canvas(bitmap); int color = 0; switch (type){ case Config.BOOK_BG_DEFAULT: canvas = null; bitmap.recycle(); if (getBgBitmap() != null) { getBgBitmap().recycle(); } bitmap = BitmapUtil.decodeSampledBitmapFromResource( mContext.getResources(), R.drawable.paper, mWidth, mHeight); color = mContext.getResources().getColor(R.color.read_font_default); setBookPageBg(mContext.getResources().getColor(R.color.read_bg_default)); break; case Config.BOOK_BG_1: canvas.drawColor(mContext.getResources().getColor(R.color.read_bg_1)); color = mContext.getResources().getColor(R.color.read_font_1); setBookPageBg(mContext.getResources().getColor(R.color.read_bg_1)); break; case Config.BOOK_BG_2: canvas.drawColor(mContext.getResources().getColor(R.color.read_bg_2)); color = mContext.getResources().getColor(R.color.read_font_2); setBookPageBg(mContext.getResources().getColor(R.color.read_bg_2)); break; case Config.BOOK_BG_3: canvas.drawColor(mContext.getResources().getColor(R.color.read_bg_3)); color = mContext.getResources().getColor(R.color.read_font_3); if (mBookPageWidget != null) { mBookPageWidget.setBgColor(mContext.getResources().getColor(R.color.read_bg_3)); } break; case Config.BOOK_BG_4: canvas.drawColor(mContext.getResources().getColor(R.color.read_bg_4)); color = mContext.getResources().getColor(R.color.read_font_4); setBookPageBg(mContext.getResources().getColor(R.color.read_bg_4)); break; } setBgBitmap(bitmap); //设置字体颜色 setM_textColor(color); } public void setBookPageBg(int color){ if (mBookPageWidget != null) { mBookPageWidget.setBgColor(color); } } //设置日间或者夜间模式 public void setDayOrNight(Boolean isNgiht){ initBg(isNgiht); currentPage(false); } public void clear(){ // Log.d(TAG, String .format("prepare Book: clearing book info %s" , getNovle().getName())); // if(mBookUtil!=null) { // mBookUtil.clear(); // mBookUtil=null; // } /* try{ throw new Exception("factory cleared"); }catch (Exception e){ Log.e(TAG, "prepare book: clear() called", e); }*/ fileRetryCnt.clear(); lastPageTime=0; if(chaptMap!=null){ chaptMap.clear(); } currentChapter = 0; bookPath = ""; bookName = ""; //getNovel() = null; // mBookPageWidget = null; mPageEvent = null; cancelPage = null; prePage = null; currentPage = null; // mAd=null; currentChaptPages =null; preChaptPages=null; nextChaptPages=null; mNavtiveBannerPlusCnt=0; mSmallBannerMinusCnt =0; mSmallBannerPlusCnt=0; } public static Status getStatus(){ return mStatus; } //是否是第一页 public boolean isfirstPage() { return m_isfirstPage; } //询问是否可以退出阅读 public boolean canExitSilent(){ return m_islastPage || mStatus==Status.FAIL ||mStatus==Status.NETWORKFAILE || mStatus==Status.SERVERERROR; } //是否是最后一页 public boolean islastPage() { return m_islastPage; } //是否可以翻页 public boolean isReady() { return mStatus==Status.FINISH; } //设置页面背景 public void setBgBitmap(Bitmap BG) { m_book_bg = BG; } //设置页面背景 public Bitmap getBgBitmap() { return m_book_bg; } //设置文字颜色 public void setM_textColor(int m_textColor) { this.m_textColor = m_textColor; } //获取文字颜色 public int getTextColor() { return this.m_textColor; } //获取文字大小 public float getFontSize() { return this.m_fontSize; } public void setPageWidget(PageWidget mBookPageWidget){ this.mBookPageWidget = mBookPageWidget; } public PageWidget getPageWidget( ){ return mBookPageWidget; } public void setPageEvent(PageEvent pageEvent){ this.mPageEvent = pageEvent; } public interface PageEvent{ void changeProgress(float progress); } public void refreshCate(){ mBookUtil.getChapters().clear(); mBookUtil.getSiteRule(true); } public long getChapterLen(){ return mBookUtil.getChapterLen(); } public TRPage getCurrentPage(){ return currentPage; } //获取书本的章 public List getChapters(){ return mBookUtil.getChapters(); } public boolean isReadingCatalogs(){ return mBookUtil.isReadingCatalogs(); } public String getBookPath(){ return bookPath; } public String getBookName(){ return getNovel().getName(); } public Novel getNovle(){ return getNovel(); } private Novel getNovel(){ if(mBookUtil!=null){ return mBookUtil.getNovel(); } return new Novel(); } public Site getSite(){ if(mBookUtil!=null){ return mBookUtil.getSite(); } else{ return new Site(); } } public boolean isWorking(){ return mBookUtil !=null; } public String getChapterFileName(int chapid) { return mBookUtil.fileChapterName(chapid); } }