From: Michal Horn Date: Tue, 17 Feb 2015 14:36:43 +0000 (+0100) Subject: Clean and coment the code. X-Git-Url: http://rtime.felk.cvut.cz/gitweb/hornmich/skoda-qr-demo.git/commitdiff_plain/9da9d8a5a309f3b3041cf3bab3603a36ce253121 Clean and coment the code. --- diff --git a/QRScanner/.idea/misc.xml b/QRScanner/.idea/misc.xml index 99b2e43..e7e6052 100644 --- a/QRScanner/.idea/misc.xml +++ b/QRScanner/.idea/misc.xml @@ -3,6 +3,30 @@ + + + + diff --git a/QRScanner/glass/src/main/java/cz/cvut/fel/dce/qrscanner/MainActivity.java b/QRScanner/glass/src/main/java/cz/cvut/fel/dce/qrscanner/MainActivity.java index 1f9ca08..6791d44 100644 --- a/QRScanner/glass/src/main/java/cz/cvut/fel/dce/qrscanner/MainActivity.java +++ b/QRScanner/glass/src/main/java/cz/cvut/fel/dce/qrscanner/MainActivity.java @@ -1,55 +1,32 @@ package cz.cvut.fel.dce.qrscanner; import com.google.android.glass.media.Sounds; -import com.google.android.glass.widget.CardBuilder; -import com.google.android.glass.widget.CardScrollAdapter; -import com.google.android.glass.widget.CardScrollView; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.media.AudioManager; -import android.media.SoundPool; import android.os.Bundle; import android.util.Log; import android.view.KeyEvent; -import android.view.MotionEvent; -import android.view.SoundEffectConstants; -import android.view.View; -import android.view.ViewGroup; -import android.widget.AdapterView; import cz.cvut.fel.dce.qrscanner.integration.IntentIntegrator; import cz.cvut.fel.dce.qrscanner.integration.IntentResult; /** - * An {@link Activity} showing a tuggable "Hello World!" card. - *

- * The main content view is composed of a one-card {@link CardScrollView} that provides tugging - * feedback to the user when swipe gestures are detected. - * If your Glassware intends to intercept swipe gestures, you should set the content view directly - * and use a {@link com.google.android.glass.touchpad.GestureDetector}. - * - * @see GDK Developer Guide + * An {@link Activity} showing an immersive card with a Skoda Auto logo, waiting for + * user to tap the touchpad to start the QR code scanning. */ public class MainActivity extends Activity { - public final static String TAG = "MainActivity"; - - /** - * {@link CardScrollView} to use as the main content view. - */ - private CardScrollView mCardScroller; - /** - * "Hello World!" {@link View} generated by {@link #buildView()}. + * An activity tag for debug, error and info messages. */ - private View mView; + public final static String TAG = "MainActivity"; @Override protected void onCreate(Bundle bundle) { super.onCreate(bundle); setContentView(R.layout.activity_main); - } public void onActivityResult(int requestCode, int resultCode, Intent intent) { @@ -59,12 +36,10 @@ public class MainActivity extends Activity { audio.playSoundEffect(Sounds.SUCCESS); Log.i(TAG, scanResult.toString()); Intent preview = new Intent(this, PreviewActivity.class); - preview.putExtra("COMPONENT_ID", scanResult.getContents()); + preview.putExtra(PreviewActivity.COMP_ID_INTENT_KEY, scanResult.getContents()); startActivity(preview); } - // else continue with any other code you need in the method - } @Override @@ -88,19 +63,11 @@ public class MainActivity extends Activity { return super.onKeyDown(keyCode, event); } + /** + * Start the scan code activity + */ private void startScan() { IntentIntegrator integrator = new IntentIntegrator(this); integrator.initiateScan(); } - - /** - * Builds a Glass styled "Hello World!" view using the {@link CardBuilder} class. - */ - private View buildView() { - CardBuilder card = new CardBuilder(this, CardBuilder.Layout.TEXT); - - card.setText(R.string.hello_world); - return card.getView(); - } - } diff --git a/QRScanner/glass/src/main/java/cz/cvut/fel/dce/qrscanner/PreviewActivity.java b/QRScanner/glass/src/main/java/cz/cvut/fel/dce/qrscanner/PreviewActivity.java index a8aafbf..17383b0 100644 --- a/QRScanner/glass/src/main/java/cz/cvut/fel/dce/qrscanner/PreviewActivity.java +++ b/QRScanner/glass/src/main/java/cz/cvut/fel/dce/qrscanner/PreviewActivity.java @@ -3,10 +3,7 @@ package cz.cvut.fel.dce.qrscanner; import android.app.Activity; import android.content.Context; import android.content.Intent; -import android.graphics.Bitmap; -import android.graphics.Color; import android.media.AudioManager; -import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; import android.util.Log; @@ -23,28 +20,81 @@ import com.google.android.glass.media.Sounds; import java.io.File; -import cz.cvut.fel.dce.qrscanner.mupdf.MuPDFCore; import cz.cvut.fel.dce.qrscanner.pdfviewer.PdfPageView; import cz.cvut.fel.dce.qrscanner.pdfviewer.PdfViewActivity; - +/** + * An activity for component picture preview with menu for selecting documents to be shown. + * + * The activity is designed to be called via an Intent with a component identifier string passed + * with the key COMPONENT_ID. + * + * The activity loads the component picture from the PDF file asynchronously to not block the UI. + */ public class PreviewActivity extends Activity implements ViewTreeObserver.OnGlobalLayoutListener{ - + /** + * An activity tag for debug, error and info messages. + */ public static final String TAG = "PreviewActivity"; + /** + * The path to the storage folder, where the application stores its data. + *

This path should not be hardcoded like this, but the Android API functions were returning + * paths tht were not valid on our Android devices.

+ */ public static final String STORAGE_PATH = "/storage/sdcard0/Pictures"; + /** + * The path in the application data folder, where the component database is. + */ public static final String SKODA_DOCS_PATH_EXTENSION = "/skoda/components/"; + /** + * The name of the PDF file containing the pisture of the component. + */ public static final String SKODA_COMP_PICTURE_NAME = "Abbildung.pdf"; + /** + * The name of the PDF file containing the manufacturing process description. + */ public static final String SKODA_COMP_MANUFACTURING = "Arbeitseinleitung.pdf"; + /** + * The name of the PDF file containing the manufacturing process description with pictures. + */ public static final String SKODA_COMP_MANUFACT_IMAGES = "Bild_Arbeitseinleitung.pdf"; + /** + * The name of the PDF file containing the contacts for the component manufacturer. + */ public static final String SKODA_COMP_CONTACTS = "Angaben.pdf"; + /** + * The name of the PDF file containing the manufacturing guide. + */ public static final String SKODA_COMP_MANUFACT_GUIDE = "Werkstatt_Einleitung.pdf"; + /** + * The Key of the Component Identifier value, passed as a data to the activity launch intent. + */ + public static final String COMP_ID_INTENT_KEY = "COMPONENT_ID"; + /** + * The widget for showing the component preview image. + */ private ImageView mPreviewImg; + /** + * The container for progress bar widget and text view. + *

Those two are in the container to make them easily disappear and appear when needed.

+ */ private RelativeLayout mProgressContainer; + /** + * The observer of the view tree for detection of the end of the View tree loading. + */ private ViewTreeObserver mPreviewImgObserver; - private String mComponentId; + /** + * The path to the directory containing documents for the component. + */ private String mComponentRootPath; + /** + * Widget containing loaded page from a PDF file. + */ private PdfPageView mPdfView; + /** + * Flag signalling whether the PDF page has been loaded. + */ private boolean mPdfLoaded; @Override @@ -55,27 +105,28 @@ public class PreviewActivity extends Activity implements ViewTreeObserver.OnGlob mPreviewImg = (ImageView) findViewById(R.id.imgComponent); mProgressContainer = (RelativeLayout) findViewById(R.id.progress_container); - if (mPreviewImg != null) { - mPreviewImg.setMaxWidth(640); - mPreviewImg.setMaxHeight(360); - mPreviewImg.setScaleType(ImageView.ScaleType.CENTER_INSIDE); - mPreviewImgObserver = mPreviewImg.getViewTreeObserver(); - Log.i(TAG, "Registering mPreviewImgObserver OnGlobalLayoutListener."); - mPreviewImgObserver.addOnGlobalLayoutListener(this); + if (mProgressContainer == null) { + Log.e(TAG, "Progress container not found in the activity layout."); + finish(); } - else { - Log.e(TAG, "ImageView for preview image could not be found in the resources."); - mPreviewImgObserver = null; + if (mPreviewImg == null) { + Log.e(TAG, "ImageView for preview image could not be found in the activity layout."); + finish(); } + mPreviewImgObserver = mPreviewImg.getViewTreeObserver(); + Log.d(TAG, "Registering mPreviewImgObserver OnGlobalLayoutListener."); + mPreviewImgObserver.addOnGlobalLayoutListener(this); + Intent intent = getIntent(); - mComponentId = intent.getStringExtra("COMPONENT_ID"); + String mComponentId = intent.getStringExtra(COMP_ID_INTENT_KEY); if (mComponentId != null) { Log.i(TAG, "Received component id: " + mComponentId); mComponentRootPath = STORAGE_PATH + SKODA_DOCS_PATH_EXTENSION + mComponentId + "/"; File rootPath = new File(mComponentRootPath); if (!rootPath.isDirectory()) { + Log.e(TAG, "Component database root directory " + rootPath.getAbsolutePath() + " does not exist."); Toast toast = Toast.makeText(getApplicationContext(), "Component not found", Toast.LENGTH_LONG); toast.show(); AudioManager audio = (AudioManager) getSystemService(Context.AUDIO_SERVICE); @@ -84,7 +135,7 @@ public class PreviewActivity extends Activity implements ViewTreeObserver.OnGlob } } else { - Log.i(TAG, "No component id received"); + Log.e(TAG, "No component id received."); finish(); } } @@ -92,7 +143,7 @@ public class PreviewActivity extends Activity implements ViewTreeObserver.OnGlob @Override protected void onDestroy() { super.onDestroy(); - Log.i(TAG, "Unregistering mPreviewImgObserver OnGlobalLayoutListener."); + Log.d(TAG, "Unregister mPreviewImgObserver OnGlobalLayoutListener."); if (mPreviewImgObserver != null && mPreviewImgObserver.isAlive()) { mPreviewImgObserver.removeOnGlobalLayoutListener(this); } @@ -100,7 +151,6 @@ public class PreviewActivity extends Activity implements ViewTreeObserver.OnGlob @Override public boolean onCreateOptionsMenu(Menu menu) { - // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.menu_preview, menu); return true; } @@ -114,6 +164,7 @@ public class PreviewActivity extends Activity implements ViewTreeObserver.OnGlob try { String picturePath = mComponentRootPath + SKODA_COMP_PICTURE_NAME; Log.i(TAG, "Path to component files: " + picturePath); + Log.d(TAG, "Loading PDF file " + picturePath); mPdfView = new PdfPageView(getApplicationContext(), picturePath); mPdfView.setPage(0); new LoadPageTask().execute(); @@ -121,6 +172,7 @@ public class PreviewActivity extends Activity implements ViewTreeObserver.OnGlob mPdfLoaded = true; } catch (Exception e) { + Log.e(TAG, "Component picture loading from PDF file failed: " + e.getMessage()); Toast toast = Toast.makeText(getApplicationContext(), "Component preview could not be loaded.", Toast.LENGTH_LONG); toast.show(); AudioManager audio = (AudioManager) getSystemService(Context.AUDIO_SERVICE); @@ -129,29 +181,33 @@ public class PreviewActivity extends Activity implements ViewTreeObserver.OnGlob } } - /** Called when the user touches the button */ + /** Called when the user touches the button Contacts. */ public void showContacts() { showPDF(mComponentRootPath + SKODA_COMP_CONTACTS); } - /** Called when the user touches the button */ + /** Called when the user touches the button Manufacturing. */ public void showManufacturing() { showPDF(mComponentRootPath + SKODA_COMP_MANUFACTURING); } - /** Called when the user touches the button */ + /** Called when the user touches the button Manufacturing pictured. */ public void showManufactImages() { showPDF(mComponentRootPath + SKODA_COMP_MANUFACT_IMAGES); } - /** Called when the user touches the button */ + /** Called when the user touches the button Manufacture guide. */ public void showManufactGuide() { showPDF(mComponentRootPath + SKODA_COMP_MANUFACT_GUIDE); } + /** + * Launch an activity to show the PDF file. + * @param filePath Path to the PDF file to be shown + */ private void showPDF(String filePath) { Intent preview = new Intent(this, PdfViewActivity.class); - preview.putExtra("FILE_PATH", filePath); + preview.putExtra(PdfViewActivity.FILE_PATH_INTENT_KEY, filePath); startActivity(preview); } @@ -168,9 +224,6 @@ public class PreviewActivity extends Activity implements ViewTreeObserver.OnGlob @Override public boolean onOptionsItemSelected(MenuItem item) { - // Handle action bar item clicks here. The action bar will - // automatically handle clicks on the Home/Up button, so long - // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); if (id == R.id.show_contacts) { @@ -198,6 +251,9 @@ public class PreviewActivity extends Activity implements ViewTreeObserver.OnGlob } } + /** + * Class for asynchronous loading of the PDF page to a bitmap. + */ private class LoadPageTask extends AsyncTask { @Override @@ -219,10 +275,10 @@ public class PreviewActivity extends Activity implements ViewTreeObserver.OnGlob mProgressContainer.setVisibility(View.INVISIBLE); mPreviewImg.setMinimumWidth(640); mPreviewImg.setMinimumHeight(360); + mPreviewImg.setScaleType(ImageView.ScaleType.CENTER_INSIDE); mPreviewImg.setImageBitmap(mPdfView.getPageBitmap()); mPreviewImg.invalidate(); Log.d(TAG, "PDF page loaded."); } } - } diff --git a/QRScanner/glass/src/main/java/cz/cvut/fel/dce/qrscanner/pdfviewer/PdfPageView.java b/QRScanner/glass/src/main/java/cz/cvut/fel/dce/qrscanner/pdfviewer/PdfPageView.java index 44fcfb0..8ee3d6e 100644 --- a/QRScanner/glass/src/main/java/cz/cvut/fel/dce/qrscanner/pdfviewer/PdfPageView.java +++ b/QRScanner/glass/src/main/java/cz/cvut/fel/dce/qrscanner/pdfviewer/PdfPageView.java @@ -8,12 +8,15 @@ import android.util.Log; import android.view.View; import java.io.File; -import java.sql.Time; import cz.cvut.fel.dce.qrscanner.mupdf.MuPDFCore; /** - * Created by Michal Horn on 16.2.15. + * View for viewing PDF page. + * + * This view is designed to be used in two ways. + * 1) To view the PDF page itself on the device, which is supported by an interface for scrolling, zooming, switching pages and loading pages. + * 2) To load the PDF page to a bitmap, which can be accessed in the program by calling getPageBitmap() method. */ public class PdfPageView extends View { /** @@ -173,10 +176,18 @@ public class PdfPageView extends View { Log.i(TAG, "Pages: " + mPage.toString()); } + /** + * Get actual page. The actual page can be selected by setPage() method. + * @return actual page. + */ public int getActualPage() { return mPage.getValue(); } + /** + * Get total number of pages in the document + * @return total number of pages + */ public int getLastPage() { return mPage.getMaximum(); } @@ -185,6 +196,12 @@ public class PdfPageView extends View { return mPage.setValue(page); } + /** + * Load PDF and convert selected page to a bitmap. + * + * The page of the PDF document can be selected by setPage() method. + * This method can take significant time to finish. Consider calling it in separated thread. + */ public void loadPage() { long startTime = System.currentTimeMillis(); try { @@ -200,7 +217,7 @@ public class PdfPageView extends View { mYPosition = new IntervalValue<>(360.0f/2, -mSceneHeight+360.0f/2, mSceneHeight+360.0f/2); mZoom = new IntervalValue<>(1.0f, 0.2f, 2.0f); } catch (Exception e) { - Log.e(TAG, "Error in setting page dimensions."); + Log.e(TAG, "Error in setting page dimensions: " + e.getMessage()); e.printStackTrace(); } long endTime = System.currentTimeMillis(); @@ -211,12 +228,14 @@ public class PdfPageView extends View { } } + /** + * Get PDF page bitmap + * @return Bitmap of the PDF page or null, if it has not been yet loaded. + */ public Bitmap getPageBitmap() { return mPdfBitmap; } - - /** * Set a listener of the events * @param listener listener of the events @@ -225,6 +244,9 @@ public class PdfPageView extends View { mListener = listener; } + /** + * Clear listener. + */ public void clearListener() { mListener = null; } @@ -238,7 +260,7 @@ public class PdfPageView extends View { if (!mPageLoaded) return; float ratio = mZoom.getValue(); ratio += deltaRatio; - if (mZoom.setValue(ratio) == true && mListener != null) { + if (mZoom.setValue(ratio) && mListener != null) { mListener.onViewChanged(this); } } diff --git a/QRScanner/glass/src/main/java/cz/cvut/fel/dce/qrscanner/pdfviewer/PdfViewActivity.java b/QRScanner/glass/src/main/java/cz/cvut/fel/dce/qrscanner/pdfviewer/PdfViewActivity.java index 28122eb..719db79 100644 --- a/QRScanner/glass/src/main/java/cz/cvut/fel/dce/qrscanner/pdfviewer/PdfViewActivity.java +++ b/QRScanner/glass/src/main/java/cz/cvut/fel/dce/qrscanner/pdfviewer/PdfViewActivity.java @@ -12,8 +12,6 @@ import android.os.AsyncTask; import android.os.Bundle; import android.util.Log; import android.view.KeyEvent; -import android.view.Menu; -import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; import android.view.ViewTreeObserver; @@ -29,76 +27,164 @@ import java.io.File; import cz.cvut.fel.dce.qrscanner.R; +/** + * PDF Viewer for Google Glass. + * + * This activity is designed to view PDF in Google Glass. The document can be scrolled by the + * moving of the user's head and zoomed in and out by sliding forward and backward on the touchpad. + * The activity has two states, which can be toggled by taping on the touchpad. When in the Scrolling + * state, the PDF document can be scrolled and zoomed. When in the viewing state, those features are + * disabled to let the user read the document comfortably. + * + * The activity is prepared to switch between pages, which should be implemented in the future by sliding + * forward and backward in the viewing state. + */ public class PdfViewActivity extends Activity implements ViewTreeObserver.OnGlobalLayoutListener, PdfPageView.SceneChange, SensorEventListener { + /** + * The Key of the file path value, passed as a data to the activity launch intent. + */ + public static final String FILE_PATH_INTENT_KEY = "FILE_PATH"; + /** + * The states of the PDF viewer. + */ enum ViewStates { + /** + * Scrolling state - user can scroll in the page by moving of the head and zoom by sliding the touchpad. + */ SCROLLING, + /** + * Viewing state - user can read the document comfortably and in the future will be able to change the pages. + */ VIEWING - }; + } + /** + * An activity tag for debug, error and info messages. + */ public static final String TAG = "PdfViewActivity"; + /** + * The container for progress bar widget and text view. + *

Those two are in the container to make them easily disappear and appear when needed.

+ */ private FrameLayout mPdfImageContainer; + /** + * The text view widget showing the current page numeber. + */ private TextView mCurrentPageNumber; + /** + * The text view widget showing total number of the pages. + */ private TextView mLastPageNumber; + /** + * The text view widget showing current state of the viewer. + */ private TextView mViewerStateText; + /** + * The text view widget showing the zoom in percent. + */ private TextView mZoomValue; + /** + * The observer of the view tree for detection of the end of the View tree loading. + */ private ViewTreeObserver mPreviewImgObserver; + /** + * The path to the PDF file to be loaded. + */ private String mFilePath; + /** + * Widget containing loaded page from a PDF file. + */ private PdfPageView mPdfView; - private Boolean mPdfLoaded = false; + /** + * Flag signalling whether the PDF page has been loaded. + */ + private Boolean mPdfLoaded; + /** + * Sensor manager for receiving data from gyroscope to scroll the PDF page. + */ private SensorManager mSensorManager; + /** + * Stores the current state of the PDF viewer. + */ private ViewStates mViewStates; + /** + * The container for progress bar widget and text view. + *

Those two are in the container to make them easily disappear and appear when needed.

+ */ private RelativeLayout mProgressContainer; - /** - * Start position of the gesture on touchpad + * Start position of the gesture on touchpad. */ private float startX; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + mPdfLoaded = false; getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); setContentView(R.layout.activity_pdf_view); + mPdfImageContainer = (FrameLayout) findViewById(R.id.pdf_view_container); mCurrentPageNumber = (TextView) findViewById(R.id.page_number); mLastPageNumber = (TextView) findViewById(R.id.total_pages_num); mViewerStateText = (TextView) findViewById(R.id.pdf_viewer_state); mZoomValue = (TextView) findViewById(R.id.zoom_value); - mViewStates = ViewStates.SCROLLING; mProgressContainer = (RelativeLayout) findViewById(R.id.progress_container); - - if (mPdfImageContainer != null) { - mPreviewImgObserver = mPdfImageContainer.getViewTreeObserver(); - Log.i(TAG, "Registering mPreviewImgObserver OnGlobalLayoutListener."); - mPreviewImgObserver.addOnGlobalLayoutListener(this); + if (mProgressContainer == null) { + Log.e(TAG, "Progress container not found in the activity layout."); + finish(); } - else { - Log.e(TAG, "ImageView for preview image could not be found in the resources."); - mPreviewImgObserver = null; + if (mCurrentPageNumber == null) { + Log.e(TAG, "Current page number view could not be found in the activity layout."); + finish(); + } + if (mLastPageNumber == null) { + Log.e(TAG, "Last page number view could not be found in the activity layout."); + finish(); + } + if (mViewerStateText == null) { + Log.e(TAG, "Viewer state view could not be found in the activity layout."); + finish(); } + if (mZoomValue == null) { + Log.e(TAG, "Zoom number view could not be found in the activity layout."); + finish(); + } + if (mPdfImageContainer == null) { + Log.e(TAG, "Current page number view could not be found in the activity layout."); + finish(); + } + mViewStates = ViewStates.SCROLLING; + + + mPreviewImgObserver = mPdfImageContainer.getViewTreeObserver(); + Log.d(TAG, "Registering mPreviewImgObserver OnGlobalLayoutListener."); + mPreviewImgObserver.addOnGlobalLayoutListener(this); Intent intent = getIntent(); - mFilePath = intent.getStringExtra("FILE_PATH"); + mFilePath = intent.getStringExtra(FILE_PATH_INTENT_KEY); if (mFilePath != null) { Log.i(TAG, "File path: " + mFilePath); File rootPath = new File(mFilePath); if (!rootPath.exists()) { + Log.e(TAG, "File " + rootPath.getAbsolutePath() + "not found."); Toast toast = Toast.makeText(getApplicationContext(), "Document not found", Toast.LENGTH_LONG); toast.show(); finish(); } } else { - Log.i(TAG, "No file path received"); + Log.e(TAG, "No file path received"); finish(); } } public void onResume() { + Log.d(TAG, "Registering sensor listener"); mSensorManager.registerListener(this, mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE), SensorManager.SENSOR_DELAY_NORMAL); super.onResume(); } @@ -106,6 +192,7 @@ public class PdfViewActivity extends Activity implements ViewTreeObserver.OnGlob @Override protected void onPause() { super.onPause(); + Log.d(TAG, "Unregister sensor listener."); mSensorManager.unregisterListener(this); } @@ -118,30 +205,6 @@ public class PdfViewActivity extends Activity implements ViewTreeObserver.OnGlob getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); } - - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - // Inflate the menu; this adds items to the action bar if it is present. - getMenuInflater().inflate(R.menu.menu_pdf_view, menu); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - // Handle action bar item clicks here. The action bar will - // automatically handle clicks on the Home/Up button, so long - // as you specify a parent activity in AndroidManifest.xml. - int id = item.getItemId(); - - //noinspection SimplifiableIfStatement - if (id == R.id.action_settings) { - return true; - } - - return super.onOptionsItemSelected(item); - } - @Override public void onGlobalLayout() { if (mPdfLoaded) { @@ -152,22 +215,16 @@ public class PdfViewActivity extends Activity implements ViewTreeObserver.OnGlob String picturePath = mFilePath; Log.i(TAG, "Path to component files: " + picturePath); mPdfView = new PdfPageView(getApplicationContext(), picturePath); + mPdfView.setPage(0); mCurrentPageNumber.setText(Integer.toString(mPdfView.getActualPage()+1)); mLastPageNumber.setText(Integer.toString(mPdfView.getLastPage() + 1)); mPdfView.setListener(this); - mPdfView.setPage(0); new LoadPageTask().execute(); - - if (mPdfImageContainer != null) { - mPdfLoaded = true; - } - else { - Log.e(TAG, "Could not find container for PdfPageView."); - finish(); - } + mPdfLoaded = true; } catch (Exception e) { - Toast toast = Toast.makeText(getApplicationContext(), "Component preview could not be loaded.", Toast.LENGTH_LONG); + Log.e(TAG, "PDF file could not be loaded: " + e.getMessage()); + Toast toast = Toast.makeText(getApplicationContext(), "PDF file could not be loaded.", Toast.LENGTH_LONG); toast.show(); e.printStackTrace(); } @@ -204,18 +261,6 @@ public class PdfViewActivity extends Activity implements ViewTreeObserver.OnGlob return super.onKeyDown(keyCode, event); } - private void switchState() { - if (mViewStates == ViewStates.SCROLLING) { - mViewStates = ViewStates.VIEWING; - mViewerStateText.setText(getText(R.string.state_viewing)); - } - else { - mViewStates = ViewStates.SCROLLING; - mViewerStateText.setText(getText(R.string.state_scrolling)); - - } - } - @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { @@ -246,11 +291,33 @@ public class PdfViewActivity extends Activity implements ViewTreeObserver.OnGlob } + /** + * Switch the viewer state, update the state text view in the layout. + */ + private void switchState() { + if (mViewStates == ViewStates.SCROLLING) { + mViewStates = ViewStates.VIEWING; + mViewerStateText.setText(getText(R.string.state_viewing)); + } + else { + mViewStates = ViewStates.SCROLLING; + mViewerStateText.setText(getText(R.string.state_scrolling)); + + } + } + + /** + * Zoom the PDF page, update the zoom value in the layout. + * @param deltaZoom The value how much to zoom the page. + */ private void zoomPage(float deltaZoom) { mPdfView.zoom(deltaZoom); mZoomValue.setText(Integer.toString(Math.round(mPdfView.getZoomRatio() * 100))); } + /** + * Class for asynchronous loading of the PDF page to a bitmap. + */ private class LoadPageTask extends AsyncTask { @Override diff --git a/QRScanner/glass/src/main/java/cz/cvut/fel/dce/qrscanner/pdfviewer/PdfViewerException.java b/QRScanner/glass/src/main/java/cz/cvut/fel/dce/qrscanner/pdfviewer/PdfViewerException.java index 36cf105..5aa1835 100644 --- a/QRScanner/glass/src/main/java/cz/cvut/fel/dce/qrscanner/pdfviewer/PdfViewerException.java +++ b/QRScanner/glass/src/main/java/cz/cvut/fel/dce/qrscanner/pdfviewer/PdfViewerException.java @@ -1,7 +1,9 @@ package cz.cvut.fel.dce.qrscanner.pdfviewer; /** - * Created by michal on 16.2.15. + * Custom Viewer exception class + * + * Instances of this Exception class are thrown by the PdfPageView widget. */ public class PdfViewerException extends Exception { PdfViewerException(String s){ diff --git a/QRScanner/glass/src/main/res/layout/activity_main.xml b/QRScanner/glass/src/main/res/layout/activity_main.xml index 0822edb..e463cd8 100644 --- a/QRScanner/glass/src/main/res/layout/activity_main.xml +++ b/QRScanner/glass/src/main/res/layout/activity_main.xml @@ -9,12 +9,12 @@ android:layout_height="wrap_content" android:id="@+id/imageView" android:src="@drawable/skoda_logo" - android:onClick="findComponent" android:scaleType="centerInside" android:layout_below="@+id/textView8" android:layout_alignParentBottom="true" android:layout_alignParentEnd="true" - android:layout_alignParentStart="true"/> + android:layout_alignParentStart="true" + android:contentDescription="@string/skoda_logo_content_desc"/> + android:scaleType="center" + android:contentDescription="@string/preview_content_desc"/> Skoda Manufacturer Helper Scan Component preview - Skoda Demo - Skoda Demo + Skoda Demo + Skoda Demo Stop Scan code Cannot open file: %1$s @@ -39,5 +39,8 @@ limitations under the License. Tap to start scanning viewing scrolling + Component preview image + Skoda auto logo + diff --git a/QRScanner/mobile/src/main/java/cz/cvut/fel/dce/qrscanner/MainActivity.java b/QRScanner/mobile/src/main/java/cz/cvut/fel/dce/qrscanner/MainActivity.java index de3a44c..c8ba7cf 100644 --- a/QRScanner/mobile/src/main/java/cz/cvut/fel/dce/qrscanner/MainActivity.java +++ b/QRScanner/mobile/src/main/java/cz/cvut/fel/dce/qrscanner/MainActivity.java @@ -11,8 +11,14 @@ import android.view.View; import cz.cvut.fel.dce.qrscanner.integration.IntentIntegrator; import cz.cvut.fel.dce.qrscanner.integration.IntentResult; - +/** + * An {@link android.app.Activity} showing an immersive card with a Skoda Auto logo, waiting for + * user to tap the screen to start the QR code scanning. + */ public class MainActivity extends ActionBarActivity { + /** + * An activity tag for debug, error and info messages. + */ public static final String TAG = "MainActivity"; @Override @@ -31,12 +37,8 @@ public class MainActivity extends ActionBarActivity { @Override public boolean onOptionsItemSelected(MenuItem item) { - // Handle action bar item clicks here. The action bar will - // automatically handle clicks on the Home/Up button, so long - // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); - //noinspection SimplifiableIfStatement if (id == R.id.start_scan) { startScan(); } @@ -49,17 +51,20 @@ public class MainActivity extends ActionBarActivity { if (scanResult != null) { Log.i(TAG, scanResult.toString()); Intent preview = new Intent(this, PreviewActivity.class); - preview.putExtra("COMPONENT_ID", scanResult.getContents()); + preview.putExtra(PreviewActivity.COMP_ID_INTENT_KEY, scanResult.getContents()); startActivity(preview); } } + /** + * Start the scan code activity + */ private void startScan() { IntentIntegrator integrator = new IntentIntegrator(this); integrator.initiateScan(IntentIntegrator.QR_CODE_TYPES); } - /** Called when the user touches the button */ + /** Called when the user touches the screen */ public void findComponent(View view) { startScan(); } diff --git a/QRScanner/mobile/src/main/java/cz/cvut/fel/dce/qrscanner/PreviewActivity.java b/QRScanner/mobile/src/main/java/cz/cvut/fel/dce/qrscanner/PreviewActivity.java index 767d4bc..7b7db3d 100644 --- a/QRScanner/mobile/src/main/java/cz/cvut/fel/dce/qrscanner/PreviewActivity.java +++ b/QRScanner/mobile/src/main/java/cz/cvut/fel/dce/qrscanner/PreviewActivity.java @@ -1,48 +1,96 @@ package cz.cvut.fel.dce.qrscanner; -import android.content.Context; import android.content.Intent; -import android.graphics.Bitmap; -import android.media.AudioManager; import android.net.Uri; import android.os.AsyncTask; import android.support.v7.app.ActionBarActivity; import android.os.Bundle; import android.util.Log; -import android.view.Menu; -import android.view.MenuItem; import android.view.View; import android.view.ViewTreeObserver; -import android.widget.Button; import android.widget.ImageView; import android.widget.RelativeLayout; import android.widget.Toast; import cz.cvut.fel.dce.qrscanner.mupdf.MuPDFActivity; -import cz.cvut.fel.dce.qrscanner.mupdf.MuPDFCore; import cz.cvut.fel.dce.qrscanner.pdfviewer.PdfPageView; import java.io.File; +/** + * An activity for component picture preview with menu for selecting documents to be shown. + * + * The activity is designed to be called via an Intent with a component identifier string passed + * with the key COMPONENT_ID. + * + * The activity loads the component picture from the PDF file asynchronously to not block the UI. + */ public class PreviewActivity extends ActionBarActivity implements ViewTreeObserver.OnGlobalLayoutListener { + /** + * An activity tag for debug, error and info messages. + */ public static final String TAG = "PreviewActivity"; + /** + * The path to the storage folder, where the application stores its data. + *

This path should not be hardcoded like this, but the Android API functions were returning + * paths tht were not valid on our Android devices.

+ */ public static final String STORAGE_PATH = "/storage/sdcard0/Pictures"; + /** + * The path in the application data folder, where the component database is. + */ public static final String SKODA_DOCS_PATH_EXTENSION = "/skoda/components/"; + /** + * The name of the PDF file containing the pisture of the component. + */ public static final String SKODA_COMP_PICTURE_NAME = "Abbildung.pdf"; + /** + * The name of the PDF file containing the manufacturing process description. + */ public static final String SKODA_COMP_MANUFACTURING = "Arbeitseinleitung.pdf"; + /** + * The name of the PDF file containing the manufacturing process description with pictures. + */ public static final String SKODA_COMP_MANUFACT_IMAGES = "Bild_Arbeitseinleitung.pdf"; + /** + * The name of the PDF file containing the contacts for the component manufacturer. + */ public static final String SKODA_COMP_CONTACTS = "Angaben.pdf"; + /** + * The name of the PDF file containing the manufacturing guide. + */ public static final String SKODA_COMP_MANUFACT_GUIDE = "Werkstatt_Einleitung.pdf"; + /** + * The Key of the Component Identifier value, passed as a data to the activity launch intent. + */ + public static final String COMP_ID_INTENT_KEY = "COMPONENT_ID"; + /** + * The widget for showing the component preview image. + */ private ImageView mPreviewImg; + /** + * The container for progress bar widget and text view. + *

Those two are in the container to make them easily disappear and appear when needed.

+ */ private RelativeLayout mProgressContainer; + /** + * The observer of the view tree for detection of the end of the View tree loading. + */ private ViewTreeObserver mPreviewImgObserver; - private String mComponentId; + /** + * The path to the directory containing documents for the component. + */ private String mComponentRootPath; + /** + * Widget containing loaded page from a PDF file. + */ private PdfPageView mPdfView; + /** + * Flag signalling whether the PDF page has been loaded. + */ private boolean mPdfLoaded; - @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -50,35 +98,36 @@ public class PreviewActivity extends ActionBarActivity implements ViewTreeObserv mPdfLoaded = false; mPreviewImg = (ImageView) findViewById(R.id.imgComponent); mProgressContainer = (RelativeLayout) findViewById(R.id.progress_container); + if (mProgressContainer == null) { - Log.e(TAG, "Progress container was not found."); + Log.e(TAG, "Progress container not found in the activity layout."); finish(); } - - if (mPreviewImg != null) { - mPreviewImg.setScaleType(ImageView.ScaleType.CENTER_INSIDE); - mPreviewImgObserver = mPreviewImg.getViewTreeObserver(); - Log.i(TAG, "Registering mPreviewImgObserver OnGlobalLayoutListener."); - mPreviewImgObserver.addOnGlobalLayoutListener(this); - } else { - Log.e(TAG, "ImageView for preview image could not be found in the resources."); - mPreviewImgObserver = null; + if (mPreviewImg == null) { + Log.e(TAG, "ImageView for preview image could not be found in the activity layout."); + finish(); } + mPreviewImgObserver = mPreviewImg.getViewTreeObserver(); + Log.d(TAG, "Registering mPreviewImgObserver OnGlobalLayoutListener."); + mPreviewImgObserver.addOnGlobalLayoutListener(this); + Intent intent = getIntent(); - mComponentId = intent.getStringExtra("COMPONENT_ID"); + String mComponentId = intent.getStringExtra(COMP_ID_INTENT_KEY); if (mComponentId != null) { Log.i(TAG, "Received component id: " + mComponentId); mComponentRootPath = STORAGE_PATH + SKODA_DOCS_PATH_EXTENSION + mComponentId + "/"; File rootPath = new File(mComponentRootPath); if (!rootPath.isDirectory()) { + Log.e(TAG, "Component database root directory " + rootPath.getAbsolutePath() + " does not exist."); Toast toast = Toast.makeText(getApplicationContext(), "Component not found", Toast.LENGTH_LONG); toast.show(); finish(); } - } else { - Log.i(TAG, "No component id received"); + } + else { + Log.e(TAG, "No component id received."); finish(); } } @@ -86,18 +135,12 @@ public class PreviewActivity extends ActionBarActivity implements ViewTreeObserv @Override protected void onDestroy() { super.onDestroy(); - Log.i(TAG, "Unregistering mPreviewImgObserver OnGlobalLayoutListener."); + Log.d(TAG, "Unregister mPreviewImgObserver OnGlobalLayoutListener."); if (mPreviewImgObserver != null && mPreviewImgObserver.isAlive()) { mPreviewImgObserver.removeOnGlobalLayoutListener(this); } } - @Override - public boolean onCreateOptionsMenu(Menu menu) { - // Inflate the menu; this adds items to the action bar if it is present. - return true; - } - @Override public void onGlobalLayout() { if (mPdfLoaded) { @@ -107,6 +150,7 @@ public class PreviewActivity extends ActionBarActivity implements ViewTreeObserv try { String picturePath = mComponentRootPath + SKODA_COMP_PICTURE_NAME; Log.i(TAG, "Path to component files: " + picturePath); + Log.d(TAG, "Loading PDF file " + picturePath); mPdfView = new PdfPageView(getApplicationContext(), picturePath); mPdfView.setPage(0); new LoadPageTask().execute(); @@ -114,6 +158,7 @@ public class PreviewActivity extends ActionBarActivity implements ViewTreeObserv mPdfLoaded = true; } catch (Exception e) { + Log.e(TAG, "Component picture loading from PDF file failed: " + e.getMessage()); Toast toast = Toast.makeText(getApplicationContext(), "Component preview could not be loaded.", Toast.LENGTH_LONG); toast.show(); e.printStackTrace(); @@ -121,33 +166,37 @@ public class PreviewActivity extends ActionBarActivity implements ViewTreeObserv } /** - * Called when the user touches the button + * Called when the user touches the button Contacts. */ public void showContacts(View view) { showPDF(mComponentRootPath + SKODA_COMP_CONTACTS); } /** - * Called when the user touches the button + * Called when the user touches the button Manufacturing. */ public void showManufacturing(View view) { showPDF(mComponentRootPath + SKODA_COMP_MANUFACTURING); } /** - * Called when the user touches the button + * Called when the user touches the button Manufacturing pictured */ public void showManufactImages(View view) { showPDF(mComponentRootPath + SKODA_COMP_MANUFACT_IMAGES); } /** - * Called when the user touches the button + * Called when the user touches the button Manufacture guide */ public void showManufactGuide(View view) { showPDF(mComponentRootPath + SKODA_COMP_MANUFACT_GUIDE); } + /** + * Launch an activity to show the PDF file. + * @param filePath Path to the PDF file to be shown + */ private void showPDF(String filePath) { Uri uri = Uri.parse(filePath); Intent pdfIntent = new Intent(this, MuPDFActivity.class); @@ -156,6 +205,9 @@ public class PreviewActivity extends ActionBarActivity implements ViewTreeObserv startActivity(pdfIntent); } + /** + * Class for asynchronous loading of the PDF page to a bitmap. + */ private class LoadPageTask extends AsyncTask { @Override @@ -175,6 +227,7 @@ public class PreviewActivity extends ActionBarActivity implements ViewTreeObserv protected void onPostExecute(Void aVoid) { super.onPostExecute(aVoid); mProgressContainer.setVisibility(View.INVISIBLE); + mPreviewImg.setScaleType(ImageView.ScaleType.CENTER_INSIDE); mPreviewImg.setImageBitmap(mPdfView.getPageBitmap()); mPreviewImg.invalidate(); Log.d(TAG, "PDF page loaded."); diff --git a/QRScanner/mobile/src/main/java/cz/cvut/fel/dce/qrscanner/pdfviewer/PdfPageView.java b/QRScanner/mobile/src/main/java/cz/cvut/fel/dce/qrscanner/pdfviewer/PdfPageView.java index 7e18f17..af58fc3 100644 --- a/QRScanner/mobile/src/main/java/cz/cvut/fel/dce/qrscanner/pdfviewer/PdfPageView.java +++ b/QRScanner/mobile/src/main/java/cz/cvut/fel/dce/qrscanner/pdfviewer/PdfPageView.java @@ -12,9 +12,13 @@ import java.io.File; import cz.cvut.fel.dce.qrscanner.mupdf.MuPDFCore; /** - * Created by Michal Horn on 16.2.15. + * View for viewing PDF page. + * + * This view is designed to be used in two ways. + * 1) To view the PDF page itself on the device, which is supported by an interface for scrolling, zooming, switching pages and loading pages. + * 2) To load the PDF page to a bitmap, which can be accessed in the program by calling getPageBitmap() method. */ -public class PdfPageView extends View { +public class PdfPageView extends View { /** * Value with some allowed minimum and maximum. * @author Michal Horn @@ -172,10 +176,18 @@ public class PdfPageView extends View { Log.i(TAG, "Pages: " + mPage.toString()); } + /** + * Get actual page. The actual page can be selected by setPage() method. + * @return actual page. + */ public int getActualPage() { return mPage.getValue(); } + /** + * Get total number of pages in the document + * @return total number of pages + */ public int getLastPage() { return mPage.getMaximum(); } @@ -184,6 +196,12 @@ public class PdfPageView extends View { return mPage.setValue(page); } + /** + * Load PDF and convert selected page to a bitmap. + * + * The page of the PDF document can be selected by setPage() method. + * This method can take significant time to finish. Consider calling it in separated thread. + */ public void loadPage() { long startTime = System.currentTimeMillis(); try { @@ -199,7 +217,7 @@ public class PdfPageView extends View { mYPosition = new IntervalValue<>(360.0f/2, -mSceneHeight+360.0f/2, mSceneHeight+360.0f/2); mZoom = new IntervalValue<>(1.0f, 0.2f, 2.0f); } catch (Exception e) { - Log.e(TAG, "Error in setting page dimensions."); + Log.e(TAG, "Error in setting page dimensions: " + e.getMessage()); e.printStackTrace(); } long endTime = System.currentTimeMillis(); @@ -210,12 +228,14 @@ public class PdfPageView extends View { } } + /** + * Get PDF page bitmap + * @return Bitmap of the PDF page or null, if it has not been yet loaded. + */ public Bitmap getPageBitmap() { return mPdfBitmap; } - - /** * Set a listener of the events * @param listener listener of the events @@ -224,6 +244,9 @@ public class PdfPageView extends View { mListener = listener; } + /** + * Clear listener. + */ public void clearListener() { mListener = null; } @@ -237,7 +260,7 @@ public class PdfPageView extends View { if (!mPageLoaded) return; float ratio = mZoom.getValue(); ratio += deltaRatio; - if (mZoom.setValue(ratio) == true && mListener != null) { + if (mZoom.setValue(ratio) && mListener != null) { mListener.onViewChanged(this); } } diff --git a/QRScanner/mobile/src/main/java/cz/cvut/fel/dce/qrscanner/pdfviewer/PdfViewerException.java b/QRScanner/mobile/src/main/java/cz/cvut/fel/dce/qrscanner/pdfviewer/PdfViewerException.java index 36cf105..5aa1835 100644 --- a/QRScanner/mobile/src/main/java/cz/cvut/fel/dce/qrscanner/pdfviewer/PdfViewerException.java +++ b/QRScanner/mobile/src/main/java/cz/cvut/fel/dce/qrscanner/pdfviewer/PdfViewerException.java @@ -1,7 +1,9 @@ package cz.cvut.fel.dce.qrscanner.pdfviewer; /** - * Created by michal on 16.2.15. + * Custom Viewer exception class + * + * Instances of this Exception class are thrown by the PdfPageView widget. */ public class PdfViewerException extends Exception { PdfViewerException(String s){ diff --git a/QRScanner/mobile/src/main/res/layout-land/activity_preview.xml b/QRScanner/mobile/src/main/res/layout-land/activity_preview.xml index 818eb65..ccb1be8 100644 --- a/QRScanner/mobile/src/main/res/layout-land/activity_preview.xml +++ b/QRScanner/mobile/src/main/res/layout-land/activity_preview.xml @@ -51,7 +51,6 @@ android:id="@+id/butManufactImages" android:onClick="showManufactImages" android:layout_gravity="center_horizontal" - android:layout_column="0" android:layout_below="@+id/textView4" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" @@ -64,7 +63,6 @@ android:id="@+id/butManufactGuide" android:onClick="showManufactGuide" android:layout_gravity="center_horizontal" - android:layout_column="0" android:layout_above="@+id/textView4" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" @@ -91,7 +89,6 @@ android:text="@string/butContacts" android:id="@+id/butContacts" android:onClick="showContacts" - android:layout_column="0" android:layout_below="@+id/textView5" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" @@ -104,7 +101,6 @@ android:id="@+id/butManufacturing" android:onClick="showManufacturing" android:layout_gravity="center_horizontal" - android:layout_column="0" android:layout_above="@+id/textView5" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" @@ -124,7 +120,8 @@ android:layout_height="match_parent" android:id="@+id/imgComponent" android:layout_gravity="center_horizontal" - android:scaleType="center"/> + android:scaleType="center" + android:contentDescription="@string/preview_content_desc"/> + android:layout_above="@+id/button" + android:contentDescription="@string/skoda_logo_content_desc"/>