summaryrefslogtreecommitdiff
path: root/android/experimental/DocumentLoader
diff options
context:
space:
mode:
authorTor Lillqvist <tlillqvist@suse.com>2012-06-19 18:07:40 +0300
committerTor Lillqvist <tlillqvist@suse.com>2012-06-19 19:29:41 +0300
commit7bcadeadfe882fa85fb2831bb5a6a056b68297bd (patch)
treef2aeb40c0ee4e5cbf2fdaaa5412d3357285cf448 /android/experimental/DocumentLoader
parent5e380fbdcdebf762a07b0ec502a4d3c40190838d (diff)
Asynchronous document loading and page rendering
Change-Id: I085024b6bfccf6846167a5de316912a395f4e301
Diffstat (limited to 'android/experimental/DocumentLoader')
-rw-r--r--android/experimental/DocumentLoader/src/org/libreoffice/android/examples/DocumentLoader.java359
1 files changed, 225 insertions, 134 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
index 412c57d1a6a3..9f59d0959379 100644
--- a/android/experimental/DocumentLoader/src/org/libreoffice/android/examples/DocumentLoader.java
+++ b/android/experimental/DocumentLoader/src/org/libreoffice/android/examples/DocumentLoader.java
@@ -1,38 +1,42 @@
// -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
-
-// Version: MPL 1.1 / GPLv3+ / LGPLv3+
-//
-// The contents of this file are subject to the Mozilla Public License Version
-// 1.1 (the "License"); you may not use this file except in compliance with
-// the License or as specified alternatively below. You may obtain a copy of
-// the License at http://www.mozilla.org/MPL/
-//
-// Software distributed under the License is distributed on an "AS IS" basis,
-// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
-// for the specific language governing rights and limitations under the
-// License.
//
-// Major Contributor(s):
-// Copyright (C) 2011 Tor Lillqvist <tml@iki.fi> (initial developer)
-// Copyright (C) 2011 SUSE Linux http://suse.com (initial developer's employer)
+// This file is part of the LibreOffice project.
//
-// All Rights Reserved.
-//
-// For minor contributions see the git repository.
-//
-// Alternatively, the contents of this file may be used under the terms of
-// either the GNU General Public License Version 3 or later (the "GPLv3+"), or
-// the GNU Lesser General Public License Version 3 or later (the "LGPLv3+"),
-// in which case the provisions of the GPLv3+ or the LGPLv3+ are applicable
-// instead of those above.
+// 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, for instance using
+// AsyncTask.SERIAL_EXECUTOR.
+
+// While a page is loading ideally should display some animated spinner (but
+// for now just a static "please wait" text).
+
+// Just three views are used for the pages: For the current page being viewed,
+// the previous, and the next. This could be bumped higher, need to make the
+// "3" into a parameter below.
package org.libreoffice.android.examples;
import android.app.Activity;
import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.GestureDetector;
+import android.view.Gravity;
import android.view.MotionEvent;
import android.view.ViewGroup;
import android.view.animation.AlphaAnimation;
@@ -40,7 +44,9 @@ import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.TranslateAnimation;
import android.widget.ImageView;
+import android.widget.TextView;
import android.widget.ViewFlipper;
+import android.widget.ViewSwitcher;
import com.polites.android.GestureImageView;
@@ -73,16 +79,18 @@ public class DocumentLoader
private static String TAG = "DocumentLoader";
long timingOverhead;
- Object desktop;
+ XComponentContext context;
+ XMultiComponentFactory mcf;
XComponentLoader componentLoader;
XToolkit2 toolkit;
Object doc;
int pageCount;
XRenderable renderable;
- PropertyValue[] loadProps;
-
GestureDetector gestureDetector;
+
+ ViewGroup.LayoutParams matchParent;
+
ViewFlipper flipper;
class GestureListener
@@ -96,38 +104,49 @@ public class DocumentLoader
{
Log.i(TAG, "onFling: " + event1 + " " + event2);
if (event1.getX() - event2.getX() > 120) {
- AnimationSet leftIn = new AnimationSet(true);
- leftIn.addAnimation(new AlphaAnimation(0.1f, 1.0f));
- leftIn.addAnimation(new TranslateAnimation(Animation.RELATIVE_TO_SELF, 1, Animation.RELATIVE_TO_SELF, 0,
- Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 0));
- leftIn.setDuration(500);
- flipper.setInAnimation(leftIn);
-
- AnimationSet leftOut = new AnimationSet(true);
- leftOut.addAnimation(new AlphaAnimation(1f, 0.1f));
- leftOut.addAnimation(new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, -1,
- Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 0));
- leftOut.setDuration(500);
- flipper.setOutAnimation(leftOut);
+ if (((PageViewer)flipper.getCurrentView()).currentPageNumber == pageCount-1)
+ return false;
+
+ AnimationSet inFromRight = new AnimationSet(true);
+ inFromRight.addAnimation(new AlphaAnimation(0.1f, 1.0f));
+ inFromRight.addAnimation(new TranslateAnimation(Animation.RELATIVE_TO_SELF, 1, Animation.RELATIVE_TO_SELF, 0,
+ Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 0));
+ inFromRight.setDuration(500);
+ flipper.setInAnimation(inFromRight);
+
+ AnimationSet outToLeft = new AnimationSet(true);
+ outToLeft.addAnimation(new AlphaAnimation(1f, 0.1f));
+ outToLeft.addAnimation(new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, -1,
+ Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 0));
+ outToLeft.setDuration(500);
+ flipper.setOutAnimation(outToLeft);
flipper.showNext();
+
+ ((PageViewer)flipper.getChildAt((flipper.getDisplayedChild() + 1) % 3)).display(((PageViewer)flipper.getCurrentView()).currentPageNumber + 1);
return true;
} else if (event2.getX() - event1.getX() > 120) {
- AnimationSet rightIn = new AnimationSet(true);
- rightIn.addAnimation(new AlphaAnimation(0.1f, 1.0f));
- rightIn.addAnimation(new TranslateAnimation(Animation.RELATIVE_TO_SELF, -1, Animation.RELATIVE_TO_SELF, 0,
- Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 0));
- rightIn.setDuration(500);
- flipper.setInAnimation(rightIn);
-
- AnimationSet rightOut = new AnimationSet(true);
- rightOut.addAnimation(new AlphaAnimation(1f, 0.1f));
- rightOut.addAnimation(new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 1,
- Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 0));
- rightOut.setDuration(500);
- flipper.setOutAnimation(rightOut);
+ if (((PageViewer)flipper.getCurrentView()).currentPageNumber == 0)
+ return false;
+
+ AnimationSet inFromLeft = new AnimationSet(true);
+ inFromLeft.addAnimation(new AlphaAnimation(0.1f, 1.0f));
+ inFromLeft.addAnimation(new TranslateAnimation(Animation.RELATIVE_TO_SELF, -1, Animation.RELATIVE_TO_SELF, 0,
+ Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 0));
+ inFromLeft.setDuration(500);
+ flipper.setInAnimation(inFromLeft);
+
+ AnimationSet outToRight = new AnimationSet(true);
+ outToRight.addAnimation(new AlphaAnimation(1f, 0.1f));
+ outToRight.addAnimation(new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 1,
+ Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 0));
+ outToRight.setDuration(500);
+ flipper.setOutAnimation(outToRight);
flipper.showPrevious();
+
+ ((PageViewer)flipper.getChildAt((flipper.getDisplayedChild() + 2) % 3)).display(((PageViewer)flipper.getCurrentView()).currentPageNumber - 1);
+
return true;
}
return false;
@@ -199,8 +218,6 @@ public class DocumentLoader
}
}
- enum PageState { LOADING, READY };
-
ByteBuffer renderPage(int number)
{
try {
@@ -274,19 +291,153 @@ public class DocumentLoader
return null;
}
- class Page
+ enum PageState { NONEXISTENT, LOADING, READY };
+
+ class PageViewer
+ extends ViewSwitcher
{
- int number;
- PageState state = PageState.LOADING;
+ int currentPageNumber = -1;
+ TextView waitView;
+ PageState state = PageState.NONEXISTENT;
ByteBuffer bb;
- Page(int number)
+ class PageLoadTask
+ extends AsyncTask<Void, Void, Void>
+ {
+ protected Void doInBackground(Void... params)
+ {
+ if (currentPageNumber == pageCount)
+ return null;
+
+ try {
+ Thread.sleep(5000);
+ }
+ catch (InterruptedException e) {
+ }
+ state = PageState.LOADING;
+ bb = renderPage(currentPageNumber);
+ return null;
+ }
+
+ protected void onPostExecute(Void result)
+ {
+ if (currentPageNumber == pageCount)
+ return;
+
+ Bitmap bm = Bitmap.createBitmap(1024, 1024, Bitmap.Config.ARGB_8888);
+ bm.copyPixelsFromBuffer(bb);
+
+ ImageView imageView = new ImageView(DocumentLoader.this);
+ imageView.setImageBitmap(bm);
+
+ imageView.setScaleY(-1);
+
+ if (getChildCount() == 2)
+ removeViewAt(1);
+ addView(imageView, 1, matchParent);
+ showNext();
+ state = PageState.READY;
+ }
+ }
+
+ void display(int number)
+ {
+ if (number == currentPageNumber)
+ return;
+
+ currentPageNumber = number;
+
+ waitView.setText("Page " + (currentPageNumber + 1) + ", wait...");
+ state = PageState.NONEXISTENT;
+
+ if (getDisplayedChild() == 1) {
+ showPrevious();
+ removeViewAt(1);
+ }
+
+ Log.i(TAG, "PageViewer display(" + number + ")");
+ if (currentPageNumber >= 0) {
+ new PageLoadTask().executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
+ }
+ }
+
+ PageViewer(int number)
{
- this.number = number;
+ super(DocumentLoader.this);
- bb = renderPage(number);
+ waitView = new TextView(DocumentLoader.this);
+ waitView.setTextSize(24);
+ waitView.setGravity(Gravity.CENTER);
+ waitView.setBackgroundColor(Color.WHITE);
+ waitView.setTextColor(Color.BLACK);
+ addView(waitView, 0, matchParent);
- state = PageState.READY;
+ 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 = new Boolean(true);
+ loadProps[1] = new PropertyValue();
+ loadProps[1].Name = "ReadOnly";
+ loadProps[1].Value = new Boolean(true);
+ loadProps[2] = new PropertyValue();
+ loadProps[2].Name = "Preview";
+ loadProps[2].Value = new Boolean(true);
+
+ long t0 = System.currentTimeMillis();
+ doc = componentLoader.loadComponentFromURL(url, "_blank", 0, loadProps);
+ long t1 = System.currentTimeMillis();
+ Log.i(TAG, "Loading took " + ((t1-t0)-timingOverhead) + " ms");
+
+ dumpUNOObject("doc", doc);
+
+ Object toolkitService = mcf.createInstanceWithContext
+ ("com.sun.star.awt.Toolkit", context);
+
+ dumpUNOObject("toolkitService", toolkitService);
+
+ toolkit = (XToolkit2) UnoRuntime.queryInterface(XToolkit2.class, toolkitService);
+ dumpUNOObject("toolkit", toolkit);
+
+ renderable = (XRenderable) UnoRuntime.queryInterface(XRenderable.class, doc);
+
+ ByteBuffer smallbb = ByteBuffer.allocateDirect(128*128*4);
+ long wrapped_smallbb = Bootstrap.new_byte_buffer_wrapper(smallbb);
+ XDevice smalldevice = toolkit.createScreenCompatibleDeviceUsingBuffer(128, 128, 1, 1, 0, 0, wrapped_smallbb);
+
+ PropertyValue renderProps[] = new PropertyValue[3];
+ renderProps[0] = new PropertyValue();
+ renderProps[0].Name = "IsPrinter";
+ renderProps[0].Value = new Boolean(true);
+ renderProps[1] = new PropertyValue();
+ renderProps[1].Name = "RenderDevice";
+ renderProps[1].Value = smalldevice;
+ renderProps[2] = new PropertyValue();
+ renderProps[2].Name = "View";
+ renderProps[2].Value = new MyXController();
+
+ t0 = System.currentTimeMillis();
+ pageCount = renderable.getRendererCount(doc, renderProps);
+ t1 = System.currentTimeMillis();
+ Log.i(TAG, "getRendererCount: " + pageCount + ", took " + ((t1-t0)-timingOverhead) + " ms");
+ }
+ catch (Exception e) {
+ e.printStackTrace(System.err);
+ finish();
+ }
+ return null;
}
}
@@ -376,16 +527,14 @@ public class DocumentLoader
Bootstrap.dlopen("libswdlo.so");
Bootstrap.dlopen("libswlo.so");
- Log.i(TAG, "Sleeping NOW");
- Thread.sleep(20000);
-
- XComponentContext context = null;
+ // Log.i(TAG, "Sleeping NOW");
+ // Thread.sleep(20000);
context = com.sun.star.comp.helper.Bootstrap.defaultBootstrap_InitialComponentContext();
Log.i(TAG, "context is" + (context!=null ? " not" : "") + " null");
- XMultiComponentFactory mcf = context.getServiceManager();
+ mcf = context.getServiceManager();
Log.i(TAG, "mcf is" + (mcf!=null ? " not" : "") + " null");
@@ -404,85 +553,27 @@ public class DocumentLoader
Bootstrap.initVCL();
- Object oDesktop = mcf.createInstanceWithContext
+ Object desktop = mcf.createInstanceWithContext
("com.sun.star.frame.Desktop", context);
- Log.i(TAG, "oDesktop is" + (oDesktop!=null ? " not" : "") + " null");
+ Log.i(TAG, "desktop is" + (desktop!=null ? " not" : "") + " null");
Bootstrap.initUCBHelper();
- XComponentLoader xCompLoader = (XComponentLoader) UnoRuntime.queryInterface(XComponentLoader.class, oDesktop);
+ componentLoader = (XComponentLoader) UnoRuntime.queryInterface(XComponentLoader.class, desktop);
- Log.i(TAG, "xCompLoader is" + (xCompLoader!=null ? " not" : "") + " null");
+ Log.i(TAG, "componentLoader is" + (componentLoader!=null ? " not" : "") + " null");
// Load the wanted document
-
- PropertyValue loadProps[] = new PropertyValue[3];
- loadProps[0] = new PropertyValue();
- loadProps[0].Name = "Hidden";
- loadProps[0].Value = new Boolean(true);
- loadProps[1] = new PropertyValue();
- loadProps[1].Name = "ReadOnly";
- loadProps[1].Value = new Boolean(true);
- loadProps[2] = new PropertyValue();
- loadProps[2].Name = "Preview";
- loadProps[2].Value = new Boolean(true);
-
- String sUrl = "file://" + input;
-
- Log.i(TAG, "Attempting to load " + sUrl);
-
- t0 = System.currentTimeMillis();
- doc = xCompLoader.loadComponentFromURL(sUrl, "_blank", 0, loadProps);
- t1 = System.currentTimeMillis();
- Log.i(TAG, "Loading took " + ((t1-t0)-timingOverhead) + " ms");
-
- dumpUNOObject("doc", doc);
-
- Object toolkitService = mcf.createInstanceWithContext
- ("com.sun.star.awt.Toolkit", context);
-
- dumpUNOObject("toolkitService", toolkitService);
-
- toolkit = (XToolkit2) UnoRuntime.queryInterface(XToolkit2.class, toolkitService);
- dumpUNOObject("toolkit", toolkit);
-
- renderable = (XRenderable) UnoRuntime.queryInterface(XRenderable.class, doc);
-
- ByteBuffer smallbb = ByteBuffer.allocateDirect(128*128*4);
- long wrapped_smallbb = Bootstrap.new_byte_buffer_wrapper(smallbb);
- XDevice smalldevice = toolkit.createScreenCompatibleDeviceUsingBuffer(128, 128, 1, 1, 0, 0, wrapped_smallbb);
-
- PropertyValue renderProps[] = new PropertyValue[3];
- renderProps[0] = new PropertyValue();
- renderProps[0].Name = "IsPrinter";
- renderProps[0].Value = new Boolean(true);
- renderProps[1] = new PropertyValue();
- renderProps[1].Name = "RenderDevice";
- renderProps[1].Value = smalldevice;
- renderProps[2] = new PropertyValue();
- renderProps[2].Name = "View";
- renderProps[2].Value = new MyXController();
-
- t0 = System.currentTimeMillis();
- pageCount = renderable.getRendererCount(doc, renderProps);
- t1 = System.currentTimeMillis();
- Log.i(TAG, "getRendererCount: " + pageCount + ", took " + ((t1-t0)-timingOverhead) + " ms");
+ new DocumentLoadTask().executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, "file://" + input);
flipper = new ViewFlipper(this);
- flipper.setScaleY(-1);
-
- for (int i = 0; i < pageCount; i++) {
- ByteBuffer bb = renderPage(i);
- Bitmap bm = Bitmap.createBitmap(1024, 1024, Bitmap.Config.ARGB_8888);
- bm.copyPixelsFromBuffer(bb);
+ matchParent = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
- ImageView imageView = new ImageView(this);
- imageView.setImageBitmap(bm);
-
- flipper.addView(imageView, i, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
- }
+ flipper.addView(new PageViewer(0), 0, matchParent);
+ flipper.addView(new PageViewer(1), 1, matchParent);
+ flipper.addView(new PageViewer(-1), 2, matchParent);
setContentView(flipper);
}