> For the complete documentation index, see [llms.txt](https://docs.apryse.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.apryse.com/android/get-started/samples/undoredotest.md).

# UndoRedoTest

Sample Java code for using Apryse SDK to take snapshots of edits and move between them using the API.

The Apryse SDK has a low-level facility for undo and redo operations. It is a API that applies to any edits made to a particular document (not just annotations). This sample Java code shows how to use Apryse SDK to walk back and forth on a fully general, bit-exact list of document states. Saving changes in a mode that is not 'incremental' will wipe out the undo-redo state list; the API will not be able to access old snapshots anymore. See the [undoing and redoing guide](/core/pdf-editing/undoredo.md) for more information. Learn more about our [Android SDK](/core/get-started/languages/java.md).

{% tabs %}
{% tab title="Java" %}
{% code lineNumbers="true" %}

```java
package com.pdftron.android.pdfnetsdksamples.samples;//---------------------------------------------------------------------------------------
// Copyright (c) 2001-2019 by PDFTron Systems Inc. All Rights Reserved.
// Consult legal.txt regarding legal and license information.
//---------------------------------------------------------------------------------------

import com.pdftron.android.pdfnetsdksamples.OutputListener;
import com.pdftron.android.pdfnetsdksamples.PDFNetSample;
import com.pdftron.android.pdfnetsdksamples.R;
import com.pdftron.android.pdfnetsdksamples.util.Utils;
import com.pdftron.common.Matrix2D;
import com.pdftron.pdf.Element;
import com.pdftron.pdf.ElementBuilder;
import com.pdftron.pdf.ElementWriter;
import com.pdftron.pdf.Image;
import com.pdftron.pdf.PDFDoc;
import com.pdftron.pdf.Page;
import com.pdftron.sdf.DocSnapshot;
import com.pdftron.sdf.ResultSnapshot;
import com.pdftron.sdf.SDFDoc;
import com.pdftron.sdf.UndoManager;

import java.util.ArrayList;

//---------------------------------------------------------------------------------------
// The following sample illustrates how to use the UndoRedo API.
//---------------------------------------------------------------------------------------
public class UndoRedoTest extends PDFNetSample {

	private static OutputListener mOutputListener;

	private static ArrayList<String> mFileList = new ArrayList<>();

    public UndoRedoTest() {
        setTitle(R.string.sample_undoredo_title);
        setDescription(R.string.sample_undoredo_description);
    }

	@Override
	public void run(OutputListener outputListener) {
		super.run(outputListener);
		mOutputListener = outputListener;
		mFileList.clear();
		printHeader(outputListener);
		try 
		{
			// The first step in every application using PDFNet is to initialize the
			// library and set the path to common PDF resources. The library is usually
			// initialized only once, but calling Initialize() multiple times is also fine.

			// Open the PDF document.
			try (PDFDoc doc = new PDFDoc(Utils.getAssetTempFile(INPUT_PATH + "newsletter.pdf").getAbsolutePath())) {

				UndoManager undo_manager = doc.getUndoManager();

				// Take a snapshot to which we can undo after making changes.
				ResultSnapshot snap0 = undo_manager.takeSnapshot();

				DocSnapshot snap0_state = snap0.currentState();
				
				Page page = doc.pageCreate();	// Start a new page

				ElementBuilder bld = new ElementBuilder();		// Used to build new Element objects
				ElementWriter writer = new ElementWriter();		// Used to write Elements to the page	
				writer.begin(page);		// Begin writing to this page

				// ----------------------------------------------------------
				// Add JPEG image to the file
				Image img = Image.create(doc, Utils.getAssetTempFile(INPUT_PATH + "peppers.jpg").getAbsolutePath());
				Element element = bld.createImage(img, new Matrix2D(200, 0, 0, 250, 50, 500));
				writer.writePlacedElement(element);

				writer.end();	// Finish writing to the page
				doc.pagePushFront(page);

				// Take a snapshot after making changes, so that we can redo later (after undoing first).
				ResultSnapshot snap1 = undo_manager.takeSnapshot();

				if (snap1.previousState().equals(snap0_state))
				{
					mOutputListener.println("snap1 previous state equals snap0_state; previous state is correct");
				}
				
				DocSnapshot snap1_state = snap1.currentState();

				doc.save(Utils.createExternalFile("addimage.pdf", mFileList).getAbsolutePath(), SDFDoc.SaveMode.INCREMENTAL, null);

				if (undo_manager.canUndo())
				{
					ResultSnapshot undo_snap;
					undo_snap = undo_manager.undo();

					doc.save(Utils.createExternalFile("addimage_undone.pdf", mFileList).getAbsolutePath(), SDFDoc.SaveMode.INCREMENTAL, null);

					DocSnapshot undo_snap_state = undo_snap.currentState();

					if (undo_snap_state.equals(snap0_state))
					{
						mOutputListener.println("undo_snap_state equals snap0_state; undo was successful");
					}
					
					if (undo_manager.canRedo())
					{
						ResultSnapshot redo_snap = undo_manager.redo();

						doc.save(Utils.createExternalFile("addimage_redone.pdf", mFileList).getAbsolutePath(), SDFDoc.SaveMode.INCREMENTAL, null);

						if (redo_snap.previousState().equals(undo_snap_state))
						{
							mOutputListener.println("redo_snap previous state equals undo_snap_state; previous state is correct");
						}
						
						DocSnapshot redo_snap_state = redo_snap.currentState();
						
						if (redo_snap_state.equals(snap1_state))
						{
							mOutputListener.println("Snap1 and redo_snap are equal; redo was successful");
						}
					}
					else
					{
						mOutputListener.println("Problem encountered - cannot redo.");
					}
				}
				else
				{
					mOutputListener.println("Problem encountered - cannot undo.");
				}
			}

			// Calling Terminate when PDFNet is no longer in use is a good practice, but
			// is not required.
		}
		catch (Exception e) 
		{
			mOutputListener.printError(e.getStackTrace());
		}

		for (String file : mFileList) {
			addToFileList(file);
		}
		printFooter(outputListener);
	}

}
```

{% endcode %}
{% endtab %}

{% tab title="Kotlin" %}
{% code lineNumbers="true" %}

```kotlin
package com.pdftron.android.pdfnetsdksamples.samples

//---------------------------------------------------------------------------------------
// Copyright (c) 2001-2019 by PDFTron Systems Inc. All Rights Reserved.
// Consult legal.txt regarding legal and license information.
//---------------------------------------------------------------------------------------

import com.pdftron.android.pdfnetsdksamples.OutputListener
import com.pdftron.android.pdfnetsdksamples.PDFNetSample
import com.pdftron.android.pdfnetsdksamples.R
import com.pdftron.android.pdfnetsdksamples.util.Utils
import com.pdftron.common.Matrix2D
import com.pdftron.pdf.ElementBuilder
import com.pdftron.pdf.ElementWriter
import com.pdftron.pdf.Image
import com.pdftron.pdf.PDFDoc
import com.pdftron.sdf.ResultSnapshot
import com.pdftron.sdf.SDFDoc
import java.util.*

//---------------------------------------------------------------------------------------
// The following sample illustrates how to use the UndoRedo API.
//---------------------------------------------------------------------------------------
class UndoRedoTest : PDFNetSample() {
    init {
        setTitle(R.string.sample_undoredo_title)
        setDescription(R.string.sample_undoredo_description)
    }

    override fun run(outputListener: OutputListener?) {
        super.run(outputListener)
        mOutputListener = outputListener
        mFileList.clear()
        printHeader(outputListener!!)
        try {
            // The first step in every application using PDFNet is to initialize the
            // library and set the path to common PDF resources. The library is usually
            // initialized only once, but calling Initialize() multiple times is also fine.

            // Open the PDF document.
            PDFDoc(Utils.getAssetTempFile(PDFNetSample.INPUT_PATH + "newsletter.pdf")!!.absolutePath).use { doc ->
                val undo_manager = doc.undoManager

                // Take a snapshot to which we can undo after making changes.
                val snap0 = undo_manager.takeSnapshot()

                val snap0_state = snap0.currentState()

                val page = doc.pageCreate()    // Start a new page

                val bld = ElementBuilder()        // Used to build new Element objects
                val writer = ElementWriter()        // Used to write Elements to the page
                writer.begin(page)        // Begin writing to this page

                // ----------------------------------------------------------
                // Add JPEG image to the file
                val img = Image.create(doc, Utils.getAssetTempFile(PDFNetSample.INPUT_PATH + "peppers.jpg")!!.absolutePath)
                val element = bld.createImage(img, Matrix2D(200.0, 0.0, 0.0, 250.0, 50.0, 500.0))
                writer.writePlacedElement(element)

                writer.end()    // Finish writing to the page
                doc.pagePushFront(page)

                // Take a snapshot after making changes, so that we can redo later (after undoing first).
                val snap1 = undo_manager.takeSnapshot()

                if (snap1.previousState().equals(snap0_state)) {
                    mOutputListener!!.println("snap1 previous state equals snap0_state; previous state is correct")
                }

                val snap1_state = snap1.currentState()

                doc.save(Utils.createExternalFile("addimage.pdf", mFileList).absolutePath, SDFDoc.SaveMode.INCREMENTAL, null)

                if (undo_manager.canUndo()) {
                    val undo_snap: ResultSnapshot
                    undo_snap = undo_manager.undo()

                    doc.save(Utils.createExternalFile("addimage_undone.pdf", mFileList).absolutePath, SDFDoc.SaveMode.INCREMENTAL, null)

                    val undo_snap_state = undo_snap.currentState()

                    if (undo_snap_state.equals(snap0_state)) {
                        mOutputListener!!.println("undo_snap_state equals snap0_state; undo was successful")
                    }

                    if (undo_manager.canRedo()) {
                        val redo_snap = undo_manager.redo()

                        doc.save(Utils.createExternalFile("addimage_redone.pdf", mFileList).absolutePath, SDFDoc.SaveMode.INCREMENTAL, null)

                        if (redo_snap.previousState().equals(undo_snap_state)) {
                            mOutputListener!!.println("redo_snap previous state equals undo_snap_state; previous state is correct")
                        }

                        val redo_snap_state = redo_snap.currentState()

                        if (redo_snap_state.equals(snap1_state)) {
                            mOutputListener!!.println("Snap1 and redo_snap are equal; redo was successful")
                        }
                    } else {
                        mOutputListener!!.println("Problem encountered - cannot redo.")
                    }
                } else {
                    mOutputListener!!.println("Problem encountered - cannot undo.")
                }
                // Calling Terminate when PDFNet is no longer in use is a good practice, but
                // is not required.
            }
        } catch (e: Exception) {
            mOutputListener!!.printError(e.stackTrace)
        }

        for (file in mFileList) {
            addToFileList(file)
        }
        printFooter(outputListener)
    }

    companion object {

        private var mOutputListener: OutputListener? = null

        private val mFileList = ArrayList<String>()
    }

}
```

{% endcode %}
{% endtab %}
{% endtabs %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.apryse.com/android/get-started/samples/undoredotest.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
