/*
Copyright (C) 2014 Sergii Pylypenko.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.cups.android;
import android.app.Activity;
import android.app.Service;
import android.content.Context;
import android.os.Bundle;
import android.os.IBinder;
import android.os.CancellationSignal;
import android.os.ParcelFileDescriptor;
import android.view.MotionEvent;
import android.view.KeyEvent;
import android.view.Window;
import android.view.WindowManager;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.EditText;
import android.text.Editable;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.FrameLayout;
import android.graphics.drawable.Drawable;
import android.graphics.Color;
import android.content.res.Configuration;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Intent;
import android.view.View.OnKeyListener;
import android.view.MenuItem;
import android.view.Menu;
import android.view.Gravity;
import android.text.method.TextKeyListener;
import java.util.LinkedList;
import java.io.SequenceInputStream;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.FileOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.util.Set;
import android.text.SpannedString;
import java.io.BufferedReader;
import java.io.BufferedInputStream;
import java.io.InputStreamReader;
import android.view.inputmethod.InputMethodManager;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import java.util.concurrent.Semaphore;
import android.content.pm.ActivityInfo;
import android.view.Display;
import android.text.InputType;
import android.util.Log;
import android.view.Surface;
import android.app.ProgressDialog;
import android.text.util.Linkify;
import android.widget.ScrollView;
import java.util.*;
import android.text.TextWatcher;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.app.ProgressDialog;
import android.text.method.PasswordTransformationMethod;
import android.widget.Toast;
import android.net.Uri;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.print.*;
import android.print.pdf.PrintedPdfDocument;
import android.graphics.pdf.PdfDocument;
import android.graphics.Bitmap;
import android.graphics.Paint;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.text.StaticLayout;
import android.text.Layout;
import android.text.TextPaint;
public class SharePrinterActivity extends Activity
{
private ScrollView scroll = null;
private LinearLayout layout = null;
private EditText notes = null;
private EditText user = null;
private EditText password = null;
private Button shareClipboard = null;
private Button printQr = null;
private Button close = null;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Log.d(TAG, "onCreate");
final String name = getIntent().getStringExtra("n");
if (name == null)
finish();
scroll = new ScrollView(this);
setContentView(scroll);
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
layout = new LinearLayout(this);
layout.setOrientation(LinearLayout.VERTICAL);
layout.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
layout.setPadding(10, 10, 10, 10);
scroll.addView(layout, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
TextView text = null;
text = new TextView(this);
text.setText(getResources().getString(R.string.share_printer_x_address, name));
text.setTextSize(20);
text.setTextAlignment(TextView.TEXT_ALIGNMENT_CENTER);
text.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
layout.addView(text);
text = new TextView(this);
text.setText(R.string.user_desc_optional);
text.setTextSize(20);
layout.addView(text);
user = new EditText(this);
user.setHint(R.string.user_hint);
user.setInputType(InputType.TYPE_CLASS_TEXT|InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
layout.addView(user);
text = new TextView(this);
text.setText(R.string.password_desc_optional);
text.setTextSize(20);
layout.addView(text);
password = new EditText(this);
password.setHint(R.string.password_hint);
password.setInputType(InputType.TYPE_CLASS_TEXT|InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
layout.addView(password);
text = new TextView(this);
text.setText(R.string.notes_desc);
text.setTextSize(20);
layout.addView(text);
notes = new EditText(this);
notes.setHint(R.string.notes_hint);
notes.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_MULTI_LINE);
notes.setMinLines(2);
notes.setMaxLines(5);
layout.addView(notes);
shareClipboard = new Button(this);
shareClipboard.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
shareClipboard.setText(getResources().getString(R.string.share_to_clipboard));
shareClipboard.setOnClickListener(new View.OnClickListener()
{
public void onClick(View v)
{
final Uri uriNoAuth = Cups.getPrinterAddress(SharePrinterActivity.this, name);
if (uriNoAuth == null)
return;
showPasswordWarning(new Runnable()
{
public void run()
{
Log.d(TAG, "Printer URI: " + uriNoAuth.toString());
Uri.Builder uri = uriNoAuth.buildUpon();
if (user.getText().toString().length() > 0)
uri.appendQueryParameter("u", user.getText().toString());
if (password.getText().toString().length() > 0)
uri.appendQueryParameter("pw", password.getText().toString());
ClipData clip = ClipData.newUri(getContentResolver(), name, uri.build());
ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
clipboard.setPrimaryClip(clip);
Toast.makeText(SharePrinterActivity.this, R.string.copied_to_clipboard, Toast.LENGTH_LONG).show();
}
});
}
});
layout.addView(shareClipboard);
printQr = new Button(this);
printQr.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
printQr.setText(getResources().getString(R.string.print_qr));
printQr.setOnClickListener(new View.OnClickListener()
{
public void onClick(View v)
{
final Uri uriNoAuth = Cups.getPrinterAddress(SharePrinterActivity.this, name);
if (uriNoAuth == null)
return;
showPasswordWarning(new Runnable()
{
public void run()
{
Log.d(TAG, "Printer URI: " + uriNoAuth.toString());
Uri.Builder uri = uriNoAuth.buildUpon();
if (user.getText().toString().length() > 0)
uri.appendQueryParameter("u", user.getText().toString());
if (password.getText().toString().length() > 0)
uri.appendQueryParameter("pw", password.getText().toString());
Bitmap qr = QRCodeEncoder.encodeAsBitmap("URI:" + uri.build().toString());
Bitmap myAppAddr = QRCodeEncoder.encodeAsBitmap("URI:" + getResources().getString(R.string.google_play_url));
PrintManager printManager = (PrintManager)getSystemService(Context.PRINT_SERVICE);
printManager.print(getResources().getString(R.string.share_printer_address) + " " + name,
new PrintQrCode(name, qr, myAppAddr, notes.getText().toString()),
new PrintAttributes.Builder()
.setMediaSize(PrintAttributes.MediaSize.UNKNOWN_PORTRAIT)
.setColorMode(PrintAttributes.COLOR_MODE_MONOCHROME).build());
}
});
}
});
layout.addView(printQr);
text = new TextView(this);
text.setText("");
layout.addView(text);
close = new Button(this);
close.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
close.setText(getResources().getString(R.string.close));
close.setOnClickListener(new View.OnClickListener()
{
public void onClick(View v)
{
finish();
}
});
layout.addView(close);
}
void showPasswordWarning(final Runnable r)
{
if (password.getText().toString().length() == 0)
{
runOnUiThread(r);
return;
}
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(R.string.share_password_warning_title);
builder.setMessage(R.string.share_password_warning);
builder.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface d, int s)
{
d.dismiss();
runOnUiThread(r);
}
});
builder.setNegativeButton(R.string.no, new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface d, int s)
{
password.setText("");
d.dismiss();
runOnUiThread(r);
}
});
builder.setOnCancelListener(new DialogInterface.OnCancelListener()
{
public void onCancel(DialogInterface dialog)
{
password.setText("");
runOnUiThread(r);
}
});
AlertDialog alert = builder.create();
alert.setOwnerActivity(this);
alert.show();
}
class PrintQrCode extends PrintDocumentAdapter
{
String name;
Bitmap qr;
Bitmap myAppAddr;
String notes;
PrintedPdfDocument pdf;
public PrintQrCode(String name, Bitmap qr, Bitmap myAppAddr, String notes)
{
this.name = name;
this.qr = qr;
this.myAppAddr = myAppAddr;
this.notes = notes;
}
@Override
public void onLayout( PrintAttributes oldAttributes,
PrintAttributes newAttributes,
CancellationSignal cancellationSignal,
LayoutResultCallback callback,
Bundle metadata)
{
Log.d(TAG, "Creating new PDF");
pdf = new PrintedPdfDocument(SharePrinterActivity.this, newAttributes);
if (cancellationSignal.isCanceled())
{
callback.onLayoutCancelled();
return;
}
PrintDocumentInfo info = new PrintDocumentInfo
.Builder("printer_qr_code.pdf")
.setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
.setPageCount(1)
.build();
callback.onLayoutFinished(info, true);
}
@Override
public void onWrite(final PageRange[] pageRanges,
final ParcelFileDescriptor destination,
final CancellationSignal cancellationSignal,
final WriteResultCallback callback)
{
if (pageRanges.length == 0 || !(
pageRanges[0].getStart() <= 0 && pageRanges[0].getEnd() >= 0 ||
pageRanges[0] == PageRange.ALL_PAGES))
{
Log.d(TAG, "Saving PDF failed - no valid page range");
return;
}
if (cancellationSignal.isCanceled())
{
callback.onWriteCancelled();
pdf.close();
pdf = null;
return;
}
PdfDocument.Page page = pdf.startPage(0);
drawPage(page);
pdf.finishPage(page);
Log.d(TAG, "Saving PDF");
try
{
pdf.writeTo(new FileOutputStream(destination.getFileDescriptor()));
Log.w(TAG, "Saving PDF succeeded");
} catch (IOException e) {
Log.w(TAG, "Saving PDF failed: " + e.toString());
callback.onWriteFailed(e.toString());
return;
} finally {
pdf.close();
pdf = null;
}
callback.onWriteFinished(new PageRange[]{ new PageRange(0, 0) });
}
private void drawPage(PdfDocument.Page page)
{
Log.d(TAG, "Drawing PDF page");
Canvas canvas = page.getCanvas();
int w = canvas.getWidth();
int h = canvas.getHeight();
int x = w / 2;
int y = 0;
int size = h / 50;
Log.d(TAG, "w " + w + " h " + h + " x " + x + " y " + y + " size " + size + " bounds " + canvas.getClipBounds().toString());
//layout.draw(canvas);
Paint paint = new Paint();
paint.setColor(Color.BLACK);
paint.setTextSize(size * 1.5f);
paint.setTextAlign(Paint.Align.CENTER);
y += (paint.descent() - paint.ascent()) * 2.5;
canvas.drawText(getResources().getString(R.string.add_printer_android, name), x, y, paint);
paint.setTextSize(size / 1.3f);
y += (paint.descent() - paint.ascent()) * 1.5;
canvas.drawText(getResources().getString(R.string.add_printer_android_ver), x, y, paint);
y += (paint.descent() - paint.ascent()) * 1.2;
canvas.drawText(getResources().getString(R.string.install_barcode_scanner, name), x, y, paint);
paint.setTextSize(size);
y += (paint.descent() - paint.ascent()) * 1.5;
canvas.drawText(getResources().getString(R.string.install_printer_plugin, getResources().getString(R.string.app_name)), x, y, paint);
y += (paint.descent() - paint.ascent()) * 0.2;
int qrSize = size * 13;
paint.setFilterBitmap(false);
canvas.drawBitmap(myAppAddr, null, new Rect(x - qrSize / 2, y, x + qrSize / 2, y + qrSize), paint);
y += qrSize;
y += (paint.descent() - paint.ascent()) * 0.7;
canvas.drawText(getResources().getString(R.string.install_printer_plugin_enable, getResources().getString(R.string.app_name)), x, y, paint);
y += (paint.descent() - paint.ascent()) * 1;
canvas.drawText(getResources().getString(R.string.scan_qr, name), x, y, paint);
paint.setTextSize(size / 1.3f);
y += (paint.descent() - paint.ascent()) * 1;
canvas.drawText(getResources().getString(R.string.scan_qr_open_browser), x, y, paint);
paint.setTextSize(size);
y += (paint.descent() - paint.ascent()) * 0.2;
qrSize = size * 20;
canvas.drawBitmap(qr, null, new Rect(x - qrSize / 2, y, x + qrSize / 2, y + qrSize), paint);
y += qrSize;
y += (paint.descent() - paint.ascent()) * 0.8;
for (String line: notes.split("\n"))
{
canvas.drawText(line, x, y, paint);
y += (paint.descent() - paint.ascent()) * 1;
}
}
}
static public final String TAG = "SharePrinterActivity";
}