Merge "Adding an API demo for how to implement printing in an app." into klp-dev
This commit is contained in:
@@ -996,6 +996,15 @@
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity android:name=".app.PrintCustomContent"
|
||||
android:label="@string/print_custom_content"
|
||||
android:enabled="@bool/atLeastKitKat">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.SAMPLE_CODE" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<!-- Application Updating Samples -->
|
||||
|
||||
<!-- BEGIN_INCLUDE(app_update_declaration) -->
|
||||
|
||||
59
samples/ApiDemos/res/layout/motogp_stat_item.xml
Normal file
59
samples/ApiDemos/res/layout/motogp_stat_item.xml
Normal file
@@ -0,0 +1,59 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2013 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="16dip"
|
||||
android:paddingEnd="16dip"
|
||||
android:minHeight="64dip"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/year"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_weight="1"
|
||||
android:gravity="start"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:textIsSelectable="false">
|
||||
</TextView>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/champion"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="end"
|
||||
android:textIsSelectable="false"
|
||||
android:duplicateParentState="true">
|
||||
</TextView>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/constructor"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_weight="1"
|
||||
android:gravity="end"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:textIsSelectable="false">
|
||||
</TextView>
|
||||
|
||||
</LinearLayout>
|
||||
21
samples/ApiDemos/res/menu/print_custom_content.xml
Normal file
21
samples/ApiDemos/res/menu/print_custom_content.xml
Normal file
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2013 Google Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:id="@+id/menu_print"
|
||||
android:title="@string/print"
|
||||
android:showAsAction="never" />
|
||||
</menu>
|
||||
@@ -154,4 +154,209 @@
|
||||
<item>No.</item>
|
||||
<item>Mmm... cheese.</item>
|
||||
</string-array>
|
||||
|
||||
<!-- Used in app/Print/Custom Layout example -->
|
||||
<string-array name="motogp_years">
|
||||
<item>2012</item>
|
||||
<item>2011</item>
|
||||
<item>2010</item>
|
||||
<item>2009</item>
|
||||
<item>2008</item>
|
||||
<item>2007</item>
|
||||
<item>2006</item>
|
||||
<item>2005</item>
|
||||
<item>2004</item>
|
||||
<item>2003</item>
|
||||
<item>2002</item>
|
||||
<item>2001</item>
|
||||
<item>2000</item>
|
||||
<item>1999</item>
|
||||
<item>1998</item>
|
||||
<item>1997</item>
|
||||
<item>1996</item>
|
||||
<item>1995</item>
|
||||
<item>1994</item>
|
||||
<item>1993</item>
|
||||
<item>1992</item>
|
||||
<item>1991</item>
|
||||
<item>1990</item>
|
||||
<item>1989</item>
|
||||
<item>1988</item>
|
||||
<item>1987</item>
|
||||
<item>1986</item>
|
||||
<item>1985</item>
|
||||
<item>1984</item>
|
||||
<item>1983</item>
|
||||
<item>1982</item>
|
||||
<item>1981</item>
|
||||
<item>1980</item>
|
||||
<item>1979</item>
|
||||
<item>1978</item>
|
||||
<item>1977</item>
|
||||
<item>1976</item>
|
||||
<item>1975</item>
|
||||
<item>1974</item>
|
||||
<item>1973</item>
|
||||
<item>1972</item>
|
||||
<item>1971</item>
|
||||
<item>1970</item>
|
||||
<item>1969</item>
|
||||
<item>1968</item>
|
||||
<item>1967</item>
|
||||
<item>1966</item>
|
||||
<item>1965</item>
|
||||
<item>1964</item>
|
||||
<item>1963</item>
|
||||
<item>1962</item>
|
||||
<item>1961</item>
|
||||
<item>1960</item>
|
||||
<item>1959</item>
|
||||
<item>1958</item>
|
||||
<item>1957</item>
|
||||
<item>1956</item>
|
||||
<item>1955</item>
|
||||
<item>1954</item>
|
||||
<item>1953</item>
|
||||
<item>1952</item>
|
||||
<item>1951</item>
|
||||
<item>1950</item>
|
||||
<item>1949</item>
|
||||
</string-array>
|
||||
|
||||
<!-- Used in app/Print/Custom Layout example -->
|
||||
<string-array name="motogp_champions">
|
||||
<item>Jorge Lorenzo</item>
|
||||
<item>Casey Stoner</item>
|
||||
<item>Jorge Lorenzo</item>
|
||||
<item>Valentino Rossi</item>
|
||||
<item>Valentino Rossi</item>
|
||||
<item>Casey Stoner</item>
|
||||
<item>Nicky Hayden</item>
|
||||
<item>Valentino Rossi</item>
|
||||
<item>Valentino Rossi</item>
|
||||
<item>Valentino Rossi</item>
|
||||
<item>Valentino Rossi</item>
|
||||
<item>Valentino Rossi</item>
|
||||
<item>Kenny Roberts, Jr.</item>
|
||||
<item>Àlex Crivillé</item>
|
||||
<item>Michael Doohan</item>
|
||||
<item>Michael Doohan</item>
|
||||
<item>Michael Doohan</item>
|
||||
<item>Michael Doohan</item>
|
||||
<item>Michael Doohan</item>
|
||||
<item>Kevin Schwantz</item>
|
||||
<item>Wayne Rainey</item>
|
||||
<item>Wayne Rainey</item>
|
||||
<item>Wayne Rainey</item>
|
||||
<item>Eddie Lawson</item>
|
||||
<item>Eddie Lawson</item>
|
||||
<item>Wayne Gardner</item>
|
||||
<item>Eddie Lawson</item>
|
||||
<item>Freddie Spencer</item>
|
||||
<item>Eddie Lawson</item>
|
||||
<item>Freddie Spencer</item>
|
||||
<item>Franco Uncini</item>
|
||||
<item>Marco Lucchinelli</item>
|
||||
<item>Kenny Roberts</item>
|
||||
<item>Kenny Roberts</item>
|
||||
<item>Kenny Roberts</item>
|
||||
<item>Barry Sheene</item>
|
||||
<item>Barry Sheene</item>
|
||||
<item>Giacomo Agostini</item>
|
||||
<item>Phil Read</item>
|
||||
<item>Phil Read</item>
|
||||
<item>Giacomo Agostini</item>
|
||||
<item>Giacomo Agostini</item>
|
||||
<item>Giacomo Agostini</item>
|
||||
<item>Giacomo Agostini</item>
|
||||
<item>Giacomo Agostini</item>
|
||||
<item>Giacomo Agostini</item>
|
||||
<item>Giacomo Agostini</item>
|
||||
<item>Mike Hailwood</item>
|
||||
<item>Mike Hailwood</item>
|
||||
<item>Mike Hailwood</item>
|
||||
<item>Mike Hailwood</item>
|
||||
<item>Gary Hocking</item>
|
||||
<item>John Surtees</item>
|
||||
<item>John Surtees</item>
|
||||
<item>John Surtees</item>
|
||||
<item>Libero Liberati</item>
|
||||
<item>John Surtees</item>
|
||||
<item>Geoff Duke</item>
|
||||
<item>Geoff Duke</item>
|
||||
<item>Geoff Duke</item>
|
||||
<item>Umberto Masetti</item>
|
||||
<item>Geoff Duke</item>
|
||||
<item>Umberto Masetti</item>
|
||||
<item>Leslie Graham</item>
|
||||
</string-array>
|
||||
|
||||
<!-- Used in app/Print/Custom Layout example -->
|
||||
<string-array name="motogp_constructors">
|
||||
<item>Yamaha</item>
|
||||
<item>Honda</item>
|
||||
<item>Yamaha</item>
|
||||
<item>Yamaha</item>
|
||||
<item>Yamaha</item>
|
||||
<item>Ducati</item>
|
||||
<item>Honda</item>
|
||||
<item>Yamaha</item>
|
||||
<item>Yamaha</item>
|
||||
<item>Honda</item>
|
||||
<item>Honda</item>
|
||||
<item>Honda</item>
|
||||
<item>Suzuki</item>
|
||||
<item>Honda</item>
|
||||
<item>Honda</item>
|
||||
<item>Honda</item>
|
||||
<item>Honda</item>
|
||||
<item>Honda</item>
|
||||
<item>Honda</item>
|
||||
<item>Suzuki</item>
|
||||
<item>Yamaha</item>
|
||||
<item>Yamaha</item>
|
||||
<item>Yamaha</item>
|
||||
<item>Honda</item>
|
||||
<item>Yamaha</item>
|
||||
<item>Honda</item>
|
||||
<item>Yamaha</item>
|
||||
<item>Honda</item>
|
||||
<item>Yamaha</item>
|
||||
<item>Honda</item>
|
||||
<item>Suzuki</item>
|
||||
<item>Suzuki</item>
|
||||
<item>Yamaha</item>
|
||||
<item>Yamaha</item>
|
||||
<item>Yamaha</item>
|
||||
<item>Suzuki</item>
|
||||
<item>Suzuki</item>
|
||||
<item>Giacomo Agostini</item>
|
||||
<item>Phil Read</item>
|
||||
<item>Phil Read</item>
|
||||
<item>Yamaha</item>
|
||||
<item>MV Agusta</item>
|
||||
<item>MV Agusta</item>
|
||||
<item>MV Agusta</item>
|
||||
<item>MV Agusta</item>
|
||||
<item>MV Agusta</item>
|
||||
<item>MV Agusta</item>
|
||||
<item>MV Agusta</item>
|
||||
<item>MV Agusta</item>
|
||||
<item>MV Agusta</item>
|
||||
<item>MV Agusta</item>
|
||||
<item>MV Agusta</item>
|
||||
<item>MV Agusta</item>
|
||||
<item>MV Agusta</item>
|
||||
<item>MV Agusta</item>
|
||||
<item>Gilera</item>
|
||||
<item>MV Agusta</item>
|
||||
<item>Gilera</item>
|
||||
<item>Gilera</item>
|
||||
<item>Gilera</item>
|
||||
<item>Gilera</item>
|
||||
<item>Norton</item>
|
||||
<item>Gilera</item>
|
||||
<item>AJS</item>
|
||||
</string-array>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -871,6 +871,13 @@
|
||||
<string name="btn_toggle_tabs">Toggle tab mode</string>
|
||||
<string name="btn_remove_all_tabs">Remove all tabs</string>
|
||||
|
||||
<!-- ================================= -->
|
||||
<!-- app/print print examples strings -->
|
||||
<!-- ================================= -->
|
||||
|
||||
<string name="print_custom_content">App/Print/Print Custom Layout</string>
|
||||
<string name="print">Print</string>
|
||||
|
||||
<!-- ============================ -->
|
||||
<!-- graphics examples strings -->
|
||||
<!-- ============================ -->
|
||||
|
||||
@@ -0,0 +1,562 @@
|
||||
/*
|
||||
* Copyright (C) 2013 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.example.android.apis.app;
|
||||
|
||||
import android.app.ListActivity;
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.pdf.PdfDocument.Page;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.os.CancellationSignal;
|
||||
import android.os.CancellationSignal.OnCancelListener;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.print.PageRange;
|
||||
import android.print.PrintAttributes;
|
||||
import android.print.PrintDocumentAdapter;
|
||||
import android.print.PrintDocumentInfo;
|
||||
import android.print.PrintManager;
|
||||
import android.print.pdf.PrintedPdfDocument;
|
||||
import android.util.SparseIntArray;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.View.MeasureSpec;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.example.android.apis.R;
|
||||
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This class demonstrates how to implement custom printing support.
|
||||
* <p>
|
||||
* This activity shows the list of the MotoGP champions by year and
|
||||
* brand. The print option in the overflow menu allows the user to
|
||||
* print the content. The list list of items is laid out to such that
|
||||
* it fits the options selected by the user from the UI such as page
|
||||
* size. Hence, for different page sizes the printed content will have
|
||||
* different page count.
|
||||
* </p>
|
||||
* <p>
|
||||
* This sample demonstrates how to completely implement a {@link
|
||||
* PrintDocumentAdapter} in which:
|
||||
* <ul>
|
||||
* <li>Layout based on the selected print options is performed.</li>
|
||||
* <li>Layout work is performed only if print options change would change the content.</li>
|
||||
* <li>Layout result is properly reported.</li>
|
||||
* <li>Only requested pages are written.</li>
|
||||
* <li>Write result is properly reported.</li>
|
||||
* <li>Both Layout and write respond to cancellation.</li>
|
||||
* <li>Layout and render of views is demonstrated.</li>
|
||||
* </ul>
|
||||
* </p>
|
||||
*
|
||||
* @see PrintManager
|
||||
* @see PrintDocumentAdapter
|
||||
*/
|
||||
public class PrintCustomContent extends ListActivity {
|
||||
|
||||
private static final int MILS_IN_INCH = 1000;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setListAdapter(new MotoGpStatAdapter(loadMotoGpStats(),
|
||||
getLayoutInflater()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
super.onCreateOptionsMenu(menu);
|
||||
getMenuInflater().inflate(R.menu.print_custom_content, menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
if (item.getItemId() == R.id.menu_print) {
|
||||
print();
|
||||
return true;
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
private void print() {
|
||||
PrintManager printManager = (PrintManager) getSystemService(
|
||||
Context.PRINT_SERVICE);
|
||||
|
||||
printManager.print("MotoGP stats",
|
||||
new PrintDocumentAdapter() {
|
||||
private int mRenderPageWidth;
|
||||
private int mRenderPageHeight;
|
||||
|
||||
private PrintAttributes mPrintAttributes;
|
||||
private PrintDocumentInfo mDocumentInfo;
|
||||
private Context mPrintContext;
|
||||
|
||||
@Override
|
||||
public void onLayout(final PrintAttributes oldAttributes,
|
||||
final PrintAttributes newAttributes,
|
||||
final CancellationSignal cancellationSignal,
|
||||
final LayoutResultCallback callback,
|
||||
final Bundle metadata) {
|
||||
|
||||
// If we are already cancelled, don't do any work.
|
||||
if (cancellationSignal.isCanceled()) {
|
||||
callback.onLayoutCancelled();
|
||||
return;
|
||||
}
|
||||
|
||||
// Now we determined if the print attributes changed in a way that
|
||||
// would change the layout and if so we will do a layout pass.
|
||||
boolean layoutNeeded = false;
|
||||
|
||||
final int density = Math.max(newAttributes.getResolution().getHorizontalDpi(),
|
||||
newAttributes.getResolution().getVerticalDpi());
|
||||
|
||||
// Note that we are using the PrintedPdfDocument class which creates
|
||||
// a PDF generating canvas whose size is in points (1/72") not screen
|
||||
// pixels. Hence, this canvas is pretty small compared to the screen.
|
||||
// The recommended way is to layout the content in the desired size,
|
||||
// in this case as large as the printer can do, and set a translation
|
||||
// to the PDF canvas to shrink in. Note that PDF is a vector format
|
||||
// and you will not lose data during the transformation.
|
||||
|
||||
// The content width is equal to the page width minus the margins times
|
||||
// the horizontal printer density. This way we get the maximal number
|
||||
// of pixels the printer can put horizontally.
|
||||
final int marginLeft = (int) (density * (float) newAttributes.getMinMargins()
|
||||
.getLeftMils() / MILS_IN_INCH);
|
||||
final int marginRight = (int) (density * (float) newAttributes.getMinMargins()
|
||||
.getRightMils() / MILS_IN_INCH);
|
||||
final int contentWidth = (int) (density * (float) newAttributes.getMediaSize()
|
||||
.getWidthMils() / MILS_IN_INCH) - marginLeft - marginRight;
|
||||
if (mRenderPageWidth != contentWidth) {
|
||||
mRenderPageWidth = contentWidth;
|
||||
layoutNeeded = true;
|
||||
}
|
||||
|
||||
// The content height is equal to the page height minus the margins times
|
||||
// the vertical printer resolution. This way we get the maximal number
|
||||
// of pixels the printer can put vertically.
|
||||
final int marginTop = (int) (density * (float) newAttributes.getMinMargins()
|
||||
.getTopMils() / MILS_IN_INCH);
|
||||
final int marginBottom = (int) (density * (float) newAttributes.getMinMargins()
|
||||
.getBottomMils() / MILS_IN_INCH);
|
||||
final int contentHeight = (int) (density * (float) newAttributes.getMediaSize()
|
||||
.getHeightMils() / MILS_IN_INCH) - marginTop - marginBottom;
|
||||
if (mRenderPageHeight != contentHeight) {
|
||||
mRenderPageHeight = contentHeight;
|
||||
layoutNeeded = true;
|
||||
}
|
||||
|
||||
// Create a context for resources at printer density. We will
|
||||
// be inflating views to render them and would like them to use
|
||||
// resources for a density the printer supports.
|
||||
if (mPrintContext == null || mPrintContext.getResources()
|
||||
.getConfiguration().densityDpi != density) {
|
||||
Configuration configuration = new Configuration();
|
||||
configuration.densityDpi = density;
|
||||
mPrintContext = createConfigurationContext(
|
||||
configuration);
|
||||
mPrintContext.setTheme(android.R.style.Theme_Holo_Light);
|
||||
}
|
||||
|
||||
// If no layout is needed that we did a layout at least once and
|
||||
// the document info is not null, also the second argument is false
|
||||
// to notify the system that the content did not change. This is
|
||||
// important as if the system has some pages and the content didn't
|
||||
// change the system will ask, the application to write them again.
|
||||
if (!layoutNeeded) {
|
||||
callback.onLayoutFinished(mDocumentInfo, false);
|
||||
return;
|
||||
}
|
||||
|
||||
// For demonstration purposes we will do the layout off the main
|
||||
// thread but for small content sizes like this one it is OK to do
|
||||
// that on the main thread.
|
||||
|
||||
// Store the data as we will layout off the main thread.
|
||||
final List<MotoGpStatItem> items = ((MotoGpStatAdapter)
|
||||
getListAdapter()).cloneItems();
|
||||
|
||||
new AsyncTask<Void, Void, PrintDocumentInfo>() {
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
// First register for cancellation requests.
|
||||
cancellationSignal.setOnCancelListener(new OnCancelListener() {
|
||||
@Override
|
||||
public void onCancel() {
|
||||
cancel(true);
|
||||
}
|
||||
});
|
||||
// Stash the attributes as we will need them for rendering.
|
||||
mPrintAttributes = newAttributes;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PrintDocumentInfo doInBackground(Void... params) {
|
||||
try {
|
||||
// Create an adapter with the stats and an inflater
|
||||
// to load resources for the printer density.
|
||||
MotoGpStatAdapter adapter = new MotoGpStatAdapter(items,
|
||||
(LayoutInflater) mPrintContext.getSystemService(
|
||||
Context.LAYOUT_INFLATER_SERVICE));
|
||||
|
||||
int currentPage = 0;
|
||||
int pageContentHeight = 0;
|
||||
int viewType = -1;
|
||||
View view = null;
|
||||
LinearLayout dummyParent = new LinearLayout(mPrintContext);
|
||||
dummyParent.setOrientation(LinearLayout.VERTICAL);
|
||||
|
||||
final int itemCount = adapter.getCount();
|
||||
for (int i = 0; i < itemCount; i++) {
|
||||
// Be nice and respond to cancellation.
|
||||
if (isCancelled()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Get the next view.
|
||||
final int nextViewType = adapter.getItemViewType(i);
|
||||
if (viewType == nextViewType) {
|
||||
view = adapter.getView(i, view, dummyParent);
|
||||
} else {
|
||||
view = adapter.getView(i, null, dummyParent);
|
||||
}
|
||||
viewType = nextViewType;
|
||||
|
||||
// Measure the next view
|
||||
measureView(view);
|
||||
|
||||
// Add the height but if the view crosses the page
|
||||
// boundary we will put it to the next page.
|
||||
pageContentHeight += view.getMeasuredHeight();
|
||||
if (pageContentHeight > mRenderPageHeight) {
|
||||
pageContentHeight = view.getMeasuredHeight();
|
||||
currentPage++;
|
||||
}
|
||||
}
|
||||
|
||||
// Create a document info describing the result.
|
||||
PrintDocumentInfo info = new PrintDocumentInfo
|
||||
.Builder("MotoGP_stats.pdf")
|
||||
.setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
|
||||
.setPageCount(currentPage + 1)
|
||||
.build();
|
||||
|
||||
// We completed the layout as a result of print attributes
|
||||
// change. Hence, if we are here the content changed for
|
||||
// sure which is why we pass true as the second argument.
|
||||
callback.onLayoutFinished(info, true);
|
||||
return info;
|
||||
} catch (Exception e) {
|
||||
// An unexpected error, report that we failed and
|
||||
// one may pass in a human readable localized text
|
||||
// for what the error is if known.
|
||||
callback.onLayoutFailed(null);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(PrintDocumentInfo result) {
|
||||
// Update the cached info to send it over if the next
|
||||
// layout pass does not result in a content change.
|
||||
mDocumentInfo = result;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCancelled(PrintDocumentInfo result) {
|
||||
// Task was cancelled, report that.
|
||||
callback.onLayoutCancelled();
|
||||
}
|
||||
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWrite(final PageRange[] pages,
|
||||
final ParcelFileDescriptor destination,
|
||||
final CancellationSignal cancellationSignal,
|
||||
final WriteResultCallback callback) {
|
||||
|
||||
// If we are already cancelled, don't do any work.
|
||||
if (cancellationSignal.isCanceled()) {
|
||||
callback.onWriteCancelled();
|
||||
return;
|
||||
}
|
||||
|
||||
// Store the data as we will layout off the main thread.
|
||||
final List<MotoGpStatItem> items = ((MotoGpStatAdapter)
|
||||
getListAdapter()).cloneItems();
|
||||
|
||||
new AsyncTask<Void, Void, Void>() {
|
||||
private final SparseIntArray mWrittenPages = new SparseIntArray();
|
||||
private final PrintedPdfDocument mPdfDocument = new PrintedPdfDocument(
|
||||
PrintCustomContent.this, mPrintAttributes);
|
||||
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
// First register for cancellation requests.
|
||||
cancellationSignal.setOnCancelListener(new OnCancelListener() {
|
||||
@Override
|
||||
public void onCancel() {
|
||||
cancel(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Void doInBackground(Void... params) {
|
||||
// Go over all the pages and write only the requested ones.
|
||||
// Create an adapter with the stats and an inflater
|
||||
// to load resources for the printer density.
|
||||
MotoGpStatAdapter adapter = new MotoGpStatAdapter(items,
|
||||
(LayoutInflater) mPrintContext.getSystemService(
|
||||
Context.LAYOUT_INFLATER_SERVICE));
|
||||
|
||||
int currentPage = -1;
|
||||
int pageContentHeight = 0;
|
||||
int viewType = -1;
|
||||
View view = null;
|
||||
Page page = null;
|
||||
LinearLayout dummyParent = new LinearLayout(mPrintContext);
|
||||
dummyParent.setOrientation(LinearLayout.VERTICAL);
|
||||
|
||||
// The content is laid out and rendered in screen pixels with
|
||||
// the width and height of the paper size times the print
|
||||
// density but the PDF canvas size is in points which are 1/72",
|
||||
// so we will scale down the content.
|
||||
final float scale = Math.min(
|
||||
(float) mPdfDocument.getPageContentRect().width()
|
||||
/ mRenderPageWidth,
|
||||
(float) mPdfDocument.getPageContentRect().height()
|
||||
/ mRenderPageHeight);
|
||||
|
||||
final int itemCount = adapter.getCount();
|
||||
for (int i = 0; i < itemCount; i++) {
|
||||
// Be nice and respond to cancellation.
|
||||
if (isCancelled()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Get the next view.
|
||||
final int nextViewType = adapter.getItemViewType(i);
|
||||
if (viewType == nextViewType) {
|
||||
view = adapter.getView(i, view, dummyParent);
|
||||
} else {
|
||||
view = adapter.getView(i, null, dummyParent);
|
||||
}
|
||||
viewType = nextViewType;
|
||||
|
||||
// Measure the next view
|
||||
measureView(view);
|
||||
|
||||
// Add the height but if the view crosses the page
|
||||
// boundary we will put it to the next one.
|
||||
pageContentHeight += view.getHeight();
|
||||
if (currentPage < 0 || pageContentHeight > mRenderPageHeight) {
|
||||
pageContentHeight = view.getHeight();
|
||||
currentPage++;
|
||||
// Done with the current page - finish it.
|
||||
if (page != null) {
|
||||
mPdfDocument.finishPage(page);
|
||||
}
|
||||
// If the page is requested, render it.
|
||||
if (containsPage(pages, currentPage)) {
|
||||
page = mPdfDocument.startPage(currentPage);
|
||||
page.getCanvas().scale(scale, scale);
|
||||
// Keep track which pages are written.
|
||||
mWrittenPages.append(mWrittenPages.size(), currentPage);
|
||||
} else {
|
||||
page = null;
|
||||
}
|
||||
}
|
||||
|
||||
// If the current view is on a requested page, render it.
|
||||
if (page != null) {
|
||||
// Layout an render the content.
|
||||
view.layout(0, 0, view.getMeasuredWidth(),
|
||||
view.getMeasuredHeight());
|
||||
view.draw(page.getCanvas());
|
||||
// Move the canvas for the next view.
|
||||
page.getCanvas().translate(0, view.getHeight());
|
||||
}
|
||||
}
|
||||
|
||||
// Done with the last page.
|
||||
if (page != null) {
|
||||
mPdfDocument.finishPage(page);
|
||||
}
|
||||
|
||||
// Write the data and return success or failure.
|
||||
try {
|
||||
mPdfDocument.writeTo(new FileOutputStream(
|
||||
destination.getFileDescriptor()));
|
||||
// Compute which page ranges were written based on
|
||||
// the bookkeeping we maintained.
|
||||
PageRange[] pageRanges = computeWrittenPageRanges(mWrittenPages);
|
||||
callback.onWriteFinished(pageRanges);
|
||||
} catch (IOException ioe) {
|
||||
callback.onWriteFailed(null);
|
||||
} finally {
|
||||
mPdfDocument.close();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCancelled(Void result) {
|
||||
// Task was cancelled, report that.
|
||||
callback.onWriteCancelled();
|
||||
mPdfDocument.close();
|
||||
}
|
||||
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
|
||||
}
|
||||
|
||||
private void measureView(View view) {
|
||||
final int widthMeasureSpec = ViewGroup.getChildMeasureSpec(
|
||||
MeasureSpec.makeMeasureSpec(mRenderPageWidth,
|
||||
MeasureSpec.EXACTLY), 0, view.getLayoutParams().width);
|
||||
final int heightMeasureSpec = ViewGroup.getChildMeasureSpec(
|
||||
MeasureSpec.makeMeasureSpec(mRenderPageHeight,
|
||||
MeasureSpec.EXACTLY), 0, view.getLayoutParams().height);
|
||||
view.measure(widthMeasureSpec, heightMeasureSpec);
|
||||
}
|
||||
|
||||
private PageRange[] computeWrittenPageRanges(SparseIntArray writtenPages) {
|
||||
List<PageRange> pageRanges = new ArrayList<PageRange>();
|
||||
|
||||
int start = -1;
|
||||
int end = -1;
|
||||
final int writtenPageCount = writtenPages.size();
|
||||
for (int i = 0; i < writtenPageCount; i++) {
|
||||
if (start < 0) {
|
||||
start = writtenPages.valueAt(i);
|
||||
}
|
||||
int oldEnd = end = start;
|
||||
while (i < writtenPageCount && (end - oldEnd) <= 1) {
|
||||
oldEnd = end;
|
||||
end = writtenPages.valueAt(i);
|
||||
i++;
|
||||
}
|
||||
PageRange pageRange = new PageRange(start, end);
|
||||
pageRanges.add(pageRange);
|
||||
start = end = -1;
|
||||
}
|
||||
|
||||
PageRange[] pageRangesArray = new PageRange[pageRanges.size()];
|
||||
pageRanges.toArray(pageRangesArray);
|
||||
return pageRangesArray;
|
||||
}
|
||||
|
||||
private boolean containsPage(PageRange[] pageRanges, int page) {
|
||||
final int pageRangeCount = pageRanges.length;
|
||||
for (int i = 0; i < pageRangeCount; i++) {
|
||||
if (pageRanges[i].getStart() <= page
|
||||
&& pageRanges[i].getEnd() >= page) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}, null);
|
||||
}
|
||||
|
||||
private List<MotoGpStatItem> loadMotoGpStats() {
|
||||
String[] years = getResources().getStringArray(R.array.motogp_years);
|
||||
String[] champions = getResources().getStringArray(R.array.motogp_champions);
|
||||
String[] constructors = getResources().getStringArray(R.array.motogp_constructors);
|
||||
|
||||
List<MotoGpStatItem> items = new ArrayList<MotoGpStatItem>();
|
||||
|
||||
final int itemCount = years.length;
|
||||
for (int i = 0; i < itemCount; i++) {
|
||||
MotoGpStatItem item = new MotoGpStatItem();
|
||||
item.year = years[i];
|
||||
item.champion = champions[i];
|
||||
item.constructor = constructors[i];
|
||||
items.add(item);
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
private static final class MotoGpStatItem {
|
||||
String year;
|
||||
String champion;
|
||||
String constructor;
|
||||
}
|
||||
|
||||
private class MotoGpStatAdapter extends BaseAdapter {
|
||||
private final List<MotoGpStatItem> mItems;
|
||||
private final LayoutInflater mInflater;
|
||||
|
||||
public MotoGpStatAdapter(List<MotoGpStatItem> items, LayoutInflater inflater) {
|
||||
mItems = items;
|
||||
mInflater = inflater;
|
||||
}
|
||||
|
||||
public List<MotoGpStatItem> cloneItems() {
|
||||
return new ArrayList<MotoGpStatItem>(mItems);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return mItems.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getItem(int position) {
|
||||
return mItems.get(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
if (convertView == null) {
|
||||
convertView = mInflater.inflate(R.layout.motogp_stat_item, parent, false);
|
||||
}
|
||||
|
||||
MotoGpStatItem item = (MotoGpStatItem) getItem(position);
|
||||
|
||||
TextView yearView = (TextView) convertView.findViewById(R.id.year);
|
||||
yearView.setText(item.year);
|
||||
|
||||
TextView championView = (TextView) convertView.findViewById(R.id.champion);
|
||||
championView.setText(item.champion);
|
||||
|
||||
TextView constructorView = (TextView) convertView.findViewById(R.id.constructor);
|
||||
constructorView.setText(item.constructor);
|
||||
|
||||
return convertView;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user