diff --git a/README.md b/README.md index d9a5e79..b6cf2fd 100644 --- a/README.md +++ b/README.md @@ -163,8 +163,9 @@ A few notes: - For text, please use `DocumentTextView`: it will notify the parent when it gets bigger. - For editable text, please use `DocumentEditText`: same as above. - If using app compat, you might want to use the `AppCompat-` version of these widgets. -- We can't split text of a single view into multiple pages or columns. +- We can't split text of a single view into multiple pages or columns (for now). It is your responsibility to have Views that are small enough to avoid blank spaces. +- For custom views, take a look at `DocumentHelper` methods. To enable columns, use `document.setColumnsPerPage(int)` or the XML attribute `app:columnsPerPage`. @@ -230,7 +231,10 @@ You must have appropriate permissions to write the file in that location. On Marshmallow+, these permissions must be explicitly asked to the user. The library currently will automatically ask the `READ_EXTERNAL_STORAGE` and `WRITE_EXTERNAL_STORAGE` -permissions (this can be improved though). Make sure you implement `onRequestPermissionResult`: +permissions if the output file appears to be in the external storage. Make sure you + +- declare these permissions in your manifest +- implement `onRequestPermissionResult` as such: ```java @Override diff --git a/demo/src/main/AndroidManifest.xml b/demo/src/main/AndroidManifest.xml index 22396bc..a325af8 100644 --- a/demo/src/main/AndroidManifest.xml +++ b/demo/src/main/AndroidManifest.xml @@ -2,6 +2,9 @@ + + + - - - diff --git a/library/src/main/java/com/otaliastudios/printer/BitmapPrinter.java b/library/src/main/java/com/otaliastudios/printer/BitmapPrinter.java index a6ff9b5..e3d2d38 100644 --- a/library/src/main/java/com/otaliastudios/printer/BitmapPrinter.java +++ b/library/src/main/java/com/otaliastudios/printer/BitmapPrinter.java @@ -100,11 +100,11 @@ public void setPrintScale(int maxWidth, int maxHeight) { @Override public void print(final String printId, @NonNull final File directory, @NonNull String filename) { Context context = mDocument.getContext(); - if (!checkPermission(context)) return; + if (!checkPermission(context, directory)) return; if (!checkPreview(printId, directory, filename)) return; if (filename.toLowerCase().endsWith(mFormat)) { - filename = filename.substring(0, filename.length() - 4); + filename = filename.substring(0, filename.length() - mFormat.length()); } if (mDocument.getPageCount() == 0) return; diff --git a/library/src/main/java/com/otaliastudios/printer/Container.java b/library/src/main/java/com/otaliastudios/printer/Container.java index dae30ea..54d450c 100644 --- a/library/src/main/java/com/otaliastudios/printer/Container.java +++ b/library/src/main/java/com/otaliastudios/printer/Container.java @@ -110,9 +110,8 @@ interface Container { * - check if {@code child} can get some views from the next child * * @param child the container notifying us - * @param space the available space */ - void onSpaceAvailable(Child child, int space); + void onSpaceAvailable(Child child); /** * Our child notifies that he has no more space, and some of the views would actually diff --git a/library/src/main/java/com/otaliastudios/printer/DocumentColumn.java b/library/src/main/java/com/otaliastudios/printer/DocumentColumn.java index 732dceb..5437b40 100644 --- a/library/src/main/java/com/otaliastudios/printer/DocumentColumn.java +++ b/library/src/main/java/com/otaliastudios/printer/DocumentColumn.java @@ -27,7 +27,7 @@ class DocumentColumn extends LinearLayout implements Container oldHeight) return; // Nothing to do, hope we get calls to notifyTooSmall. - if (mAvailableSpace <= 0) return; + if (space <= 0) return; // Go out of the layout pass, it's not safe to pass views around during layout, // even if you use addViewInLayout or removeViewInLayout. - final int availableSpace = mAvailableSpace; post(new Runnable() { @Override public void run() { mLog.i("onLayoutChange:", "page:", pn, "dispatching onSpaceAvailable."); - getRoot().onSpaceAvailable(DocumentColumn.this, availableSpace); + getRoot().onSpaceAvailable(DocumentColumn.this); } }); } diff --git a/library/src/main/java/com/otaliastudios/printer/DocumentTextHelper.java b/library/src/main/java/com/otaliastudios/printer/DocumentHelper.java similarity index 56% rename from library/src/main/java/com/otaliastudios/printer/DocumentTextHelper.java rename to library/src/main/java/com/otaliastudios/printer/DocumentHelper.java index c9f349b..bbdca1a 100644 --- a/library/src/main/java/com/otaliastudios/printer/DocumentTextHelper.java +++ b/library/src/main/java/com/otaliastudios/printer/DocumentHelper.java @@ -9,32 +9,42 @@ import com.otaliastudios.printer.view.DocumentTextView; /** - * Static utilities for text containers that might become smaller than they would like to, - * without notifying the parent. + * Static utilities for views that might become smaller than they would like to, + * without notifying the parent. In that case we want to move them to the next page, for example. * - * It is recommended that they call {@link #onLayout(View)} here to have our splitting - * policy working. + * It is recommended that these views call {@link #onLayout(View)} to let us determine if they would + * like to be bigger, or {@link #onSpaceOver(View)} if they have already determined that. * - * @see DocumentTextView - * @see DocumentEditText */ -public class DocumentTextHelper { +public class DocumentHelper { - private final static String TAG = DocumentTextHelper.class.getSimpleName(); + private final static String TAG = DocumentHelper.class.getSimpleName(); private final static PrinterLogger LOG = PrinterLogger.create(TAG); + /** + * To be called after the View has been laid out. If the view is presumably to small, + * this will call {@link #onSpaceOver(View)} for you. + * + * @param view The view that has been laid out + */ public static void onLayout(View view) { if (view.getLayoutParams().height == ViewGroup.LayoutParams.WRAP_CONTENT) { - LOG.i("onLayout:", "We are wrap content. Looking if we can scroll."); // TODO: don't do this if getMaxLines is >= 0 (< MAX_VALUE). Same for getMaxheight. if (view.canScrollVertically(-1) || view.canScrollVertically(1)) { LOG.w("onLayout:", "We can scroll. Notifying the parent column."); - notifyContainer(view); + onSpaceOver(view); } } } - private static void notifyContainer(View view) { + /** + * Notifies the {@link DocumentView} that this view would like to be bigger than + * it actually is. This might trigger a re-layout, for example moving the view to the + * next page. + * + * @param view The view that would like to be bigger + */ + public static void onSpaceOver(View view) { Container container = null; View current = view; while (true) { diff --git a/library/src/main/java/com/otaliastudios/printer/DocumentPage.java b/library/src/main/java/com/otaliastudios/printer/DocumentPage.java index 419af5f..98a8570 100644 --- a/library/src/main/java/com/otaliastudios/printer/DocumentPage.java +++ b/library/src/main/java/com/otaliastudios/printer/DocumentPage.java @@ -266,7 +266,7 @@ public boolean contains(View view) { } @Override - public void onSpaceAvailable(DocumentColumn child, int space) { + public void onSpaceAvailable(DocumentColumn child) { Utils.clearUntakableView(child); mLog.i("onSpaceAvailable:", "fromColumn:", child.getNumber()); @@ -286,9 +286,7 @@ public void onSpaceAvailable(DocumentColumn child, int space) { DocumentColumn next = mColumns.get(which + 1); while (tryPassFirstViewToPrevious(next, child)) {} // try until it stops } else { - // TODO: the 'space' value at this point might not be meaningful - // (might be bigger if we gave something to previous column). But it's unused - getRoot().onSpaceAvailable(this, space); + getRoot().onSpaceAvailable(this); } } diff --git a/library/src/main/java/com/otaliastudios/printer/DocumentPager.java b/library/src/main/java/com/otaliastudios/printer/DocumentPager.java index d6fccec..df7027c 100644 --- a/library/src/main/java/com/otaliastudios/printer/DocumentPager.java +++ b/library/src/main/java/com/otaliastudios/printer/DocumentPager.java @@ -318,7 +318,7 @@ public boolean contains(View view) { } @Override - public void onSpaceAvailable(DocumentPage child, int space) { + public void onSpaceAvailable(DocumentPage child) { Utils.clearUntakableView(child); LOG.i("onSpaceAvailable:", "fromPage:", child.getNumber()); diff --git a/library/src/main/java/com/otaliastudios/printer/PdfPrinter.java b/library/src/main/java/com/otaliastudios/printer/PdfPrinter.java index 828234e..5e36c64 100644 --- a/library/src/main/java/com/otaliastudios/printer/PdfPrinter.java +++ b/library/src/main/java/com/otaliastudios/printer/PdfPrinter.java @@ -47,7 +47,7 @@ public PdfPrinter(@NonNull DocumentView document, @NonNull PrintCallback callbac @Override public void print(final String printId, @NonNull final File directory, @NonNull String filename) { Context context = mDocument.getContext(); - if (!checkPermission(context)) return; + if (!checkPermission(context, directory)) return; if (!checkPreview(printId, directory, filename)) return; if (!filename.toLowerCase().endsWith(".pdf")) filename += ".pdf"; final File file = new File(directory, filename); diff --git a/library/src/main/java/com/otaliastudios/printer/Printer.java b/library/src/main/java/com/otaliastudios/printer/Printer.java index 57aaade..41b5d89 100644 --- a/library/src/main/java/com/otaliastudios/printer/Printer.java +++ b/library/src/main/java/com/otaliastudios/printer/Printer.java @@ -7,12 +7,16 @@ import android.content.ContextWrapper; import android.content.pm.PackageManager; import android.os.Build; +import android.os.Environment; import android.support.annotation.CallSuper; import android.support.annotation.NonNull; import android.view.ViewTreeObserver; import java.io.File; import java.io.IOException; +import java.net.URI; +import java.nio.file.Path; +import java.nio.file.Paths; /** * A general interface for engines that can print view hierarchies to some sort or file or folder. @@ -57,7 +61,16 @@ public void onGlobalLayout() { return true; } - boolean checkPermission(Context context) { + boolean checkPermission(Context context, File directory) { + // Check external permissions... But only if the directory is external. + // For external dirs, this still implies that the developers add the permissions to their manifest. + + // Could be better, but anyway.. + File ext = Environment.getExternalStorageDirectory(); + if (!directory.getAbsolutePath().startsWith(ext.getAbsolutePath())) { + return true; // Not external + } + if (Build.VERSION.SDK_INT < 23) return true; String[] permissions = new String[2]; diff --git a/library/src/main/java/com/otaliastudios/printer/view/AppCompatDocumentEditText.java b/library/src/main/java/com/otaliastudios/printer/view/AppCompatDocumentEditText.java index d5060f8..4c40d7e 100644 --- a/library/src/main/java/com/otaliastudios/printer/view/AppCompatDocumentEditText.java +++ b/library/src/main/java/com/otaliastudios/printer/view/AppCompatDocumentEditText.java @@ -6,7 +6,7 @@ import android.support.v7.widget.AppCompatEditText; import android.util.AttributeSet; -import com.otaliastudios.printer.DocumentTextHelper; +import com.otaliastudios.printer.DocumentHelper; import com.otaliastudios.printer.DocumentView; /** @@ -15,7 +15,7 @@ * Don't use if you don't have appcompat in your classpath. * * @see AppCompatDocumentTextView - * @see DocumentTextHelper + * @see DocumentHelper */ public class AppCompatDocumentEditText extends AppCompatEditText { @@ -34,6 +34,6 @@ public AppCompatDocumentEditText(Context context, @Nullable AttributeSet attrs, @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); - DocumentTextHelper.onLayout(this); + DocumentHelper.onLayout(this); } } diff --git a/library/src/main/java/com/otaliastudios/printer/view/AppCompatDocumentTextView.java b/library/src/main/java/com/otaliastudios/printer/view/AppCompatDocumentTextView.java index 1a86b0c..2aa5d5b 100644 --- a/library/src/main/java/com/otaliastudios/printer/view/AppCompatDocumentTextView.java +++ b/library/src/main/java/com/otaliastudios/printer/view/AppCompatDocumentTextView.java @@ -6,9 +6,8 @@ import android.support.v7.widget.AppCompatTextView; import android.util.AttributeSet; -import com.otaliastudios.printer.DocumentTextHelper; +import com.otaliastudios.printer.DocumentHelper; import com.otaliastudios.printer.DocumentView; -import com.otaliastudios.printer.view.AppCompatDocumentEditText; /** * A {@link android.support.v7.widget.AppCompatTextView} implementation that works well when @@ -16,7 +15,7 @@ * Don't use if you don't have appcompat in your classpath. * * @see AppCompatDocumentEditText - * @see DocumentTextHelper + * @see DocumentHelper */ public class AppCompatDocumentTextView extends AppCompatTextView { @@ -35,6 +34,6 @@ public AppCompatDocumentTextView(Context context, @Nullable AttributeSet attrs, @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); - DocumentTextHelper.onLayout(this); + DocumentHelper.onLayout(this); } } diff --git a/library/src/main/java/com/otaliastudios/printer/view/DocumentEditText.java b/library/src/main/java/com/otaliastudios/printer/view/DocumentEditText.java index b7ea614..71a8a52 100644 --- a/library/src/main/java/com/otaliastudios/printer/view/DocumentEditText.java +++ b/library/src/main/java/com/otaliastudios/printer/view/DocumentEditText.java @@ -8,16 +8,15 @@ import android.util.AttributeSet; import android.widget.EditText; -import com.otaliastudios.printer.DocumentTextHelper; +import com.otaliastudios.printer.DocumentHelper; import com.otaliastudios.printer.DocumentView; -import com.otaliastudios.printer.view.DocumentTextView; /** * An {@link EditText} implementation that works well when laid out inside * a {@link DocumentView}. * * @see DocumentTextView - * @see DocumentTextHelper + * @see DocumentHelper */ @SuppressLint("AppCompatCustomView") public class DocumentEditText extends EditText { @@ -42,6 +41,6 @@ public DocumentEditText(Context context, @Nullable AttributeSet attrs, int defSt @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); - DocumentTextHelper.onLayout(this); + DocumentHelper.onLayout(this); } } diff --git a/library/src/main/java/com/otaliastudios/printer/view/DocumentTextView.java b/library/src/main/java/com/otaliastudios/printer/view/DocumentTextView.java index 945486d..f507fb9 100644 --- a/library/src/main/java/com/otaliastudios/printer/view/DocumentTextView.java +++ b/library/src/main/java/com/otaliastudios/printer/view/DocumentTextView.java @@ -8,7 +8,7 @@ import android.util.AttributeSet; import android.widget.TextView; -import com.otaliastudios.printer.DocumentTextHelper; +import com.otaliastudios.printer.DocumentHelper; import com.otaliastudios.printer.DocumentView; /** @@ -16,7 +16,7 @@ * a {@link DocumentView}. * * @see DocumentEditText - * @see DocumentTextHelper + * @see DocumentHelper */ @SuppressLint("AppCompatCustomView") public class DocumentTextView extends TextView { @@ -41,6 +41,6 @@ public DocumentTextView(Context context, @Nullable AttributeSet attrs, int defSt @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); - DocumentTextHelper.onLayout(this); + DocumentHelper.onLayout(this); } }