summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXimeng Zu <uznomis@yahoo.com>2017-07-26 11:15:26 -0500
committerTomaž Vajngerl <quikee@gmail.com>2017-08-27 20:12:52 +0200
commit43f5161991cffedabb280a6e4e388c5bcbac4f96 (patch)
tree2dda51149a9174dc1e7de414f89b1cba96ef5a36
parentc4bc3822298a663c31c676648262c223c1be4ab6 (diff)
[Android Viewer] Password support
Added password support for documents. Change-Id: Ifd9cf86894ddaf2fd5ad97510d2ac1b5850611ad Reviewed-on: https://gerrit.libreoffice.org/40458 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Tomaž Vajngerl <quikee@gmail.com> Tested-by: Tomaž Vajngerl <quikee@gmail.com>
-rw-r--r--android/Bootstrap/src/org/libreoffice/kit/Document.java9
-rw-r--r--android/Bootstrap/src/org/libreoffice/kit/Office.java36
-rw-r--r--android/source/res/layout/password_dialog.xml17
-rw-r--r--android/source/res/values/strings.xml5
-rw-r--r--android/source/src/java/org/libreoffice/InvalidationHandler.java19
-rw-r--r--android/source/src/java/org/libreoffice/LOKitThread.java1
-rw-r--r--android/source/src/java/org/libreoffice/LOKitTileProvider.java22
-rwxr-xr-xandroid/source/src/java/org/libreoffice/LibreOfficeMainActivity.java34
-rw-r--r--android/source/src/java/org/libreoffice/PasswordDialogFragment.java56
-rw-r--r--desktop/source/lib/lokandroid.cxx40
10 files changed, 235 insertions, 4 deletions
diff --git a/android/Bootstrap/src/org/libreoffice/kit/Document.java b/android/Bootstrap/src/org/libreoffice/kit/Document.java
index 8278532c6381..6a1f402970ea 100644
--- a/android/Bootstrap/src/org/libreoffice/kit/Document.java
+++ b/android/Bootstrap/src/org/libreoffice/kit/Document.java
@@ -119,6 +119,15 @@ public class Document {
public static final int KEYBOARD_MODIFIER_MOD2 = 0x4000;
public static final int KEYBOARD_MODIFIER_MOD3 = 0x8000;
+ /** Optional features of LibreOfficeKit, in particular callbacks that block
+ * LibreOfficeKit until the corresponding reply is received, which would
+ * deadlock if the client does not support the feature.
+ */
+ public static final long LOK_FEATURE_DOCUMENT_PASSWORD = 1;
+ public static final long LOK_FEATURE_DOCUMENT_PASSWORD_TO_MODIFY = (1 << 1);
+ public static final long LOK_FEATURE_PART_IN_INVALIDATION_CALLBACK = (1 << 2);
+ public static final long LOK_FEATURE_NO_TILED_ANNOTATIONS = (1 << 3);
+
private final ByteBuffer handle;
private MessageCallback messageCallback = null;
diff --git a/android/Bootstrap/src/org/libreoffice/kit/Office.java b/android/Bootstrap/src/org/libreoffice/kit/Office.java
index 8c616d0e9ce2..25c838ffb2e4 100644
--- a/android/Bootstrap/src/org/libreoffice/kit/Office.java
+++ b/android/Bootstrap/src/org/libreoffice/kit/Office.java
@@ -13,11 +13,18 @@ import java.nio.ByteBuffer;
public class Office {
private ByteBuffer handle;
+ private MessageCallback messageCallback = null;
public Office(ByteBuffer handle) {
this.handle = handle;
+ bindMessageCallback();
}
+ /**
+ * Bind the signal callback in LOK.
+ */
+ private native void bindMessageCallback();
+
public native String getError();
private native ByteBuffer documentLoadNative(String url);
@@ -33,4 +40,33 @@ public class Office {
public native void destroy();
public native void destroyAndExit();
+ public native void setDocumentPassword(String url, String pwd);
+ public native void setOptionalFeatures(long options);
+
+ public void setMessageCallback(MessageCallback messageCallback) {
+ this.messageCallback = messageCallback;
+ }
+
+ /**
+ * Callback triggered through JNI to indicate that a new signal
+ * from LibreOfficeKit was retrieved.
+ */
+ private void messageRetrievedLOKit(int signalNumber, String payload) {
+ if (messageCallback != null) {
+ messageCallback.messageRetrieved(signalNumber, payload);
+ }
+
+ }
+
+ /**
+ * Callback to retrieve messages from LOK
+ */
+ public interface MessageCallback {
+ /**
+ * Invoked when a message is retrieved from LOK
+ * @param signalNumber - signal type / number
+ * @param payload - retrieved for the signal
+ */
+ void messageRetrieved(int signalNumber, String payload);
+ }
}
diff --git a/android/source/res/layout/password_dialog.xml b/android/source/res/layout/password_dialog.xml
new file mode 100644
index 000000000000..adc4f4249daf
--- /dev/null
+++ b/android/source/res/layout/password_dialog.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical" android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+
+ <EditText
+ android:id="@+id/password"
+ android:inputType="textPassword"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="4dp"
+ android:layout_marginLeft="4dp"
+ android:layout_marginRight="4dp"
+ android:layout_marginBottom="16dp"
+ android:hint="@string/password"/>
+
+</LinearLayout> \ No newline at end of file
diff --git a/android/source/res/values/strings.xml b/android/source/res/values/strings.xml
index 04f1be3cc029..c8c84f9702ba 100644
--- a/android/source/res/values/strings.xml
+++ b/android/source/res/values/strings.xml
@@ -152,4 +152,9 @@
<string name="calc_optimal_length_default_text">Enter Extra Length in 100th/mm</string>
<string name="calc_alert_double_click_optimal_length">Hint: Double tap on a header sets optimal width/height.</string>
+ <!-- Password dialog strings -->
+ <string name="action_pwd_dialog_OK">OK</string>
+ <string name="action_pwd_dialog_cancel">Cancel</string>
+ <string name="action_pwd_dialog_title">Please enter password</string>
+
</resources>
diff --git a/android/source/src/java/org/libreoffice/InvalidationHandler.java b/android/source/src/java/org/libreoffice/InvalidationHandler.java
index 7bfffc8ab4ec..fbe7d96b63d6 100644
--- a/android/source/src/java/org/libreoffice/InvalidationHandler.java
+++ b/android/source/src/java/org/libreoffice/InvalidationHandler.java
@@ -11,6 +11,7 @@ import org.json.JSONException;
import org.json.JSONObject;
import org.libreoffice.canvas.SelectionHandle;
import org.libreoffice.kit.Document;
+import org.libreoffice.kit.Office;
import org.libreoffice.overlay.DocumentOverlay;
import org.mozilla.gecko.gfx.GeckoLayerClient;
@@ -21,7 +22,7 @@ import java.util.List;
/**
* Parses (interprets) and handles invalidation messages from LibreOffice.
*/
-public class InvalidationHandler implements Document.MessageCallback {
+public class InvalidationHandler implements Document.MessageCallback, Office.MessageCallback {
private static String LOGTAG = InvalidationHandler.class.getSimpleName();
private final DocumentOverlay mDocumentOverlay;
private final GeckoLayerClient mLayerClient;
@@ -97,6 +98,9 @@ public class InvalidationHandler implements Document.MessageCallback {
case Document.CALLBACK_INVALIDATE_HEADER:
invalidateHeader();
break;
+ case Document.CALLBACK_DOCUMENT_PASSWORD:
+ documentPassword();
+ break;
default:
Log.d(LOGTAG, "LOK_CALLBACK uncaught: " + messageID + " : " + payload);
}
@@ -106,6 +110,19 @@ public class InvalidationHandler implements Document.MessageCallback {
LOKitShell.sendEvent(new LOEvent(LOEvent.UPDATE_CALC_HEADERS));
}
+ private void documentPassword() {
+ mContext.setPasswordProtected(true);
+ mContext.promptForPassword();
+ synchronized (this) {
+ try {
+ this.wait();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ mContext.setPassword();
+ }
+
private void invalidateCellCursor(String payload) {
RectF cellCursorRect = convertPayloadToRectangle(payload);
diff --git a/android/source/src/java/org/libreoffice/LOKitThread.java b/android/source/src/java/org/libreoffice/LOKitThread.java
index 50836ce5b65a..721853d08a99 100644
--- a/android/source/src/java/org/libreoffice/LOKitThread.java
+++ b/android/source/src/java/org/libreoffice/LOKitThread.java
@@ -172,6 +172,7 @@ class LOKitThread extends Thread {
}
private void updateZoomConstraints() {
+ if (mTileProvider == null) return;
mLayerClient = mContext.getLayerClient();
if (mTileProvider.isSpreadsheet()) {
// Calc has a fixed zoom at 1x and doesn't allow zooming for now
diff --git a/android/source/src/java/org/libreoffice/LOKitTileProvider.java b/android/source/src/java/org/libreoffice/LOKitTileProvider.java
index ba49cfaf26ee..7be5ac31f60c 100644
--- a/android/source/src/java/org/libreoffice/LOKitTileProvider.java
+++ b/android/source/src/java/org/libreoffice/LOKitTileProvider.java
@@ -50,7 +50,7 @@ class LOKitTileProvider implements TileProvider {
* @param messageCallback - callback for messages retrieved from LOKit
* @param input - input path of the document
*/
- LOKitTileProvider(LibreOfficeMainActivity context, Document.MessageCallback messageCallback, String input) {
+ LOKitTileProvider(LibreOfficeMainActivity context, InvalidationHandler messageCallback, String input) {
mContext = context;
mMessageCallback = messageCallback;
@@ -58,13 +58,16 @@ class LOKitTileProvider implements TileProvider {
LibreOfficeKit.init(mContext);
mOffice = new Office(LibreOfficeKit.getLibreOfficeKitHandle());
+ mOffice.setMessageCallback(messageCallback);
+ mOffice.setOptionalFeatures(Document.LOK_FEATURE_DOCUMENT_PASSWORD);
+ mContext.setTileProvider(this);
mInputFile = input;
Log.i(LOGTAG, "====> Loading file '" + input + "'");
mDocument = mOffice.documentLoad(input);
- if (mDocument == null) {
+ if (mDocument == null && !mContext.isPasswordProtected()) {
Log.i(LOGTAG, "====> mOffice.documentLoad() returned null, trying to restart 'Office' and loading again");
mOffice.destroy();
Log.i(LOGTAG, "====> mOffice.destroy() done");
@@ -72,6 +75,9 @@ class LOKitTileProvider implements TileProvider {
Log.i(LOGTAG, "====> getLibreOfficeKitHandle() = " + handle);
mOffice = new Office(handle);
Log.i(LOGTAG, "====> new Office created");
+ mOffice.setMessageCallback(messageCallback);
+ mOffice.setOptionalFeatures(Document.LOK_FEATURE_DOCUMENT_PASSWORD);
+ Log.i(LOGTAG, "====> setup Lokit callback and optional features (password support)");
mDocument = mOffice.documentLoad(input);
}
@@ -287,7 +293,7 @@ class LOKitTileProvider implements TileProvider {
}
}
- if (!ret) {
+ if (!ret && !mContext.isPasswordProtected()) {
final String message = error;
LOKitShell.getMainHandler().post(new Runnable() {
@Override
@@ -295,6 +301,8 @@ class LOKitTileProvider implements TileProvider {
mContext.showAlertDialog(message);
}
});
+ } else if (!ret && mContext.isPasswordProtected()) {
+ mContext.finish();
}
return ret;
@@ -594,6 +602,14 @@ class LOKitTileProvider implements TileProvider {
return mDocument.getPart();
}
+
+ public void setDocumentPassword(String url, String password) {
+ mOffice.setDocumentPassword(url, password);
+ }
+
+ public Document.MessageCallback getMessageCallback() {
+ return mMessageCallback;
+ }
}
// vim:set shiftwidth=4 softtabstop=4 expandtab:
diff --git a/android/source/src/java/org/libreoffice/LibreOfficeMainActivity.java b/android/source/src/java/org/libreoffice/LibreOfficeMainActivity.java
index 20e25b2c6c32..97e23f238d09 100755
--- a/android/source/src/java/org/libreoffice/LibreOfficeMainActivity.java
+++ b/android/source/src/java/org/libreoffice/LibreOfficeMainActivity.java
@@ -95,6 +95,9 @@ public class LibreOfficeMainActivity extends AppCompatActivity implements Settin
private SearchController mSearchController;
private CalcHeadersController mCalcHeadersController;
private boolean mIsSpreadsheet;
+ private LOKitTileProvider mTileProvider;
+ private String mPassword;
+ private boolean mPasswordProtected;
public GeckoLayerClient getLayerClient() {
return mLayerClient;
@@ -699,6 +702,37 @@ public class LibreOfficeMainActivity extends AppCompatActivity implements Settin
}
}
+ public void promptForPassword() {
+ PasswordDialogFragment passwordDialogFragment = new PasswordDialogFragment();
+ passwordDialogFragment.setLOMainActivity(this);
+ passwordDialogFragment.show(getSupportFragmentManager(), "PasswordDialogFragment");
+ }
+
+ // this function can only be called in InvalidationHandler.java
+ public void setPassword() {
+ mTileProvider.setDocumentPassword("file://"+mInputFile.getPath(), mPassword);
+ }
+
+ // setTileProvider is meant to let main activity have a handle of LOKit when dealing with password
+ public void setTileProvider(LOKitTileProvider loKitTileProvider) {
+ mTileProvider = loKitTileProvider;
+ }
+
+ public void savePassword(String pwd) {
+ mPassword = pwd;
+ synchronized (mTileProvider.getMessageCallback()) {
+ mTileProvider.getMessageCallback().notifyAll();
+ }
+ }
+
+ public void setPasswordProtected(boolean b) {
+ mPasswordProtected = b;
+ }
+
+ public boolean isPasswordProtected() {
+ return mPasswordProtected;
+ }
+
public void initializeCalcHeaders() {
mCalcHeadersController = new CalcHeadersController(this, mLayerClient.getView());
mCalcHeadersController.setupHeaderPopupView();
diff --git a/android/source/src/java/org/libreoffice/PasswordDialogFragment.java b/android/source/src/java/org/libreoffice/PasswordDialogFragment.java
new file mode 100644
index 000000000000..112e35c4b7ed
--- /dev/null
+++ b/android/source/src/java/org/libreoffice/PasswordDialogFragment.java
@@ -0,0 +1,56 @@
+package org.libreoffice;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.app.DialogFragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.EditText;
+
+public class PasswordDialogFragment extends DialogFragment {
+
+ private LibreOfficeMainActivity mContext;
+
+ @NonNull
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+ LayoutInflater inflater = getActivity().getLayoutInflater();
+
+ final View dialogView = inflater.inflate(R.layout.password_dialog, null);
+
+ builder.setView(dialogView)
+ .setPositiveButton(R.string.action_pwd_dialog_OK, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ String pwd = ((EditText)dialogView.findViewById(R.id.password)).getText().toString();
+ mContext.savePassword(pwd);
+ }
+ })
+ .setNegativeButton(R.string.action_pwd_dialog_cancel, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ mContext.savePassword(null);
+ }
+ }).setTitle(R.string.action_pwd_dialog_title);
+
+ return builder.create();
+ }
+
+ @Nullable
+ @Override
+ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ getDialog().setCanceledOnTouchOutside(false);
+ setCancelable(false);
+ return super.onCreateView(inflater, container, savedInstanceState);
+ }
+
+ public void setLOMainActivity(LibreOfficeMainActivity context) {
+ mContext = context;
+ }
+}
diff --git a/desktop/source/lib/lokandroid.cxx b/desktop/source/lib/lokandroid.cxx
index 0f807d061590..3055d38957da 100644
--- a/desktop/source/lib/lokandroid.cxx
+++ b/desktop/source/lib/lokandroid.cxx
@@ -85,6 +85,7 @@ struct CallbackData
};
static CallbackData gCallbackData;
+static CallbackData gCallbackDataLOKit;
/**
* Handle retrieved callback
@@ -143,6 +144,45 @@ extern "C" SAL_JNI_EXPORT jobject JNICALL Java_org_libreoffice_kit_Office_docume
return aHandle;
}
+extern "C" SAL_JNI_EXPORT void JNICALL Java_org_libreoffice_kit_Office_setDocumentPassword
+ (JNIEnv* pEnv, jobject aObject, jstring sUrl, jstring sPassword)
+{
+ LibreOfficeKit* pLibreOfficeKit = getHandle<LibreOfficeKit>(pEnv, aObject);
+
+ char const* pUrl = copyJavaString(pEnv, sUrl);
+ if (sPassword == NULL) {
+ pLibreOfficeKit->pClass->setDocumentPassword(pLibreOfficeKit, pUrl, nullptr);
+ } else {
+ char const* pPassword = copyJavaString(pEnv, sPassword);
+ pLibreOfficeKit->pClass->setDocumentPassword(pLibreOfficeKit, pUrl, pPassword);
+ }
+}
+
+extern "C" SAL_JNI_EXPORT void JNICALL Java_org_libreoffice_kit_Office_setOptionalFeatures
+ (JNIEnv* pEnv, jobject aObject, jlong options)
+{
+ LibreOfficeKit* pLibreOfficeKit = getHandle<LibreOfficeKit>(pEnv, aObject);
+
+ uint64_t pOptions = (uint64_t)options;
+
+ pLibreOfficeKit->pClass->setOptionalFeatures(pLibreOfficeKit, pOptions);
+}
+
+/** Implementation of org.libreoffice.kit.Office.bindMessageCallback method */
+extern "C" SAL_JNI_EXPORT void JNICALL Java_org_libreoffice_kit_Office_bindMessageCallback
+ (JNIEnv* pEnv, jobject aObject)
+{
+ LibreOfficeKit* pLibreOfficeKit = getHandle<LibreOfficeKit>(pEnv, aObject);
+
+ gCallbackDataLOKit.aObject = (jobject) pEnv->NewGlobalRef(aObject);
+ jclass aClass = pEnv->GetObjectClass(aObject);
+ gCallbackDataLOKit.aClass = (jclass) pEnv->NewGlobalRef(aClass);
+
+ gCallbackDataLOKit.aJavaCallbackMethod = pEnv->GetMethodID(aClass, "messageRetrievedLOKit", "(ILjava/lang/String;)V");
+
+ pLibreOfficeKit->pClass->registerCallback(pLibreOfficeKit, messageCallback, (void*) &gCallbackDataLOKit);
+}
+
/* Document */
/** Implementation of org.libreoffice.kit.Document.bindMessageCallback method */