import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
+import android.media.AudioManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
-import android.view.Menu;
-import android.view.MenuItem;
+import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.TextView;
import android.widget.Toast;
+import com.google.android.glass.media.Sounds;
+
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.
+ * <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);
- mViewStates = ViewStates.SCROLLING;
+ mZoomValue = (TextView) findViewById(R.id.zoom_value);
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));
+ 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();
}
@Override
public boolean onGenericMotionEvent(MotionEvent event) {
- /*
- Zoom ratio gained during one gesture on touchpad
- */
- float dzoom;
- if (event.getAction() == MotionEvent.ACTION_DOWN) {
- startX = event.getRawX();
- return false;
- }
- if (event.getAction() == MotionEvent.ACTION_MOVE) {
- dzoom = event.getRawX() - startX;
- Log.d(TAG,"move_action, dzoom: " + dzoom);
- mPdfView.zoom(dzoom /1000f);
- startX = event.getRawX();
- return false;
+ if (mViewStates == ViewStates.SCROLLING) {
+ /*
+ Zoom ratio gained during one gesture on touchpad
+ */
+ float dzoom;
+ if (event.getAction() == MotionEvent.ACTION_DOWN) {
+ startX = event.getRawX();
+ return false;
+ }
+ if (event.getAction() == MotionEvent.ACTION_MOVE) {
+ dzoom = event.getRawX() - startX;
+ zoomPage(dzoom / 1000f);
+ startX = event.getRawX();
+ return false;
+ }
}
return super.onGenericMotionEvent(event);
}
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
+ AudioManager audio = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
+ audio.playSoundEffect(Sounds.TAP);
+ switchState();
+ }
+ return super.onKeyDown(keyCode, event);
+ }
+
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
float dx = event.values[1]*12;
float dy = event.values[0]*12;
if (mPdfView != null) {
- mPdfView.move(-dx, -dy);
+ if (mViewStates == ViewStates.SCROLLING) {
+ mPdfView.move(-dx, -dy);
+ }
}
}
}
}
+ /**
+ * 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
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
mProgressContainer.setVisibility(View.INVISIBLE);
+ switchState();
mPdfImageContainer.addView(mPdfView);
+ zoomPage(0.0f); // just for update the zoom value indicator
Log.d(TAG, "PDF page loaded.");
}
}