public interface IUIManager { LogContext LCTX = LogManager.root().lctx("UIManager"); IUIManager instance = /* Check old versions */ AndroidVersion.lessThan3x /* UIManager1x */ ? new UIManager1x() /* Check Android 3.x versions */ : AndroidVersion.is3x /* UIManager3x */ ? new UIManager3x() /* Check Android 4.0.x versions */ : AndroidVersion.is40x /* UIManager40x */ ? new UIManager40x() /* UIManager41x */ : new UIManager41x(); void onPause(Activity activity); void onResume(Activity activity); void onDestroy(Activity activity); void setFullScreenMode(Activity activity, View view, boolean fullScreen); void setTitleVisible(Activity activity, boolean visible, boolean firstTime); boolean isTitleVisible(Activity activity); void openOptionsMenu(final Activity activity, final View view); void invalidateOptionsMenu(final Activity activity); void onMenuOpened(Activity activity); void onMenuClosed(Activity activity); boolean isTabletUi(final Activity activity); }
public class EBookDroidLibraryLoader { private static final LogContext LCTX = LogManager.root().lctx("LibraryLoader"); private static boolean alreadyLoaded = false; public static void load() { if (alreadyLoaded) { return; } try { System.loadLibrary("ebookdroid"); alreadyLoaded = true; } catch (Throwable th) { LCTX.e("Native library cannot be loaded: ", th); throw new RuntimeException(th); } } public static native void free(); }
public class TouchManagerView extends View { private static final LogContext LCTX = LogManager.root().lctx("TouchManagerView"); private static final float GRID_X = 10; private static final float GRID_Y = 10; private static final int[] COLORS = {Color.BLUE, Color.GRAY, Color.RED, Color.YELLOW}; private final IActivityController base; private final Paint bgPaint; private final Paint gridPaint; private final ActionController<TouchManagerView> actions; private final DefaultGestureDetector detector; private TouchProfile profile; private final Paint rPaint = new Paint(); public TouchManagerView(final IActivityController base) { super(base.getContext()); this.base = base; this.actions = new ActionController<TouchManagerView>(base, this); this.detector = new DefaultGestureDetector(getContext(), new GestureListener()); super.setVisibility(View.GONE); setFocusable(true); setFocusableInTouchMode(true); bgPaint = new Paint(); bgPaint.setColor(Color.BLACK); bgPaint.setStyle(Paint.Style.FILL); bgPaint.setAlpha(0x40); gridPaint = new Paint(); gridPaint.setColor(Color.GREEN); } @Override public void setVisibility(final int visibility) { if (visibility == View.VISIBLE) { profile = TouchManager.topProfile(); } else { profile = null; } super.setVisibility(visibility); } @Override protected void onDraw(final Canvas canvas) { super.onDraw(canvas); if (profile == null) { return; } final int width = getWidth(); final int height = getHeight(); canvas.drawRect(0, 0, width, height, bgPaint); final float xStep = width / GRID_X; final float yStep = height / GRID_Y; int cIndex = 0; ListIterator<Region> regions = profile.regions(false); while (regions.hasPrevious()) { final Region region = regions.previous(); final RectF r = region.getActualRect(width, height); rPaint.setColor(COLORS[cIndex]); rPaint.setAlpha(0x80); canvas.drawRect(r, rPaint); cIndex = (cIndex + 1) % COLORS.length; } drawGrid(canvas, xStep, yStep); cIndex = 0; regions = profile.regions(false); while (regions.hasPrevious()) { final Region region = regions.previous(); final RectF r = region.getActualRect(width, height); rPaint.setColor(COLORS[cIndex]); drawBounds(canvas, r, rPaint); cIndex = (cIndex + 1) % COLORS.length; } if (current != null) { rPaint.setColor(Color.WHITE); rPaint.setAlpha(0x80); final RectF r = current.getActualRect(width, height); canvas.drawRect(r, rPaint); rPaint.setColor(Color.WHITE); drawBounds(canvas, r, rPaint); } } protected void drawGrid(final Canvas canvas, final float xStep, final float yStep) { for (float x = xStep; x < getWidth(); x += xStep) { canvas.drawLine(x, 0, x, getHeight(), gridPaint); } for (float y = yStep; y < getHeight(); y += yStep) { canvas.drawLine(0, y, getWidth(), y, gridPaint); } } protected void drawBounds(final Canvas canvas, final RectF r, final Paint p) { canvas.drawLine(r.left, r.top, r.right - 1, r.top, p); canvas.drawLine(r.left, r.bottom - 1, r.right - 1, r.bottom - 1, p); canvas.drawLine(r.left, r.top, r.left, r.bottom - 1, p); canvas.drawLine(r.right - 1, r.top, r.right - 1, r.bottom - 1, p); } private PointF startPoint; private PointF endPoint; private Region current; protected void processRegion() { if (profile != null) { if (startPoint != null && endPoint != null) { current = getOrCreareRegion(startPoint, endPoint); } if (LCTX.isDebugEnabled()) { LCTX.d("processRegion(): " + current); } if (current != null) { final TouchConfigDialog dlg = new TouchConfigDialog(base, this, profile, current); dlg.show(); } } startPoint = null; endPoint = null; current = null; } protected Region getOrCreareRegion(final PointF startPoint, final PointF endPoint) { final Region selected = getRegion(startPoint, endPoint); for (final Region r : profile.regions) { if (r.getRect().equals(selected.getRect())) { return r; } } profile.addRegion(selected); return selected; } @Override public final boolean onTouchEvent(final MotionEvent ev) { try { Thread.sleep(16); } catch (final InterruptedException e) { Thread.interrupted(); } if (LCTX.isDebugEnabled()) { LCTX.d("onTouchEvent(): " + ev); } boolean res = detector.onTouchEvent(ev); int action = ev.getAction(); if (!res && (action == MotionEvent.ACTION_UP)) { if (startPoint != null) { endPoint = new PointF(ev.getX(), ev.getY()); current = getRegion(startPoint, endPoint); processRegion(); } invalidate(); return true; } return res; } protected Region getRegion(final PointF startPoint, final PointF endPoint) { final float width = getWidth(); final float height = getHeight(); final float xStep = width / GRID_X; final float yStep = height / GRID_Y; final float cellWidth = 100 / GRID_X; final float cellHeight = 100 / GRID_X; float left = MathUtils.fmin(startPoint.x, endPoint.x); float right = MathUtils.fmax(startPoint.x, endPoint.x); float top = MathUtils.fmin(startPoint.y, endPoint.y); float bottom = MathUtils.fmax(startPoint.y, endPoint.y); left = cellWidth * FloatMath.floor(left / xStep); right = cellWidth * FloatMath.floor(right / xStep) + cellWidth; top = cellHeight * FloatMath.floor(top / yStep); bottom = cellHeight * FloatMath.floor(bottom / yStep) + cellHeight; return new Region(MathUtils.rect(left, top, right, bottom)); } protected class GestureListener extends SimpleOnGestureListener { @Override public boolean onDoubleTap(final MotionEvent e) { actions.getOrCreateAction(R.id.actions_toggleTouchManagerView).run(); return true; } @Override public boolean onDown(final MotionEvent e) { startPoint = new PointF(e.getX(), e.getY()); endPoint = startPoint; current = getRegion(startPoint, endPoint); if (LCTX.isDebugEnabled()) { LCTX.d("onDown(): " + current); } return true; } @Override public boolean onSingleTapUp(MotionEvent e) { if (LCTX.isDebugEnabled()) { LCTX.d("onSingleTapUp(): " + current); } endPoint = null; return true; } @Override public boolean onScroll( final MotionEvent e1, final MotionEvent e2, final float distanceX, final float distanceY) { final float x = e2.getX(), y = e2.getY(); endPoint = new PointF(x, y); current = getRegion(startPoint, endPoint); if (LCTX.isDebugEnabled()) { LCTX.d("onScroll(): " + current); } invalidate(); return true; } @Override public boolean onSingleTapConfirmed(final MotionEvent e) { if (profile != null) { current = profile.getRegion(e.getX(), e.getY(), getWidth(), getHeight()); if (LCTX.isDebugEnabled()) { LCTX.d("onSingleTapConfirmed(): " + current); } processRegion(); } return true; } @Override public void onLongPress(final MotionEvent e) {} } }
public class FileSystemScanner { private static final LogContext LCTX = LogManager.root().lctx("FileSystemScanner", false); private static final int EVENT_MASK = CLOSE_WRITE | MOVED_TO | DELETE | MOVED_FROM; final EventDispatcher listeners; final AtomicBoolean inScan = new AtomicBoolean(); final Map<File, FileObserver> observers = new HashMap<File, FileObserver>(); private ScanTask m_scanTask; public FileSystemScanner(final Activity activity) { this.listeners = new EventDispatcher( activity, InvokationType.AsyncUI, Listener.class, ProgressListener.class); } public void shutdown() { stopScan(); stopObservers(); } public void startScan(final FileExtensionFilter filter, final String... paths) { if (inScan.compareAndSet(false, true)) { m_scanTask = new ScanTask(filter); m_scanTask.execute(paths); } else { m_scanTask.addPaths(paths); } } public void startScan(final FileExtensionFilter filter, final Collection<String> paths) { final String[] arr = paths.toArray(new String[paths.size()]); if (inScan.compareAndSet(false, true)) { m_scanTask = new ScanTask(filter); m_scanTask.execute(arr); } else { m_scanTask.addPaths(arr); } } public boolean isScan() { return inScan.get(); } public void stopScan() { if (inScan.compareAndSet(true, false)) { m_scanTask = null; } } public FileObserver getObserver(final File dir) { // final String path = dir.getAbsolutePath(); synchronized (observers) { // FileObserver fo = observers.get(path); FileObserver fo = observers.get(dir); if (fo == null) { fo = new FileObserverImpl(dir); observers.put(dir, fo); } return fo; } } public void removeObserver(final File dir) { synchronized (observers) { observers.remove(dir); } } public void stopObservers() { synchronized (observers) { for (final FileObserver o : observers.values()) { o.stopWatching(); } observers.clear(); } } public void addListener(final Object listener) { listeners.addListener(listener); } public void removeListener(final Object listener) { listeners.removeListener(listener); } class ScanTask extends AsyncTask<String, String, Void> { final FileExtensionFilter filter; final LinkedList<File> paths = new LinkedList<File>(); public ScanTask(final FileExtensionFilter filter) { this.filter = filter; } @Override protected void onPreExecute() { final ProgressListener pl = listeners.getListener(); pl.showProgress(true); } @Override protected Void doInBackground(final String... paths) { addPaths(paths); try { for (File dir = getDir(); dir != null && inScan.get(); dir = getDir()) { scanDir(dir); } } finally { inScan.set(false); } return null; } @Override protected void onPostExecute(final Void v) { final ProgressListener pl = listeners.getListener(); pl.showProgress(false); } void scanDir(final File dir) { // Checks if scan should be continued if (!inScan.get()) { return; } if (dir == null || !dir.isDirectory()) { return; } if (dir.getAbsolutePath().startsWith("/sys")) { LCTX.d("Skip system dir: " + dir); return; } try { final File cd = CacheManager.getCacheDir(); if (dir.getCanonicalPath().equals(cd.getCanonicalPath())) { LCTX.d("Skip file cache: " + dir); return; } } catch (final IOException ex) { ex.printStackTrace(); } if (LCTX.isDebugEnabled()) { LCTX.d("Scan dir: " + dir); } // Retrieves file observer for scanning folder final FileObserver observer = getObserver(dir); // Stop watching observer.stopWatching(); // Retrieves listener final Listener l = listeners.getListener(); // Retrieves file list final File[] files = dir.listFiles((FilenameFilter) filter); // Sort file list if (LengthUtils.isNotEmpty(files)) { Arrays.sort(files, StringUtils.NFC); } // Call the file scan callback l.onFileScan(dir, files); // Retrieves files from current directory final File[] childDirs = dir.listFiles(DirectoryFilter.ALL); // Immediately starts folder watching getObserver(dir).startWatching(); if (LengthUtils.isNotEmpty(childDirs)) { // Sort child dir list Arrays.sort(childDirs, StringUtils.NFC); // Add children for deep ordered scanning synchronized (this) { for (int i = childDirs.length - 1; i >= 0; i--) { this.paths.addFirst(childDirs[i]); } } } } synchronized void addPaths(final String... paths) { for (final String path : paths) { final File dir = new File(path); if (dir.exists() && dir.isDirectory()) { this.paths.add(dir); } } } synchronized File getDir() { return this.paths.isEmpty() ? null : this.paths.removeFirst(); } } public class FileObserverImpl extends FileObserver { private final File folder; public FileObserverImpl(final File folder) { super(folder.getAbsolutePath(), EVENT_MASK); this.folder = folder; } @Override public void onEvent(final int event, final String path) { if (folder == null || path == null) { return; } final File f = new File(folder, path); final boolean isDirectory = f.isDirectory(); final Listener l = listeners.getListener(); switch (event) { case CLOSE_WRITE: case MOVED_TO: if (isDirectory) { l.onDirAdded(folder, f); getObserver(f).startWatching(); } else { l.onFileAdded(folder, f); } break; case DELETE: case MOVED_FROM: if (isDirectory) { l.onDirDeleted(folder, f); removeObserver(f); } else { l.onFileDeleted(folder, f); } break; default: break; } } } public static interface Listener { void onFileScan(File parent, File[] files); void onFileAdded(File parent, File f); void onFileDeleted(File parent, File f); void onDirAdded(File parent, File f); void onDirDeleted(File parent, File f); } public static interface ProgressListener { public void showProgress(boolean show); } }
public class EventGotoPage implements IEvent { public static final LogContext LCTX = LogManager.root().lctx("EventGotoPage"); protected final boolean centerPage; protected AbstractViewController ctrl; protected final ViewState viewState; protected DocumentModel model; protected int viewIndex; protected final float offsetX; protected final float offsetY; public EventGotoPage(final AbstractViewController ctrl, final int viewIndex) { this.viewState = ViewState.get(ctrl); this.ctrl = ctrl; this.model = viewState.model; this.centerPage = true; this.viewIndex = viewIndex; this.offsetX = 0; this.offsetY = 0; } public EventGotoPage( final AbstractViewController ctrl, final int viewIndex, final float offsetX, final float offsetY) { this.viewState = ViewState.get(ctrl); this.ctrl = ctrl; this.model = viewState.model; this.centerPage = false; this.viewIndex = viewIndex; this.offsetX = offsetX; this.offsetY = offsetY; } @Override public ViewState process() { if (model == null) { return null; } final int pageCount = model.getPageCount(); if (viewIndex < 0 && viewIndex >= pageCount) { if (LCTX.isDebugEnabled()) { LCTX.d("Bad page index: " + viewIndex + ", page count: " + pageCount); } return viewState; } final Page page = model.getPageObject(viewIndex); if (page == null) { if (LCTX.isDebugEnabled()) { LCTX.d("No page found for index: " + viewIndex); } return viewState; } model.setCurrentPageIndex(page.index); final IView view = ctrl.getView(); final int scrollX = view.getScrollX(); final int scrollY = view.getScrollY(); final PointF p = calculateScroll(page, scrollX, scrollY); final int left = Math.round(p.x); final int top = Math.round(p.y); if (isScrollRequired(left, top, scrollX, scrollY)) { view.forceFinishScroll(); view.scrollTo(left, top); viewState.update(); return viewState; } viewState.release(); return EventPool.newEventScrollTo(ctrl, viewIndex).process(); } protected PointF calculateScroll(final Page page, final int scrollX, final int scrollY) { final RectF viewRect = ctrl.getView().getViewRect(); final RectF bounds = page.getBounds(viewState.zoom); final float width = bounds.width(); final float height = bounds.height(); if (centerPage) { switch (ctrl.mode) { case HORIZONTAL_SCROLL: return new PointF(bounds.left - (viewRect.width() - width) / 2, scrollY); case VERTICALL_SCROLL: return new PointF(scrollX, bounds.top - (viewRect.height() - height) / 2); } } return new PointF(bounds.left + offsetX * width, bounds.top + offsetY * height); } protected boolean isScrollRequired( final int left, final int top, final int scrollX, final int scrollY) { switch (ctrl.mode) { case HORIZONTAL_SCROLL: return left != scrollX; case VERTICALL_SCROLL: return top != scrollY; } return true; } @Override public boolean process(final Page page) { return false; } @Override public boolean process(final PageTree nodes) { return false; } @Override public boolean process(final PageTree nodes, final PageTreeLevel level) { return false; } @Override public boolean process(final PageTreeNode node) { return false; } }