[Libreoffice-commits] core.git: android/Bootstrap android/source desktop/source

Ximeng Zu uznomis at yahoo.com
Sun Aug 27 18:16:13 UTC 2017


 android/Bootstrap/src/org/libreoffice/kit/Document.java              |    9 +
 android/Bootstrap/src/org/libreoffice/kit/Office.java                |   36 ++++++
 android/source/res/layout/password_dialog.xml                        |   17 +++
 android/source/res/values/strings.xml                                |    5 
 android/source/src/java/org/libreoffice/InvalidationHandler.java     |   19 +++
 android/source/src/java/org/libreoffice/LOKitThread.java             |    1 
 android/source/src/java/org/libreoffice/LOKitTileProvider.java       |   22 +++
 android/source/src/java/org/libreoffice/LibreOfficeMainActivity.java |   34 ++++++
 android/source/src/java/org/libreoffice/PasswordDialogFragment.java  |   56 ++++++++++
 desktop/source/lib/lokandroid.cxx                                    |   40 +++++++
 10 files changed, 235 insertions(+), 4 deletions(-)

New commits:
commit 43f5161991cffedabb280a6e4e388c5bcbac4f96
Author: Ximeng Zu <uznomis at yahoo.com>
Date:   Wed Jul 26 11:15:26 2017 -0500

    [Android Viewer] Password support
    
    Added password support for documents.
    
    Change-Id: Ifd9cf86894ddaf2fd5ad97510d2ac1b5850611ad
    Reviewed-on: https://gerrit.libreoffice.org/40458
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Tomaž Vajngerl <quikee at gmail.com>
    Tested-by: Tomaž Vajngerl <quikee at gmail.com>

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 */


More information about the Libreoffice-commits mailing list