diff options
author | Jorge Ruesga <jorge@ruesga.com> | 2014-10-01 20:36:47 +0000 |
---|---|---|
committer | Gerrit Code Review <gerrit@cyanogenmod.org> | 2014-10-01 20:36:47 +0000 |
commit | a2e8778cc0742fa13a940c417c155136c77b5682 (patch) | |
tree | fbb51c772fe7ac98c951ccde8c2c6cfd05594bc1 | |
parent | 4276df4ec1bf6270b27429fae7190a7af64831e7 (diff) | |
parent | bc60c88e33f0f0d1a068e8605f2de2c5121b9916 (diff) | |
download | android_packages_apps_CMFileManager-a2e8778cc0742fa13a940c417c155136c77b5682.tar.gz android_packages_apps_CMFileManager-a2e8778cc0742fa13a940c417c155136c77b5682.tar.bz2 android_packages_apps_CMFileManager-a2e8778cc0742fa13a940c417c155136c77b5682.zip |
Merge "cmfm: print support" into cm-11.0
-rw-r--r-- | assets/fonts/Courier-Prime.ttf | bin | 0 -> 98156 bytes | |||
-rw-r--r-- | res/menu/actions.xml | 4 | ||||
-rw-r--r-- | res/values/dimen.xml | 5 | ||||
-rw-r--r-- | res/values/strings.xml | 12 | ||||
-rw-r--r-- | src/com/cyanogenmod/filemanager/activities/EditorActivity.java | 22 | ||||
-rw-r--r-- | src/com/cyanogenmod/filemanager/ui/dialogs/ActionsDialog.java | 12 | ||||
-rw-r--r-- | src/com/cyanogenmod/filemanager/ui/policy/PrintActionPolicy.java | 549 | ||||
-rw-r--r-- | src/com/cyanogenmod/filemanager/util/StringHelper.java | 103 |
8 files changed, 687 insertions, 20 deletions
diff --git a/assets/fonts/Courier-Prime.ttf b/assets/fonts/Courier-Prime.ttf Binary files differnew file mode 100644 index 00000000..db4e6c14 --- /dev/null +++ b/assets/fonts/Courier-Prime.ttf diff --git a/res/menu/actions.xml b/res/menu/actions.xml index 305c6bba..ba5f50cf 100644 --- a/res/menu/actions.xml +++ b/res/menu/actions.xml @@ -131,6 +131,10 @@ android:showAsAction="ifRoom" android:title="@string/actions_menu_send"/> <item + android:id="@+id/mnu_actions_print" + android:showAsAction="ifRoom" + android:title="@string/actions_menu_print"/> + <item android:id="@+id/mnu_actions_add_to_bookmarks" android:showAsAction="ifRoom" android:title="@string/actions_menu_add_to_bookmarks"/> diff --git a/res/values/dimen.xml b/res/values/dimen.xml index 91eb40da..a597dc13 100644 --- a/res/values/dimen.xml +++ b/res/values/dimen.xml @@ -114,4 +114,9 @@ <!-- Theme width/height --> <dimen name="theme_max_width">300dip</dimen> <dimen name="theme_max_height">600dip</dimen> + + <!-- Print text size --> + <dimen name="print_text_size">6sp</dimen> + <!-- Print page margins --> + <dimen name="print_page_margins">5dp</dimen> </resources> diff --git a/res/values/strings.xml b/res/values/strings.xml index d353bcd7..2c51d02f 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -474,6 +474,8 @@ <string name="actions_menu_open_parent_folder">Open parent</string> <!-- Actions Dialog - Menu - Compute checksum --> <string name="actions_menu_compute_checksum">Compute checksum</string> + <!-- Actions Dialog - Menu - Print --> + <string name="actions_menu_print">Print</string> <!-- Actions - Ask user prior to do an undone operation. Dialog message --> <string name="actions_ask_undone_operation_msg">This action cannot be undone. Do you want to continue?</string> @@ -723,6 +725,16 @@ <string name="ash_quoted_string">Quoted string</string> <string name="ash_variable">Variable</string> + <!-- Print messages --> + <!-- Unsupported document format --> + <string name="print_unsupported_document">Unsupported document format</string> + <!-- Unsupported image format --> + <string name="print_unsupported_image">Unsupported image format</string> + <!-- Print header --> + <string name="print_document_header">Document: <xliff:g id="document_name">%1$s</xliff:g></string> + <!-- Print footer --> + <string name="print_document_footer">Page <xliff:g id="page_number">%1$s</xliff:g></string> + <!-- Security - Extract relative or absolute files --> <string name="security_warning_extract">Warning!\n\nExtracting an archive file with relative or absolute paths may cause damage to your device by overwriting system files.\n\nDo you want to continue?</string> diff --git a/src/com/cyanogenmod/filemanager/activities/EditorActivity.java b/src/com/cyanogenmod/filemanager/activities/EditorActivity.java index 26b048e8..1ccf3488 100644 --- a/src/com/cyanogenmod/filemanager/activities/EditorActivity.java +++ b/src/com/cyanogenmod/filemanager/activities/EditorActivity.java @@ -84,6 +84,7 @@ import com.cyanogenmod.filemanager.util.ExceptionUtil.OnRelaunchCommandResult; import com.cyanogenmod.filemanager.util.FileHelper; import com.cyanogenmod.filemanager.util.MediaHelper; import com.cyanogenmod.filemanager.util.ResourcesHelper; +import com.cyanogenmod.filemanager.util.StringHelper; import java.io.BufferedReader; import java.io.ByteArrayInputStream; @@ -304,7 +305,7 @@ public class EditorActivity extends Activity implements TextWatcher { // is read-only if (!EditorActivity.this.mReadOnly) { for (int i = 0; i < partial.length-1; i++) { - if (!isPrintableCharacter((char)partial[i])) { + if (!StringHelper.isPrintableCharacter((char)partial[i])) { EditorActivity.this.mBinary = true; EditorActivity.this.mReadOnly = true; break; @@ -550,8 +551,6 @@ public class EditorActivity extends Activity implements TextWatcher { */ Handler mHandler; - private static final char[] VALID_NON_PRINTABLE_CHARS = {' ', '\t', '\r', '\n'}; - /** * @hide */ @@ -1508,23 +1507,6 @@ public class EditorActivity extends Activity implements TextWatcher { } /** - * Method that check if a character is valid printable character - * - * @param c The character to check - * @return boolean If the character is printable - * @hide - */ - static boolean isPrintableCharacter(char c) { - int cc = VALID_NON_PRINTABLE_CHARS.length; - for (int i = 0; i < cc; i++) { - if (c == VALID_NON_PRINTABLE_CHARS[i]) { - return true; - } - } - return TextUtils.isGraphic(c); - } - - /** * Method that applies the current theme to the activity * @hide */ diff --git a/src/com/cyanogenmod/filemanager/ui/dialogs/ActionsDialog.java b/src/com/cyanogenmod/filemanager/ui/dialogs/ActionsDialog.java index bb34dceb..cb2ceab4 100644 --- a/src/com/cyanogenmod/filemanager/ui/dialogs/ActionsDialog.java +++ b/src/com/cyanogenmod/filemanager/ui/dialogs/ActionsDialog.java @@ -55,6 +55,7 @@ import com.cyanogenmod.filemanager.ui.policy.InfoActionPolicy; import com.cyanogenmod.filemanager.ui.policy.IntentsActionPolicy; import com.cyanogenmod.filemanager.ui.policy.NavigationActionPolicy; import com.cyanogenmod.filemanager.ui.policy.NewActionPolicy; +import com.cyanogenmod.filemanager.ui.policy.PrintActionPolicy; import com.cyanogenmod.filemanager.util.DialogHelper; import com.cyanogenmod.filemanager.util.FileHelper; import com.cyanogenmod.filemanager.util.MimeTypeHelper; @@ -410,6 +411,11 @@ public class ActionsDialog implements OnItemClickListener, OnItemLongClickListen InfoActionPolicy.showComputeChecksumDialog(this.mContext, this.mFso); break; + //- Print + case R.id.mnu_actions_print: + PrintActionPolicy.printDocument(this.mContext, this.mFso); + break; + //- Properties case R.id.mnu_actions_properties: case R.id.mnu_actions_properties_current_folder: @@ -635,6 +641,12 @@ public class ActionsDialog implements OnItemClickListener, OnItemLongClickListen if (FileHelper.isDirectory(this.mFso) || this.mFso instanceof Symlink) { menu.removeItem(R.id.mnu_actions_compute_checksum); } + + //- Print (only for text and image categories) + if (category.compareTo(MimeTypeCategory.TEXT) != 0 && + category.compareTo(MimeTypeCategory.IMAGE) != 0) { + menu.removeItem(R.id.mnu_actions_print); + } } //- Add to bookmarks -> Only directories diff --git a/src/com/cyanogenmod/filemanager/ui/policy/PrintActionPolicy.java b/src/com/cyanogenmod/filemanager/ui/policy/PrintActionPolicy.java new file mode 100644 index 00000000..13d08cd2 --- /dev/null +++ b/src/com/cyanogenmod/filemanager/ui/policy/PrintActionPolicy.java @@ -0,0 +1,549 @@ +/* + * Copyright (C) 2012 The CyanogenMod Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.cyanogenmod.filemanager.ui.policy; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Color; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.Rect; +import android.graphics.RectF; +import android.graphics.Typeface; +import android.graphics.pdf.PdfDocument.Page; +import android.os.Bundle; +import android.os.CancellationSignal; +import android.os.ParcelFileDescriptor; +import android.print.PageRange; +import android.print.PrintAttributes; +import android.print.PrintDocumentAdapter; +import android.print.PrintDocumentInfo; +import android.print.PrintManager; +import android.print.PrintAttributes.Margins; +import android.print.PrintAttributes.MediaSize; +import android.print.pdf.PrintedPdfDocument; +import android.util.Log; +import android.widget.Toast; + +import com.cyanogenmod.filemanager.R; +import com.cyanogenmod.filemanager.model.FileSystemObject; +import com.cyanogenmod.filemanager.util.DialogHelper; +import com.cyanogenmod.filemanager.util.ExceptionUtil; +import com.cyanogenmod.filemanager.util.MimeTypeHelper; +import com.cyanogenmod.filemanager.util.MimeTypeHelper.MimeTypeCategory; +import com.cyanogenmod.filemanager.util.StringHelper; + +import java.io.BufferedInputStream; +import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.FileReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.StringReader; +import java.util.ArrayList; +import java.util.List; + +/** + * A class with the convenience methods to print documents + */ +public final class PrintActionPolicy extends ActionsPolicy { + + private static final String TAG = "PrintActionPolicy"; //$NON-NLS-1$ + + /** + * Method that prints the passed document + * + * @param ctx The current context + * @param fso The document to print + */ + public static void printDocument(final Context ctx, FileSystemObject fso) { + MimeTypeCategory category = MimeTypeHelper.getCategory(ctx, fso); + if (category.equals(MimeTypeCategory.TEXT)) { + printTextDocument(ctx, fso); + return; + } + if (category.equals(MimeTypeCategory.IMAGE)) { + printImage(ctx, fso); + return; + } + DialogHelper.showToast(ctx, R.string.print_unsupported_document, Toast.LENGTH_SHORT); + } + + /** + * Method that prints the document as a text document + * + * @param ctx The current context + * @param fso The document to print + */ + private static void printTextDocument(final Context ctx, final FileSystemObject document) { + final int printPageMargins = ctx.getResources().getDimensionPixelSize( + R.dimen.print_page_margins); + + PrintManager printManager = (PrintManager) ctx.getSystemService(Context.PRINT_SERVICE); + PrintAttributes attr = new PrintAttributes.Builder() + .setMediaSize(PrintAttributes.MediaSize.UNKNOWN_PORTRAIT) + .setColorMode(PrintAttributes.COLOR_MODE_MONOCHROME) + .build(); + printManager.print(document.getName(), new PrintDocumentAdapter() { + private PrintAttributes mAttributes; + private Paint mPaint; + private RectF mTextBounds; + private boolean mIsBinaryDocument; + private List<String> mLines; + private List<String> mAdjustedLines; + + private static final int MILS_PER_INCH = 1000; + private static final int POINTS_IN_INCH = 72; + + @Override + public void onStart() { + super.onStart(); + + // Create the paint used for draw text + Typeface courier = Typeface.createFromAsset(ctx.getAssets(), + "fonts/Courier-Prime.ttf"); + mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mPaint.setTypeface(courier); + mPaint.setTextSize(ctx.getResources().getDimensionPixelSize( + R.dimen.print_text_size)); + mPaint.setColor(Color.BLACK); + + // Get the text width and height + mTextBounds = new RectF(); + mTextBounds.right = mPaint.measureText(new char[]{'A'}, 0, 1); + mTextBounds.bottom = mPaint.getFontMetrics().descent + - mPaint.getFontMetrics().ascent + mPaint.getFontMetrics().leading; + + mLines = new ArrayList<String>(); + readFile(); + } + + @Override + public void onWrite(PageRange[] pages, ParcelFileDescriptor destination, + CancellationSignal cancellationSignal, WriteResultCallback callback) { + PrintedPdfDocument pdfDocument = new PrintedPdfDocument(ctx, + mAttributes); + try { + Rect pageContentRect = getContentRect(mAttributes); + int charsPerRow = (int) (pageContentRect.width() / mTextBounds.width()); + int rowsPerPage = rowsPerPage(pageContentRect); + + int currentPage = 0; + int currentLine = 0; + Page page = null; + if (mAdjustedLines.size() > 0) { + page = pdfDocument.startPage(currentPage++); + printHeader(ctx, page, pageContentRect, charsPerRow); + } + // Top (with margin) + header + float top = pageContentRect.top + (mTextBounds.height() * 2); + for (String line : mAdjustedLines) { + currentLine++; + page.getCanvas().drawText(line, pageContentRect.left, + top + (currentLine * mTextBounds.height()), mPaint); + + if (currentLine >= rowsPerPage) { + if (page != null) { + printFooter(ctx, page, pageContentRect, currentPage); + pdfDocument.finishPage(page); + } + currentLine = 0; + page = pdfDocument.startPage(currentPage++); + printHeader(ctx, page, pageContentRect, charsPerRow); + } + } + + // Finish the last page + printFooter(ctx, page, pageContentRect, currentPage); + pdfDocument.finishPage(page); + + try { + // Write the document + pdfDocument.writeTo(new FileOutputStream(destination.getFileDescriptor())); + + // Done + callback.onWriteFinished(new PageRange[]{PageRange.ALL_PAGES}); + } catch (IOException ioe) { + // Failed. + ExceptionUtil.translateException(ctx, ioe); + callback.onWriteFailed(null); + } + } finally { + if (destination != null) { + try { + destination.close(); + } catch (IOException ioe) { + /* ignore */ + } + } + } + } + + @Override + public void onLayout(PrintAttributes oldAttributes, PrintAttributes newAttributes, + CancellationSignal cancellationSignal, LayoutResultCallback callback, + Bundle extras) { + + mAttributes = newAttributes; + Rect pageContentRect = getContentRect(newAttributes); + int charsPerRow = (int) (pageContentRect.width() / mTextBounds.width()); + int rowsPerPage = rowsPerPage(pageContentRect); + adjustLines(pageContentRect, charsPerRow); + + PrintDocumentInfo info = new PrintDocumentInfo.Builder(document.getName()) + .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT) + .setPageCount(calculatePageCount(rowsPerPage)) + .build(); + info.setDataSize(document.getSize()); + boolean changed = !newAttributes.equals(oldAttributes); + callback.onLayoutFinished(info, changed); + } + + private Rect getContentRect(PrintAttributes attributes) { + MediaSize mediaSize = attributes.getMediaSize(); + + // Compute the size of the target canvas from the attributes. + int pageWidth = (int) (((float) mediaSize.getWidthMils() / MILS_PER_INCH) + * POINTS_IN_INCH); + int pageHeight = (int) (((float) mediaSize.getHeightMils() / MILS_PER_INCH) + * POINTS_IN_INCH); + + // Compute the content size from the attributes. + Margins minMargins = attributes.getMinMargins(); + final int marginLeft = (int) (((float) minMargins.getLeftMils() / MILS_PER_INCH) + * POINTS_IN_INCH); + final int marginTop = (int) (((float) minMargins.getTopMils() / MILS_PER_INCH) + * POINTS_IN_INCH); + final int marginRight = (int) (((float) minMargins.getRightMils() / MILS_PER_INCH) + * POINTS_IN_INCH); + final int marginBottom = (int) (((float) minMargins.getBottomMils() / MILS_PER_INCH) + * POINTS_IN_INCH); + return new Rect( + Math.max(marginLeft, printPageMargins), + Math.max(marginTop, printPageMargins), + pageWidth - Math.max(marginRight, printPageMargins), + pageHeight - Math.max(marginBottom, printPageMargins)); + } + + private void printHeader(Context ctx, Page page, Rect pageContentRect, + int charsPerRow) { + String header = ctx.getString(R.string.print_document_header, document.getName()); + if (header.length() >= charsPerRow) { + header = header.substring(header.length() - 3) + "..."; + } + page.getCanvas().drawText(header, + (int) (pageContentRect.width() / 2) - (mPaint.measureText(header) / 2), + pageContentRect.top + mTextBounds.height(), mPaint); + } + + private void printFooter(Context ctx, Page page, Rect pageContentRect, int pageNumber) { + String footer = ctx.getString(R.string.print_document_footer, pageNumber); + page.getCanvas().drawText(footer, + (int) (pageContentRect.width() / 2) - (mPaint.measureText(footer) / 2), + pageContentRect.bottom - mTextBounds.height(), mPaint); + } + + private void adjustLines(Rect pageRect, int charsPerRow) { + if (mIsBinaryDocument) { + return; + } + mAdjustedLines = new ArrayList<String>(mLines); + for (int i = 0; i < mAdjustedLines.size(); i++) { + String line = mAdjustedLines.get(i); + if (line.length() > charsPerRow) { + int prevSpace = line.lastIndexOf(" ", charsPerRow); + if (prevSpace != -1) { + // Split in the previous word + String currentLine = line.substring(0, prevSpace + 1); + String nextLine = line.substring(prevSpace + 1); + mAdjustedLines.set(i, currentLine); + mAdjustedLines.add(i + 1, nextLine); + } else { + // Just split at margin + String currentLine = line.substring(0, charsPerRow); + String nextLine = line.substring(charsPerRow); + mAdjustedLines.set(i, currentLine); + mAdjustedLines.add(i + 1, nextLine); + } + } + } + } + + private int calculatePageCount(int rowsPerPage) { + int pages = mAdjustedLines.size() / rowsPerPage; + return pages <= 0 ? PrintDocumentInfo.PAGE_COUNT_UNKNOWN : pages; + } + + private int rowsPerPage(Rect pageContentRect) { + // Text height - header - footer + return (int) ((pageContentRect.height() / mTextBounds.height()) - 4); + } + + private void readFile() { + mIsBinaryDocument = isBinaryDocument(); + if (mIsBinaryDocument) { + readHexDumpDocumentFile(); + } else { + readDocumentFile(); + } + } + + private boolean isBinaryDocument() { + BufferedReader br = null; + try { + br = new BufferedReader(new FileReader(document.getFullPath())); + char[] data = new char[50]; + int read = br.read(data); + for (int i = 0; i < read; i++) { + if (!StringHelper.isPrintableCharacter(data[i])) { + return true; + } + } + } catch (IOException ex) { + //Ignore + } finally { + if (br != null) { + try { + br.close(); + } catch (IOException ex) { + //Ignore + } + } + } + return false; + } + + private void readDocumentFile() { + BufferedReader br = null; + try { + br = new BufferedReader(new FileReader(document.getFullPath())); + String line = null; + while((line = br.readLine()) != null) { + mLines.add(line); + } + } catch (IOException ex) { + mLines.clear(); + Log.e(TAG, "Failed to read file " + document.getFullPath(), ex); + } finally { + if (br != null) { + try { + br.close(); + } catch (IOException ex) { + //Ignore + } + } + } + } + + private void readHexDumpDocumentFile() { + InputStream is = null; + ByteArrayOutputStream baos; + try { + int bufferSize = ctx.getResources().getInteger(R.integer.buffer_size); + + baos = new ByteArrayOutputStream(); + is = new BufferedInputStream(new FileInputStream(document.getFullPath())); + byte[] data = new byte[bufferSize]; + int read = 0; + while((read = is.read(data, 0, bufferSize)) != -1) { + baos.write(data, 0, read); + } + } catch (IOException ex) { + mLines.clear(); + Log.e(TAG, "Failed to read file " + document.getFullPath(), ex); + return; + } finally { + if (is != null) { + try { + is.close(); + } catch (IOException ex) { + //Ignore + } + } + } + + // Convert the bytes to a hex printable string and free resources + String documentBuffer = StringHelper.toHexPrintableString(baos.toByteArray()); + try { + baos.close(); + } catch (IOException ex) { + //Ignore + } + + BufferedReader br = null; + try { + br = new BufferedReader(new StringReader(documentBuffer)); + String line = null; + while((line = br.readLine()) != null) { + mLines.add(line); + } + } catch (IOException ex) { + mLines.clear(); + Log.e(TAG, "Failed to read file " + document.getFullPath(), ex); + } finally { + if (br != null) { + try { + br.close(); + } catch (IOException ex) { + //Ignore + } + } + } + + // Use the final array and clear the original (we don't use it anymore) + mAdjustedLines = new ArrayList<String>(mLines); + mLines.clear(); + } + + }, attr); + } + + /** + * Method that prints the document as an image + * + * @param ctx The current context + * @param fso The image to print + */ + private static void printImage(final Context ctx, final FileSystemObject image) { + // Check that the image is supported by Android + if (isValidImageDocument(image.getFullPath())) { + DialogHelper.showToast(ctx, R.string.print_unsupported_image, Toast.LENGTH_SHORT); + return; + } + + final BitmapFactory.Options options = new BitmapFactory.Options(); + options.inPreferredConfig = Bitmap.Config.RGB_565; + final Bitmap bitmap = BitmapFactory.decodeFile(image.getFullPath(), options); + + PrintManager printManager = (PrintManager) ctx.getSystemService(Context.PRINT_SERVICE); + PrintAttributes.MediaSize mediaSize = PrintAttributes.MediaSize.UNKNOWN_PORTRAIT; + if (bitmap.getWidth() > bitmap.getHeight()) { + mediaSize = PrintAttributes.MediaSize.UNKNOWN_LANDSCAPE; + } + PrintAttributes attr = new PrintAttributes.Builder() + .setMediaSize(mediaSize) + .setColorMode(PrintAttributes.COLOR_MODE_COLOR) + .build(); + printManager.print(image.getName(), new PrintDocumentAdapter() { + private PrintAttributes mAttributes; + + @Override + public void onWrite(PageRange[] pages, ParcelFileDescriptor destination, + CancellationSignal cancellationSignal, WriteResultCallback callback) { + PrintedPdfDocument pdfDocument = new PrintedPdfDocument(ctx, + mAttributes); + try { + Page page = pdfDocument.startPage(1); + + RectF content = new RectF(page.getInfo().getContentRect()); + + Matrix matrix = getMatrix(bitmap.getWidth(), bitmap.getHeight(), content); + + // Draw the bitmap. + page.getCanvas().drawBitmap(bitmap, matrix, null); + + // Finish the page. + pdfDocument.finishPage(page); + + try { + // Write the document + pdfDocument.writeTo(new FileOutputStream(destination.getFileDescriptor())); + + // Done + callback.onWriteFinished(new PageRange[]{PageRange.ALL_PAGES}); + } catch (IOException ioe) { + // Failed. + ExceptionUtil.translateException(ctx, ioe); + callback.onWriteFailed(null); + } + } finally { + if (pdfDocument != null) { + pdfDocument.close(); + } + if (destination != null) { + try { + destination.close(); + } catch (IOException ioe) { + /* ignore */ + } + } + } + } + + @Override + public void onLayout(PrintAttributes oldAttributes, PrintAttributes newAttributes, + CancellationSignal cancellationSignal, LayoutResultCallback callback, + Bundle extras) { + + mAttributes = newAttributes; + + PrintDocumentInfo info = new PrintDocumentInfo.Builder(image.getName()) + .setContentType(PrintDocumentInfo.CONTENT_TYPE_PHOTO) + .setPageCount(1) + .build(); + boolean changed = !newAttributes.equals(oldAttributes); + callback.onLayoutFinished(info, changed); + } + + @Override + public void onFinish() { + super.onFinish(); + if (bitmap != null) { + bitmap.recycle(); + } + } + + private Matrix getMatrix(int imageWidth, int imageHeight, RectF content) { + Matrix matrix = new Matrix(); + + // Compute and apply scale to fill the page. + int widthRatio = content.width() / imageWidth; + int heightRatio = content.height() / imageHeight; + float scale = Math.max(widthRatio, heightRatio); + matrix.postScale(scale, scale); + + // Center the content. + final float translateX = (content.width() + - imageWidth * scale) / 2; + final float translateY = (content.height() + - imageHeight * scale) / 2; + matrix.postTranslate(translateX, translateY); + return matrix; + } + }, attr); + } + + /** + * Check if the file is a valid image document allowed by android to be printed + * + * @param file The image to check + * @return boolean If the image is a valid document + */ + private static boolean isValidImageDocument(String file) { + final BitmapFactory.Options options = new BitmapFactory.Options(); + options.inJustDecodeBounds = true; + options.inPreferredConfig = Bitmap.Config.RGB_565; + Bitmap bitmap = BitmapFactory.decodeFile(file, options); + if (bitmap != null) { + bitmap.recycle(); + } + return bitmap != null; + } +}
\ No newline at end of file diff --git a/src/com/cyanogenmod/filemanager/util/StringHelper.java b/src/com/cyanogenmod/filemanager/util/StringHelper.java new file mode 100644 index 00000000..3702746b --- /dev/null +++ b/src/com/cyanogenmod/filemanager/util/StringHelper.java @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2012 The CyanogenMod Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.cyanogenmod.filemanager.util; + +import android.text.TextUtils; + +import com.android.internal.util.HexDump; + +import java.io.ByteArrayInputStream; +import java.util.Arrays; +import java.util.UUID; + +/** + * A helper class with useful methods for deal with strings. + */ +public final class StringHelper { + + private static final char[] VALID_NON_PRINTABLE_CHARS = {' ', '\t', '\r', '\n'}; + + /** + * Method that check if a character is valid printable character + * + * @param c The character to check + * @return boolean If the character is printable + */ + public static boolean isPrintableCharacter(char c) { + int cc = VALID_NON_PRINTABLE_CHARS.length; + for (int i = 0; i < cc; i++) { + if (c == VALID_NON_PRINTABLE_CHARS[i]) { + return true; + } + } + return TextUtils.isGraphic(c); + } + + /** + * Method that converts to a visual printable hex string + * + * @param string The string to check + */ + public static String toHexPrintableString(byte[] data) { + String hexLineSeparator = UUID.randomUUID().toString() + UUID.randomUUID().toString(); + String hex = toHexDump(data, hexLineSeparator); + + // Remove characters without visual representation + final String REPLACED_SYMBOL = "."; //$NON-NLS-1$ + final String NEWLINE = System.getProperty("line.separator"); //$NON-NLS-1$ + String printable = hex.replaceAll("\\p{Cntrl}", REPLACED_SYMBOL); //$NON-NLS-1$ + printable = printable.replaceAll("[^\\p{Print}]", REPLACED_SYMBOL); //$NON-NLS-1$ + printable = printable.replaceAll("\\p{C}", REPLACED_SYMBOL); //$NON-NLS-1$ + printable = printable.replaceAll(hexLineSeparator, NEWLINE); + return printable; + } + + /** + * Create a hex dump of the data while show progress to user + * + * @param data The data to hex dump + * @param hexLineSeparator Internal line separator + * @return StringBuilder The hex dump buffer + */ + private static String toHexDump(byte[] data, String hexLineSeparator) { + final int DISPLAY_SIZE = 16; // Bytes per line + ByteArrayInputStream bais = new ByteArrayInputStream(data); + byte[] line = new byte[DISPLAY_SIZE]; + int read = 0; + int offset = 0; + StringBuilder sb = new StringBuilder(); + while ((read = bais.read(line, 0, DISPLAY_SIZE)) != -1) { + //offset dump(16) data\n + String linedata = new String(line, 0, read); + sb.append(HexDump.toHexString(offset)); + sb.append(" "); //$NON-NLS-1$ + String hexDump = HexDump.toHexString(line, 0, read); + if (hexDump.length() != (DISPLAY_SIZE * 2)) { + char[] array = new char[(DISPLAY_SIZE * 2) - hexDump.length()]; + Arrays.fill(array, ' '); + hexDump += new String(array); + } + sb.append(hexDump); + sb.append(" "); //$NON-NLS-1$ + sb.append(linedata); + sb.append(hexLineSeparator); + offset += DISPLAY_SIZE; + } + + return sb.toString(); + } +}
\ No newline at end of file |