<component name="EntryPointsManager">
<entry_points version="2.0" />
</component>
+ <component name="NullableNotNullManager">
+ <option name="myDefaultNullable" value="org.jetbrains.annotations.Nullable" />
+ <option name="myDefaultNotNull" value="android.support.annotation.NonNull" />
+ <option name="myNullables">
+ <value>
+ <list size="4">
+ <item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" />
+ <item index="1" class="java.lang.String" itemvalue="javax.annotation.Nullable" />
+ <item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" />
+ <item index="3" class="java.lang.String" itemvalue="android.support.annotation.Nullable" />
+ </list>
+ </value>
+ </option>
+ <option name="myNotNulls">
+ <value>
+ <list size="4">
+ <item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" />
+ <item index="1" class="java.lang.String" itemvalue="javax.annotation.Nonnull" />
+ <item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" />
+ <item index="3" class="java.lang.String" itemvalue="android.support.annotation.NonNull" />
+ </list>
+ </value>
+ </option>
+ </component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" assert-keyword="true" jdk-15="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
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.
- * <p/>
- * 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 <a href="https://developers.google.com/glass/develop/gdk/touch">GDK Developer Guide</a>
+ * 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) {
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
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();
- }
-
}
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;
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.
+ * <p>This path should not be hardcoded like this, but the Android API functions were returning
+ * paths tht were not valid on our Android devices.</p>
+ */
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.
+ * <p>Those two are in the container to make them easily disappear and appear when needed.</p>
+ */
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
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);
}
}
else {
- Log.i(TAG, "No component id received");
+ Log.e(TAG, "No component id received.");
finish();
}
}
@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.
getMenuInflater().inflate(R.menu.menu_preview, menu);
return true;
}
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();
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);
}
}
- /** 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);
}
@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) {
}
}
+ /**
+ * Class for asynchronous loading of the PDF page to a bitmap.
+ */
private class LoadPageTask extends AsyncTask<Void, Void, Void> {
@Override
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.");
}
}
-
}
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 {
/**
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();
}
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 {
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();
}
}
+ /**
+ * 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
mListener = listener;
}
+ /**
+ * Clear listener.
+ */
public void clearListener() {
mListener = null;
}
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);
}
}
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;
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.
+ * <p>Those two are in the container to make them easily disappear and appear when needed.</p>
+ */
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.
+ * <p>Those two are in the container to make them easily disappear and appear when needed.</p>
+ */
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();
}
@Override
protected void onPause() {
super.onPause();
+ Log.d(TAG, "Unregister sensor listener.");
mSensorManager.unregisterListener(this);
}
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) {
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();
}
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) {
}
+ /**
+ * 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<Void, Void, Void> {
@Override
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){
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"/>
<TextView
android:layout_width="wrap_content"
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"/>
<RelativeLayout
android:layout_width="73dp"
<string name="app_name">Skoda Manufacturer Helper</string>
<string name="start_scan">Scan</string>
<string name="title_activity_preview">Component preview</string>
- <string name="title_activity_main">Skoda Demo</string>
- <string name="hello_world">Skoda Demo</string>
+ <string name="title_activity_main">Skoda Demo</string>
+ <string name="hello_world">Skoda Demo</string>
<string name="action_stop">Stop</string>
<string name="action_scan">Scan code</string>
<string name="cannot_open_file_Path">Cannot open file: %1$s</string>
<string name="tap_to_start_scan">Tap to start scanning</string>
<string name="state_viewing" type="id">viewing</string>
<string name="state_scrolling" type="id">scrolling</string>
+ <string name="preview_content_desc">Component preview image</string>
+ <string name="skoda_logo_content_desc">Skoda auto logo</string>
+
</resources>
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
@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();
}
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();
}
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.
+ * <p>This path should not be hardcoded like this, but the Android API functions were returning
+ * paths tht were not valid on our Android devices.</p>
+ */
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.
+ * <p>Those two are in the container to make them easily disappear and appear when needed.</p>
+ */
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);
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();
}
}
@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) {
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();
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();
}
/**
- * 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);
startActivity(pdfIntent);
}
+ /**
+ * Class for asynchronous loading of the PDF page to a bitmap.
+ */
private class LoadPageTask extends AsyncTask<Void, Void, Void> {
@Override
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.");
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
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();
}
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 {
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();
}
}
+ /**
+ * 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
mListener = listener;
}
+ /**
+ * Clear listener.
+ */
public void clearListener() {
mListener = null;
}
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);
}
}
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){
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"
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"
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"
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"
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"/>
<RelativeLayout
android:layout_width="73dp"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:onClick="findComponent"
- android:layout_above="@+id/button"/>
+ android:layout_above="@+id/button"
+ android:contentDescription="@string/skoda_logo_content_desc"/>
<Button
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:id="@+id/imgComponent"
android:layout_gravity="center_vertical"
- android:scaleType="center"/>
+ android:scaleType="center"
+ android:contentDescription="@string/preview_content_desc"/>
<RelativeLayout
android:layout_width="73dp"
<string name="butManufacturingGuide">Workshop manual</string>
<string name="previewHeading">Select document to view</string>
<string name="loading_page">Loading...</string>
+ <string name="preview_content_desc">Component preview image</string>
+ <string name="skoda_logo_content_desc">Skoda auto logo</string>
</resources>