diff options
Diffstat (limited to 'android/experimental/DocumentLoader/src/org/libreoffice/android/examples/DocumentLoader.java')
-rw-r--r-- | android/experimental/DocumentLoader/src/org/libreoffice/android/examples/DocumentLoader.java | 1140 |
1 files changed, 0 insertions, 1140 deletions
diff --git a/android/experimental/DocumentLoader/src/org/libreoffice/android/examples/DocumentLoader.java b/android/experimental/DocumentLoader/src/org/libreoffice/android/examples/DocumentLoader.java deleted file mode 100644 index a7a2214e792f..000000000000 --- a/android/experimental/DocumentLoader/src/org/libreoffice/android/examples/DocumentLoader.java +++ /dev/null @@ -1,1140 +0,0 @@ -// -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- -// -// This file is part of the LibreOffice project. -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/. - -// This is just a testbed for ideas and implementations. (Still, it might turn -// out to be somewhat useful as such while waiting for "real" apps.) - -// Important points: - -// Everything that might take a long time should be done asynchronously: -// - loading the document (loadComponentFromURL()) -// - counting number of pages (getRendererCount()) -// - rendering a page (render()) - -// Unclear whether pages can be rendered in parallel. Probably best to -// serialize all the above in the same worker thread. We use -// AsyncTask.SERIAL_EXECUTOR below. - -// While a page is loading ideally should display some animated spinner (but -// for now just a static "please wait" text). - -// === - -// How should we handle re-rendering at higher resolution when zooming in, and -// then panning around? - -// Hopefully when LO is asked to render just a part of a page (i.e. the -// MapMode of the device rendered to causes significant parts of the page to -// be outside the device) the code is clever enough to quickly skip stuff that -// will be clipped. But I don't hold my breath. - -// How could we do it? - -// 1/ Re-render just the zoomed-in area. Probably not a good idea, as probably -// the user will almost immediately also pan a bit or zoom out a bit, which -// would cause a re-render. - -// 2/ Some kind of tiled approach. Initially just one tile for the whole -// page. When zooming in, at some point (2x?) split the currently visible -// tiles into four sub-tiles, each initially displaying the same resolution as -// the parent tile. Start asynchronous rendering of visible sub-tiles at -// double resolution. Keep the "parent" rendered bitmap but don't keep bitmaps -// that go out of view. (Except perhaps for some caching.) When zooming out, -// at some point (0.5x?) merge four sub-tiles back into one. Hmm. Is this the -// right approach? - -// In any case, also this rendering at higher resolution should be done -// asynchronously, of course. If the user zooms in and pans around, the -// existing bitmap will be shown scaled (and ugly) until required rendering -// has finished and then the affected tiles are replaced with -// higher-resolution ones. - -package org.libreoffice.android.examples; - -import android.app.Activity; -import android.app.AlertDialog; -import android.content.DialogInterface; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.ColorFilter; -import android.graphics.Matrix; -import android.graphics.PixelFormat; -import android.graphics.Paint; -import android.graphics.Point; -import android.graphics.Rect; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.ColorDrawable; -import android.graphics.drawable.Drawable; -import android.os.AsyncTask; -import android.os.Bundle; -import android.util.Log; -import android.view.GestureDetector; -import android.view.Gravity; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.MotionEvent; -import android.view.ViewGroup; -import android.view.animation.Animation; -import android.view.animation.AnimationSet; -import android.view.animation.TranslateAnimation; -import android.widget.ImageView; -import android.widget.NumberPicker; -import android.widget.TextView; -import android.widget.ViewFlipper; -import android.widget.ViewSwitcher; - -import junit.framework.Assert; - -import com.polites.android.GestureImageView; - -import com.sun.star.awt.Size; -import com.sun.star.awt.XBitmap; -import com.sun.star.awt.XControl; -import com.sun.star.awt.XDevice; -import com.sun.star.awt.XToolkitExperimental; -import com.sun.star.beans.PropertyValue; -import com.sun.star.frame.XComponentLoader; -import com.sun.star.frame.XController; -import com.sun.star.frame.XFrame; -import com.sun.star.frame.XModel; -import com.sun.star.lang.XEventListener; -import com.sun.star.lang.XMultiComponentFactory; -import com.sun.star.lang.XTypeProvider; -import com.sun.star.uno.Type; -import com.sun.star.uno.UnoRuntime; -import com.sun.star.uno.XComponentContext; -import com.sun.star.view.XRenderable; - -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.util.ArrayList; - -import org.libreoffice.android.Bootstrap; - -public class DocumentLoader - extends Activity -{ - private static final String TAG = "DocumentLoader"; - - // Size of a small virtual (bitmap) device used to find out page count and - // page sizes - private static final int SMALLSIZE = 128; - - // We pre-render this many pages preceding and succeeding the currently - // viewed one, i.e. the total number of rendered pages kept is - // PAGECACHE_PLUSMINUS*2+1. - private static final int PAGECACHE_PLUSMINUS = 2; - private static final int PAGECACHE_SIZE = PAGECACHE_PLUSMINUS*2 + 1; - - BootstrapContext bootstrapContext; - DocumentContext documentContext; - - GestureDetector.OnGestureListener gestureListener; - GestureDetector gestureDetector; - - ViewGroup.LayoutParams matchParent; - - ViewFlipper flipper; - - Bundle extras; - - PageViewer getPageViewerAt(int index) - { - return (PageViewer)flipper.getChildAt(index); - } - - PageViewer getCurrentPageViewer() - { - return (PageViewer)flipper.getCurrentView(); - } - - class GestureListener - extends GestureDetector.SimpleOnGestureListener - { - @Override - public boolean onFling(MotionEvent event1, - MotionEvent event2, - float velocityX, - float velocityY) - { - Log.i(TAG, "onFling: " + event1 + " " + event2); - if (event1.getX() - event2.getX() > 120) { - if (getCurrentPageViewer().currentPageNumber == documentContext.pageCount-1) - return false; - - Animation inFromRight = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 1, Animation.RELATIVE_TO_SELF, 0, - Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 0); - int duration = Math.abs((int)((float)flipper.getWidth()/velocityX*1000f)); - inFromRight.setDuration(duration); - flipper.setInAnimation(inFromRight); - - Animation outToLeft = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, -1, - Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 0); - outToLeft.setDuration(duration); - flipper.setOutAnimation(outToLeft); - - flipper.showNext(); - - // The entry after the next, both child index and next is 0..PAGECACHE_SIZE. - int next = (flipper.getDisplayedChild() + PAGECACHE_PLUSMINUS) % PAGECACHE_SIZE; - getPageViewerAt(next).display(getCurrentPageViewer().currentPageNumber + PAGECACHE_PLUSMINUS); - return true; - } else if (event2.getX() - event1.getX() > 120) { - if (getCurrentPageViewer().currentPageNumber == 0) - return false; - - Animation inFromLeft = new TranslateAnimation(Animation.RELATIVE_TO_SELF, -1, Animation.RELATIVE_TO_SELF, 0, - Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 0); - int duration = Math.abs((int)((float)flipper.getWidth()/velocityX*1000f)); - inFromLeft.setDuration(duration); - flipper.setInAnimation(inFromLeft); - - Animation outToRight = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 1, - Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 0); - outToRight.setDuration(duration); - flipper.setOutAnimation(outToRight); - - flipper.showPrevious(); - - // The entry before the previous, both child index and previous is 0..PAGECACHE_SIZE. - int previous = (flipper.getDisplayedChild() + PAGECACHE_SIZE - PAGECACHE_PLUSMINUS) % PAGECACHE_SIZE; - getPageViewerAt(previous).display(getCurrentPageViewer().currentPageNumber - PAGECACHE_PLUSMINUS); - - return true; - } - return false; - } - } - - class MyXController - implements XController - { - - XFrame frame; - XModel model; - - public void attachFrame(XFrame frame) - { - Log.i(TAG, "attachFrame"); - this.frame = frame; - } - - public boolean attachModel(XModel model) - { - Log.i(TAG, "attachModel"); - this.model = model; - return true; - } - - public boolean suspend(boolean doSuspend) - { - Log.i(TAG, "suspend"); - return false; - } - - public Object getViewData() - { - Log.i(TAG, "getViewData"); - return null; - } - - public void restoreViewData(Object data) - { - Log.i(TAG, "restoreViewData"); - } - - public XModel getModel() - { - Log.i(TAG, "getModel"); - return model; - } - - public XFrame getFrame() - { - Log.i(TAG, "getFrame"); - return frame; - } - - public void dispose() - { - Log.i(TAG, "dispose"); - } - - public void addEventListener(XEventListener listener) - { - Log.i(TAG, "addEventListener"); - } - - public void removeEventListener(XEventListener listener) - { - Log.i(TAG, "removeEventListener"); - } - } - - static int zoomLevel(float scale) - { - if (scale <= 1) - return 0; - - int result = 1; - int power = 2; - - while (scale > power) { - result++; - power *= 2; - } - return result; - } - - static int scaleOfZoom(int zoom) - { - int result = 1; - - while (zoom > 0) { - result *= 2; - zoom--; - } - - return result; - } - - static int setColorAlpha(int color, - double alpha) - { - return Color.argb((int)(alpha*255), Color.red(color), Color.green(color), Color.blue(color)); - } - - // Each (Gesture)ImageView is showing an object of this subclass of - // BitmapDrawable, the root of a quadtree of higher-resolution partial - // page bitmaps. Obviously these should be rendered asynchronously on - // demand but that code is not here yet. And anyway, rendering partial - // pages won't work until I have figured out why offsetting VirtualDevice - // has no effect. - class QuadTree - extends BitmapDrawable - { - final int pageNumber; - final int level; - final int location; - final int w, h; - - static final int NW = 0; - static final int NE = 1; - static final int SE = 2; - static final int SW = 3; - - QuadTree sub[] = new QuadTree[4]; - - QuadTree(Bitmap bm, - int level, - int pageNumber, - int location) - { - super(bm); - - w = getIntrinsicWidth(); - h = getIntrinsicHeight(); - - this.pageNumber = pageNumber; - this.level = level; - this.location = location; - - // I spent several days wondering why nothing showed up for the - // sub-tiles, desperately tweaking stuff left and right, until I - // found out I need to call setBounds()... (For the level 0 - // drawable the GestureImageView handles calling setBounds(), but - // it doesn't hurt to do it here for all levels.) - setBounds(0, 0, w, h); - - // Just for testing until properly doing this asynchronously and - // with insert() - if (level == 0) { - // Don't do it anyway for now - - // 1) offsetting of VirtualDevice doesn't seem to work so this - // would work for the NW sub-tile only anyway. - - // 2) LO renders Windows-style "Y grows upwards" bitmaps, thus - // the imageView.setScaleY(-1) below in - // PageLoadTask.onPostExecute(), but that means that the - // scaling and translation stuff here in QuadTree needs to be - // twiddled for Y coordinates. (Just try: comment out the - // createSub(NW) call below. If you also comment out the - // setScaleY() call, the sub-tile will show up in the correct - // location, otherwise not. Or something like that. It's hard - // to try to write up sevral nights of desperate hacking back - // and forth... which in the end turned out to be just chasing - // the wrong ducks. If that is how the metaphor goes?) - - // So probably should write a native method to reflect the - // rendered byte buffer in the Y direction, and call that - // after rendering, instead? Or maybe the tweaks needed aren't - // that large anyway, and I just am mixing up my memory of the - // trouble caused by that with the trouble caused by not - // calling setBounds()... - - //createSub(NW); - //createSub(NE); - //createSub(SE); - //createSub(SW); - } - } - - QuadTree(QuadTree rhs, - Bitmap bm) - { - this(bm, rhs.level, rhs.pageNumber, rhs.location); - - sub = rhs.sub; - } - - QuadTree(Bitmap bm, - int pageNumber) - { - this(bm, 0, pageNumber, 0); - } - - QuadTree(int level, - int pageNumber, - int location) - { - this.level = level; - this.pageNumber = pageNumber; - this.location = location; - w = -1; - h = -1; - } - - void createSub(int q) - { - if (true) { - ByteBuffer bb = renderPage(pageNumber, level+1, (location<<2)+q); - Bitmap subbm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); - subbm.copyPixelsFromBuffer(bb); - sub[q] = new QuadTree(subbm, level+1, pageNumber, (location<<2)+q); - } else { - // Test... just use transparent single colour subtiles - Bitmap subbm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); - int color = 0; - switch (q) { - case NW: color = Color.RED; break; - case NE: color = Color.GREEN; break; - case SE: color = Color.BLUE; break; - case SW: color = Color.YELLOW; break; - } - subbm.eraseColor(setColorAlpha(color, 0.5)); - sub[q] = new QuadTree(subbm, 1, pageNumber, (location<<2)+q); - } - } - - int quadrantOf(int x, - int y) - { - if (x < 0 || y < 0 || x >= w || y >= h) - return -1; - - if (x < w/2 && y < h/2) - return NW; - if (x >= w/2 && y < h/2) - return NE; - if (x >= w/2 && y >= h/2) - return SE; - if (x < w/2 && y >= h/2) - return SW; - - return -1; - } - - int quadrantOf(Point p) - { - return quadrantOf(p.x, p.y); - } - - Point subCoord(Point p) - { - return subCoord(quadrantOf(p), p); - } - - Point subCoord(int q, - Point p) - { - switch (q) { - case NW: - return new Point(p.x*2, p.y*2); - case NE: - return new Point((p.x-w/2)*2, p.y*2); - case SE: - return new Point((p.x-w/2)*2, (p.y-h/2)*2); - case SW: - return new Point(p.x*2, (p.y-h/2)*2); - } - return null; - } - - // The insert() stuff has not been tested and is just a draft - void insert(Bitmap bm, - int level, - int x, - int y) - { - insert(bm, level, 1, new Point(x, y)); - } - - void insert(Bitmap bm, - int level, - int recursionDepth, - Point p) - { - int q = quadrantOf(p); - - if (q == -1) - return; - - if (recursionDepth == level) { - if (sub[q] == null) - sub[q] = new QuadTree(bm, level); - else - sub[q] = new QuadTree(sub[q], bm); - } else { - if (sub[q] == null) - sub[q] = new QuadTree(this.level+1, pageNumber, location); - sub[q].insert(bm, level, recursionDepth+1, subCoord(q, p)); - } - } - - // Ditto for find() - - QuadTree find(int levelCountdown, - int x, - int y) - { - return find(levelCountdown, new Point(x, y)); - } - - QuadTree find(int levelCountdown, - Point p) - { - final int x = p.x, y = p.y; - - Log.i(TAG, "find(" + levelCountdown + ", (" + p.x + ", " + p.y + "))"); - - if (x < 0 || y < 0 || x >= w || y >= h) - return null; - - if (levelCountdown == 0) { - Log.i(TAG, "Returning this at level " + this.level); - return this; - } - - int q = quadrantOf(p); - - if (sub[q] != null) - return sub[q].find(levelCountdown-1, subCoord(q, p)); - - return null; - } - - void subDraw(Canvas canvas, - int q) - { - if (q == -1 || sub[q] == null) - return; - - Log.i(TAG, "subDraw 1: q=" + q + ", matrix=" + canvas.getMatrix() + ", clip=" + canvas.getClipBounds()); - - canvas.save(); - canvas.scale(0.5f, 0.5f); - - float[] values = new float[9]; - canvas.getMatrix().getValues(values); - - Log.i(TAG, "subDraw 2: q=" + q + ", matrix=" + canvas.getMatrix() + ", clip=" + canvas.getClipBounds() + ", translate(" + - (((q == NW || q == SW) ? -w : w) /* * values[Matrix.MSCALE_X]*/) + "," + - (((q == NW || q == NE) ? -h : h) /* * values[Matrix.MSCALE_X]*/) + ")"); - - canvas.translate(((q == NW || q == SW) ? -w : 0) /* * values[Matrix.MSCALE_X]*/, - ((q == NW || q == NE) ? -h : 0) /* * values[Matrix.MSCALE_X]*/); - - Log.i(TAG, "subDraw 3: q=" + q + ", matrix=" + canvas.getMatrix() + ", clip=" + canvas.getClipBounds()); - - sub[q].draw(canvas); - - canvas.restore(); - } - - @Override - public void draw(Canvas canvas) - { - float[] values = new float[9]; - canvas.getMatrix().getValues(values); - - float scale = values[Matrix.MSCALE_X]; - int zoom = zoomLevel(scale); - - Log.i(TAG, "draw: level=" + level + ", scale=" + scale + ", zoom=" + zoom + ", matrix=" + canvas.getMatrix()); - Rect bounds = new Rect(); - if (canvas.getClipBounds(bounds)) - Log.i(TAG, " clip=" + bounds + ", bounds=" + getBounds()); - else - Log.i(TAG, " no clip"); - - int l = (int)(w/2 - values[Matrix.MTRANS_X]/scale); - int t = (int)(h/2 - values[Matrix.MTRANS_Y]/scale); - Log.i(TAG, "Unzoomed rect: " + l + ", " + t + ", " + (int)(l+w/scale) + ", " + (int)(t+h/scale)); - - Log.i(TAG, "Scales: " + values[Matrix.MSCALE_X] + ", " + values[Matrix.MSCALE_Y]); - - // Assert.assertTrue(values[Matrix.MSCALE_X] == values[Matrix.MSCALE_Y]); - - super.draw(canvas); - - if (/*zoom > 0 */ scale >= 1) { - subDraw(canvas, quadrantOf(l, t)); - subDraw(canvas, quadrantOf((int)(l+w/scale)-1, t)); - subDraw(canvas, quadrantOf((int)(l+w/scale)-1, (int)(t+h/scale)-1)); - subDraw(canvas, quadrantOf(l, (int)(t+h/scale)-1)); - } - } - } - - ByteBuffer renderPage(int number) - { - return renderPage(number, 0, 0); - } - - ByteBuffer renderPage(final int number, - final int level, - final int location) - { - Log.i(TAG, "renderPage(" + number + ", " + level + ", " + location + ")"); - try { - // Use dummySmallDevice with no scale or offset just to find out - // the paper size of this page. - - PropertyValue renderProps[] = new PropertyValue[3]; - renderProps[0] = new PropertyValue(); - renderProps[0].Name = "IsPrinter"; - renderProps[0].Value = Boolean.TRUE; - renderProps[1] = new PropertyValue(); - renderProps[1].Name = "RenderDevice"; - renderProps[1].Value = bootstrapContext.dummySmallDevice; - renderProps[2] = new PropertyValue(); - renderProps[2].Name = "View"; - renderProps[2].Value = new MyXController(); - - // getRenderer returns a set of properties that include the PageSize - long t0 = System.currentTimeMillis(); - PropertyValue rendererProps[] = documentContext.renderable.getRenderer(number, documentContext.doc, renderProps); - long t1 = System.currentTimeMillis(); - Log.i(TAG, "getRenderer took " + ((t1-t0)-bootstrapContext.timingOverhead) + " ms"); - - int pageWidth = 0, pageHeight = 0; - for (int i = 0; i < rendererProps.length; i++) { - if (rendererProps[i].Name.equals("PageSize")) { - pageWidth = ((Size) rendererProps[i].Value).Width; - pageHeight = ((Size) rendererProps[i].Value).Height; - Log.i(TAG, "PageSize: " + pageWidth + "x" + pageHeight); - } - } - - // Create a new device with the correct scale and offset - ByteBuffer bb = ByteBuffer.allocateDirect(flipper.getWidth()*flipper.getHeight()*4); - long wrapped_bb = Bootstrap.new_byte_buffer_wrapper(bb); - - XDevice device; - if (pageWidth == 0) { - // Huh? - device = bootstrapContext.toolkit.createScreenCompatibleDeviceUsingBuffer(flipper.getWidth(), flipper.getHeight(), 1, 1, 0, 0, wrapped_bb); - } else { - - // Scale so that it fits our device which has a resolution of - // 96/inch (see SvpSalGraphics::GetResolution()). The page - // size returned from getRenderer() is in 1/mm * 100. 2540 is - // one inch in mm/100. - - int scaleNumerator, scaleDenominator; - - // If the view has a wider aspect ratio than the page, fit - // height; otherwise, fit width - if ((double) flipper.getWidth() / flipper.getHeight() > (double) pageWidth / pageHeight) { - scaleNumerator = flipper.getHeight(); - scaleDenominator = pageHeight / 2540 * 96; - } else { - scaleNumerator = flipper.getWidth(); - scaleDenominator = pageWidth / 2540 * 96; - } - scaleNumerator *= scaleOfZoom(level); - - int xOffset = 0, yOffset = 0; - int hiX = pageWidth, hiY = pageHeight; - int lvl = level; - int loc = location; - while (lvl > 0) { - int q = (loc & 0x03); - - if (q == QuadTree.NE || q == QuadTree.SE) { - xOffset += (hiX - xOffset)/2; - } else { - hiX -= (hiX - xOffset)/2; - } - if (q == QuadTree.SW || q == QuadTree.SE) { - yOffset += (hiY - yOffset)/2; - } else { - hiY -= (hiY - yOffset)/2; - } - lvl--; - loc >>= 2; - } - - // Seems that the offsets passed in (which get passed to - // MapMode::SetOrigin() in - // VirtualDevice::SetOutputSizePixelScaleOffsetAndBuffer() - // are ignored... try a random value, no effect ;( - xOffset = 12345; xOffset = 789; - - Log.i(TAG, "Rendering page " + number + " level=" + level + " scale=" + scaleNumerator + "/" + scaleDenominator + ", offset=(" + xOffset + ", " + yOffset + ")"); - - device = bootstrapContext.toolkit.createScreenCompatibleDeviceUsingBuffer(flipper.getWidth(), flipper.getHeight(), - scaleNumerator, scaleDenominator, - -xOffset, -yOffset, - wrapped_bb); - } - - // Update the property that points to the device - renderProps[1].Value = device; - - t0 = System.currentTimeMillis(); - documentContext.renderable.render(number, documentContext.doc, renderProps); - t1 = System.currentTimeMillis(); - Log.i(TAG, "Rendering page " + number + " took " + ((t1-t0)-bootstrapContext.timingOverhead) + " ms"); - - Bootstrap.force_full_alpha_bb(bb, 0, flipper.getWidth() * flipper.getHeight() * 4); - - return bb; - } - catch (Exception e) { - e.printStackTrace(System.err); - finish(); - } - - return null; - } - - enum PageState { NONEXISTENT, LOADING, READY }; - - class PageViewer - extends ViewSwitcher - { - int currentPageNumber = -1; - TextView waitView; - PageState state = PageState.NONEXISTENT; - Bitmap bm; - - class PageLoadTask - extends AsyncTask<Integer, Void, Integer> - { - protected Integer doInBackground(Integer... params) - { - int number = params[0]; - - Log.i(TAG, "doInBackground(" + number + ")"); - - if (number >= documentContext.pageCount) - return -1; - - state = PageState.LOADING; - currentPageNumber = number; - ByteBuffer bb = renderPage(currentPageNumber); - bm = Bitmap.createBitmap(flipper.getWidth(), flipper.getHeight(), Bitmap.Config.ARGB_8888); - bm.copyPixelsFromBuffer(bb); - - return currentPageNumber; - } - - protected void onPostExecute(Integer result) - { - Log.i(TAG, "onPostExecute: " + result); - if (result == -1) - return; - - GestureImageView imageView = new GestureImageView(DocumentLoader.this, gestureListener); - imageView.setImageDrawable(new QuadTree(bm, result)); - - imageView.setScaleY(-1); - - if (getChildCount() == 2) - removeViewAt(1); - addView(imageView, 1, matchParent); - showNext(); - state = PageState.READY; - } - } - - void display(int number) - { - Log.i(TAG, "PageViewer display(" + number + ")"); - if (number >= 0) - waitView.setText("Page " + (number+1) + ", wait..."); - state = PageState.NONEXISTENT; - - if (getDisplayedChild() == 1) { - showPrevious(); - removeViewAt(1); - } - - if (number >= 0) { - new PageLoadTask().executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, number); - } - } - - PageViewer(int number) - { - super(DocumentLoader.this); - - waitView = new TextView(DocumentLoader.this); - waitView.setTextSize(24); - waitView.setGravity(Gravity.CENTER); - waitView.setBackgroundColor(Color.WHITE); - waitView.setTextColor(Color.BLACK); - addView(waitView, 0, matchParent); - - display(number); - } - } - - class DocumentLoadTask - extends AsyncTask<String, Void, Void> - { - protected Void doInBackground(String... params) - { - try { - String url = params[0]; - Log.i(TAG, "Attempting to load " + url); - - PropertyValue loadProps[] = new PropertyValue[3]; - loadProps[0] = new PropertyValue(); - loadProps[0].Name = "Hidden"; - loadProps[0].Value = Boolean.TRUE; - loadProps[1] = new PropertyValue(); - loadProps[1].Name = "ReadOnly"; - loadProps[1].Value = Boolean.TRUE; - loadProps[2] = new PropertyValue(); - loadProps[2].Name = "Preview"; - loadProps[2].Value = Boolean.TRUE; - - long t0 = System.currentTimeMillis(); - documentContext.doc = bootstrapContext.componentLoader.loadComponentFromURL(url, "_blank", 0, loadProps); - long t1 = System.currentTimeMillis(); - Log.i(TAG, "Loading took " + ((t1-t0)-bootstrapContext.timingOverhead) + " ms"); - - documentContext.renderable = (XRenderable) UnoRuntime.queryInterface(XRenderable.class, documentContext.doc); - - PropertyValue renderProps[] = new PropertyValue[3]; - renderProps[0] = new PropertyValue(); - renderProps[0].Name = "IsPrinter"; - renderProps[0].Value = Boolean.TRUE; - renderProps[1] = new PropertyValue(); - renderProps[1].Name = "RenderDevice"; - renderProps[1].Value = bootstrapContext.dummySmallDevice; - renderProps[2] = new PropertyValue(); - renderProps[2].Name = "View"; - renderProps[2].Value = new MyXController(); - - t0 = System.currentTimeMillis(); - documentContext.pageCount = documentContext.renderable.getRendererCount(documentContext.doc, renderProps); - t1 = System.currentTimeMillis(); - Log.i(TAG, "getRendererCount: " + documentContext.pageCount + ", took " + ((t1-t0)-bootstrapContext.timingOverhead) + " ms"); - } - catch (Exception e) { - e.printStackTrace(System.err); - finish(); - } - return null; - } - } - - /** - * This class contains the state that is initialized once and never changes - * (not specific to a document or a view). - */ - class BootstrapContext - { - public long timingOverhead; - public XComponentContext componentContext; - public XMultiComponentFactory mcf; - public XComponentLoader componentLoader; - public XToolkitExperimental toolkit; - public XDevice dummySmallDevice; - } - - /** - * This class contains the state that is specific to a document, but - * independent from a view. - */ - class DocumentContext - { - public Object doc; - public int pageCount; - public XRenderable renderable; - public String input; - // This is not updated constantly, just in onRetainNonConfigurationInstance() - public int currentPageNumber; - } - - static void dumpUNOObject(String objectName, Object object) - { - Log.i(TAG, objectName + " is " + (object != null ? object.toString() : "null")); - - if (object == null) - return; - - XTypeProvider typeProvider = (XTypeProvider) - UnoRuntime.queryInterface(XTypeProvider.class, object); - if (typeProvider == null) - return; - - Type[] types = typeProvider.getTypes(); - if (types == null) - return; - - for (Type t : types) - Log.i(TAG, " " + t.getTypeName()); - } - - static void dumpBytes(String name, byte[] bytes, int offset) - { - if (bytes == null) { - Log.i(TAG, name + " is null"); - return; - } - Log.i(TAG, name + ":"); - - if (offset != 0) - Log.i(TAG, " (offset " + offset + ")"); - - for (int i = offset; i < Math.min(bytes.length, offset+160); i += 16) { - String s = ""; - for (int j = i; j < Math.min(bytes.length, i+16); j++) - s = s + String.format(" %02x", bytes[j]); - - Log.i(TAG, s); - } - } - - static void dumpBytes(String name, ByteBuffer bytes, int offset) - { - if (bytes == null) { - Log.i(TAG, name + " is null"); - return; - } - Log.i(TAG, name + ":"); - - if (offset != 0) - Log.i(TAG, " (offset " + offset + ")"); - - for (int i = offset; i < Math.min(bytes.limit(), offset+160); i += 16) { - String s = ""; - for (int j = i; j < Math.min(bytes.limit(), i+16); j++) - s = s + String.format(" %02x", bytes.get(j)); - - Log.i(TAG, s); - } - } - - @Override - public Object onRetainNonConfigurationInstance() { - ArrayList ret = new ArrayList(2); - ret.add(bootstrapContext); - documentContext.currentPageNumber = getCurrentPageViewer().currentPageNumber; - ret.add(documentContext); - return ret; - } - - private void initBootstrapContext() - { - try - { - bootstrapContext = new BootstrapContext(); - - long t0 = System.currentTimeMillis(); - long t1 = System.currentTimeMillis(); - bootstrapContext.timingOverhead = t1 - t0; - - Bootstrap.setup(this); - - // Avoid all the old style OSL_TRACE calls especially in vcl - Bootstrap.putenv("SAL_LOG=+WARN+INFO"); - - // Log.i(TAG, "Sleeping NOW"); - // Thread.sleep(20000); - - bootstrapContext.componentContext = com.sun.star.comp.helper.Bootstrap.defaultBootstrap_InitialComponentContext(); - - Log.i(TAG, "context is" + (bootstrapContext.componentContext!=null ? " not" : "") + " null"); - - bootstrapContext.mcf = bootstrapContext.componentContext.getServiceManager(); - - Log.i(TAG, "mcf is" + (bootstrapContext.mcf!=null ? " not" : "") + " null"); - - Bootstrap.initVCL(); - - Object desktop = bootstrapContext.mcf.createInstanceWithContext - ("com.sun.star.frame.Desktop", bootstrapContext.componentContext); - - Log.i(TAG, "desktop is" + (desktop!=null ? " not" : "") + " null"); - - bootstrapContext.componentLoader = (XComponentLoader) UnoRuntime.queryInterface(XComponentLoader.class, desktop); - - Log.i(TAG, "componentLoader is" + (bootstrapContext.componentLoader!=null ? " not" : "") + " null"); - - Object toolkitService = bootstrapContext.mcf.createInstanceWithContext - ("com.sun.star.awt.Toolkit", bootstrapContext.componentContext); - bootstrapContext.toolkit = (XToolkitExperimental) UnoRuntime.queryInterface(XToolkitExperimental.class, toolkitService); - - // Set up dummySmallDevice and use it to find out the number - // of pages ("renderers"). - ByteBuffer smallbb = ByteBuffer.allocateDirect(SMALLSIZE*SMALLSIZE*4); - long wrapped_smallbb = Bootstrap.new_byte_buffer_wrapper(smallbb); - bootstrapContext.dummySmallDevice = bootstrapContext.toolkit.createScreenCompatibleDeviceUsingBuffer(SMALLSIZE, SMALLSIZE, 1, 1, 0, 0, wrapped_smallbb); - - } - catch (Exception e) - { - e.printStackTrace(System.err); - finish(); - } - } - - private void initDocumentContext(String input) - { - documentContext = new DocumentContext(); - documentContext.input = input; - // Load the wanted document - new DocumentLoadTask().executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, "file://" + input); - } - - private void goToPage(int number) - { - // Remove old views. - flipper.removeAllViews(); - - // Add new ones. - flipper.addView(new PageViewer(number), 0, matchParent); - for (int i = 0; i < PAGECACHE_PLUSMINUS; i++) - flipper.addView(new PageViewer(number + i + 1), i + 1, matchParent); - for (int i = 0; i < PAGECACHE_PLUSMINUS; i++) - flipper.addView(new PageViewer(number + (i * -1) - 1), PAGECACHE_PLUSMINUS + i + 1, matchParent); - } - - private void askPageNumber() - { - AlertDialog.Builder alert = new AlertDialog.Builder(this); - alert.setTitle(R.string.go_to_page); - final NumberPicker input = new NumberPicker(this); - input.setMinValue(1); - input.setMaxValue(documentContext.pageCount); - alert.setView(input); - alert.setPositiveButton("OK", new DialogInterface.OnClickListener() - { - public void onClick(DialogInterface dialog, int whichButton) - { - goToPage(input.getValue() - 1); - } - }); - - alert.setNegativeButton("Cancel", new DialogInterface.OnClickListener() - { - public void onClick(DialogInterface dialog, int whichButton) - { - } - }); - alert.show(); - } - - @Override - public void onCreate(Bundle savedInstanceState) - { - super.onCreate(savedInstanceState); - - ArrayList contexts = (ArrayList)getLastNonConfigurationInstance(); - if (contexts != null) - { - bootstrapContext = (BootstrapContext)contexts.get(0); - documentContext = (DocumentContext)contexts.get(1); - } - - extras = getIntent().getExtras(); - - gestureListener = new GestureListener(); - gestureDetector = new GestureDetector(this, gestureListener); - - try { - String input = getIntent().getStringExtra("input"); - if (input == null) - input = "/assets/test1.odt"; - - // We need to fake up an argv, and the argv[0] even needs to - // point to some file name that we can pretend is the "program". - // setCommandArgs() will prefix argv[0] with the app's data - // directory. - - String[] argv = { "lo-document-loader", input }; - - Bootstrap.setCommandArgs(argv); - - if (bootstrapContext == null) - initBootstrapContext(); - - if (documentContext == null || !documentContext.input.equals(input)) - initDocumentContext(input); - - flipper = new ViewFlipper(this); - - matchParent = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); - - goToPage(documentContext.currentPageNumber); - - setContentView(flipper); - } - catch (Exception e) { - e.printStackTrace(System.err); - finish(); - } - } - - @Override - public boolean onTouchEvent(MotionEvent event) - { - return gestureDetector.onTouchEvent(event); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) - { - MenuInflater inflater = getMenuInflater(); - inflater.inflate(R.menu.option, menu); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) - { - // Handle item selection - switch (item.getItemId()) { - case R.id.go_to_page: - askPageNumber(); - return true; - default: - return super.onOptionsItemSelected(item); - } - } -} - -// vim:set shiftwidth=4 softtabstop=4 expandtab: |