Introduction
MuPDF Android App Kit
MuPDF iOS App Kit
Download App Kit

Document Lifecycle

Lifecycle

PDF documents in App Kit are always rendered inside a document view instance. Files which require to instantiate and access document views should reference the following:

Kotlin
import com.artifex.sonui.editor.DocumentView
Java
import com.artifex.sonui.editor.DocumentView;

Your Android Activity should handle the regular Android Activity Lifecycle events and inform any DocumentView instance of the corresponding Activity events. Additionally Activity interfaces require to be setup for full App Kit functionality.

For the Custom UI, there are also a set of common document events during the lifecycle of a document. An application developer can set up Listeners to respond to these events as required.

Activity events

Other events should be passed through to your DocumentView instance as follows:

Kotlin
public override fun onPause() {
    mDocumentView?.onPause()
    super.onPause()
}

override fun onResume() {
    super.onResume()
    mDocumentView?.onResume()
}

override fun onDestroy() {
    super.onDestroy()
    mDocumentView?.onDestroy()
}

override fun onBackPressed() {
    mDocumentView?.onBackPressed()
}

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    mDocumentView?.onActivityResult(requestCode, resultCode, data)
}

override fun onConfigurationChanged(newConfig: Configuration) {
    super.onConfigurationChanged(newConfig)
    mDocumentView?.onConfigurationChange(newConfig)
}
Java
@Override
public void onPause() {
    if (mDocumentView != null)
        mDocumentView.onPause();
    super.onPause();
}

@Override
protected void onResume() {
    super.onResume();
    if (mDocumentView != null)
        mDocumentView.onResume();
}

@Override
protected void onDestroy() {
    super.onDestroy();
    if (mDocumentView != null)
        mDocumentView.onDestroy();
}

@Override
public void onBackPressed() {
    if (mDocumentView != null)
        mDocumentView.onBackPressed();
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (mDocumentView != null)
        mDocumentView.onActivityResult(requestCode, resultCode, data);
}

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);

    if (mDocumentView != null)
        mDocumentView.onConfigurationChange(newConfig);
}

NOTE
The above events with their corresponding document view calls are critical for document text editing and selection.

Activity interfaces

Security setup

There are four interfaces that should be implemented via your own custom classes in order to get the full functionality of App Kit.

NOTE
There are no defaults for these interfaces.

These interfaces are specifically important when considering a Custom UI approach.

SODataLeakHandlers

SODataLeakHandlers is a Java interface that provides hooks for an app to control file saving and other functions. An application developer should provide their own implementation of this class as follows:

Kotlin

MyOwnDataLeakHandlers.kt

import android.app.Activity
import android.content.Intent
import com.artifex.solib.ArDkDoc
import com.artifex.solib.ConfigOptions
import com.artifex.sonui.editor.NUIDocView
import com.artifex.sonui.editor.SOCustomSaveComplete
import com.artifex.sonui.editor.SODataLeakHandlers
import com.artifex.sonui.editor.SOSaveAsComplete

class MyOwnDataLeakHandlers : SODataLeakHandlers {
    override fun initDataLeakHandlers(p0: Activity?, p1: ConfigOptions?) {
        TODO("Not yet implemented")
    }

    override fun finaliseDataLeakHandlers() {
        TODO("Not yet implemented")
    }

    override fun onActivityResult(p0: Int, p1: Int, p2: Intent?) {
        TODO("Not yet implemented")
    }

    override fun insertImageHandler(p0: NUIDocView?) {
        TODO("Not yet implemented")
    }

    override fun insertPhotoHandler(p0: NUIDocView?) {
        TODO("Not yet implemented")
    }

    override fun pauseHandler(p0: ArDkDoc?, p1: Boolean, p2: Runnable?) {
        TODO("Not yet implemented")
    }

    override fun doInsert() {
        TODO("Not yet implemented")
    }

    override fun printHandler(p0: ArDkDoc?) {
        TODO("Not yet implemented")
    }

    override fun launchUrlHandler(p0: String?) {
        TODO("Not yet implemented")
    }

    override fun customSaveHandler(
        p0: String?,
        p1: ArDkDoc?,
        p2: String?,
        p3: SOCustomSaveComplete?
    ) {
        TODO("Not yet implemented")
    }

    override fun saveAsHandler(p0: String?, p1: ArDkDoc?, p2: SOSaveAsComplete?) {
        TODO("Not yet implemented")
    }

    override fun postSaveHandler(p0: SOSaveAsComplete?) {
        TODO("Not yet implemented")
    }

    override fun saveAsPdfHandler(p0: String?, p1: ArDkDoc?) {
        TODO("Not yet implemented")
    }

    override fun openInHandler(p0: String?, p1: ArDkDoc?) {
        TODO("Not yet implemented")
    }

    override fun openPdfInHandler(p0: String?, p1: ArDkDoc?) {
        TODO("Not yet implemented")
    }

    override fun shareHandler(p0: String?, p1: ArDkDoc?) {
        TODO("Not yet implemented")
    }
}
Java

MyOwnDataLeakHandlers.java

import android.app.Activity;
import android.content.Intent;

import com.artifex.solib.ArDkDoc;
import com.artifex.solib.ConfigOptions;
import com.artifex.sonui.editor.NUIDocView;
import com.artifex.sonui.editor.SOCustomSaveComplete;
import com.artifex.sonui.editor.SODataLeakHandlers;
import com.artifex.sonui.editor.SOSaveAsComplete;

import java.io.IOException;

public class MyOwnDataLeakHandlers implements SODataLeakHandlers {

    @Override
    public void initDataLeakHandlers(Activity activity, ConfigOptions configOptions) throws IOException {

    }

    @Override
    public void finaliseDataLeakHandlers() {

    }

    @Override
    public void onActivityResult(int i, int i1, Intent intent) {

    }

    @Override
    public void insertImageHandler(NUIDocView nuiDocView) throws UnsupportedOperationException {

    }

    @Override
    public void insertPhotoHandler(NUIDocView nuiDocView) throws UnsupportedOperationException {

    }

    @Override
    public void pauseHandler(ArDkDoc arDkDoc, boolean b, Runnable runnable) {

    }

    @Override
    public void doInsert() {

    }

    @Override
    public void printHandler(ArDkDoc arDkDoc) throws UnsupportedOperationException {

    }

    @Override
    public void launchUrlHandler(String s) throws UnsupportedOperationException {

    }

    @Override
    public void customSaveHandler(String s, ArDkDoc arDkDoc, String s1, SOCustomSaveComplete soCustomSaveComplete) throws UnsupportedOperationException, IOException {

    }

    @Override
    public void saveAsHandler(String s, ArDkDoc arDkDoc, SOSaveAsComplete soSaveAsComplete) throws UnsupportedOperationException {

    }

    @Override
    public void postSaveHandler(SOSaveAsComplete soSaveAsComplete) {

    }

    @Override
    public void saveAsPdfHandler(String s, ArDkDoc arDkDoc) throws UnsupportedOperationException {

    }

    @Override
    public void openInHandler(String s, ArDkDoc arDkDoc) throws UnsupportedOperationException {

    }

    @Override
    public void openPdfInHandler(String s, ArDkDoc arDkDoc) throws UnsupportedOperationException {

    }

    @Override
    public void shareHandler(String s, ArDkDoc arDkDoc) throws UnsupportedOperationException {

    }
}

SOPersistentStorage

SOPersistentStorage is an interface that specifies the basis for implementing a class allowing for storage/retrieval of key/value pairs. An application developer should provide their own implementation of this class as follows:

Kotlin

MyOwnPersistentStorage.kt

import android.content.Context
import com.artifex.sonui.editor.SOPersistentStorage

class MyOwnPersistentStorage : SOPersistentStorage {
    override fun getStorageObject(p0: Context?, p1: String?): Any {
        TODO("Not yet implemented")
    }

    override fun setStringPreference(p0: Any?, p1: String?, p2: String?) {
        TODO("Not yet implemented")
    }

    override fun getStringPreference(p0: Any?, p1: String?, p2: String?): String {
        TODO("Not yet implemented")
    }

    override fun getAllStringPreferences(p0: Any?): MutableMap<String, *> {
        TODO("Not yet implemented")
    }

    override fun removePreference(p0: Any?, p1: String?) {
        TODO("Not yet implemented")
    }
}
Java

MyOwnPersistentStorage.java

import android.content.Context;
import com.artifex.sonui.editor.SOPersistentStorage;
import java.util.Map;

public class MyOwnPersistentStorage implements SOPersistentStorage {
    @Override
    public Object getStorageObject(Context context, String s) {
        return null;
    }

    @Override
    public void setStringPreference(Object o, String s, String s1) {

    }

    @Override
    public String getStringPreference(Object o, String s, String s1) {
        return null;
    }

    @Override
    public Map<String, ?> getAllStringPreferences(Object o) {
        return null;
    }

    @Override
    public void removePreference(Object o, String s) {

    }
}

SOClipboardHandler

SOClipboardHandler is an interface that specifies the basis for implementing a class to handle clipboard actions for the document editor. An application developer should provide their own implementation of this class as follows:

Kotlin

MyOwnClipboardHandler.kt

import android.app.Activity
import com.artifex.solib.SOClipboardHandler

class MyOwnClipboardHandler : SOClipboardHandler {
    override fun putPlainTextToClipboard(p0: String?) {
        TODO("Not yet implemented")
    }

    override fun getPlainTextFromClipoard(): String {
        TODO("Not yet implemented")
    }

    override fun clipboardHasPlaintext(): Boolean {
        TODO("Not yet implemented")
    }

    override fun initClipboardHandler(p0: Activity?) {
        TODO("Not yet implemented")
    }
}
Java

MyOwnClipboardHandler.java

import android.app.Activity;
import com.artifex.solib.SOClipboardHandler;

public class MyOwnClipboardHander implements SOClipboardHandler {

    @Override
    public void putPlainTextToClipboard(String s) {

    }

    @Override
    public String getPlainTextFromClipoard() {
        return null;
    }

    @Override
    public boolean clipboardHasPlaintext() {
        return false;
    }

    @Override
    public void initClipboardHandler(Activity activity) {

    }
}

SOSecureFS

SOSecureFS is an interface that specifies the basis for implementing a class allowing proprietary encrypted files, stored in a secure container. All file i/o done by the core library is passed through this class. A developer can use this opportunity to enforce security and role restrictions, or map the file operations onto another mechanism such as a database. An application developer should provide their own implementation of this class as follows:

Kotlin

MyOwnSecureFS.kt

import com.artifex.solib.SOSecureFS

class MyOwnSecureFS : SOSecureFS {
    override fun isSecurePath(p0: String?): Boolean {
        TODO("Not yet implemented")
    }

    override fun getTempPath(): String {
        TODO("Not yet implemented")
    }

    override fun getFileAttributes(p0: String?): SOSecureFS.FileAttributes {
        TODO("Not yet implemented")
    }

    override fun renameFile(p0: String?, p1: String?): Boolean {
        TODO("Not yet implemented")
    }

    override fun copyFile(p0: String?, p1: String?): Boolean {
        TODO("Not yet implemented")
    }

    override fun deleteFile(p0: String?): Boolean {
        TODO("Not yet implemented")
    }

    override fun fileExists(p0: String?): Boolean {
        TODO("Not yet implemented")
    }

    override fun recursivelyRemoveDirectory(p0: String?): Boolean {
        TODO("Not yet implemented")
    }

    override fun createDirectory(p0: String?): Boolean {
        TODO("Not yet implemented")
    }

    override fun createFile(p0: String?): Boolean {
        TODO("Not yet implemented")
    }

    override fun getFileHandleForReading(p0: String?): Any {
        TODO("Not yet implemented")
    }

    override fun getFileHandleForWriting(p0: String?): Any {
        TODO("Not yet implemented")
    }

    override fun getFileHandleForUpdating(p0: String?): Any {
        TODO("Not yet implemented")
    }

    override fun closeFile(p0: Any?): Boolean {
        TODO("Not yet implemented")
    }

    override fun setFileLength(p0: Any?, p1: Long): Boolean {
        TODO("Not yet implemented")
    }

    override fun readFromFile(p0: Any?, p1: ByteArray?): Int {
        TODO("Not yet implemented")
    }

    override fun writeToFile(p0: Any?, p1: ByteArray?): Int {
        TODO("Not yet implemented")
    }

    override fun syncFile(p0: Any?): Boolean {
        TODO("Not yet implemented")
    }

    override fun getFileLength(p0: Any?): Long {
        TODO("Not yet implemented")
    }

    override fun getFileOffset(p0: Any?): Long {
        TODO("Not yet implemented")
    }

    override fun seekToFileOffset(p0: Any?, p1: Long): Boolean {
        TODO("Not yet implemented")
    }

    override fun getSecurePath(): String {
        TODO("Not yet implemented")
    }

    override fun getSecurePrefix(): String {
        TODO("Not yet implemented")
    }
}
Java
import com.artifex.solib.SOSecureFS;

public class MyOwnSecureFS implements SOSecureFS {

    @Override
    public boolean isSecurePath(String s) {
        return false;
    }

    @Override
    public String getTempPath() {
        return null;
    }

    @Override
    public FileAttributes getFileAttributes(String s) {
        return null;
    }

    @Override
    public boolean renameFile(String s, String s1) {
        return false;
    }

    @Override
    public boolean copyFile(String s, String s1) {
        return false;
    }

    @Override
    public boolean deleteFile(String s) {
        return false;
    }

    @Override
    public boolean fileExists(String s) {
        return false;
    }

    @Override
    public boolean recursivelyRemoveDirectory(String s) {
        return false;
    }

    @Override
    public boolean createDirectory(String s) {
        return false;
    }

    @Override
    public boolean createFile(String s) {
        return false;
    }

    @Override
    public Object getFileHandleForReading(String s) {
        return null;
    }

    @Override
    public Object getFileHandleForWriting(String s) {
        return null;
    }

    @Override
    public Object getFileHandleForUpdating(String s) {
        return null;
    }

    @Override
    public boolean closeFile(Object o) {
        return false;
    }

    @Override
    public boolean setFileLength(Object o, long l) {
        return false;
    }

    @Override
    public int readFromFile(Object o, byte[] bytes) {
        return 0;
    }

    @Override
    public int writeToFile(Object o, byte[] bytes) {
        return 0;
    }

    @Override
    public boolean syncFile(Object o) {
        return false;
    }

    @Override
    public long getFileLength(Object o) {
        return 0;
    }

    @Override
    public long getFileOffset(Object o) {
        return 0;
    }

    @Override
    public boolean seekToFileOffset(Object o, long l) {
        return false;
    }

    @Override
    public String getSecurePath() {
        return null;
    }

    @Override
    public String getSecurePrefix() {
        return null;
    }
}

Taken together, these classes can be used to implement security at all the points where a user’s data might flow into, or out of, the application.

The following code ( with it's own implementations of the above four classes as required ) should be invoked at the start of your app's main activity.

Kotlin
import com.artifex.solib.*
import com.artifex.sonui.editor.Utilities

private var isSetup: Boolean = false
public override fun onCreate(savedInstanceState: Bundle) {
    super.onCreate(savedInstanceState)

    if (!isSetup) {
        Utilities.setDataLeakHandlers(MyOwnDataLeakHandlers())
        Utilities.setPersistentStorage(MyOwnPersistentStorage())
        ArDkLib.setClipboardHandler(MyOwnClipboardHandler())
        ArDkLib.setSecureFS(MyOwnSecureFS())
        FileUtils.init(this)
        isSetup = true
    }

    ...

}
Java
import com.artifex.solib.*;
import com.artifex.sonui.editor.Utilities;

private static boolean isSetup = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    //  create/register handlers (but only once)
    if (!isSetup) {
        Utilities.setDataLeakHandlers(new MyOwnDataLeakHandlers());
        Utilities.setPersistentStorage(new MyOwnPersistentStorage());
        SOLib.setClipboardHandler(new MyOwnClipboardHandler());
        SOLib.setSecureFS(new MyOwnSecureFS());
        isSetup = true;
    }

    ...
}