summaryrefslogtreecommitdiff
path: root/android/src/com/artifex
diff options
context:
space:
mode:
authorPaul Gardiner <paulg.artifex@glidos.net>2012-11-19 16:03:21 +0000
committerPaul Gardiner <paulg.artifex@glidos.net>2012-11-19 16:03:21 +0000
commit88e4317b964d09b6581818a6f18fc64817559ec3 (patch)
tree5d99537f3af58b08f4f02f71e13524aaac302ba9 /android/src/com/artifex
parented8a4b8d38b7709daf3db302fc4604c0ff6cdc69 (diff)
downloadmupdf-88e4317b964d09b6581818a6f18fc64817559ec3.tar.xz
Android: implement alert dialog
Diffstat (limited to 'android/src/com/artifex')
-rw-r--r--android/src/com/artifex/mupdf/MuPDFActivity.java131
-rw-r--r--android/src/com/artifex/mupdf/MuPDFAlert.java21
-rw-r--r--android/src/com/artifex/mupdf/MuPDFAlertInternal.java30
-rw-r--r--android/src/com/artifex/mupdf/MuPDFCore.java21
4 files changed, 203 insertions, 0 deletions
diff --git a/android/src/com/artifex/mupdf/MuPDFActivity.java b/android/src/com/artifex/mupdf/MuPDFActivity.java
index b4c10ee9..cf1d2abd 100644
--- a/android/src/com/artifex/mupdf/MuPDFActivity.java
+++ b/android/src/com/artifex/mupdf/MuPDFActivity.java
@@ -1,5 +1,7 @@
package com.artifex.mupdf;
+import java.util.concurrent.Executor;
+
import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
@@ -10,6 +12,7 @@ import android.content.SharedPreferences;
import android.database.Cursor;
import android.graphics.RectF;
import android.net.Uri;
+import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.text.Editable;
@@ -31,6 +34,11 @@ import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.ViewSwitcher;
+class ThreadPerTaskExecutor implements Executor {
+ public void execute(Runnable r) {
+ new Thread(r).start();
+ }
+}
class SearchTaskResult {
public final String txt;
public final int pageNumber;
@@ -99,6 +107,106 @@ public class MuPDFActivity extends Activity
private AlertDialog.Builder mAlertBuilder;
private LinkState mLinkState = LinkState.DEFAULT;
private final Handler mHandler = new Handler();
+ private AsyncTask<Void,Void,MuPDFAlert> mAlertTask;
+
+ public void createAlertWaiter() {
+ // All mupdf library calls are performed on asynchronous tasks to avoid stalling
+ // the UI. Some calls can lead to javascript-invoked requests to display an
+ // alert dialog and collect a reply from the user. The task has to be blocked
+ // until the user's reply is received. This method creates an asynchronous task,
+ // the purpose of which is to wait of these requests and produce the dialog
+ // in response, while leaving the core blocked. When the dialog receives the
+ // user's response, it is sent to the core via replyToAlert, unblocking it.
+ // Another alert-waiting task is then created to pick up the next alert.
+ if (mAlertTask != null) {
+ mAlertTask.cancel(true);
+ mAlertTask = null;
+ }
+ mAlertTask = new SafeAsyncTask<Void,Void,MuPDFAlert>() {
+
+ @Override
+ protected MuPDFAlert doInBackground(Void... arg0) {
+ return core.waitForAlert();
+ }
+
+ @Override
+ protected void onPostExecute(final MuPDFAlert result) {
+ // core.waitForAlert may return null when shutting down
+ if (result == null)
+ return;
+ final MuPDFAlert.ButtonPressed pressed[] = new MuPDFAlert.ButtonPressed[3];
+ for(int i = 0; i < 3; i++)
+ pressed[i] = MuPDFAlert.ButtonPressed.None;
+ DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ int index = 0;
+ switch (which) {
+ case AlertDialog.BUTTON1: index=0; break;
+ case AlertDialog.BUTTON2: index=1; break;
+ case AlertDialog.BUTTON3: index=2; break;
+ }
+ result.buttonPressed = pressed[index];
+ // Send the user's response to the core, so that it can
+ // continue processing.
+ core.replyToAlert(result);
+ // Create another alert-waiter to pick up the next alert.
+ createAlertWaiter();
+ }
+ };
+ AlertDialog alert = mAlertBuilder.create();
+ alert.setTitle(result.title);
+ alert.setMessage(result.message);
+ switch (result.iconType)
+ {
+ case Error:
+ break;
+ case Warning:
+ break;
+ case Question:
+ break;
+ case Status:
+ break;
+ }
+ switch (result.buttonGroupType)
+ {
+ case OkCancel:
+ alert.setButton(AlertDialog.BUTTON2, "Cancel", listener);
+ pressed[1] = MuPDFAlert.ButtonPressed.Cancel;
+ case Ok:
+ alert.setButton(AlertDialog.BUTTON1, "Ok", listener);
+ pressed[0] = MuPDFAlert.ButtonPressed.Ok;
+ break;
+ case YesNoCancel:
+ alert.setButton(AlertDialog.BUTTON3, "Cancel", listener);
+ pressed[2] = MuPDFAlert.ButtonPressed.Cancel;
+ case YesNo:
+ alert.setButton(AlertDialog.BUTTON1, "Yes", listener);
+ pressed[0] = MuPDFAlert.ButtonPressed.Yes;
+ alert.setButton(AlertDialog.BUTTON2, "No", listener);
+ pressed[1] = MuPDFAlert.ButtonPressed.No;
+ break;
+ }
+ alert.setOnCancelListener(new DialogInterface.OnCancelListener() {
+ public void onCancel(DialogInterface dialog) {
+ result.buttonPressed = MuPDFAlert.ButtonPressed.None;
+ core.replyToAlert(result);
+ createAlertWaiter();
+ }
+ });
+
+ alert.show();
+ }
+ };
+
+ mAlertTask.executeOnExecutor(new ThreadPerTaskExecutor());
+ }
+
+ public void destroyAlertWaiter() {
+ if (mAlertTask != null) {
+ mAlertTask.cancel(true);
+ mAlertTask = null;
+ }
+ }
private MuPDFCore openFile(String path)
{
@@ -205,6 +313,7 @@ public class MuPDFActivity extends Activity
public void createUI(Bundle savedInstanceState) {
if (core == null)
return;
+
// Now create the UI.
// First create the document view making use of the ReaderView's internal
// gesture recognition
@@ -521,6 +630,10 @@ public class MuPDFActivity extends Activity
{
if (core != null)
core.onDestroy();
+ if (mAlertTask != null) {
+ mAlertTask.cancel(true);
+ mAlertTask = null;
+ }
core = null;
super.onDestroy();
}
@@ -768,4 +881,22 @@ public class MuPDFActivity extends Activity
}
return super.onPrepareOptionsMenu(menu);
}
+
+ @Override
+ protected void onStart() {
+ if (core != null)
+ core.startAlerts();
+
+ createAlertWaiter();
+ super.onStart();
+ }
+
+ @Override
+ protected void onStop() {
+ destroyAlertWaiter();
+ if (core != null)
+ core.stopAlerts();
+
+ super.onStop();
+ }
}
diff --git a/android/src/com/artifex/mupdf/MuPDFAlert.java b/android/src/com/artifex/mupdf/MuPDFAlert.java
new file mode 100644
index 00000000..c024ad44
--- /dev/null
+++ b/android/src/com/artifex/mupdf/MuPDFAlert.java
@@ -0,0 +1,21 @@
+package com.artifex.mupdf;
+
+public class MuPDFAlert {
+ public enum IconType {Error,Warning,Question,Status};
+ public enum ButtonPressed {None,Ok,Cancel,No,Yes};
+ public enum ButtonGroupType {Ok,OkCancel,YesNo,YesNoCancel};
+
+ public final String message;
+ public final IconType iconType;
+ public final ButtonGroupType buttonGroupType;
+ public final String title;
+ public ButtonPressed buttonPressed;
+
+ MuPDFAlert(String aMessage, IconType aIconType, ButtonGroupType aButtonGroupType, String aTitle, ButtonPressed aButtonPressed) {
+ message = aMessage;
+ iconType = aIconType;
+ buttonGroupType = aButtonGroupType;
+ title = aTitle;
+ buttonPressed = aButtonPressed;
+ }
+}
diff --git a/android/src/com/artifex/mupdf/MuPDFAlertInternal.java b/android/src/com/artifex/mupdf/MuPDFAlertInternal.java
new file mode 100644
index 00000000..d1e93701
--- /dev/null
+++ b/android/src/com/artifex/mupdf/MuPDFAlertInternal.java
@@ -0,0 +1,30 @@
+package com.artifex.mupdf;
+
+// Version of MuPDFAlert without enums to simplify JNI
+public class MuPDFAlertInternal {
+ public final String message;
+ public final int iconType;
+ public final int buttonGroupType;
+ public final String title;
+ public int buttonPressed;
+
+ MuPDFAlertInternal(String aMessage, int aIconType, int aButtonGroupType, String aTitle, int aButtonPressed) {
+ message = aMessage;
+ iconType = aIconType;
+ buttonGroupType = aButtonGroupType;
+ title = aTitle;
+ buttonPressed = aButtonPressed;
+ }
+
+ MuPDFAlertInternal(MuPDFAlert alert) {
+ message = alert.message;
+ iconType = alert.iconType.ordinal();
+ buttonGroupType = alert.buttonGroupType.ordinal();
+ title = alert.message;
+ buttonPressed = alert.buttonPressed.ordinal();
+ }
+
+ MuPDFAlert toAlert() {
+ return new MuPDFAlert(message, MuPDFAlert.IconType.values()[iconType], MuPDFAlert.ButtonGroupType.values()[buttonGroupType], title, MuPDFAlert.ButtonPressed.values()[buttonPressed]);
+ }
+}
diff --git a/android/src/com/artifex/mupdf/MuPDFCore.java b/android/src/com/artifex/mupdf/MuPDFCore.java
index b7ab2834..98413504 100644
--- a/android/src/com/artifex/mupdf/MuPDFCore.java
+++ b/android/src/com/artifex/mupdf/MuPDFCore.java
@@ -43,6 +43,10 @@ public class MuPDFCore
private static native boolean hasOutlineInternal();
private static native boolean needsPasswordInternal();
private static native boolean authenticatePasswordInternal(String password);
+ private static native MuPDFAlertInternal waitForAlertInternal();
+ private static native void replyToAlertInternal(MuPDFAlertInternal alert);
+ private static native void startAlertsInternal();
+ private static native void stopAlertsInternal();
private static native void destroying();
public static native boolean javascriptSupported();
@@ -84,6 +88,23 @@ public class MuPDFCore
return new PointF(pageWidth, pageHeight);
}
+ public MuPDFAlert waitForAlert() {
+ MuPDFAlertInternal alert = waitForAlertInternal();
+ return alert != null ? alert.toAlert() : null;
+ }
+
+ public void replyToAlert(MuPDFAlert alert) {
+ replyToAlertInternal(new MuPDFAlertInternal(alert));
+ }
+
+ public void stopAlerts() {
+ stopAlertsInternal();
+ }
+
+ public void startAlerts() {
+ startAlertsInternal();
+ }
+
public synchronized void onDestroy() {
destroying();
}