Various android enhancements - see the changelog

This commit is contained in:
Sebastián Katzer 2016-07-23 10:33:28 +02:00
parent f44ed52148
commit 13c9d3dbef
3 changed files with 178 additions and 33 deletions

View File

@ -1,4 +1,12 @@
## ChangeLog
#### Version 0.7.2 (not yet released)
- [__change__:] Changed plugin ID to `cordova-plugin-printer`
- [__change__:] Plugin requires Android KitKat or newer
- [__change__:] `isAvailable` returns false if no enabled print services can be found (Android)
- [enhancement:] `isAvailable` returns additional list of available print services (Android)
- [enhancement:] Support `duplex` attribute (Android)
#### Version 0.7.1 (23.04.2015)
- [bugfix:] `isAvailable` does not block the main thread anymore.
- [bugfix:] iPad+iOS8 incompatibility (Thanks to __zmagyar__)

View File

@ -42,7 +42,8 @@
<!-- cordova -->
<engines>
<engine name="cordova" version=">=6.0.0" />
<engine name="cordova" version=">=3.0.0" />
<engine name="android-sdk" version=">=19" />
</engines>
<!-- interface -->

View File

@ -21,14 +21,6 @@
package de.appplant.cordova.plugin.printer;
import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.PluginResult;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.os.Build;
@ -39,7 +31,20 @@ import android.print.PrintManager;
import android.webkit.WebView;
import android.webkit.WebViewClient;
@TargetApi(19)
import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.PluginResult;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class Printer extends CordovaPlugin {
private WebView view;
@ -65,23 +70,20 @@ public class Printer extends CordovaPlugin {
*/
@Override
public boolean execute (String action, JSONArray args,
CallbackContext callback) throws JSONException {
CallbackContext callback) throws JSONException {
command = callback;
if (action.equalsIgnoreCase("isAvailable")) {
isAvailable();
return true;
}
if (action.equalsIgnoreCase("print")) {
print(args);
return true;
}
// Returning false results in a "MethodNotFound" error.
return false;
}
@ -93,10 +95,17 @@ public class Printer extends CordovaPlugin {
cordova.getThreadPool().execute(new Runnable() {
@Override
public void run() {
Boolean supported = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
PluginResult result = new PluginResult(PluginResult.Status.OK, supported);
List<String> ids = getEnabledPrintServiceIds();
Boolean available = ids.size() > 1;
command.sendPluginResult(result);
PluginResult res1 = new PluginResult(
PluginResult.Status.OK, available);
PluginResult res2 = new PluginResult(
PluginResult.Status.OK, new JSONArray(ids));
PluginResult res = new PluginResult(
PluginResult.Status.OK, Arrays.asList(res1, res2));
command.sendPluginResult(res);
}
});
}
@ -130,11 +139,12 @@ public class Printer extends CordovaPlugin {
if (content.startsWith("http") || content.startsWith("file:")) {
view.loadUrl(content);
} else {
//Set base URI to the assets/www folder
String baseURL = webView.getUrl();
baseURL = baseURL.substring(0, baseURL.lastIndexOf('/') + 1);
view.loadDataWithBaseURL(baseURL, content, "text/html", "UTF-8", null);
// Set base URI to the assets/www folder
view.loadDataWithBaseURL(
baseURL, content, "text/html", "UTF-8", null);
}
}
@ -161,9 +171,10 @@ public class Printer extends CordovaPlugin {
* The JSON object with the containing page properties
*/
private void setWebViewClient (JSONObject props) {
final String docName = props.optString("name", DEFAULT_DOC_NAME);
final String docName = props.optString("name", DEFAULT_DOC_NAME);
final boolean landscape = props.optBoolean("landscape", false);
final boolean graystyle = props.optBoolean("graystyle", false);
final String duplex = props.optString("duplex", "none");
view.setWebViewClient(new WebViewClient() {
@Override
@ -173,27 +184,31 @@ public class Printer extends CordovaPlugin {
@Override
public void onPageFinished (WebView webView, String url) {
// Get a PrintManager instance
PrintManager printManager = (PrintManager) cordova.getActivity()
.getSystemService(Context.PRINT_SERVICE);
// Get a print adapter instance
PrintDocumentAdapter printAdapter = webView.createPrintDocumentAdapter();
// Get a print builder instance
PrintManager printManager = getPrintMgr();
PrintAttributes.Builder builder = new PrintAttributes.Builder();
PrintDocumentAdapter adapter = getAdapter(webView, docName);
// The page does itself set its own margins
builder.setMinMargins(PrintAttributes.Margins.NO_MARGINS);
builder.setColorMode(graystyle ? PrintAttributes.COLOR_MODE_MONOCHROME
builder.setColorMode(graystyle
? PrintAttributes.COLOR_MODE_MONOCHROME
: PrintAttributes.COLOR_MODE_COLOR);
builder.setMediaSize(landscape ? PrintAttributes.MediaSize.UNKNOWN_LANDSCAPE
builder.setMediaSize(landscape
? PrintAttributes.MediaSize.UNKNOWN_LANDSCAPE
: PrintAttributes.MediaSize.UNKNOWN_PORTRAIT);
// Create a print job with name and adapter instance
PrintJob job = printManager.print(docName, printAdapter, builder.build());
if (!duplex.equals("none") && Build.VERSION.SDK_INT >= 23) {
boolean longEdge = duplex.equals("long");
Method setDuplexModeMethod = getMethod(builder.getClass(),
"setDuplexMode", int.class);
invokeMethod(builder, setDuplexModeMethod,
longEdge ? 2 : 4);
}
PrintJob job = printManager.print(
docName, adapter, builder.build());
invokeCallbackOnceCompletedOrCanceled(job);
@ -221,4 +236,125 @@ public class Printer extends CordovaPlugin {
}
});
}
/**
* Get a PrintManager instance.
*
* @return A PrintManager instance.
*/
private PrintManager getPrintMgr () {
return (PrintManager) cordova.getActivity()
.getSystemService(Context.PRINT_SERVICE);
}
/**
* Create the print document adapter for the web view component. On
* devices older then SDK 21 it will use the deprecated method
* `createPrintDocumentAdapter` without arguments and on newer devices
* the recommended way.
*
* @param webView
* The web view which content to print out.
* @param docName
* The name of the printed document.
* @return
* The created adapter.
*/
private PrintDocumentAdapter getAdapter (WebView webView, String docName) {
if (Build.VERSION.SDK_INT >= 21) {
Method createPrintDocumentAdapterMethod = getMethod(
WebView.class, "createPrintDocumentAdapter", String.class);
return (PrintDocumentAdapter) invokeMethod(
webView, createPrintDocumentAdapterMethod, docName);
} else {
Method createPrintDocumentAdapterMethod = getMethod(
WebView.class, "createPrintDocumentAdapter");
return (PrintDocumentAdapter) invokeMethod(
webView, createPrintDocumentAdapterMethod);
}
}
/**
* Get a list of ids of all installed and enabled print services. For
* that it uses reflections to call public but hidden methods from the
* PrintManager.
*
* @return A list of found print service ids.
*/
private List<String> getEnabledPrintServiceIds () {
try {
PrintManager printMgr = getPrintMgr();
Class<?> printerCls = Class.forName(
"android.printservice.PrintServiceInfo");
Method getPrinterMethod = getMethod(printMgr.getClass(),
"getEnabledPrintServices");
Method getIdMethod = getMethod(printerCls,
"getId");
List printers = (List) invokeMethod(printMgr, getPrinterMethod);
ArrayList<String> printerIds = new ArrayList<String>();
printerIds.add("android.print.pdf");
if (printers == null)
return printerIds;
for (Object printer : printers) {
String printerId = (String) invokeMethod(printer, getIdMethod);
printerIds.add(printerId);
}
return printerIds;
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return Collections.emptyList();
}
/**
* Finds the method with given name and set of arguments.
*
* @param cls
* The class in where to look for the method declaration.
* @param name
* The name of the method.
* @param params
* The arguments of the method.
* @return
* The found method or null.
*/
private Method getMethod (Class<?> cls, String name, Class<?>... params) {
try {
return cls.getDeclaredMethod(name, params);
} catch (NoSuchMethodException e) {
return null;
}
}
/**
* Invokes the method on the given object with the specified arguments.
*
* @param obj
* An object which class defines the method.
* @param method
* The method to invoke.
* @param args
* Set of arguments.
* @return
* The returned object or null.
*/
private Object invokeMethod (Object obj, Method method, Object... args) {
try {
return method.invoke(obj, args);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return null;
}
}