1525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov/* 2525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov * Copyright (C) 2014 The Android Open Source Project 3525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov * 4525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov * Licensed under the Apache License, Version 2.0 (the "License"); 5525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov * you may not use this file except in compliance with the License. 6525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov * You may obtain a copy of the License at 7525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov * 8525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov * http://www.apache.org/licenses/LICENSE-2.0 9525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov * 10525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov * Unless required by applicable law or agreed to in writing, software 11525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov * distributed under the License is distributed on an "AS IS" BASIS, 12525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov * See the License for the specific language governing permissions and 14525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov * limitations under the License. 15525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov */ 16525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 17525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovpackage com.android.printspooler.ui; 18525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 19525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovimport android.os.Handler; 20525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovimport android.os.Looper; 21525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovimport android.os.Message; 22525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovimport android.os.ParcelFileDescriptor; 23525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovimport android.print.PageRange; 24525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovimport android.print.PrintAttributes.MediaSize; 25525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovimport android.print.PrintAttributes.Margins; 26525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovimport android.print.PrintDocumentInfo; 276f249835a4ff9e7e7e3ca0190b7ecf72e689656dSvetoslavimport android.support.v7.widget.GridLayoutManager; 28525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovimport android.support.v7.widget.RecyclerView; 29525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovimport android.support.v7.widget.RecyclerView.ViewHolder; 30525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovimport android.support.v7.widget.RecyclerView.LayoutManager; 31525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovimport android.view.View; 32525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovimport com.android.internal.os.SomeArgs; 33525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovimport com.android.printspooler.R; 34525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovimport com.android.printspooler.model.MutexFileProvider; 35525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovimport com.android.printspooler.widget.PrintContentView; 36525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovimport com.android.printspooler.widget.EmbeddedContentContainer; 37525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovimport com.android.printspooler.widget.PrintOptionsLayout; 38525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 39525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovimport java.io.File; 40525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovimport java.io.FileNotFoundException; 41525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovimport java.util.ArrayList; 42525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovimport java.util.List; 43525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 44525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovclass PrintPreviewController implements MutexFileProvider.OnReleaseRequestCallback, 45525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov PageAdapter.PreviewArea, EmbeddedContentContainer.OnSizeChangeListener { 46525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 4715cbc8a03250eafdf947cd8ad4e77f34444d5ba4Svetoslav private final PrintActivity mActivity; 48525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 49525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov private final MutexFileProvider mFileProvider; 50525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov private final MyHandler mHandler; 51525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 52525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov private final PageAdapter mPageAdapter; 536f249835a4ff9e7e7e3ca0190b7ecf72e689656dSvetoslav private final GridLayoutManager mLayoutManger; 54525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 5515cbc8a03250eafdf947cd8ad4e77f34444d5ba4Svetoslav private final PrintOptionsLayout mPrintOptionsLayout; 56525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov private final RecyclerView mRecyclerView; 57525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov private final PrintContentView mContentView; 58525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov private final EmbeddedContentContainer mEmbeddedContentContainer; 59525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 60525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov private final PreloadController mPreloadController; 61525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 62525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov private int mDocumentPageCount; 63525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 64525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov public PrintPreviewController(PrintActivity activity, MutexFileProvider fileProvider) { 65525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov mActivity = activity; 66525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov mHandler = new MyHandler(activity.getMainLooper()); 67525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov mFileProvider = fileProvider; 68525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 69525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov mPrintOptionsLayout = (PrintOptionsLayout) activity.findViewById(R.id.options_container); 70525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov mPageAdapter = new PageAdapter(activity, activity, this); 71525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 72525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov final int columnCount = mActivity.getResources().getInteger( 73525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov R.integer.preview_page_per_row_count); 74525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 756f249835a4ff9e7e7e3ca0190b7ecf72e689656dSvetoslav mLayoutManger = new GridLayoutManager(mActivity, columnCount); 7615cbc8a03250eafdf947cd8ad4e77f34444d5ba4Svetoslav 77525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov mRecyclerView = (RecyclerView) activity.findViewById(R.id.preview_content); 78525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov mRecyclerView.setLayoutManager(mLayoutManger); 79525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov mRecyclerView.setAdapter(mPageAdapter); 807fd5ada98aa9e035682531d9fe25633fdd24a058Svetoslav mRecyclerView.setItemViewCacheSize(0); 81525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov mPreloadController = new PreloadController(mRecyclerView); 82525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov mRecyclerView.setOnScrollListener(mPreloadController); 83525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 84525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov mContentView = (PrintContentView) activity.findViewById(R.id.options_content); 85525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov mEmbeddedContentContainer = (EmbeddedContentContainer) activity.findViewById( 86525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov R.id.embedded_content_container); 87525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov mEmbeddedContentContainer.setOnSizeChangeListener(this); 88525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 89525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 90525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov @Override 91525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov public void onSizeChanged(int width, int height) { 92525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov mPageAdapter.onPreviewAreaSizeChanged(); 93525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 94525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 95525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov public boolean isOptionsOpened() { 96525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov return mContentView.isOptionsOpened(); 97525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 98525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 99525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov public void closeOptions() { 100525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov mContentView.closeOptions(); 101525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 102525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 103525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov public void setUiShown(boolean shown) { 104525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov if (shown) { 105525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov mRecyclerView.setVisibility(View.VISIBLE); 106525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } else { 107525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov mRecyclerView.setVisibility(View.GONE); 108525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 109525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 110525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 111525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov public void onOrientationChanged() { 112525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov // Adjust the print option column count. 113525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov final int optionColumnCount = mActivity.getResources().getInteger( 114525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov R.integer.print_option_column_count); 115525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov mPrintOptionsLayout.setColumnCount(optionColumnCount); 116525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov mPageAdapter.onOrientationChanged(); 117525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 118525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 119525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov public int getFilePageCount() { 120525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov return mPageAdapter.getFilePageCount(); 121525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 122525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 123525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov public PageRange[] getSelectedPages() { 124525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov return mPageAdapter.getSelectedPages(); 125525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 126525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 127525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov public PageRange[] getRequestedPages() { 128525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov return mPageAdapter.getRequestedPages(); 129525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 130525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 131525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov public void onContentUpdated(boolean documentChanged, int documentPageCount, 132525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov PageRange[] writtenPages, PageRange[] selectedPages, MediaSize mediaSize, 133525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov Margins minMargins) { 134f3f963b0bebea91b17f7e60d9b826c458bfde38cSvetoslav boolean contentChanged = false; 135525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 136525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov if (documentChanged) { 137525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov contentChanged = true; 138525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 139525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 140525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov if (documentPageCount != mDocumentPageCount) { 141525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov mDocumentPageCount = documentPageCount; 142525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov contentChanged = true; 143525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 144525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 145525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov if (contentChanged) { 146525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov // If not closed, close as we start over. 147525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov if (mPageAdapter.isOpened()) { 148525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov Message operation = mHandler.obtainMessage(MyHandler.MSG_CLOSE); 149525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov mHandler.enqueueOperation(operation); 150525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 151525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 152525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 153525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov // The content changed. In this case we have to invalidate 154525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov // all rendered pages and reopen the file... 155f3f963b0bebea91b17f7e60d9b826c458bfde38cSvetoslav if ((contentChanged || !mPageAdapter.isOpened()) && writtenPages != null) { 156525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov Message operation = mHandler.obtainMessage(MyHandler.MSG_OPEN); 157525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov mHandler.enqueueOperation(operation); 158525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 159525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 160525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov // Update the attributes before after closed to avoid flicker. 161525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov SomeArgs args = SomeArgs.obtain(); 162525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov args.arg1 = writtenPages; 163525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov args.arg2 = selectedPages; 164525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov args.arg3 = mediaSize; 165525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov args.arg4 = minMargins; 166525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov args.argi1 = documentPageCount; 167525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 168525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov Message operation = mHandler.obtainMessage(MyHandler.MSG_UPDATE, args); 169525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov mHandler.enqueueOperation(operation); 170525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 171525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov // If document changed and has pages we want to start preloading. 172525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov if (contentChanged && writtenPages != null) { 173525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov operation = mHandler.obtainMessage(MyHandler.MSG_START_PRELOAD); 174525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov mHandler.enqueueOperation(operation); 175525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 176525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 177525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 178525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov @Override 179525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov public void onReleaseRequested(final File file) { 180525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov // This is called from the async task's single threaded executor 181525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov // thread, i.e. not on the main thread - so post a message. 182525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov mHandler.post(new Runnable() { 183525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov @Override 184525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov public void run() { 185525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov // At this point the other end will write to the file, hence 186525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov // we have to close it and reopen after the write completes. 18762ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav if (mPageAdapter.isOpened()) { 18862ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav Message operation = mHandler.obtainMessage(MyHandler.MSG_CLOSE); 18962ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav mHandler.enqueueOperation(operation); 19062ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav } 191525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 192525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov }); 193525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 194525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 195c80814e70aea8940d0d43cd7170baae8c0c4e8e3Svet Ganov public void destroy(Runnable callback) { 1964237c92d850b7fb0fa0be15df94e4d1689e353fcSvet Ganov mHandler.cancelQueuedOperations(); 1974237c92d850b7fb0fa0be15df94e4d1689e353fcSvet Ganov mRecyclerView.setAdapter(null); 198c80814e70aea8940d0d43cd7170baae8c0c4e8e3Svet Ganov mPageAdapter.destroy(callback); 199525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 200525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 201525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov @Override 202525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov public int getWidth() { 203525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov return mEmbeddedContentContainer.getWidth(); 204525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 205525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 206525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov @Override 207525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov public int getHeight() { 208525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov return mEmbeddedContentContainer.getHeight(); 209525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 210525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 211525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov @Override 212525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov public void setColumnCount(int columnCount) { 213525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov mLayoutManger.setSpanCount(columnCount); 214525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 215525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 216525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov @Override 217525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov public void setPadding(int left, int top , int right, int bottom) { 218525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov mRecyclerView.setPadding(left, top, right, bottom); 219525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 220525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 221525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov private final class MyHandler extends Handler { 222525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov public static final int MSG_OPEN = 1; 223525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov public static final int MSG_CLOSE = 2; 224525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov public static final int MSG_UPDATE = 4; 225525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov public static final int MSG_START_PRELOAD = 5; 226525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 227525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov private boolean mAsyncOperationInProgress; 228525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 229525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov private final Runnable mOnAsyncOperationDoneCallback = new Runnable() { 230525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov @Override 231525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov public void run() { 232525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov mAsyncOperationInProgress = false; 233525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov handleNextOperation(); 234525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 235525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov }; 236525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 237525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov private final List<Message> mPendingOperations = new ArrayList<>(); 238525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 239525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov public MyHandler(Looper looper) { 240525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov super(looper, null, false); 241525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 242525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 2434237c92d850b7fb0fa0be15df94e4d1689e353fcSvet Ganov public void cancelQueuedOperations() { 2444237c92d850b7fb0fa0be15df94e4d1689e353fcSvet Ganov mPendingOperations.clear(); 2454237c92d850b7fb0fa0be15df94e4d1689e353fcSvet Ganov } 2464237c92d850b7fb0fa0be15df94e4d1689e353fcSvet Ganov 247525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov public void enqueueOperation(Message message) { 248525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov mPendingOperations.add(message); 249525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov handleNextOperation(); 250525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 251525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 252525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov public void handleNextOperation() { 253525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov while (!mPendingOperations.isEmpty() && !mAsyncOperationInProgress) { 254525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov Message operation = mPendingOperations.remove(0); 255525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov handleMessage(operation); 256525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 257525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 258525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 259525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov @Override 260525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov public void handleMessage(Message message) { 261525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov switch (message.what) { 262525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov case MSG_OPEN: { 263525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov try { 264525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov File file = mFileProvider.acquireFile(PrintPreviewController.this); 265525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov ParcelFileDescriptor pfd = ParcelFileDescriptor.open(file, 266525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov ParcelFileDescriptor.MODE_READ_ONLY); 267525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 268525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov mAsyncOperationInProgress = true; 269525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov mPageAdapter.open(pfd, new Runnable() { 270525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov @Override 271525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov public void run() { 272525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov if (mDocumentPageCount == PrintDocumentInfo.PAGE_COUNT_UNKNOWN) { 273525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov mDocumentPageCount = mPageAdapter.getFilePageCount(); 274525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov mActivity.updateOptionsUi(); 275525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 276525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov mOnAsyncOperationDoneCallback.run(); 277525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 278525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov }); 279525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } catch (FileNotFoundException fnfe) { 280525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov /* ignore - file guaranteed to be there */ 281525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 282525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } break; 283525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 284525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov case MSG_CLOSE: { 285525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov mAsyncOperationInProgress = true; 286525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov mPageAdapter.close(new Runnable() { 287525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov @Override 288525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov public void run() { 289525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov mFileProvider.releaseFile(); 290525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov mOnAsyncOperationDoneCallback.run(); 291525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 292525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov }); 293525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } break; 294525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 295525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov case MSG_UPDATE: { 296525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov SomeArgs args = (SomeArgs) message.obj; 297525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov PageRange[] writtenPages = (PageRange[]) args.arg1; 298525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov PageRange[] selectedPages = (PageRange[]) args.arg2; 299525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov MediaSize mediaSize = (MediaSize) args.arg3; 300525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov Margins margins = (Margins) args.arg4; 301525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov final int pageCount = args.argi1; 302525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov args.recycle(); 303525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 304525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov mPageAdapter.update(writtenPages, selectedPages, pageCount, 305525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov mediaSize, margins); 306525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 307525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } break; 308525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 309525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov case MSG_START_PRELOAD: { 310525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov mPreloadController.startPreloadContent(); 311525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } break; 312525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 313525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 314525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 315525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 316753c114d84328219a0ccbffdd462a69e04ef8c4fYigit Boyar private final class PreloadController extends RecyclerView.OnScrollListener { 317525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov private final RecyclerView mRecyclerView; 318525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 319525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov private int mOldScrollState; 320525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 321525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov public PreloadController(RecyclerView recyclerView) { 322525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov mRecyclerView = recyclerView; 323525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov mOldScrollState = mRecyclerView.getScrollState(); 324525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 325525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 326525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov @Override 327753c114d84328219a0ccbffdd462a69e04ef8c4fYigit Boyar public void onScrollStateChanged(RecyclerView recyclerView, int state) { 328525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov switch (mOldScrollState) { 329525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov case RecyclerView.SCROLL_STATE_SETTLING: { 330525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov if (state == RecyclerView.SCROLL_STATE_IDLE 331525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov || state == RecyclerView.SCROLL_STATE_DRAGGING){ 332525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov startPreloadContent(); 333525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 334525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } break; 335525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 336525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov case RecyclerView.SCROLL_STATE_IDLE: 337525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov case RecyclerView.SCROLL_STATE_DRAGGING: { 338525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov if (state == RecyclerView.SCROLL_STATE_SETTLING) { 339525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov stopPreloadContent(); 340525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 341525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } break; 342525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 343525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov mOldScrollState = state; 344525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 345525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 346525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov public void startPreloadContent() { 347525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov PageAdapter pageAdapter = (PageAdapter) mRecyclerView.getAdapter(); 3487fd5ada98aa9e035682531d9fe25633fdd24a058Svetoslav if (pageAdapter != null && pageAdapter.isOpened()) { 349525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov PageRange shownPages = computeShownPages(); 350525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov if (shownPages != null) { 351525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov pageAdapter.startPreloadContent(shownPages); 352525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 353525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 354525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 355525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 356525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov public void stopPreloadContent() { 357525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov PageAdapter pageAdapter = (PageAdapter) mRecyclerView.getAdapter(); 3587fd5ada98aa9e035682531d9fe25633fdd24a058Svetoslav if (pageAdapter != null && pageAdapter.isOpened()) { 359525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov pageAdapter.stopPreloadContent(); 360525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 361525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 362525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 363525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov private PageRange computeShownPages() { 364525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov final int childCount = mRecyclerView.getChildCount(); 365525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov if (childCount > 0) { 366525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov LayoutManager layoutManager = mRecyclerView.getLayoutManager(); 367525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 368525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov View firstChild = layoutManager.getChildAt(0); 369525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov ViewHolder firstHolder = mRecyclerView.getChildViewHolder(firstChild); 370525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 371525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov View lastChild = layoutManager.getChildAt(layoutManager.getChildCount() - 1); 372525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov ViewHolder lastHolder = mRecyclerView.getChildViewHolder(lastChild); 373525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 374525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov return new PageRange(firstHolder.getPosition(), lastHolder.getPosition()); 375525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 376525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov return null; 377525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 378525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 379525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov} 380