diff options
author | Ximeng Zu <uznomis@yahoo.com> | 2017-07-26 11:15:26 -0500 |
---|---|---|
committer | Tomaž Vajngerl <quikee@gmail.com> | 2017-08-27 20:12:52 +0200 |
commit | 43f5161991cffedabb280a6e4e388c5bcbac4f96 (patch) | |
tree | 2dda51149a9174dc1e7de414f89b1cba96ef5a36 /android | |
parent | c4bc3822298a663c31c676648262c223c1be4ab6 (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>
Diffstat (limited to 'android')
9 files changed, 195 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; + } +} |