Initial reimplementation for Android
This commit is contained in:
parent
652c6c62c2
commit
6c16959267
43
plugin.xml
43
plugin.xml
@ -26,7 +26,7 @@
|
|||||||
<plugin id="cordova-plugin-printer"
|
<plugin id="cordova-plugin-printer"
|
||||||
xmlns="http://apache.org/cordova/ns/plugins/1.0"
|
xmlns="http://apache.org/cordova/ns/plugins/1.0"
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
version="0.8.0.beta">
|
version="0.8.0.alpha">
|
||||||
|
|
||||||
<name>Printer</name>
|
<name>Printer</name>
|
||||||
|
|
||||||
@ -97,37 +97,24 @@
|
|||||||
</feature>
|
</feature>
|
||||||
</config-file>
|
</config-file>
|
||||||
|
|
||||||
<config-file target="AndroidManifest.xml" parent="/manifest/application">
|
<preference name="ANDROID_SUPPORT_V4_VERSION" default="28.+"/>
|
||||||
<activity
|
|
||||||
android:name="de.appplant.cordova.plugin.printer.ui.SelectPrinterActivity"
|
<framework src="com.android.support:support-v4:$ANDROID_SUPPORT_V4_VERSION"/>
|
||||||
android:label="Printer"
|
|
||||||
android:exported="false">
|
<source-file src="src/android/AssetUtil.java"
|
||||||
</activity>
|
target-dir="src/de/appplant/cordova/plugin/printer" />
|
||||||
</config-file>
|
|
||||||
|
<source-file src="src/android/Options.java"
|
||||||
|
target-dir="src/de/appplant/cordova/plugin/printer" />
|
||||||
|
|
||||||
|
<source-file src="src/android/PdfAdapter.java"
|
||||||
|
target-dir="src/de/appplant/cordova/plugin/printer" />
|
||||||
|
|
||||||
<source-file src="src/android/Printer.java"
|
<source-file src="src/android/Printer.java"
|
||||||
target-dir="src/de/appplant/cordova/plugin/printer" />
|
target-dir="src/de/appplant/cordova/plugin/printer" />
|
||||||
|
|
||||||
<source-file src="src/android/ui/SelectPrinterActivity.java"
|
<source-file src="src/android/PrintManager.java"
|
||||||
target-dir="src/de/appplant/cordova/plugin/printer/ui" />
|
target-dir="src/de/appplant/cordova/plugin/printer" />
|
||||||
|
|
||||||
<source-file src="src/android/reflect/Meta.java"
|
|
||||||
target-dir="src/de/appplant/cordova/plugin/printer/reflect" />
|
|
||||||
|
|
||||||
<source-file src="src/android/ext/PrinterDiscoverySession.java"
|
|
||||||
target-dir="src/de/appplant/cordova/plugin/printer/ext" />
|
|
||||||
|
|
||||||
<source-file src="src/android/ext/PrintManager.java"
|
|
||||||
target-dir="src/de/appplant/cordova/plugin/printer/ext" />
|
|
||||||
|
|
||||||
<source-file src="src/android/ext/PrintServiceInfo.java"
|
|
||||||
target-dir="src/de/appplant/cordova/plugin/printer/ext" />
|
|
||||||
|
|
||||||
<resource-file src="res/android/layout/printer_list_item.xml"
|
|
||||||
target="res/layout/printer_list_item.xml" />
|
|
||||||
|
|
||||||
<resource-file src="res/android/layout/select_printer_activity.xml"
|
|
||||||
target="res/layout/select_printer_activity.xml" />
|
|
||||||
</platform>
|
</platform>
|
||||||
|
|
||||||
<!-- windows -->
|
<!-- windows -->
|
||||||
|
@ -1,80 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
|
|
||||||
<!--
|
|
||||||
* Copyright (c) 2013-2016 by appPlant GmbH. All rights reserved.
|
|
||||||
*
|
|
||||||
* @APPPLANT_LICENSE_HEADER_START@
|
|
||||||
*
|
|
||||||
* This file contains Original Code and/or Modifications of Original Code
|
|
||||||
* as defined in and that are subject to the Apache License
|
|
||||||
* Version 2.0 (the 'License'). You may not use this file except in
|
|
||||||
* compliance with the License. Please obtain a copy of the License at
|
|
||||||
* http://opensource.org/licenses/Apache-2.0/ and read it before using this
|
|
||||||
* file.
|
|
||||||
*
|
|
||||||
* The Original Code and all software distributed under the License are
|
|
||||||
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
|
|
||||||
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
|
|
||||||
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
|
|
||||||
* Please see the License for the specific language governing rights and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* @APPPLANT_LICENSE_HEADER_END@
|
|
||||||
-->
|
|
||||||
|
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
|
|
||||||
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
|
|
||||||
android:minHeight="?android:attr/listPreferredItemHeight"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:gravity="start|center_vertical">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@android:id/icon"
|
|
||||||
android:layout_width="32dip"
|
|
||||||
android:layout_height="32dip"
|
|
||||||
android:layout_gravity="center_vertical"
|
|
||||||
android:layout_marginEnd="8dip"
|
|
||||||
android:duplicateParentState="true"
|
|
||||||
android:contentDescription="@null"
|
|
||||||
android:visibility="invisible">
|
|
||||||
</ImageView>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:duplicateParentState="true">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@android:id/title"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
|
||||||
android:singleLine="true"
|
|
||||||
android:ellipsize="end"
|
|
||||||
android:textIsSelectable="false"
|
|
||||||
android:gravity="top|start"
|
|
||||||
android:textColor="?android:attr/textColorPrimary"
|
|
||||||
android:duplicateParentState="true">
|
|
||||||
</TextView>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@android:id/hint"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
|
||||||
android:singleLine="true"
|
|
||||||
android:ellipsize="end"
|
|
||||||
android:textIsSelectable="false"
|
|
||||||
android:visibility="gone"
|
|
||||||
android:textColor="?android:attr/textColorPrimary"
|
|
||||||
android:duplicateParentState="true">
|
|
||||||
</TextView>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
@ -1,74 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
|
|
||||||
<!--
|
|
||||||
* Copyright (c) 2013-2016 by appPlant GmbH. All rights reserved.
|
|
||||||
*
|
|
||||||
* @APPPLANT_LICENSE_HEADER_START@
|
|
||||||
*
|
|
||||||
* This file contains Original Code and/or Modifications of Original Code
|
|
||||||
* as defined in and that are subject to the Apache License
|
|
||||||
* Version 2.0 (the 'License'). You may not use this file except in
|
|
||||||
* compliance with the License. Please obtain a copy of the License at
|
|
||||||
* http://opensource.org/licenses/Apache-2.0/ and read it before using this
|
|
||||||
* file.
|
|
||||||
*
|
|
||||||
* The Original Code and all software distributed under the License are
|
|
||||||
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
|
|
||||||
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
|
|
||||||
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
|
|
||||||
* Please see the License for the specific language governing rights and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* @APPPLANT_LICENSE_HEADER_END@
|
|
||||||
-->
|
|
||||||
|
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="fill_parent">
|
|
||||||
|
|
||||||
<ListView
|
|
||||||
android:id="@android:id/list"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="fill_parent"
|
|
||||||
android:scrollbarStyle="outsideOverlay"
|
|
||||||
android:cacheColorHint="@android:color/transparent"
|
|
||||||
android:scrollbarAlwaysDrawVerticalTrack="true" >
|
|
||||||
</ListView>
|
|
||||||
|
|
||||||
<FrameLayout
|
|
||||||
android:id="@android:id/empty"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="fill_parent"
|
|
||||||
android:visibility="gone">
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center"
|
|
||||||
android:gravity="center"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@android:id/title"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
|
||||||
android:textColor="?android:attr/textColorSecondary"
|
|
||||||
android:text="Searching for printers">
|
|
||||||
</TextView>
|
|
||||||
|
|
||||||
<ProgressBar
|
|
||||||
android:id="@android:id/progress"
|
|
||||||
android:layout_width="fill_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:indeterminate="true"
|
|
||||||
style="@android:style/Widget.DeviceDefault.Light.ProgressBar.Horizontal">
|
|
||||||
</ProgressBar>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</FrameLayout>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
343
src/android/AssetUtil.java
Normal file
343
src/android/AssetUtil.java
Normal file
@ -0,0 +1,343 @@
|
|||||||
|
/*
|
||||||
|
Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
or more contributor license agreements. See the NOTICE file
|
||||||
|
distributed with this work for additional information
|
||||||
|
regarding copyright ownership. The ASF licenses this file
|
||||||
|
to you 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 de.appplant.cordova.plugin.printer;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.res.AssetManager;
|
||||||
|
import android.content.res.Resources;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.BitmapFactory;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
import android.util.Base64;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
|
||||||
|
class AssetUtil {
|
||||||
|
|
||||||
|
// List of supported content types
|
||||||
|
enum ContentType { PLAIN, HTML, IMAGE, PDF, SELF }
|
||||||
|
|
||||||
|
// Application context
|
||||||
|
private final @NonNull Context context;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the asset utils.
|
||||||
|
*
|
||||||
|
* @param ctx The application context.
|
||||||
|
*/
|
||||||
|
AssetUtil (@NonNull Context ctx) {
|
||||||
|
this.context = ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the content type for the file referenced by its uri.
|
||||||
|
*
|
||||||
|
* @param path The path to check.
|
||||||
|
*
|
||||||
|
* @return The content type even the file does not exist.
|
||||||
|
*/
|
||||||
|
static @NonNull ContentType getContentType (@Nullable String path)
|
||||||
|
{
|
||||||
|
ContentType type = ContentType.PLAIN;
|
||||||
|
|
||||||
|
if (path == null || path.isEmpty())
|
||||||
|
{
|
||||||
|
type = ContentType.SELF;
|
||||||
|
}
|
||||||
|
else if (path.charAt(0) == '<')
|
||||||
|
{
|
||||||
|
type = ContentType.HTML;
|
||||||
|
}
|
||||||
|
else if (path.matches("^[a-z]+://.+"))
|
||||||
|
{
|
||||||
|
return path.endsWith(".pdf") ? ContentType.PDF : ContentType.IMAGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens a file://, res:// or base64:// Uri as a stream.
|
||||||
|
*
|
||||||
|
* @param path The file path to decode.
|
||||||
|
*
|
||||||
|
* @return An open IO stream or null if the file does not exist.
|
||||||
|
*/
|
||||||
|
@Nullable InputStream open (@NonNull String path)
|
||||||
|
{
|
||||||
|
InputStream stream = null;
|
||||||
|
|
||||||
|
if (path.startsWith("res:"))
|
||||||
|
{
|
||||||
|
stream = openResource(path);
|
||||||
|
}
|
||||||
|
else if (path.startsWith("file:///"))
|
||||||
|
{
|
||||||
|
stream = openFile(path);
|
||||||
|
}
|
||||||
|
else if (path.startsWith("file://"))
|
||||||
|
{
|
||||||
|
stream = openAsset(path);
|
||||||
|
}
|
||||||
|
else if (path.startsWith("base64:"))
|
||||||
|
{
|
||||||
|
stream = openBase64(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decodes a file://, res:// or base64:// Uri to bitmap.
|
||||||
|
*
|
||||||
|
* @param path The file path to decode.
|
||||||
|
*
|
||||||
|
* @return A bitmap or null if the path is not valid
|
||||||
|
*/
|
||||||
|
@Nullable Bitmap decode (@NonNull String path)
|
||||||
|
{
|
||||||
|
Bitmap bitmap;
|
||||||
|
|
||||||
|
if (path.startsWith("res:"))
|
||||||
|
{
|
||||||
|
bitmap = decodeResource(path);
|
||||||
|
}
|
||||||
|
else if (path.startsWith("file:///"))
|
||||||
|
{
|
||||||
|
bitmap = decodeFile(path);
|
||||||
|
}
|
||||||
|
else if (path.startsWith("file://"))
|
||||||
|
{
|
||||||
|
bitmap = decodeAsset(path);
|
||||||
|
}
|
||||||
|
else if (path.startsWith("base64:"))
|
||||||
|
{
|
||||||
|
bitmap = decodeBase64(path);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
bitmap = BitmapFactory.decodeFile(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
return bitmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copies content of input stream to output stream.
|
||||||
|
*
|
||||||
|
* @param input The readable input stream.
|
||||||
|
* @param output The writable output stream.
|
||||||
|
*
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
static void copy (@NonNull InputStream input,
|
||||||
|
@NonNull OutputStream output) throws IOException
|
||||||
|
{
|
||||||
|
byte[] buf = new byte[1024];
|
||||||
|
int bytesRead;
|
||||||
|
|
||||||
|
while ((bytesRead = input.read(buf)) > 0) {
|
||||||
|
output.write(buf, 0, bytesRead);
|
||||||
|
}
|
||||||
|
|
||||||
|
output.close();
|
||||||
|
input.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens an file given as a file:/// path.
|
||||||
|
*
|
||||||
|
* @param path The path to the file.
|
||||||
|
*
|
||||||
|
* @return An open IO stream or null if the file does not exist.
|
||||||
|
*/
|
||||||
|
private @Nullable InputStream openFile (@NonNull String path)
|
||||||
|
{
|
||||||
|
String absPath = path.substring(7);
|
||||||
|
|
||||||
|
try {
|
||||||
|
return new FileInputStream(absPath);
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decodes an file given as a file:/// path to a bitmap.
|
||||||
|
*
|
||||||
|
* @param path The path to the file.
|
||||||
|
*
|
||||||
|
* @return A bitmap or null if the path is not valid
|
||||||
|
*/
|
||||||
|
private @Nullable Bitmap decodeFile (@NonNull String path)
|
||||||
|
{
|
||||||
|
String absPath = path.substring(7);
|
||||||
|
|
||||||
|
return BitmapFactory.decodeFile(absPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens an asset file given as a file:// path.
|
||||||
|
*
|
||||||
|
* @param path The path to the asset.
|
||||||
|
*
|
||||||
|
* @return An open IO stream or null if the file does not exist.
|
||||||
|
*/
|
||||||
|
private @Nullable InputStream openAsset (@NonNull String path)
|
||||||
|
{
|
||||||
|
String resPath = path.replaceFirst("file:/", "www");
|
||||||
|
|
||||||
|
try {
|
||||||
|
return getAssets().open(resPath);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decodes an asset file given as a file:// path to a bitmap.
|
||||||
|
*
|
||||||
|
* @param path The path to the asset.
|
||||||
|
*
|
||||||
|
* @return A bitmap or null if the path is not valid
|
||||||
|
*/
|
||||||
|
private @Nullable Bitmap decodeAsset (@NonNull String path)
|
||||||
|
{
|
||||||
|
InputStream stream = openAsset(path);
|
||||||
|
Bitmap bitmap;
|
||||||
|
|
||||||
|
if (stream == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
bitmap = BitmapFactory.decodeStream(stream);
|
||||||
|
|
||||||
|
try {
|
||||||
|
stream.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
return bitmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens a resource file given as a res:// path.
|
||||||
|
*
|
||||||
|
* @param path The path to the resource.
|
||||||
|
*
|
||||||
|
* @return An open IO stream or null if the file does not exist.
|
||||||
|
*/
|
||||||
|
private @NonNull InputStream openResource (@NonNull String path)
|
||||||
|
{
|
||||||
|
String resPath = path.substring(6);
|
||||||
|
int resId = getResId(resPath);
|
||||||
|
|
||||||
|
return getResources().openRawResource(resId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decodes a resource given as a res:// path to a bitmap.
|
||||||
|
*
|
||||||
|
* @param path The path to the resource.
|
||||||
|
*
|
||||||
|
* @return A bitmap or null if the path is not valid
|
||||||
|
*/
|
||||||
|
private @Nullable Bitmap decodeResource (@NonNull String path)
|
||||||
|
{
|
||||||
|
String data = path.substring(9);
|
||||||
|
byte[] bytes = Base64.decode(data, 0);
|
||||||
|
|
||||||
|
return BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens a resource file given as a res:// path.
|
||||||
|
*
|
||||||
|
* @param path The path to the resource.
|
||||||
|
*
|
||||||
|
* @return An open IO stream or null if the file does not exist.
|
||||||
|
*/
|
||||||
|
private @NonNull InputStream openBase64 (@NonNull String path)
|
||||||
|
{
|
||||||
|
String data = path.substring(9);
|
||||||
|
byte[] bytes = Base64.decode(data, 0);
|
||||||
|
|
||||||
|
return new ByteArrayInputStream(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decodes a resource given as a base64:// string to a bitmap.
|
||||||
|
*
|
||||||
|
* @param path The given relative path.
|
||||||
|
*
|
||||||
|
* @return A bitmap or null if the path is not valid
|
||||||
|
*/
|
||||||
|
private @Nullable Bitmap decodeBase64 (@NonNull String path)
|
||||||
|
{
|
||||||
|
String data = path.substring(9);
|
||||||
|
byte[] bytes = Base64.decode(data, 0);
|
||||||
|
|
||||||
|
return BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the resource ID for the given resource path.
|
||||||
|
*
|
||||||
|
* @return The resource ID for the given resource.
|
||||||
|
*/
|
||||||
|
private int getResId (@NonNull String resPath)
|
||||||
|
{
|
||||||
|
Resources res = getResources();
|
||||||
|
String pkgName = context.getPackageName();
|
||||||
|
String dirName = "drawable";
|
||||||
|
String fileName = resPath;
|
||||||
|
|
||||||
|
if (resPath.contains("/")) {
|
||||||
|
dirName = resPath.substring(0, resPath.lastIndexOf('/'));
|
||||||
|
fileName = resPath.substring(resPath.lastIndexOf('/') + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
String resName = fileName.substring(0, fileName.lastIndexOf('.'));
|
||||||
|
int resId = res.getIdentifier(resName, dirName, pkgName);
|
||||||
|
|
||||||
|
if (resId == 0) {
|
||||||
|
resId = res.getIdentifier(resName, "mipmap", pkgName);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resId == 0) {
|
||||||
|
resId = res.getIdentifier(resName, "drawable", pkgName);
|
||||||
|
}
|
||||||
|
|
||||||
|
return resId;
|
||||||
|
}
|
||||||
|
|
||||||
|
private AssetManager getAssets() {
|
||||||
|
return context.getAssets();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Resources getResources() {
|
||||||
|
return context.getResources();
|
||||||
|
}
|
||||||
|
}
|
167
src/android/Options.java
Normal file
167
src/android/Options.java
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
/*
|
||||||
|
Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
or more contributor license agreements. See the NOTICE file
|
||||||
|
distributed with this work for additional information
|
||||||
|
regarding copyright ownership. The ASF licenses this file
|
||||||
|
to you 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 de.appplant.cordova.plugin.printer;
|
||||||
|
|
||||||
|
import android.print.PrintAttributes;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.v4.print.PrintHelper;
|
||||||
|
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import static android.os.Build.VERSION.SDK_INT;
|
||||||
|
import static android.print.PrintAttributes.DUPLEX_MODE_LONG_EDGE;
|
||||||
|
import static android.print.PrintAttributes.DUPLEX_MODE_NONE;
|
||||||
|
import static android.print.PrintAttributes.DUPLEX_MODE_SHORT_EDGE;
|
||||||
|
import static android.print.PrintAttributes.Margins.NO_MARGINS;
|
||||||
|
import static android.print.PrintAttributes.MediaSize.UNKNOWN_LANDSCAPE;
|
||||||
|
import static android.print.PrintAttributes.MediaSize.UNKNOWN_PORTRAIT;
|
||||||
|
import static android.support.v4.print.PrintHelper.ORIENTATION_LANDSCAPE;
|
||||||
|
import static android.support.v4.print.PrintHelper.ORIENTATION_PORTRAIT;
|
||||||
|
import static android.support.v4.print.PrintHelper.SCALE_MODE_FILL;
|
||||||
|
import static android.support.v4.print.PrintHelper.SCALE_MODE_FIT;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper for the print job settings.
|
||||||
|
*/
|
||||||
|
class Options {
|
||||||
|
|
||||||
|
// The print job settings
|
||||||
|
private @NonNull JSONObject spec;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*
|
||||||
|
* @param spec The print job settings.
|
||||||
|
*/
|
||||||
|
Options (@NonNull JSONObject spec)
|
||||||
|
{
|
||||||
|
this.spec = spec;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the name for the print job.
|
||||||
|
*/
|
||||||
|
@NonNull String getJobName()
|
||||||
|
{
|
||||||
|
String jobName = spec.optString("name");
|
||||||
|
|
||||||
|
if (jobName == null || jobName.isEmpty())
|
||||||
|
{
|
||||||
|
jobName = "Printer Plugin Job #" + System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
return jobName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the options into a PrintAttributes object.
|
||||||
|
*/
|
||||||
|
@NonNull PrintAttributes toPrintAttributes()
|
||||||
|
{
|
||||||
|
PrintAttributes.Builder builder = new PrintAttributes.Builder();
|
||||||
|
|
||||||
|
switch (spec.optString("orientation"))
|
||||||
|
{
|
||||||
|
case "landscape":
|
||||||
|
builder.setMediaSize(UNKNOWN_LANDSCAPE);
|
||||||
|
break;
|
||||||
|
case "portrait":
|
||||||
|
builder.setMediaSize(UNKNOWN_PORTRAIT);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (spec.has("graystyle"))
|
||||||
|
{
|
||||||
|
if (spec.optBoolean("graystyle"))
|
||||||
|
{
|
||||||
|
builder.setColorMode(PrintAttributes.COLOR_MODE_MONOCHROME);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
builder.setColorMode(PrintAttributes.COLOR_MODE_COLOR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!spec.optBoolean("border", true))
|
||||||
|
{
|
||||||
|
builder.setMinMargins(NO_MARGINS);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SDK_INT >= 23)
|
||||||
|
{
|
||||||
|
switch (spec.optString("duplex"))
|
||||||
|
{
|
||||||
|
case "long":
|
||||||
|
builder.setDuplexMode(DUPLEX_MODE_LONG_EDGE);
|
||||||
|
break;
|
||||||
|
case "short":
|
||||||
|
builder.setDuplexMode(DUPLEX_MODE_SHORT_EDGE);
|
||||||
|
break;
|
||||||
|
case "none":
|
||||||
|
builder.setDuplexMode(DUPLEX_MODE_NONE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tweaks the printer helper depending on the job spec.
|
||||||
|
*
|
||||||
|
* @param printer The printer to decorate.
|
||||||
|
*/
|
||||||
|
void decoratePrintHelper (@NonNull PrintHelper printer)
|
||||||
|
{
|
||||||
|
switch (spec.optString("orientation"))
|
||||||
|
{
|
||||||
|
case "landscape":
|
||||||
|
printer.setOrientation(ORIENTATION_LANDSCAPE);
|
||||||
|
break;
|
||||||
|
case "portrait":
|
||||||
|
printer.setOrientation(ORIENTATION_PORTRAIT);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (spec.has("graystyle"))
|
||||||
|
{
|
||||||
|
if (spec.optBoolean("graystyle"))
|
||||||
|
{
|
||||||
|
printer.setColorMode(PrintHelper.COLOR_MODE_MONOCHROME);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printer.setColorMode(PrintHelper.COLOR_MODE_COLOR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (spec.has("autoFit"))
|
||||||
|
{
|
||||||
|
if (spec.optBoolean("autoFit"))
|
||||||
|
{
|
||||||
|
printer.setScaleMode(SCALE_MODE_FIT);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printer.setScaleMode(SCALE_MODE_FILL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
108
src/android/PdfAdapter.java
Normal file
108
src/android/PdfAdapter.java
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
/*
|
||||||
|
Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
or more contributor license agreements. See the NOTICE file
|
||||||
|
distributed with this work for additional information
|
||||||
|
regarding copyright ownership. The ASF licenses this file
|
||||||
|
to you 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 de.appplant.cordova.plugin.printer;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
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.support.annotation.NonNull;
|
||||||
|
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
|
||||||
|
import static android.print.PrintDocumentInfo.CONTENT_TYPE_DOCUMENT;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Document adapter to render and print PDF files.
|
||||||
|
*/
|
||||||
|
class PdfAdapter extends PrintDocumentAdapter {
|
||||||
|
|
||||||
|
// The application context
|
||||||
|
private @NonNull Context context;
|
||||||
|
|
||||||
|
// The path to the PDF file
|
||||||
|
private @NonNull String path;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*
|
||||||
|
* @param context The context where to look for.
|
||||||
|
*/
|
||||||
|
PdfAdapter (@NonNull String path, @NonNull Context context)
|
||||||
|
{
|
||||||
|
this.path = path;
|
||||||
|
this.context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLayout (PrintAttributes oldAttributes,
|
||||||
|
PrintAttributes newAttributes,
|
||||||
|
CancellationSignal cancellationSignal,
|
||||||
|
LayoutResultCallback callback,
|
||||||
|
Bundle bundle)
|
||||||
|
{
|
||||||
|
PrintDocumentInfo pdi;
|
||||||
|
|
||||||
|
if (cancellationSignal.isCanceled())
|
||||||
|
return;
|
||||||
|
|
||||||
|
pdi = new PrintDocumentInfo.Builder("test")
|
||||||
|
.setContentType(CONTENT_TYPE_DOCUMENT)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
callback.onLayoutFinished(pdi, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onWrite (PageRange[] range,
|
||||||
|
ParcelFileDescriptor dest,
|
||||||
|
CancellationSignal cancellationSignal,
|
||||||
|
WriteResultCallback callback)
|
||||||
|
{
|
||||||
|
if (cancellationSignal.isCanceled())
|
||||||
|
return;
|
||||||
|
|
||||||
|
AssetUtil io = new AssetUtil(context);
|
||||||
|
InputStream in = io.open(path);
|
||||||
|
|
||||||
|
if (in == null) {
|
||||||
|
callback.onWriteFailed("File not found: " + path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
OutputStream out = new FileOutputStream(dest.getFileDescriptor());
|
||||||
|
|
||||||
|
try {
|
||||||
|
AssetUtil.copy(in, out);
|
||||||
|
} catch (IOException e) {
|
||||||
|
callback.onWriteFailed(e.getMessage());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
callback.onWriteFinished(new PageRange[]{ PageRange.ALL_PAGES });
|
||||||
|
}
|
||||||
|
}
|
167
src/android/PrintManager.java
Normal file
167
src/android/PrintManager.java
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2013-2016 appPlant GmbH
|
||||||
|
|
||||||
|
Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
or more contributor license agreements. See the NOTICE file
|
||||||
|
distributed with this work for additional information
|
||||||
|
regarding copyright ownership. The ASF licenses this file
|
||||||
|
to you 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 de.appplant.cordova.plugin.printer;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.print.PrintAttributes;
|
||||||
|
import android.print.PrintDocumentAdapter;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
import android.support.v4.print.PrintHelper;
|
||||||
|
|
||||||
|
import org.json.JSONArray;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import static android.content.Context.PRINT_SERVICE;
|
||||||
|
|
||||||
|
class PrintManager {
|
||||||
|
|
||||||
|
// The application context
|
||||||
|
private @NonNull Context context;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*
|
||||||
|
* @param context The context where to look for.
|
||||||
|
*/
|
||||||
|
PrintManager (@NonNull Context context)
|
||||||
|
{
|
||||||
|
this.context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the print framework is able to render the referenced file.
|
||||||
|
*
|
||||||
|
* @param item Any kind of URL like file://, file:///, res:// or base64://
|
||||||
|
*
|
||||||
|
* @return true if its able to render the content of the file.
|
||||||
|
*/
|
||||||
|
boolean canPrintItem (@Nullable String item)
|
||||||
|
{
|
||||||
|
boolean supported = PrintHelper.systemSupportsPrint();
|
||||||
|
|
||||||
|
if (item != null)
|
||||||
|
{
|
||||||
|
supported = new AssetUtil(context).open(item) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return supported;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return List of all printable document types (utis).
|
||||||
|
*/
|
||||||
|
static JSONArray getPrintableUTIs()
|
||||||
|
{
|
||||||
|
JSONArray utis = new JSONArray();
|
||||||
|
|
||||||
|
utis.put("com.adobe.pdf");
|
||||||
|
utis.put("com.microsoft.bmp");
|
||||||
|
utis.put("public.jpeg");
|
||||||
|
utis.put("public.jpeg-2000");
|
||||||
|
utis.put("public.png");
|
||||||
|
utis.put("public.heif");
|
||||||
|
utis.put("com.compuserve.gif");
|
||||||
|
utis.put("com.microsoft.ico");
|
||||||
|
utis.put("com.microsoft.bmp");
|
||||||
|
utis.put("com.microsoft.bmp");
|
||||||
|
|
||||||
|
return utis;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends the provided content to the printing controller and opens
|
||||||
|
* them.
|
||||||
|
*
|
||||||
|
* @param content The content or file to print.
|
||||||
|
* @param settings Additional settings how to render the content.
|
||||||
|
* @param callback The function to invoke once the job is done.
|
||||||
|
*/
|
||||||
|
void print (@Nullable String content, JSONObject settings,
|
||||||
|
@Nullable PrintHelper.OnPrintFinishCallback callback)
|
||||||
|
{
|
||||||
|
switch (AssetUtil.getContentType(content))
|
||||||
|
{
|
||||||
|
case IMAGE:
|
||||||
|
printImage(content, settings, callback);
|
||||||
|
break;
|
||||||
|
case PDF:
|
||||||
|
printPdf(content, settings, callback);
|
||||||
|
break;
|
||||||
|
case HTML:
|
||||||
|
case SELF:
|
||||||
|
case PLAIN:
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prints the provided PDF document.
|
||||||
|
*
|
||||||
|
* @param path The path to the file to print.
|
||||||
|
* @param settings Additional settings how to render the content.
|
||||||
|
* @param callback The function to invoke once the job is done.
|
||||||
|
*/
|
||||||
|
private void printPdf (String path, JSONObject settings,
|
||||||
|
@Nullable PrintHelper.OnPrintFinishCallback callback)
|
||||||
|
{
|
||||||
|
Options options = new Options(settings);
|
||||||
|
String jobName = options.getJobName();
|
||||||
|
PrintDocumentAdapter adapter = new PdfAdapter(path, context);
|
||||||
|
PrintAttributes attributes = options.toPrintAttributes();
|
||||||
|
|
||||||
|
getPrintService().print(jobName, adapter, attributes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prints the specified image by file uri.
|
||||||
|
*
|
||||||
|
* @param path The path to the file to print.
|
||||||
|
* @param settings Additional settings how to render the content.
|
||||||
|
* @param callback The function to invoke once the job is done.
|
||||||
|
*/
|
||||||
|
private void printImage (String path, JSONObject settings,
|
||||||
|
@Nullable PrintHelper.OnPrintFinishCallback callback)
|
||||||
|
{
|
||||||
|
AssetUtil decoder = new AssetUtil(context);
|
||||||
|
Bitmap bitmap = decoder.decode(path);
|
||||||
|
|
||||||
|
if (bitmap == null) return;
|
||||||
|
|
||||||
|
Options options = new Options(settings);
|
||||||
|
PrintHelper printer = new PrintHelper(context);
|
||||||
|
String jobName = options.getJobName();
|
||||||
|
|
||||||
|
options.decoratePrintHelper(printer);
|
||||||
|
|
||||||
|
printer.printBitmap(jobName, bitmap, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the print service of the app.
|
||||||
|
*/
|
||||||
|
private @NonNull android.print.PrintManager getPrintService()
|
||||||
|
{
|
||||||
|
return (android.print.PrintManager) context.getSystemService(PRINT_SERVICE);
|
||||||
|
}
|
||||||
|
}
|
@ -21,83 +21,20 @@
|
|||||||
|
|
||||||
package de.appplant.cordova.plugin.printer;
|
package de.appplant.cordova.plugin.printer;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.support.annotation.Nullable;
|
||||||
import android.content.Intent;
|
|
||||||
import android.os.Build;
|
|
||||||
import android.print.PrintAttributes;
|
|
||||||
import android.print.PrintDocumentAdapter;
|
|
||||||
import android.print.PrintJob;
|
|
||||||
import android.print.PrinterId;
|
|
||||||
import android.view.View;
|
|
||||||
import android.webkit.WebSettings;
|
|
||||||
import android.webkit.WebView;
|
|
||||||
import android.webkit.WebViewClient;
|
|
||||||
|
|
||||||
import org.apache.cordova.CallbackContext;
|
import org.apache.cordova.CallbackContext;
|
||||||
import org.apache.cordova.CordovaPlugin;
|
import org.apache.cordova.CordovaPlugin;
|
||||||
import org.apache.cordova.CordovaWebView;
|
|
||||||
import org.apache.cordova.CordovaInterface;
|
|
||||||
import org.apache.cordova.PluginResult;
|
import org.apache.cordova.PluginResult;
|
||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
import org.json.JSONException;
|
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import de.appplant.cordova.plugin.printer.ext.PrintManager;
|
|
||||||
import de.appplant.cordova.plugin.printer.ext.PrintManager.OnPrintJobStateChangeListener;
|
|
||||||
import de.appplant.cordova.plugin.printer.ext.PrintServiceInfo;
|
|
||||||
import de.appplant.cordova.plugin.printer.reflect.Meta;
|
|
||||||
import de.appplant.cordova.plugin.printer.ui.SelectPrinterActivity;
|
|
||||||
|
|
||||||
import static android.print.PrintJobInfo.STATE_STARTED;
|
|
||||||
import static de.appplant.cordova.plugin.printer.ui.SelectPrinterActivity.ACTION_SELECT_PRINTER;
|
|
||||||
import static de.appplant.cordova.plugin.printer.ui.SelectPrinterActivity.EXTRA_PRINTER_ID;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Plugin to print HTML documents. Therefore it creates an invisible web view
|
* Plugin to print HTML documents. Therefore it creates an invisible web view
|
||||||
* that loads the markup data. Once the page has been fully rendered it takes
|
* that loads the markup data. Once the page has been fully rendered it takes
|
||||||
* the print adapter of that web view and initializes a print job.
|
* the print adapter of that web view and initializes a print job.
|
||||||
*/
|
*/
|
||||||
public class Printer extends CordovaPlugin {
|
public class Printer extends CordovaPlugin {
|
||||||
CordovaWebView _webView;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The web view that loads all the content.
|
|
||||||
*/
|
|
||||||
private WebView view;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reference is necessary to invoke the callback in the onresume event.
|
|
||||||
*/
|
|
||||||
private CallbackContext command;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Instance of the print manager to listen for job status changes.
|
|
||||||
*/
|
|
||||||
private PrintManager pm;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Invokes the callback once the job has reached a final state.
|
|
||||||
*/
|
|
||||||
private OnPrintJobStateChangeListener listener = new OnPrintJobStateChangeListener() {
|
|
||||||
/**
|
|
||||||
* Callback notifying that a print job state changed.
|
|
||||||
*
|
|
||||||
* @param job The print job.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void onPrintJobStateChanged(PrintJob job) {
|
|
||||||
notifyAboutPrintJobResult(job);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Default name of the printed document (PDF-Printer).
|
|
||||||
*/
|
|
||||||
private static final String DEFAULT_DOC_NAME = "unknown";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Executes the request.
|
* Executes the request.
|
||||||
@ -112,298 +49,85 @@ public class Printer extends CordovaPlugin {
|
|||||||
* @param action The action to execute.
|
* @param action The action to execute.
|
||||||
* @param args The exec() arguments in JSON form.
|
* @param args The exec() arguments in JSON form.
|
||||||
* @param callback The callback context used when calling back into JavaScript.
|
* @param callback The callback context used when calling back into JavaScript.
|
||||||
|
*
|
||||||
* @return Whether the action was valid.
|
* @return Whether the action was valid.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean execute (String action, JSONArray args,
|
public boolean execute (String action, JSONArray args,
|
||||||
CallbackContext callback) throws JSONException {
|
CallbackContext callback)
|
||||||
|
{
|
||||||
|
boolean valid = true;
|
||||||
|
|
||||||
command = callback;
|
if (action.equalsIgnoreCase("check"))
|
||||||
|
{
|
||||||
if (action.equalsIgnoreCase("check")) {
|
check(args.optString(0), callback);
|
||||||
check();
|
}
|
||||||
return true;
|
else if (action.equalsIgnoreCase("utis"))
|
||||||
|
{
|
||||||
|
utis(callback);
|
||||||
|
}
|
||||||
|
else if (action.equalsIgnoreCase("print"))
|
||||||
|
{
|
||||||
|
print(args.optString(0), args.optJSONObject(1), callback);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
valid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action.equalsIgnoreCase("pick")) {
|
return valid;
|
||||||
pick();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (action.equalsIgnoreCase("print")) {
|
|
||||||
print(args);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Informs if the device is able to print documents.
|
* If the print framework is able to render the referenced file.
|
||||||
* A Internet connection is required to load the cloud print dialog.
|
|
||||||
*/
|
|
||||||
private void check () {
|
|
||||||
cordova.getThreadPool().execute(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
List<PrintServiceInfo> services = pm.getEnabledPrintServices();
|
|
||||||
Boolean available = services.size() > 0;
|
|
||||||
|
|
||||||
PluginResult res1 = new PluginResult(
|
|
||||||
PluginResult.Status.OK, available);
|
|
||||||
PluginResult res2 = new PluginResult(
|
|
||||||
PluginResult.Status.OK, services.size());
|
|
||||||
PluginResult res = new PluginResult(
|
|
||||||
PluginResult.Status.OK, Arrays.asList(res1, res2));
|
|
||||||
|
|
||||||
command.sendPluginResult(res);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads the HTML content into the web view and invokes the print manager.
|
|
||||||
*
|
*
|
||||||
* @param args
|
* @param item Any kind of URL like file://, file:///, res:// or base64://
|
||||||
* The exec arguments as JSON
|
* @param callback The plugin function to invoke with the result.
|
||||||
*/
|
*/
|
||||||
private void print (final JSONArray args) {
|
private void check (@Nullable String item, CallbackContext callback)
|
||||||
final String content = args.optString(0);
|
{
|
||||||
final JSONObject props = args.optJSONObject(1);
|
cordova.getThreadPool().execute(() -> {
|
||||||
|
PrintManager pm = new PrintManager(cordova.getContext());
|
||||||
cordova.getActivity().runOnUiThread( new Runnable() {
|
boolean printable = pm.canPrintItem(item);
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
if( content.isEmpty() ) {
|
|
||||||
do_print((WebView)_webView.getView(), props);
|
|
||||||
} else {
|
|
||||||
initWebView(props);
|
|
||||||
loadContent(content);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Presents a list with all enabled print services and invokes the
|
|
||||||
* callback with the selected one.
|
|
||||||
*/
|
|
||||||
private void pick () {
|
|
||||||
Intent intent = new Intent(
|
|
||||||
cordova.getActivity(), SelectPrinterActivity.class);
|
|
||||||
|
|
||||||
cordova.startActivityForResult(this, intent, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads the content into the web view.
|
|
||||||
*
|
|
||||||
* @param content
|
|
||||||
* Either an HTML string or URI
|
|
||||||
*/
|
|
||||||
private void loadContent(String content) {
|
|
||||||
if (content.startsWith("http") || content.startsWith("file:")) {
|
|
||||||
view.loadUrl(content);
|
|
||||||
} else {
|
|
||||||
String baseURL = webView.getUrl();
|
|
||||||
baseURL = baseURL.substring(0, baseURL.lastIndexOf('/') + 1);
|
|
||||||
|
|
||||||
// Set base URI to the assets/www folder
|
|
||||||
view.loadDataWithBaseURL(
|
|
||||||
baseURL, content, "text/html", "UTF-8", null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Configures the WebView components which will call the Google Cloud Print
|
|
||||||
* Service.
|
|
||||||
*
|
|
||||||
* @param props
|
|
||||||
* The JSON object with the containing page properties
|
|
||||||
*/
|
|
||||||
private void initWebView (JSONObject props) {
|
|
||||||
Activity ctx = cordova.getActivity();
|
|
||||||
view = new WebView(ctx);
|
|
||||||
WebSettings settings = view.getSettings();
|
|
||||||
final boolean jsEnabled = props.optBoolean("javascript", false);
|
|
||||||
|
|
||||||
settings.setDatabaseEnabled(true);
|
|
||||||
settings.setGeolocationEnabled(true);
|
|
||||||
settings.setSaveFormData(true);
|
|
||||||
settings.setUseWideViewPort(true);
|
|
||||||
if (jsEnabled) {
|
|
||||||
settings.setJavaScriptEnabled(jsEnabled);
|
|
||||||
}
|
|
||||||
view.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
|
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= 21) {
|
|
||||||
Method setMixedContentModeMethod = Meta.getMethod(
|
|
||||||
settings.getClass(), "setMixedContentMode", int.class);
|
|
||||||
|
|
||||||
Meta.invokeMethod(settings, setMixedContentModeMethod, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
setWebViewClient(props);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void do_print(WebView webView, JSONObject props) {
|
|
||||||
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");
|
|
||||||
|
|
||||||
PrintAttributes.Builder builder = new PrintAttributes.Builder();
|
|
||||||
PrintDocumentAdapter adapter = getAdapter(webView, docName);
|
|
||||||
|
|
||||||
builder.setMinMargins(PrintAttributes.Margins.NO_MARGINS);
|
|
||||||
|
|
||||||
builder.setColorMode(graystyle
|
|
||||||
? PrintAttributes.COLOR_MODE_MONOCHROME
|
|
||||||
: PrintAttributes.COLOR_MODE_COLOR);
|
|
||||||
|
|
||||||
builder.setMediaSize(landscape
|
|
||||||
? PrintAttributes.MediaSize.UNKNOWN_LANDSCAPE
|
|
||||||
: PrintAttributes.MediaSize.UNKNOWN_PORTRAIT);
|
|
||||||
|
|
||||||
if (!duplex.equals("none") && Build.VERSION.SDK_INT >= 23) {
|
|
||||||
boolean longEdge = duplex.equals("long");
|
|
||||||
Method setDuplexModeMethod = Meta.getMethod(
|
|
||||||
builder.getClass(), "setDuplexMode", int.class);
|
|
||||||
|
|
||||||
Meta.invokeMethod(builder, setDuplexModeMethod,
|
|
||||||
longEdge ? 2 : 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
pm.getInstance().print(docName, adapter, builder.build());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates the web view client which sets the print document.
|
|
||||||
*
|
|
||||||
* @param props
|
|
||||||
* The JSON object with the containing page properties
|
|
||||||
*/
|
|
||||||
private void setWebViewClient (JSONObject props) {
|
|
||||||
view.setWebViewClient(new WebViewClient() {
|
|
||||||
@Override
|
|
||||||
public boolean shouldOverrideUrlLoading (WebView view, String url) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onPageFinished (WebView webView, String url) {
|
|
||||||
do_print(webView, props);
|
|
||||||
view = null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Invoke the callback send with `print` to inform about the result.
|
|
||||||
*
|
|
||||||
* @param job The print job.
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("ConstantConditions")
|
|
||||||
private void notifyAboutPrintJobResult(PrintJob job) {
|
|
||||||
|
|
||||||
if (job == null || command == null ||
|
|
||||||
job.getInfo().getState() <= STATE_STARTED) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
PluginResult res = new PluginResult(
|
PluginResult res = new PluginResult(
|
||||||
PluginResult.Status.OK, job.isCompleted());
|
PluginResult.Status.OK, printable);
|
||||||
|
|
||||||
command.sendPluginResult(res);
|
callback.sendPluginResult(res);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create the print document adapter for the web view component. On
|
* List of all printable document types (utis).
|
||||||
* devices older then SDK 21 it will use the deprecated method
|
|
||||||
* `createPrintDocumentAdapter` without arguments and on newer devices
|
|
||||||
* the recommended way.
|
|
||||||
*
|
*
|
||||||
* @param webView
|
* @param callback The plugin function to invoke with the result.
|
||||||
* 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) {
|
private void utis (CallbackContext callback)
|
||||||
if (Build.VERSION.SDK_INT >= 21) {
|
{
|
||||||
Method createPrintDocumentAdapterMethod = Meta.getMethod(
|
cordova.getThreadPool().execute(() -> {
|
||||||
WebView.class, "createPrintDocumentAdapter", String.class);
|
JSONArray utis = PrintManager.getPrintableUTIs();
|
||||||
|
|
||||||
return (PrintDocumentAdapter) Meta.invokeMethod(
|
PluginResult res = new PluginResult(
|
||||||
webView, createPrintDocumentAdapterMethod, docName);
|
PluginResult.Status.OK, utis);
|
||||||
} else {
|
|
||||||
return (PrintDocumentAdapter) Meta.invokeMethod(webView,
|
callback.sendPluginResult(res);
|
||||||
"createPrintDocumentAdapter");
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called after plugin construction and fields have been initialized.
|
* Sends the provided content to the printing controller and opens
|
||||||
*/
|
* them.
|
||||||
@Override
|
|
||||||
protected void pluginInitialize() {
|
|
||||||
super.pluginInitialize();
|
|
||||||
pm = new PrintManager(cordova.getActivity());
|
|
||||||
pm.setOnPrintJobStateChangeListener(listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void initialize(CordovaInterface cordova, CordovaWebView webView) {
|
|
||||||
super.initialize(cordova, webView);
|
|
||||||
_webView = webView;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The final call you receive before your activity is destroyed.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void onDestroy() {
|
|
||||||
if(pm != null && listener != null && command != null && view != null) {
|
|
||||||
pm.unsetOnPrintJobStateChangeListener();
|
|
||||||
|
|
||||||
pm = null;
|
|
||||||
listener = null;
|
|
||||||
command = null;
|
|
||||||
view = null;
|
|
||||||
|
|
||||||
super.onDestroy();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Invoke the callback from `pick` method.
|
|
||||||
*
|
*
|
||||||
* @param requestCode The request code originally supplied to
|
* @param content The content or file to print.
|
||||||
* startActivityForResult(), allowing you to
|
* @param settings Additional settings how to render the content.
|
||||||
* identify who this result came from.
|
* @param callback The plugin function to invoke with the result.
|
||||||
* @param resultCode The integer result code returned by the child
|
|
||||||
* activity through its setResult().
|
|
||||||
* @param intent An Intent, which can return result data to the
|
|
||||||
* caller (various data can be
|
|
||||||
*/
|
*/
|
||||||
@Override
|
private void print (@Nullable String content, JSONObject settings,
|
||||||
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
|
CallbackContext callback)
|
||||||
super.onActivityResult(requestCode, resultCode, intent);
|
{
|
||||||
|
cordova.getThreadPool().execute(() -> {
|
||||||
if (command == null || intent == null) {
|
PrintManager pm = new PrintManager(cordova.getContext());
|
||||||
return;
|
pm.print(content, settings, callback::success);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!intent.getAction().equals(ACTION_SELECT_PRINTER)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
PrinterId printer = intent.getParcelableExtra(EXTRA_PRINTER_ID);
|
|
||||||
|
|
||||||
PluginResult res = new PluginResult(PluginResult.Status.OK,
|
|
||||||
printer != null ? printer.getLocalId() : null);
|
|
||||||
|
|
||||||
command.sendPluginResult(res);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,257 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2013-2016 appPlant GmbH
|
|
||||||
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you 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 de.appplant.cordova.plugin.printer.ext;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.os.Build;
|
|
||||||
import android.print.PrintJob;
|
|
||||||
import android.print.PrintJobId;
|
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
|
||||||
import java.lang.reflect.InvocationHandler;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.lang.reflect.Proxy;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import de.appplant.cordova.plugin.printer.reflect.Meta;
|
|
||||||
|
|
||||||
public final class PrintManager {
|
|
||||||
|
|
||||||
public interface OnPrintJobStateChangeListener {
|
|
||||||
/**
|
|
||||||
* Callback notifying that a print job state changed.
|
|
||||||
*
|
|
||||||
* @param job The print job.
|
|
||||||
*/
|
|
||||||
void onPrintJobStateChanged(PrintJob job);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Required to be able to register a listener of hidden interface.
|
|
||||||
*/
|
|
||||||
private class OnPrintJobStateChangeProxy implements InvocationHandler {
|
|
||||||
@Override
|
|
||||||
public Object invoke (Object o, Method method, Object[] objects)
|
|
||||||
throws Throwable {
|
|
||||||
|
|
||||||
if (method.getName().equals("hashCode")) {
|
|
||||||
return listener.get().hashCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (method.getName().equals("onPrintJobStateChanged")) {
|
|
||||||
notifyOnPrintJobStateChanged((PrintJobId) objects[0]);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Exception();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The application context.
|
|
||||||
*/
|
|
||||||
private WeakReference<Context> ctx;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The registered listener for the state change event.
|
|
||||||
*/
|
|
||||||
private WeakReference<OnPrintJobStateChangeListener> listener;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The proxy wrapper of the listener.
|
|
||||||
*/
|
|
||||||
private Object proxy;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*
|
|
||||||
* @param context The context where to look for.
|
|
||||||
*/
|
|
||||||
public PrintManager (Context context) {
|
|
||||||
this.ctx = new WeakReference<Context>(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get an instance from PrintManager service.
|
|
||||||
*
|
|
||||||
* @return A PrintManager instance.
|
|
||||||
*/
|
|
||||||
public final android.print.PrintManager getInstance () {
|
|
||||||
return (android.print.PrintManager)
|
|
||||||
ctx.get().getSystemService(Context.PRINT_SERVICE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the list of installed print services.
|
|
||||||
*
|
|
||||||
* @return The found service list or an empty list.
|
|
||||||
*/
|
|
||||||
public final List<PrintServiceInfo> getInstalledPrintServices () {
|
|
||||||
List printers;
|
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT < 24) {
|
|
||||||
printers = (List) Meta.invokeMethod(getInstance(),
|
|
||||||
"getInstalledPrintServices");
|
|
||||||
} else {
|
|
||||||
Method getPrintServicesMethod = Meta.getMethod(
|
|
||||||
getInstance().getClass(), "getPrintServices", int.class);
|
|
||||||
|
|
||||||
printers = (List) Meta.invokeMethod(getInstance(),
|
|
||||||
getPrintServicesMethod, 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
ArrayList<PrintServiceInfo> services =
|
|
||||||
new ArrayList<PrintServiceInfo>();
|
|
||||||
|
|
||||||
if (printers == null)
|
|
||||||
return Collections.emptyList();
|
|
||||||
|
|
||||||
for (Object printer : printers) {
|
|
||||||
services.add(new PrintServiceInfo(printer));
|
|
||||||
}
|
|
||||||
|
|
||||||
return services;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the list of enabled print services.
|
|
||||||
*
|
|
||||||
* @return The found service list or an empty list.
|
|
||||||
*/
|
|
||||||
public final List<PrintServiceInfo> getEnabledPrintServices () {
|
|
||||||
List printers;
|
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT < 24) {
|
|
||||||
printers = (List) Meta.invokeMethod(getInstance(),
|
|
||||||
"getEnabledPrintServices");
|
|
||||||
} else {
|
|
||||||
Method getPrintServicesMethod = Meta.getMethod(
|
|
||||||
getInstance().getClass(), "getPrintServices", int.class);
|
|
||||||
|
|
||||||
printers = (List) Meta.invokeMethod(getInstance(),
|
|
||||||
getPrintServicesMethod, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
ArrayList<PrintServiceInfo> services =
|
|
||||||
new ArrayList<PrintServiceInfo>();
|
|
||||||
|
|
||||||
if (printers == null)
|
|
||||||
return Collections.emptyList();
|
|
||||||
|
|
||||||
for (Object printer : printers) {
|
|
||||||
services.add(new PrintServiceInfo(printer));
|
|
||||||
}
|
|
||||||
|
|
||||||
return services;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates an session object to discover all printer services. To do so
|
|
||||||
* you need to register a listener object and start the discovery process.
|
|
||||||
*
|
|
||||||
* @return An instance of class PrinterDiscoverySession.
|
|
||||||
*/
|
|
||||||
public final PrinterDiscoverySession createPrinterDiscoverySession () {
|
|
||||||
Object session = Meta.invokeMethod(getInstance(),
|
|
||||||
"createPrinterDiscoverySession");
|
|
||||||
|
|
||||||
return new PrinterDiscoverySession(session);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a listener for observing the state of print jobs.
|
|
||||||
*
|
|
||||||
* @param listener The listener to add.
|
|
||||||
*/
|
|
||||||
public void setOnPrintJobStateChangeListener(
|
|
||||||
OnPrintJobStateChangeListener listener) {
|
|
||||||
|
|
||||||
if (this.listener == listener)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (listener == null) {
|
|
||||||
unsetOnPrintJobStateChangeListener();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Class<?> interfaceCls = Meta.getClass(
|
|
||||||
"android.print.PrintManager$PrintJobStateChangeListener");
|
|
||||||
|
|
||||||
if (interfaceCls == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
this.listener =
|
|
||||||
new WeakReference<OnPrintJobStateChangeListener>(listener);
|
|
||||||
|
|
||||||
Method method = Meta.getMethod(getInstance().getClass(),
|
|
||||||
"addPrintJobStateChangeListener", interfaceCls);
|
|
||||||
|
|
||||||
Class<?>[] interfaces = {interfaceCls};
|
|
||||||
|
|
||||||
proxy = Proxy.newProxyInstance(
|
|
||||||
interfaceCls.getClassLoader(),
|
|
||||||
interfaces,
|
|
||||||
new OnPrintJobStateChangeProxy()
|
|
||||||
);
|
|
||||||
|
|
||||||
Meta.invokeMethod(getInstance(), method, proxy);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes the listener from the observing the state of print jobs.
|
|
||||||
*/
|
|
||||||
public void unsetOnPrintJobStateChangeListener() {
|
|
||||||
Class<?> interfaceCls = Meta.getClass(
|
|
||||||
"android.print.PrintManager$PrintJobStateChangeListener");
|
|
||||||
|
|
||||||
if (interfaceCls == null || proxy == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
Method method = Meta.getMethod(getInstance().getClass(),
|
|
||||||
"removePrintJobStateChangeListener", interfaceCls);
|
|
||||||
|
|
||||||
Meta.invokeMethod(getInstance(), method, proxy);
|
|
||||||
|
|
||||||
proxy = null;
|
|
||||||
listener = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback notifying that a print job state changed.
|
|
||||||
*
|
|
||||||
* @param printJobId The print job id.
|
|
||||||
*/
|
|
||||||
private void notifyOnPrintJobStateChanged(PrintJobId printJobId) {
|
|
||||||
if (listener != null && listener.get() != null) {
|
|
||||||
Method method = Meta.getMethod(getInstance().getClass(),
|
|
||||||
"getPrintJob", PrintJobId.class);
|
|
||||||
|
|
||||||
PrintJob job = (PrintJob) Meta.invokeMethod(getInstance(),
|
|
||||||
method, printJobId);
|
|
||||||
|
|
||||||
listener.get().onPrintJobStateChanged(job);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,71 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2013-2016 appPlant GmbH
|
|
||||||
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you 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 de.appplant.cordova.plugin.printer.ext;
|
|
||||||
|
|
||||||
import android.content.pm.ResolveInfo;
|
|
||||||
|
|
||||||
import de.appplant.cordova.plugin.printer.reflect.Meta;
|
|
||||||
|
|
||||||
public final class PrintServiceInfo {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The wrapped object of type android.printservice.PrintServiceInfo
|
|
||||||
*/
|
|
||||||
private Object obj;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wraps the object of the hidden class
|
|
||||||
* android.printservice.PrintServiceInfo.
|
|
||||||
*
|
|
||||||
* @param wrappedObj The object to wrap.
|
|
||||||
*/
|
|
||||||
PrintServiceInfo (Object wrappedObj) {
|
|
||||||
obj = wrappedObj;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The accessibility service id.
|
|
||||||
*
|
|
||||||
* @return @return The id.
|
|
||||||
*/
|
|
||||||
public final String getId() {
|
|
||||||
return (String) Meta.invokeMethod(obj, "getId");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The add printers activity name.
|
|
||||||
*
|
|
||||||
* @return The add printers activity name.
|
|
||||||
*/
|
|
||||||
public final String getAddPrintersActivityName() {
|
|
||||||
return (String) Meta.invokeMethod(obj, "getAddPrintersActivityName");
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* The service {@link ResolveInfo}.
|
|
||||||
*
|
|
||||||
* @return The info.
|
|
||||||
*/
|
|
||||||
public final ResolveInfo getResolveInfo() {
|
|
||||||
return (ResolveInfo) Meta.invokeMethod(obj, "getResolveInfo");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,168 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2013-2016 appPlant GmbH
|
|
||||||
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you 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 de.appplant.cordova.plugin.printer.ext;
|
|
||||||
|
|
||||||
import android.print.PrinterInfo;
|
|
||||||
|
|
||||||
import java.lang.reflect.InvocationHandler;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.lang.reflect.Proxy;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import de.appplant.cordova.plugin.printer.reflect.Meta;
|
|
||||||
|
|
||||||
public final class PrinterDiscoverySession {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Required interface of the listener.
|
|
||||||
*/
|
|
||||||
public interface OnPrintersChangeListener {
|
|
||||||
void onPrintersChanged(List<PrinterInfo> printerInfos);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Required to be able to register a listener of the expected type.
|
|
||||||
*/
|
|
||||||
private class OnPrintersChangeProxy implements InvocationHandler {
|
|
||||||
@Override
|
|
||||||
public Object invoke (Object o, Method method, Object[] objects)
|
|
||||||
throws Throwable {
|
|
||||||
|
|
||||||
if (method.getName().equals("onPrintersChanged")) {
|
|
||||||
notifyOnPrintersChanged();
|
|
||||||
return null;
|
|
||||||
} else throw new Exception();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The wrapped session of type
|
|
||||||
* android.print.PrinterDiscoverySession
|
|
||||||
*/
|
|
||||||
private Object session;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Registered listener object.
|
|
||||||
*/
|
|
||||||
private OnPrintersChangeListener listener = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*
|
|
||||||
* @param session An instance of type
|
|
||||||
* android.print.PrinterDiscoverySession
|
|
||||||
*/
|
|
||||||
PrinterDiscoverySession(Object session) {
|
|
||||||
this.session = session;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start discovering available printers.
|
|
||||||
*/
|
|
||||||
public final void startPrinterDiscovery () {
|
|
||||||
Method method = Meta.getMethod(session.getClass(),
|
|
||||||
"startPrinterDiscovery", List.class);
|
|
||||||
|
|
||||||
Meta.invokeMethod(session, method, Collections.emptyList());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stop discovering printers.
|
|
||||||
*/
|
|
||||||
private void stopPrinterDiscovery() {
|
|
||||||
Meta.invokeMethod(session, "stopPrinterDiscovery");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If session is discovering printers.
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("ConstantConditions")
|
|
||||||
public final boolean isPrinterDiscoveryStarted() {
|
|
||||||
return (Boolean) Meta.invokeMethod(session,
|
|
||||||
"isPrinterDiscoveryStarted");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register the listener.
|
|
||||||
*
|
|
||||||
* @param listener Use null to unregister the listener.
|
|
||||||
*/
|
|
||||||
public final void setOnPrintersChangeListener(
|
|
||||||
OnPrintersChangeListener listener) {
|
|
||||||
|
|
||||||
Object proxy = null;
|
|
||||||
Class<?> interfaceCls = Meta.getClass(
|
|
||||||
"android.print.PrinterDiscoverySession$OnPrintersChangeListener");
|
|
||||||
|
|
||||||
if (interfaceCls == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
this.listener = listener;
|
|
||||||
|
|
||||||
Method method = Meta.getMethod(session.getClass(),
|
|
||||||
"setOnPrintersChangeListener", interfaceCls);
|
|
||||||
|
|
||||||
if (listener != null) {
|
|
||||||
Class<?>[] interfaces = {interfaceCls};
|
|
||||||
|
|
||||||
proxy = Proxy.newProxyInstance(
|
|
||||||
interfaceCls.getClassLoader(),
|
|
||||||
interfaces,
|
|
||||||
new OnPrintersChangeProxy()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Meta.invokeMethod(session, method, proxy);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Destroy the session if not already done.
|
|
||||||
*/
|
|
||||||
public final void destroy() {
|
|
||||||
stopPrinterDiscovery();
|
|
||||||
setOnPrintersChangeListener(null);
|
|
||||||
Meta.invokeMethod(session, "destroy");
|
|
||||||
session = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a list of all yet discovered printers.
|
|
||||||
*
|
|
||||||
* @return List of their basic infos
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
private List<PrinterInfo> getPrinters() {
|
|
||||||
Method method = Meta.getMethod(session.getClass(), "getPrinters");
|
|
||||||
|
|
||||||
return (List<PrinterInfo>) Meta.invokeMethod(session, method);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Notifies the listener about the occurred event.
|
|
||||||
*/
|
|
||||||
private void notifyOnPrintersChanged() {
|
|
||||||
if (listener != null) {
|
|
||||||
listener.onPrintersChanged(getPrinters());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,146 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2013-2016 appPlant GmbH
|
|
||||||
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you 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 de.appplant.cordova.plugin.printer.reflect;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.res.Resources;
|
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is an activity for selecting a printer.
|
|
||||||
*/
|
|
||||||
public abstract class Meta {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tries to find the class for the given name.
|
|
||||||
*
|
|
||||||
* @param fullName
|
|
||||||
* The full class name including the package scope.
|
|
||||||
* @return
|
|
||||||
* The found class or null.
|
|
||||||
*/
|
|
||||||
public static Class<?> getClass (String fullName) {
|
|
||||||
try {
|
|
||||||
return Class.forName(fullName);
|
|
||||||
} catch (ClassNotFoundException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
public static Method getMethod (Class<?> cls, String name, Class<?>... params) {
|
|
||||||
try {
|
|
||||||
return cls.getDeclaredMethod(name, params);
|
|
||||||
} catch (NoSuchMethodException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
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.
|
|
||||||
*/
|
|
||||||
public static 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Invokes the method on the given object.
|
|
||||||
*
|
|
||||||
* @param obj
|
|
||||||
* An object which class defines the method.
|
|
||||||
* @param methodName
|
|
||||||
* The name of method to invoke.
|
|
||||||
* @return
|
|
||||||
* The returned object or null.
|
|
||||||
*/
|
|
||||||
public static Object invokeMethod (Object obj, String methodName) {
|
|
||||||
Method method = getMethod(obj.getClass(), methodName);
|
|
||||||
|
|
||||||
if (method == null)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
return method.invoke(obj);
|
|
||||||
} catch (IllegalAccessException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} catch (InvocationTargetException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return a resource identifier for the given resource name.
|
|
||||||
*
|
|
||||||
* @param context The applications context.
|
|
||||||
* @param type Resource type to find (id or layout or string ...)
|
|
||||||
* @param name The name of the desired resource.
|
|
||||||
*
|
|
||||||
* @return The associated resource identifier or 0 if not found.
|
|
||||||
*/
|
|
||||||
public static int getResId (Context context, String type, String name) {
|
|
||||||
Resources res = context.getResources();
|
|
||||||
String pkgName = context.getPackageName();
|
|
||||||
|
|
||||||
int resId;
|
|
||||||
resId = res.getIdentifier(name, type, pkgName);
|
|
||||||
|
|
||||||
if (resId == 0) {
|
|
||||||
resId = Resources.getSystem().getIdentifier(name, type, "android");
|
|
||||||
}
|
|
||||||
|
|
||||||
return resId;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,361 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2013-2016 appPlant GmbH
|
|
||||||
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you 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 de.appplant.cordova.plugin.printer.ui;
|
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.pm.PackageInfo;
|
|
||||||
import android.content.pm.PackageManager;
|
|
||||||
import android.content.pm.PackageManager.NameNotFoundException;
|
|
||||||
import android.graphics.drawable.Drawable;
|
|
||||||
import android.os.Build;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.print.PrinterId;
|
|
||||||
import android.print.PrinterInfo;
|
|
||||||
import android.text.TextUtils;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.AdapterView;
|
|
||||||
import android.widget.BaseAdapter;
|
|
||||||
import android.widget.ImageView;
|
|
||||||
import android.widget.ListView;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import de.appplant.cordova.plugin.printer.ext.PrintManager;
|
|
||||||
import de.appplant.cordova.plugin.printer.ext.PrinterDiscoverySession;
|
|
||||||
import de.appplant.cordova.plugin.printer.ext.PrinterDiscoverySession.OnPrintersChangeListener;
|
|
||||||
import de.appplant.cordova.plugin.printer.reflect.Meta;
|
|
||||||
|
|
||||||
@SuppressLint("SetTextI18n")
|
|
||||||
public final class SelectPrinterActivity extends Activity {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The extra string to identify the data from the intents bundle.
|
|
||||||
*/
|
|
||||||
public static final String EXTRA_PRINTER_ID =
|
|
||||||
"INTENT_EXTRA_PRINTER_ID";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The action of the intent.
|
|
||||||
*/
|
|
||||||
public static final String ACTION_SELECT_PRINTER =
|
|
||||||
"ACTION_SELECT_PRINTER";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reference to the main view which lists all discovered printers.
|
|
||||||
*/
|
|
||||||
private ListView listView;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Session for printer discovering within the network.
|
|
||||||
*/
|
|
||||||
private PrinterDiscoverySession session;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when the activity is starting.
|
|
||||||
*
|
|
||||||
* @param savedInstanceState If the activity is being re-initialized
|
|
||||||
* after previously being shut down then this
|
|
||||||
* Bundle contains the data it most recently
|
|
||||||
* supplied in.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= 21) {
|
|
||||||
setTheme(Meta.getResId(
|
|
||||||
this, "style", "Theme.Material.Settings"));
|
|
||||||
}
|
|
||||||
|
|
||||||
setContentView(Meta.getResId(
|
|
||||||
this, "layout", "select_printer_activity"));
|
|
||||||
|
|
||||||
session = new PrintManager(this).createPrinterDiscoverySession();
|
|
||||||
listView = (ListView) findViewById(android.R.id.list);
|
|
||||||
|
|
||||||
initListView();
|
|
||||||
startPrinterDiscovery();
|
|
||||||
updateEmptyView();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Perform any final cleanup before an activity is destroyed.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected void onDestroy() {
|
|
||||||
session.destroy();
|
|
||||||
super.onDestroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sent intent with empty result.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void onBackPressed() {
|
|
||||||
onPrinterSelected(null);
|
|
||||||
super.onBackPressed();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends an intent with the specified printer back to the owning activity
|
|
||||||
* and finishes that activity.
|
|
||||||
*
|
|
||||||
* @param printerId The printerId object of the printer containing
|
|
||||||
* everything necessary to identify and contact him.
|
|
||||||
*/
|
|
||||||
private void onPrinterSelected (PrinterId printerId) {
|
|
||||||
Intent intent = new Intent();
|
|
||||||
|
|
||||||
intent.putExtra(EXTRA_PRINTER_ID, printerId);
|
|
||||||
intent.setAction(ACTION_SELECT_PRINTER);
|
|
||||||
setResult(RESULT_OK, intent);
|
|
||||||
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Assigns the adapter and the click listener to the list.
|
|
||||||
*/
|
|
||||||
private void initListView() {
|
|
||||||
listView.setAdapter(new ListViewAdapter());
|
|
||||||
|
|
||||||
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
|
||||||
if (!listView.getAdapter().isEnabled(position)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
PrinterInfo printer = (PrinterInfo)
|
|
||||||
listView.getAdapter().getItem(position);
|
|
||||||
|
|
||||||
onPrinterSelected(printer.getId());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start printer discovery if there are installed services found on the
|
|
||||||
* device.
|
|
||||||
*/
|
|
||||||
private void startPrinterDiscovery() {
|
|
||||||
PrintManager pm = new PrintManager(this);
|
|
||||||
|
|
||||||
if (pm.getInstalledPrintServices().isEmpty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
session.startPrinterDiscovery();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shows or hides the empty-view of the list view depend on if the
|
|
||||||
* adapter contains any printers or not.
|
|
||||||
*/
|
|
||||||
private void updateEmptyView() {
|
|
||||||
TextView titleView = (TextView) findViewById(android.R.id.title);
|
|
||||||
View progressBar = findViewById(android.R.id.progress);
|
|
||||||
|
|
||||||
if (listView.getEmptyView() == null) {
|
|
||||||
View emptyView = findViewById(android.R.id.empty);
|
|
||||||
listView.setEmptyView(emptyView);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (session.isPrinterDiscoveryStarted()) {
|
|
||||||
titleView.setText("Searching for printers");
|
|
||||||
progressBar.setVisibility(View.VISIBLE);
|
|
||||||
} else {
|
|
||||||
titleView.setText("No printers found");
|
|
||||||
progressBar.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private final class ListViewAdapter extends BaseAdapter {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wait lock for synchronization.
|
|
||||||
*/
|
|
||||||
private final Object lock = new Object();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* List of all received printer to display in the list.
|
|
||||||
*/
|
|
||||||
private final List<PrinterInfo> printers = new ArrayList<PrinterInfo>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor registers a listener to monitor about newly discovered
|
|
||||||
* printers.
|
|
||||||
*/
|
|
||||||
ListViewAdapter() {
|
|
||||||
session.setOnPrintersChangeListener(new OnPrintersChangeListener() {
|
|
||||||
@Override
|
|
||||||
public void onPrintersChanged (List<PrinterInfo> printerInfos) {
|
|
||||||
printers.addAll(printerInfos);
|
|
||||||
notifyDataSetChanged();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* How many items are in the data set represented by this Adapter.
|
|
||||||
*
|
|
||||||
* @return Count of items.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public int getCount() {
|
|
||||||
synchronized (lock) {
|
|
||||||
return printers.size();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the data item associated with the specified position in the
|
|
||||||
* data set.
|
|
||||||
*
|
|
||||||
* @param position Position of the item whose data we want within the
|
|
||||||
* adapter's data set.
|
|
||||||
*
|
|
||||||
* @return The data at the specified position.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Object getItem (int position) {
|
|
||||||
synchronized (lock) {
|
|
||||||
return printers.get(position);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the row id associated with the specified position in the list.
|
|
||||||
*
|
|
||||||
* @param position The position of the item within the adapter's data
|
|
||||||
* set whose row id we want.
|
|
||||||
*
|
|
||||||
* @return The id of the item at the specified position.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public long getItemId (int position) {
|
|
||||||
return position;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a View that displays in the drop down popup the data at the
|
|
||||||
* specified position in the data set.
|
|
||||||
*
|
|
||||||
* @param pos The index of the item whose view we want.
|
|
||||||
* @param view The old view to reuse, if possible. Note: You should
|
|
||||||
* check that this view is non-null and of an appropriate
|
|
||||||
* type before using. If it is not possible to convert
|
|
||||||
* this view to display the correct data.
|
|
||||||
* @param parent The parent that this view will eventually be
|
|
||||||
* attached to.
|
|
||||||
*
|
|
||||||
* @return A View corresponding to the data at the specified position.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public View getDropDownView (int pos, View view, ViewGroup parent) {
|
|
||||||
return getView(pos, view, parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a View that displays the data at the specified position in the
|
|
||||||
* data set.
|
|
||||||
*
|
|
||||||
* @param pos The position of the item within the adapter's data set
|
|
||||||
* of the item whose view we want.
|
|
||||||
* @param view The old view to reuse, if possible. Note: You should
|
|
||||||
* check that this view is non-null and of an appropriate
|
|
||||||
* type before using. If it is not possible to convert
|
|
||||||
* this view to display the correct data.
|
|
||||||
* @param parent The parent that this view will eventually be
|
|
||||||
* attached to.
|
|
||||||
*
|
|
||||||
* @return A View corresponding to the data at the specified position.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public View getView (int pos, View view, ViewGroup parent) {
|
|
||||||
PrinterInfo printer = (PrinterInfo) getItem(pos);
|
|
||||||
CharSequence title = printer.getName();
|
|
||||||
CharSequence subtitle = null;
|
|
||||||
Drawable icon = null;
|
|
||||||
|
|
||||||
if (view == null) {
|
|
||||||
view = getLayoutInflater().inflate(
|
|
||||||
Meta.getResId(getApplicationContext(), "layout", "printer_list_item"),
|
|
||||||
parent, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
PackageManager pm = getPackageManager();
|
|
||||||
PrinterId pId = printer.getId();
|
|
||||||
Object cmpName = Meta.invokeMethod(pId, "getServiceName");
|
|
||||||
Object pkgName = Meta.invokeMethod(cmpName, "getPackageName");
|
|
||||||
|
|
||||||
PackageInfo packageInfo = pm.getPackageInfo(
|
|
||||||
(String) pkgName, 0);
|
|
||||||
|
|
||||||
subtitle = packageInfo.applicationInfo.loadLabel(pm);
|
|
||||||
icon = packageInfo.applicationInfo.loadIcon(pm);
|
|
||||||
} catch (NameNotFoundException e) {
|
|
||||||
/* ignore */
|
|
||||||
}
|
|
||||||
|
|
||||||
TextView titleView = (TextView) view.findViewById(android.R.id.title);
|
|
||||||
titleView.setText(title);
|
|
||||||
|
|
||||||
TextView subtitleView = (TextView) view.findViewById(android.R.id.hint);
|
|
||||||
if (!TextUtils.isEmpty(subtitle)) {
|
|
||||||
subtitleView.setText(subtitle);
|
|
||||||
subtitleView.setVisibility(View.VISIBLE);
|
|
||||||
} else {
|
|
||||||
subtitleView.setText(null);
|
|
||||||
subtitleView.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
ImageView iconView = (ImageView) view.findViewById(android.R.id.icon);
|
|
||||||
if (icon != null) {
|
|
||||||
iconView.setImageDrawable(icon);
|
|
||||||
iconView.setVisibility(View.VISIBLE);
|
|
||||||
} else {
|
|
||||||
iconView.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
return view;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicate whether the specified printer by position is available.
|
|
||||||
*
|
|
||||||
* @param position The position of the printer in the list.
|
|
||||||
*
|
|
||||||
* @return A truthy value means that the printer is available.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean isEnabled (int position) {
|
|
||||||
PrinterInfo printer = (PrinterInfo) getItem(position);
|
|
||||||
return printer.getStatus() != PrinterInfo.STATUS_UNAVAILABLE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user