Kaydet (Commit) 43f51619 authored tarafından Ximeng Zu's avatar Ximeng Zu Kaydeden (comit) Tomaž Vajngerl

[Android Viewer] Password support

Added password support for documents.

Change-Id: Ifd9cf86894ddaf2fd5ad97510d2ac1b5850611ad
Reviewed-on: https://gerrit.libreoffice.org/40458Tested-by: 's avatarJenkins <ci@libreoffice.org>
Reviewed-by: 's avatarTomaž Vajngerl <quikee@gmail.com>
Tested-by: 's avatarTomaž Vajngerl <quikee@gmail.com>
üst c4bc3822
...@@ -119,6 +119,15 @@ public class Document { ...@@ -119,6 +119,15 @@ public class Document {
public static final int KEYBOARD_MODIFIER_MOD2 = 0x4000; public static final int KEYBOARD_MODIFIER_MOD2 = 0x4000;
public static final int KEYBOARD_MODIFIER_MOD3 = 0x8000; 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 final ByteBuffer handle;
private MessageCallback messageCallback = null; private MessageCallback messageCallback = null;
......
...@@ -13,11 +13,18 @@ import java.nio.ByteBuffer; ...@@ -13,11 +13,18 @@ import java.nio.ByteBuffer;
public class Office { public class Office {
private ByteBuffer handle; private ByteBuffer handle;
private MessageCallback messageCallback = null;
public Office(ByteBuffer handle) { public Office(ByteBuffer handle) {
this.handle = handle; this.handle = handle;
bindMessageCallback();
} }
/**
* Bind the signal callback in LOK.
*/
private native void bindMessageCallback();
public native String getError(); public native String getError();
private native ByteBuffer documentLoadNative(String url); private native ByteBuffer documentLoadNative(String url);
...@@ -33,4 +40,33 @@ public class Office { ...@@ -33,4 +40,33 @@ public class Office {
public native void destroy(); public native void destroy();
public native void destroyAndExit(); 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);
}
} }
<?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
...@@ -152,4 +152,9 @@ ...@@ -152,4 +152,9 @@
<string name="calc_optimal_length_default_text">Enter Extra Length in 100th/mm</string> <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> <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> </resources>
...@@ -11,6 +11,7 @@ import org.json.JSONException; ...@@ -11,6 +11,7 @@ import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import org.libreoffice.canvas.SelectionHandle; import org.libreoffice.canvas.SelectionHandle;
import org.libreoffice.kit.Document; import org.libreoffice.kit.Document;
import org.libreoffice.kit.Office;
import org.libreoffice.overlay.DocumentOverlay; import org.libreoffice.overlay.DocumentOverlay;
import org.mozilla.gecko.gfx.GeckoLayerClient; import org.mozilla.gecko.gfx.GeckoLayerClient;
...@@ -21,7 +22,7 @@ import java.util.List; ...@@ -21,7 +22,7 @@ import java.util.List;
/** /**
* Parses (interprets) and handles invalidation messages from LibreOffice. * 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 static String LOGTAG = InvalidationHandler.class.getSimpleName();
private final DocumentOverlay mDocumentOverlay; private final DocumentOverlay mDocumentOverlay;
private final GeckoLayerClient mLayerClient; private final GeckoLayerClient mLayerClient;
...@@ -97,6 +98,9 @@ public class InvalidationHandler implements Document.MessageCallback { ...@@ -97,6 +98,9 @@ public class InvalidationHandler implements Document.MessageCallback {
case Document.CALLBACK_INVALIDATE_HEADER: case Document.CALLBACK_INVALIDATE_HEADER:
invalidateHeader(); invalidateHeader();
break; break;
case Document.CALLBACK_DOCUMENT_PASSWORD:
documentPassword();
break;
default: default:
Log.d(LOGTAG, "LOK_CALLBACK uncaught: " + messageID + " : " + payload); Log.d(LOGTAG, "LOK_CALLBACK uncaught: " + messageID + " : " + payload);
} }
...@@ -106,6 +110,19 @@ public class InvalidationHandler implements Document.MessageCallback { ...@@ -106,6 +110,19 @@ public class InvalidationHandler implements Document.MessageCallback {
LOKitShell.sendEvent(new LOEvent(LOEvent.UPDATE_CALC_HEADERS)); 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) { private void invalidateCellCursor(String payload) {
RectF cellCursorRect = convertPayloadToRectangle(payload); RectF cellCursorRect = convertPayloadToRectangle(payload);
......
...@@ -172,6 +172,7 @@ class LOKitThread extends Thread { ...@@ -172,6 +172,7 @@ class LOKitThread extends Thread {
} }
private void updateZoomConstraints() { private void updateZoomConstraints() {
if (mTileProvider == null) return;
mLayerClient = mContext.getLayerClient(); mLayerClient = mContext.getLayerClient();
if (mTileProvider.isSpreadsheet()) { if (mTileProvider.isSpreadsheet()) {
// Calc has a fixed zoom at 1x and doesn't allow zooming for now // Calc has a fixed zoom at 1x and doesn't allow zooming for now
......
...@@ -50,7 +50,7 @@ class LOKitTileProvider implements TileProvider { ...@@ -50,7 +50,7 @@ class LOKitTileProvider implements TileProvider {
* @param messageCallback - callback for messages retrieved from LOKit * @param messageCallback - callback for messages retrieved from LOKit
* @param input - input path of the document * @param input - input path of the document
*/ */
LOKitTileProvider(LibreOfficeMainActivity context, Document.MessageCallback messageCallback, String input) { LOKitTileProvider(LibreOfficeMainActivity context, InvalidationHandler messageCallback, String input) {
mContext = context; mContext = context;
mMessageCallback = messageCallback; mMessageCallback = messageCallback;
...@@ -58,13 +58,16 @@ class LOKitTileProvider implements TileProvider { ...@@ -58,13 +58,16 @@ class LOKitTileProvider implements TileProvider {
LibreOfficeKit.init(mContext); LibreOfficeKit.init(mContext);
mOffice = new Office(LibreOfficeKit.getLibreOfficeKitHandle()); mOffice = new Office(LibreOfficeKit.getLibreOfficeKitHandle());
mOffice.setMessageCallback(messageCallback);
mOffice.setOptionalFeatures(Document.LOK_FEATURE_DOCUMENT_PASSWORD);
mContext.setTileProvider(this);
mInputFile = input; mInputFile = input;
Log.i(LOGTAG, "====> Loading file '" + input + "'"); Log.i(LOGTAG, "====> Loading file '" + input + "'");
mDocument = mOffice.documentLoad(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"); Log.i(LOGTAG, "====> mOffice.documentLoad() returned null, trying to restart 'Office' and loading again");
mOffice.destroy(); mOffice.destroy();
Log.i(LOGTAG, "====> mOffice.destroy() done"); Log.i(LOGTAG, "====> mOffice.destroy() done");
...@@ -72,6 +75,9 @@ class LOKitTileProvider implements TileProvider { ...@@ -72,6 +75,9 @@ class LOKitTileProvider implements TileProvider {
Log.i(LOGTAG, "====> getLibreOfficeKitHandle() = " + handle); Log.i(LOGTAG, "====> getLibreOfficeKitHandle() = " + handle);
mOffice = new Office(handle); mOffice = new Office(handle);
Log.i(LOGTAG, "====> new Office created"); 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); mDocument = mOffice.documentLoad(input);
} }
...@@ -287,7 +293,7 @@ class LOKitTileProvider implements TileProvider { ...@@ -287,7 +293,7 @@ class LOKitTileProvider implements TileProvider {
} }
} }
if (!ret) { if (!ret && !mContext.isPasswordProtected()) {
final String message = error; final String message = error;
LOKitShell.getMainHandler().post(new Runnable() { LOKitShell.getMainHandler().post(new Runnable() {
@Override @Override
...@@ -295,6 +301,8 @@ class LOKitTileProvider implements TileProvider { ...@@ -295,6 +301,8 @@ class LOKitTileProvider implements TileProvider {
mContext.showAlertDialog(message); mContext.showAlertDialog(message);
} }
}); });
} else if (!ret && mContext.isPasswordProtected()) {
mContext.finish();
} }
return ret; return ret;
...@@ -594,6 +602,14 @@ class LOKitTileProvider implements TileProvider { ...@@ -594,6 +602,14 @@ class LOKitTileProvider implements TileProvider {
return mDocument.getPart(); 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: // vim:set shiftwidth=4 softtabstop=4 expandtab:
...@@ -95,6 +95,9 @@ public class LibreOfficeMainActivity extends AppCompatActivity implements Settin ...@@ -95,6 +95,9 @@ public class LibreOfficeMainActivity extends AppCompatActivity implements Settin
private SearchController mSearchController; private SearchController mSearchController;
private CalcHeadersController mCalcHeadersController; private CalcHeadersController mCalcHeadersController;
private boolean mIsSpreadsheet; private boolean mIsSpreadsheet;
private LOKitTileProvider mTileProvider;
private String mPassword;
private boolean mPasswordProtected;
public GeckoLayerClient getLayerClient() { public GeckoLayerClient getLayerClient() {
return mLayerClient; return mLayerClient;
...@@ -699,6 +702,37 @@ public class LibreOfficeMainActivity extends AppCompatActivity implements Settin ...@@ -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() { public void initializeCalcHeaders() {
mCalcHeadersController = new CalcHeadersController(this, mLayerClient.getView()); mCalcHeadersController = new CalcHeadersController(this, mLayerClient.getView());
mCalcHeadersController.setupHeaderPopupView(); mCalcHeadersController.setupHeaderPopupView();
......
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;
}
}
...@@ -85,6 +85,7 @@ struct CallbackData ...@@ -85,6 +85,7 @@ struct CallbackData
}; };
static CallbackData gCallbackData; static CallbackData gCallbackData;
static CallbackData gCallbackDataLOKit;
/** /**
* Handle retrieved callback * Handle retrieved callback
...@@ -143,6 +144,45 @@ extern "C" SAL_JNI_EXPORT jobject JNICALL Java_org_libreoffice_kit_Office_docume ...@@ -143,6 +144,45 @@ extern "C" SAL_JNI_EXPORT jobject JNICALL Java_org_libreoffice_kit_Office_docume
return aHandle; 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 */ /* Document */
/** Implementation of org.libreoffice.kit.Document.bindMessageCallback method */ /** Implementation of org.libreoffice.kit.Document.bindMessageCallback method */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment