I am writing an app that can create Maths worksheet with answer pages in PDF format. I want to add a print function to allow printing the worksheet directly from the app.
In the PrintDocumentAdapter, the first half of the codes check the color of a certain pixel of the page to determine whether it is an answer page and reduce the number of pages to print accordingly. It then constructs a printingPDF document and sends it to print using 's writeTo() method in the onWrite().
Everything works fine until the last part. It reads the PDF correctly, checks the number of answer pages correctly, and sends a correct PDF with question pages only to the printing page. If I choose "Save as PDF" in the printing page, it saves the pages to a new PDF file with no problem. However, if I try to print with my printer that is connected to my phone with USB by clicking the print button, the printing page simply disappears and goes back to the main page of my app. (It is supposed to past those few pages to the printer app.) I tried several different android printer driver apps and the result was the same.
private void printWS() throws IOException {
findViewById(R.id.defaultTextView).setVisibility(View.INVISIBLE);
if (!loadedFile) {
File file = new File(getApplicationContext().getCacheDir(), getString(R.string.defaultFileName));
parcelFileDescriptor = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
} else {
parcelFileDescriptor = getContentResolver().openFileDescriptor(pdfUri, "r");
}
// Start printing
PrintManager printManager = (PrintManager) this.getSystemService(PRINT_SERVICE);
String jobName = getString(R.string.app_name);
PrintAttributes printAttributes = new PrintAttributes.Builder().setMediaSize(PrintAttributes.MediaSize.ISO_A4).build();
printManager.print(jobName, new PrintDocumentAdapter() {
int finalTotal;
#Override
public void onStart() {
if (parcelFileDescriptor != null) {
try {
pdfRenderer = new PdfRenderer(parcelFileDescriptor);
} catch (IOException e) {
e.printStackTrace();
}
}
int tempTotal = pdfRenderer.getPageCount();
Bitmap[] tempBitmap = new Bitmap[tempTotal];
finalTotal = tempTotal;
for (int pageNum = 0; pageNum < tempTotal; pageNum++) {
PdfRenderer.Page tempPage = pdfRenderer.openPage(pageNum);
tempBitmap[pageNum] = Bitmap.createBitmap(WS_WIDTH, WS_HEIGHT, Bitmap.Config.ARGB_8888);
tempPage.render(tempBitmap[pageNum], null, null, PdfRenderer.Page.RENDER_MODE_FOR_PRINT);
if (tempBitmap[pageNum].getPixel(0, 0) == Color.GRAY) {
finalTotal--;
}
tempPage.close();
}
}
PrintedPdfDocument printingPDF;
#Override
public void onLayout(PrintAttributes oldAttributes, PrintAttributes newAttributes, CancellationSignal cancellationSignal, LayoutResultCallback callback, Bundle bundle) {
printingPDF = new PrintedPdfDocument(getApplicationContext(), newAttributes);
if (cancellationSignal.isCanceled()) {
callback.onLayoutCancelled();
return;
}
if (finalTotal > 0) {
PrintDocumentInfo info = new PrintDocumentInfo
.Builder("Worksheet")
.setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
.setPageCount(finalTotal)
.build();
callback.onLayoutFinished(info, true);
} else {
callback.onLayoutFailed("Page count calculation failed.");
}
}
#Override
public void onWrite(PageRange[] pageRanges, ParcelFileDescriptor destination, CancellationSignal cancellationSignal, WriteResultCallback callback) {
Bitmap[] loadedBitmap = new Bitmap[finalTotal];
for (int pageNum = 0; pageNum < finalTotal; pageNum++) {
PdfDocument.PageInfo printingPageInfo = new PdfDocument.PageInfo.Builder(WS_WIDTH, WS_HEIGHT, pageNum).create();
PdfDocument.Page printingPage = printingPDF.startPage(printingPageInfo);
if (cancellationSignal.isCanceled()) {
callback.onWriteCancelled();
printingPDF.close();
printingPDF = null;
return;
}
PdfRenderer.Page loadedPage = pdfRenderer.openPage(pageNum);
loadedBitmap[pageNum] = Bitmap.createBitmap(WS_WIDTH, WS_HEIGHT, Bitmap.Config.ARGB_8888);
loadedPage.render(loadedBitmap[pageNum], null, null, PdfRenderer.Page.RENDER_MODE_FOR_PRINT);
Canvas canvas = printingPage.getCanvas();
Paint paint = new Paint();
canvas.drawBitmap(loadedBitmap[pageNum], 0, 0, paint);
printingPDF.finishPage(printingPage);
loadedPage.close();
}
try {
printingPDF.writeTo(new FileOutputStream(destination.getFileDescriptor()));
} catch (IOException e) {
callback.onWriteFailed(e.toString());
return;
} finally {
printingPDF.close();
printingPDF = null;
}
PageRange[] writtenPages = new PageRange[]{PageRange.ALL_PAGES};
callback.onWriteFinished(writtenPages);
}
#Override
public void onFinish() {
try {
pdfRenderer.close();
parcelFileDescriptor.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}, printAttributes);
}
Can someone take a look at my codes and tell me what is going wrong? Please help! Thanks!
Nevermind. It turned out the codes are ok. What I needed to do was go to the settings of my phone and change the "Display pop-up windows while running in the background" of the printer driver app to "allow", then it worked perfectly!
I will keep the question and answer here in case someone encounters the same problem.
Related
I have an upload button in Vaadin 8 with an addSucceededListener listener on it- about which i don't know many things..and i couldn't find too much info for this type of listener.
When i click that button i want to fire up a confirmation window - which I instantiate with ConfirmButton cd = new ConfirmButton("Confirmare"); and i open the modal pop-up with cd.openInModalPopup();.
My issue here is that the pop-up -> cd.openInModalPopup(); shows up only after the "Choose a file" window is open and i must select a file.
My question is how can I show the confirmation first, and only if the uer confirms, open the "Choose a file" window.
Adding the code below:
<vaadin-upload button-caption="Incarc INDICATORI " _id="cmdIncarcRaportInd" :right></vaadin-upload>
public Upload getCmdIncarcRaportInd() {
return cmdIncarcRaportInd;
}
getCmdIncarcRaportInd().addSucceededListener(event -> {
int NR_Raport=0;
String WBL ="";
WBL = getCheBL().getValue()?"B":"I";
if(raport!=null) NR_Raport=Numeric.getValInt(raport.get("Nr. Raport"));
if (NR_Raport==0) {
Notification notif = new Notification("Atentie",
"NR Raport incorect",
Notification.Type.ERROR_MESSAGE);
notif.setDelayMsec(-1);
notif.show(Page.getCurrent());
return;
}
int NR_RaportW = NR_Raport;
if(WBL.equals("B")) {
NR_RaportW=99;
ConfirmButton cd = new ConfirmButton("Confirmare");
cd.misWinTitle = "Atentie MIS";
cd.misWinText = "Incarcati valori Base Line ? Daca exista deja, cele vechi se vor rescrie cu valorile noi. CONFIRMATI BASE LINE (DA / NU) ?";
cd.misButOK = "DA";
cd.misButCancel = "NU";
cd.setOkAction(()->{
String raspuns="ok";
if(!receiver.getFile().getName().split("_")[0].equals(proiect.get("Prj cod"))) {
Notification notif = new Notification("Atentie", "Cod Proiect Incorect",
Notification.Type.ERROR_MESSAGE);
notif.setDelayMsec(-1);
notif.show(Page.getCurrent());
return;
}
try {
raspuns = Utility.getSomeData(receiver.getFile(), proiect, 99, themeDisplay);
} catch (IOException | SQLException e) {
raspuns=e.getMessage();
}
Notification notificare = new Notification("Atentie - Incarcare Base Line Indicatori",
raspuns,
Notification.Type.ERROR_MESSAGE);
notificare.setDelayMsec(-1);
notificare.show(Page.getCurrent());
incarcGrdIndicatori(prj_cod);
receiver.uploadFinished(event);
});
cd.setCancelAction(()->{
});
cd.openInModalPopup();
} else {
String raspuns="ok";
if(!receiver.getFile().getName().split("_")[0].equals(proiect.get("Prj cod"))) {
Notification notif = new Notification("Atentie", "Cod Proiect Incorect",
Notification.Type.ERROR_MESSAGE);
notif.setDelayMsec(-1);
notif.show(Page.getCurrent());
return;
}
try {
raspuns = Utility.DoSomeStuff(receiver.getFile(), proiect, NR_RaportW, themeDisplay);
} catch (IOException | SQLException e) {
raspuns=e.getMessage();
}
Notification notificare = new Notification("Atentie - Incarcare Rap Indicatori",
raspuns,
Notification.Type.ERROR_MESSAGE);
notificare.setDelayMsec(-1);
notificare.show(Page.getCurrent());
incarcGrdIndicatori(prj_cod);
receiver.uploadFinished(event);
}
});
//);
}
Add a normal Button which the users clicks, and then show the Upload Button only when your conditions are meet?
So I basically have a List of URIs, each has a .jpeg file, and I want to show this list like a GIF file (not necessesary to make a gif, only to display).
So after a research I found the AnimationDrawble object, converted each URI into Drawable and added it as a frame to AnimationDrawable.
This is my code:
AnimationDrawable ad = new AnimationDrawable();
Drawable[] dr = new Drawable[position+1];
ProgressItem pi;
try {
for (int i = 0; i <= position; i++) {
pi = progress.get(i);
try {
dr[i] = drawableFromUrl(pi.getImage());
} catch (IOException ios) {
Toast.makeText(activity, ios.getMessage(), Toast.LENGTH_SHORT).show();
}
}
}
catch(Exception ex)
{
Toast.makeText(activity, ex.getMessage(), Toast.LENGTH_SHORT).show();
}
Intent i = new Intent(activity,ProgressImage.class);
DataWraper.setItems(dr);
drawableFromUrl:
public Drawable drawableFromUrl(String url) throws IOException {
Bitmap x;
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
MyDownloadTask mdt = new MyDownloadTask();
try{
mdt.execute(connection);
}
catch(Exception ex)
{
Toast.makeText(activity, ex.getMessage(), Toast.LENGTH_SHORT).show();
}
InputStream input = mdt.getInputStream();
x = BitmapFactory.decodeStream(input);
return new BitmapDrawable(x);
}
The implementation part:
Glide.with(this)
.load(ad)
.into(progressImage);
When I'm trying to Glide the AnimationDrawble into the ImageView I get the following exception:
java.lang.IllegalArgumentException: Unknown type class android.graphics.drawable.AnimationDrawable.
This made me hesistate the way I'm trying to pull this off. Should this be this complicated?
If this is the right way, what am I doing wrong? maybe there's another way of doing so? I'd love to get some details. Thanks in advance!
https://github.com/koral--/android-gif-drawable
Not sure if you're open to any 3rd party libraries, but i used this one for gifs before and it worked quite well for me
I'm trying to use the Camera2 API to stream camera data to a SurfaceView. I'm following this guide: Camera2 guide
I cannot get past step 5
MainActivity.java::onCreate()
setContentView(R.layout.activity_main);
surfaceView = (SurfaceView)findViewById(R.id.surface);
manager = (CameraManager)getSystemService(Context.CAMERA_SERVICE);
MainActivity.java::onClick()
for (String id : manager.getCameraIdList()) {
CameraCharacteristics characteristics = manager.getCameraCharacteristics(id);
Integer direction = characteristics.get(CameraCharacteristics.LENS_FACING);
if (direction != null && direction == CameraCharacteristics.LENS_FACING_BACK) {
if (checkCallingOrSelfPermission("android.permission.CAMERA") == PackageManager.PERMISSION_GRANTED)
manager.openCamera(id, new StateCallback(), null);
break;
}
}
MainActivity.java.StateCallback::onOpened(CameraDevice camera)
List<Surface> surfaces = new LinkedList<>();
surfaces.add(surfaceView.getHolder().getSurface());
CaptureRequest.Builder builder = camera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
builder.addTarget(surfaces.get(0));
camera.createCaptureSession(surfaces, new CameraCaptureSession.StateCallback() {
#Override
public void onConfigured(CameraCaptureSession session) {
Log.i(TAG, "Configured");
}
#Override
public void onConfigureFailed(CameraCaptureSession session) {
Log.e(TAG, "Configured failed"); // Ends up in this function :(
}
}, null);
The program ends up in the onConfigureFailed() function. I don't know what could be the error, and I don't know how to check what is.
My guess would be that I'm missing something in the CaptureRequest, but I have no idea what.
I'm running on a Samsung Galaxy S4.
add to onConfigured:
if (null == cameraDevice) {
Log.e(TAG, "updatePreview error, return");
return;
}
captureRequestBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
try {
cameraCaptureSessions.setRepeatingRequest(captureRequestBuilder.build(), null, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
Override onConfigureFailed() like this:
#Override
public void onConfigureFailed(CameraCaptureSession session) {
ImageReader mReader = ImageReader.newInstance(640, 480, ImageFormat.JPEG, 1);
takePicture() // function to get image
createCameraPreview(); // function to set camera Preview on screen
}
Call createCameraPreview function to restart the camera, otherwise, it will stay stuck.
You can change the ImageReader with new values
ImageReader mReader = ImageReader.newInstance(640, 480, ImageFormat.JPEG, 1);
And call the takePicture() function again so that user don't have to click again to capture image.
I have produced the below android code to attain code pasted to the Android clipboard. And although it works, I would like to determine which android application was being utilized whilst this data was pasted to the clipboard.
How can I accomplish this?
Android Code:
#SuppressLint("NewApi")
public String readFromClipboard(Context context) {
int sdk = android.os.Build.VERSION.SDK_INT;
if (sdk < android.os.Build.VERSION_CODES.HONEYCOMB) {
android.text.ClipboardManager clipboard = (android.text.ClipboardManager) context
.getSystemService(context.CLIPBOARD_SERVICE);
return clipboard.getText().toString();
} else {
ClipboardManager clipboard = (ClipboardManager) context
.getSystemService(Context.CLIPBOARD_SERVICE);
// Gets a content resolver instance
ContentResolver cr = context.getContentResolver();
// Gets the clipboard data from the clipboard
ClipData clip = clipboard.getPrimaryClip();
if (clip != null) {
String text = null;
String title = null;
// Gets the first item from the clipboard data
ClipData.Item item = clip.getItemAt(0);
// Tries to get the item's contents as a URI pointing to a note
Uri uri = item.getUri();
// If the contents of the clipboard wasn't a reference to a
// note, then
// this converts whatever it is to text.
if (text == null) {
text = coerceToText(context, item).toString();
}
return text;
}
}
return "";
}
#SuppressLint("NewApi")
public CharSequence coerceToText(Context context, ClipData.Item item) {
// If this Item has an explicit textual value, simply return that.
CharSequence text = item.getText();
if (text != null) {
return text;
}
// If this Item has a URI value, try using that.
Uri uri = item.getUri();
if (uri != null) {
// First see if the URI can be opened as a plain text stream
// (of any sub-type). If so, this is the best textual
// representation for it.
FileInputStream stream = null;
try {
// Ask for a stream of the desired type.
AssetFileDescriptor descr = context.getContentResolver()
.openTypedAssetFileDescriptor(uri, "text/*", null);
stream = descr.createInputStream();
InputStreamReader reader = new InputStreamReader(stream,
"UTF-8");
// Got it... copy the stream into a local string and return it.
StringBuilder builder = new StringBuilder(128);
char[] buffer = new char[8192];
int len;
while ((len = reader.read(buffer)) > 0) {
builder.append(buffer, 0, len);
}
return builder.toString();
} catch (FileNotFoundException e) {
// Unable to open content URI as text... not really an
// error, just something to ignore.
} catch (IOException e) {
// Something bad has happened.
Log.w("ClippedData", "Failure loading text", e);
return e.toString();
} finally {
if (stream != null) {
try {
stream.close();
} catch (IOException e) {
}
}
}
// If we couldn't open the URI as a stream, then the URI itself
// probably serves fairly well as a textual representation.
return uri.toString();
}
To be clear, I don't want to have to have a service running whilst this data is first pasted instead I'd like to determine the origin of the pasting after the fact.
I have been busting my head over this, this is the last thing I need to complete and he app is done.
Basically, I created a camera for my app and I need to switch from back camera to front camera on onClick()...
When I switch, I lose the preview... When I record, the screen is black but the video get recorded... but no preview at all.. here is the code
#Override
protected void onCreate(Bundle saved) {
super.onCreate(saved);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.camera);
//some initializing code like checking flash, number of cameras...
preview = (FrameLayout) findViewById(R.id.camera_preview);
}
#Override
public void onResume(){
super.onResume();
if (Camera.getNumberOfCameras() < 2) {
a.id(R.id.camera_switch).clickable(false);
}
if(m!=null){
m.reset();
m.release();
m=null;
c.lock();
}
if (c != null) {
c.release();
c = null;
}
cam = "front";
Instance();
}
public void Instance(){
if(flash.equalsIgnoreCase("yes"))
a.id(R.id.camera_flash).clickable(true);
if(cam.equalsIgnoreCase("back")){
try{
m.reset();m=null;
c.stopPreview();
c.release();c.reconnect();
c = null;
}catch(Exception e){}
a.id(R.id.camera_flash).clickable(false);
Camera c = getCameraInstanceB(this);
parameters = c.getParameters();
parameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
c.setParameters(parameters);
cam = "front";
try {
c.setPreviewDisplay(mPreview.getHolder());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}c.startPreview();
}else{
try{
c.release();
c = null;
}catch(Exception e){}
c = getCameraInstance(this);
parameters = c.getParameters();
cam = "back";
}
m = new MediaRecorder();
// Create our Preview view and set it as the content of our activity.
mPreview = new CameraPreview(this, c);
int orien =getResources().getConfiguration().orientation;
if(orien ==1){
parameters.setRotation(0); // set rotation to save the picture
c.setDisplayOrientation(90);
cam_rotation =90;
parameters.setPictureSize(640, 480);
PIC_ORIENTATION = "portrait";
Toast.makeText(this, PIC_ORIENTATION, Toast.LENGTH_SHORT).show();
}else{
parameters.setRotation(0); // set rotation to save the picture
c.setDisplayOrientation(0);
parameters.setPictureSize(640, 480);
PIC_ORIENTATION = "landscape";
cam_rotation=0;
Toast.makeText(this, PIC_ORIENTATION, Toast.LENGTH_SHORT).show();
}
c.setParameters(parameters);
m.setCamera(c);
preview.addView(mPreview);
}
now the camera instances for back and front
public static Camera getCameraInstance(Cam cam){
c = null;
try {
c = Camera.open(CameraInfo.CAMERA_FACING_BACK); // attempt to get a Camera instance
Camera.Parameters parameters = c.getParameters();
parameters.setRecordingHint(true);
parameters.setFocusMode(Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
c.setParameters(parameters);
}
catch (Exception e){
// Camera is not available (in use or does not exist)
e.printStackTrace();
text = "The camera is in use";
//---set the data to pass back---
data.putExtra("vid",text);
cam.setResult(RESULT_OK, data);
//---close the activity---
cam.finish();
}
return c; // returns null if camera is unavailable
}
public static Camera getCameraInstanceB(Cam cam){
c = null;
try {
c = Camera.open(CameraInfo.CAMERA_FACING_FRONT); // attempt to get a Camera instance
Camera.Parameters parameters = c.getParameters();
parameters.setRecordingHint(true);
c.setParameters
(parameters);
}
catch (Exception e){
// Camera is not available (in use or does not exist)
e.printStackTrace();
text = "The camera is in use";
//---set the data to pass back---
data.putExtra("vid",text);
cam.setResult(RESULT_OK, data);
//---close the activity---
cam.finish();
}
return c; // returns null if camera is unavailable
}
on Resume()... everything is fine but when I switch... no more preview
After spending hours, I finally came up with a solution, basically, I just recreate the surfaceView on each switch as it was an onStart();
public void Instance(){
preview = (FrameLayout) findViewById(R.id.camera_preview);
//rest of the code here
Now it works like a charm... no more error even onResume