Commit 58beccea authored by Thomas Krex's avatar Thomas Krex
Browse files

- code kommentiert und aufgeräumt

-shape-klassen strukturiert
parent 5cd2ac8a
......@@ -31,6 +31,16 @@ import com.actionbarsherlock.widget.SearchView.OnQueryTextListener;
import de.tum.in.tttclient.R;
/**
* Activity for the replay of the recordings. Here is done much initializing
* work. All objects are passed to the recording class, that controls the
* replay. The MediaController delegates the task to the recording object
*
*
*
* @author Thomas Krex
*
*/
public class PlayerActivity extends SherlockActivity implements
MediaPlayerControl {
static final int LAYOUT_MODE_FULL = 0;
......@@ -64,12 +74,13 @@ public class PlayerActivity extends SherlockActivity implements
final File tttFile = new File(filePath + "/" + fileName + ".ttt");
File audioFile = new File(filePath + "/" + fileName + ".mp3");
// audioPlayer for controlling mp3-file
audioPlayer = MediaPlayer.create(this, Uri.fromFile(audioFile));
// creates a MediaController without fastforward and rewind buttons
audioController = new MediaController(this, false);
audioController.setMediaPlayer(this);
// show dialog parse ttt-File
final ProgressDialog dialog = new ProgressDialog(PlayerActivity.this);
dialog.setTitle("Please Wait");
dialog.setMessage("Prepare File ...");
......@@ -77,6 +88,11 @@ public class PlayerActivity extends SherlockActivity implements
dialog.setCancelable(false);
dialog.setCanceledOnTouchOutside(false);
/**
* asynchronous task for creating the recording object. prevents ui from
* being stucked, while reading messages and creating thumbnails
*/
AsyncTask<Void, Void, Void> initTask = new AsyncTask<Void, Void, Void>() {
@Override
......@@ -96,6 +112,11 @@ public class PlayerActivity extends SherlockActivity implements
" bits/pixel "
+ recording.getProtocolPreferences().bitsPerPixel);
/*
* create listeners for prev/next buttons of mediaController
* task are delegated to recordind object
*/
OnClickListener prevListener = new OnClickListener() {
@Override
......@@ -112,6 +133,7 @@ public class PlayerActivity extends SherlockActivity implements
}
};
// set the listeners
audioController.setPrevNextListeners(nextListener,
prevListener);
......@@ -126,8 +148,9 @@ public class PlayerActivity extends SherlockActivity implements
@Override
protected void onPostExecute(Void result) {
// close dialog
dialog.dismiss();
// show control bar
audioController.show(5000);
}
......@@ -136,17 +159,52 @@ public class PlayerActivity extends SherlockActivity implements
}
@Override
protected void onPause() {
recording.pause();
super.onPause();
}
@Override
public void onBackPressed() {
super.onBackPressed();
recording.close();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (audioController != null)
audioController.show();
return true;
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.d("PlayerActivity", "onDestroy");
recording.stop();
recording = null;
audioPlayer.release();
}
/*******************************************************************************************************************
* Delegating Search *
******************************************************************************************************************/
// delegates search to index and updates the view
public void search(String word) {
if (recording.getIndex() != null)
recording.getIndex().search(word);
// update display if recording is not playing
// if (!recording.isPlaying())
// updates the image after searching
recording.graphicsContext().updateView(false);
}
/*******************************************************************************************************************
* Methods of MediaPlayerControl *
******************************************************************************************************************/
@Override
public boolean canPause() {
return true;
......@@ -212,30 +270,9 @@ public class PlayerActivity extends SherlockActivity implements
}
@Override
protected void onPause() {
recording.pause();
super.onPause();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (audioController != null)
audioController.show();
return false;
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.d("PlayerActivity", "onDestroy");
recording.stop();
recording = null;
audioPlayer.release();
}
/*******************************************************************************************************************
* configure Menu in Actionbar *
******************************************************************************************************************/
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getSupportMenuInflater();
......@@ -328,11 +365,4 @@ public class PlayerActivity extends SherlockActivity implements
}
@Override
public void onBackPressed() {
super.onBackPressed();
recording.close();
}
}
......@@ -2,29 +2,30 @@ package tttclient.core;
import java.util.ArrayList;
import tttclient.messages.Annotation;
import tttclient.messages.Message;
import tttclient.messages.MessageConsumer;
import tttclient.messages.MessageProducer;
import tttclient.messages.WhiteboardMessage;
import tttclient.messages.annotations.Annotation;
import tttclient.utils.BitmapContainer;
import android.annotation.SuppressLint;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.widget.ImageView;
@SuppressLint("NewApi")
/**
* paint the messages to the bitmap. Bitmap shown in imageview. Annotations and
* Whiteboard parts are adopted from TTT
*
*
* @author Thomas Krex
*
*/
public class GraphicsContext implements MessageConsumer {
private final Handler viewHandler;
private final BitmapContainer bitmapContainer;
private ImageView imgView;
......@@ -37,21 +38,6 @@ public class GraphicsContext implements MessageConsumer {
private final byte[] hextile_fg_encoded;
private final int[] pixels;
public static void fillRect(int[] array, Rect r, int color, int screenWidth) {
int x = r.left;
int y = r.top;
int w = r.width();
int h = r.height();
for (int i = y; i < y + h; i++) {
int offset = i * screenWidth + x;
for (int j = 0; j < w; j++) {
array[offset + j] = color;
}
}
}
public GraphicsContext(ImageView imgV, Recording record) {
setImageView(imgV);
this.producer = record;
......@@ -68,18 +54,6 @@ public class GraphicsContext implements MessageConsumer {
hextile_bg_encoded = new byte[prefs.bytesPerPixel];
hextile_fg_encoded = new byte[prefs.bytesPerPixel];
// Handler for Updating the ImageView
viewHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(android.os.Message inputMessage) {
// Gets the image task from the incoming Message object.
Bitmap bitmap = (Bitmap) inputMessage.obj;
imgView.setImageBitmap(bitmap);
}
};
}
public void enableRefresh(boolean refresh) {
......@@ -116,16 +90,25 @@ public class GraphicsContext implements MessageConsumer {
return hextile_fg_encoded;
}
/*
* There are two different modes for the painting, if the setBitmap=true,
* after the painting, the bitmap is assigned to the imageview this has to
* be made when the layout and so the imageview is changing if
* setBitmap=false, imgView only get invalidated
/**
* Painting of the bitmap is done here. After getting Bitmap from Bitmap
* containing, canvas is created on this bitmap annotations and
* highlightSearchResults are painted on this canvas
*
* @param setBitmap
* determines if bitmap has to be assign to imageView or not. It
* has assign if the layout changed and a new imageView was
* assigned to the graphicsContext. Otherwise the imageView just
* has to be invalidate
*
*
*/
public void updateView(boolean setBitmap) {
if (refreshEnabled) {
// get Bitmap without Annotations or highlighted search results
final Bitmap bitmap = bitmapContainer.getBitmap();
// define canvas, which draws in the bitmap
Canvas canvas = new Canvas(bitmap);
if (isWhiteboardEnabled())
......@@ -137,16 +120,26 @@ public class GraphicsContext implements MessageConsumer {
@Override
public void run() {
// assign bitmap to imageview in UI-Thread
imgView.setImageBitmap(bitmap);
}
});
else
// invalidate ImageView in UI-Thread
imgView.postInvalidate();
}
}
/**
* decoding Color from received colorfield of Hextile Message Copy from the
* TTTAndroidRecorder-App
*
* @param colorField
* colorField from Hextile Message
* @return int-value of decoded ARGB-color
*/
public int decodeColor(byte[] colorField) {
int color = (colorField[1] & 0xFF) << 8 | (colorField[0] & 0xFF);
......@@ -165,7 +158,9 @@ public class GraphicsContext implements MessageConsumer {
}
// used by hextile message
/**
* setter of background an foreground colors of hextile messages
*/
public void setForeground(byte[] color, int offset) {
System.arraycopy(color, offset, hextile_fg_encoded, 0,
prefs.bytesPerPixel);
......@@ -176,16 +171,30 @@ public class GraphicsContext implements MessageConsumer {
prefs.bytesPerPixel);
}
// paint message
/**
* updateView if messages is an Annotation
*/
@Override
public void handleMessage(Message message) {
message.paint(this);
// TODO hier zeichnen oder wo anders???
if (message instanceof Annotation)
updateView(false);
}
/**
* handle updated pixel of framebuffer params not needed, but maybe in
* future. params describe a rectangle of the update area.
*
* @param x
* x-coordinate of upper left corner
* @param y
* y-cordinate of upper left corner
* @param w
* width of rectangle
* @param h
* height of rectangle
*/
public void handleUpdatedPixels(int x, int y, int w, int h) {
// if recording is adjusting, messages are not painted one by one but
......@@ -196,33 +205,9 @@ public class GraphicsContext implements MessageConsumer {
}
}
public int getEncodedColor(byte[] colorField) {
int color = 0;
for (int i = 0, shift = 0; i < prefs.bytesPerPixel; i++, shift += 8) {
color += (colorField[i] & 0xFF) << shift;
}
switch (prefs.bitsPerPixel) {
case 16:
if (prefs.bigEndian)
// 16 bit big endian: swap bytes
color = (color & 0xFF) << 8 | ((color & 0xFF00) >> 8);
case 8:
break;
default:
// use default color
if (prefs.bigEndian) {
// 24 bit big endian: swap bytes
color = (color & 0xFF) << 24 | (color >> 8 & 0xFF) << 16
| (color >> 16 & 0xFF) << 8 | color >> 24 & 0xFF;
}
}
return color;
}
// // ////////////////////////////////////////////////////////////////
// // Annotations
// // ////////////////////////////////////////////////////////////////
/*******************************************************************************************************************
* Annotations *
******************************************************************************************************************/
private final ArrayList<Annotation> currentAnnotations = new ArrayList<Annotation>();
......@@ -266,6 +251,12 @@ public class GraphicsContext implements MessageConsumer {
}
/**
* creates bitmap from the pixel area, fills out the bitmap with white color
* if whiteboard has to be shown
*
* @return
*/
public Bitmap createScreenshotWithoutAnnotations() {
// create new mutable bitmap
......@@ -287,9 +278,9 @@ public class GraphicsContext implements MessageConsumer {
}
// ////////////////////////////////////////////////////////////////
// Whiteboard
// ////////////////////////////////////////////////////////////////
/*******************************************************************************************************************
* WhiteBoard *
******************************************************************************************************************/
// whiteboard (blank page for annotations)
protected int whiteboardPage;
......
......@@ -28,16 +28,15 @@ import java.io.DataInputStream;
import java.io.IOException;
import java.util.ArrayList;
import tttclient.messages.Annotation;
import tttclient.messages.DeleteAllAnnotation;
import tttclient.messages.FramebufferUpdateMessage;
import tttclient.messages.Message;
import tttclient.messages.WhiteboardMessage;
import tttclient.messages.annotations.Annotation;
import tttclient.messages.annotations.DeleteAllAnnotation;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Rect;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
......@@ -48,6 +47,15 @@ import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.TextView;
/**
* class for handling index of the recording,consist of all index entries.
* handles updating the running index, initialize scrollview and handles the
* focusing of the current indexEntry. Adopted parts from TTT will be marked
* with (TTT)
*
* @author Thomas Krex
*
*/
public class Index {
final public static int NO_SEARCHBASE = 0;
......@@ -126,7 +134,9 @@ public class Index {
}
// create index
/**
* computing index if not available in extensions(TTT)
*/
void computeIndex_regarding_length_of_sequence() {
// build slide index
// containing all message which area covers minSlideArea and a time
......@@ -243,6 +253,11 @@ public class Index {
// file I/O
// //////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Methods for extracting index information out of the ttt-File (TTT)
*
*/
// read from extension
public void readIndexExtension(DataInputStream in) throws IOException {
// remove current index
......@@ -286,8 +301,6 @@ public class Index {
index.add(new IndexEntry(context, this));
}
// TODO bufferedImage in Bitmap transformieren
// read one image representing thumbnail
private void readThumbnail(DataInputStream in) throws IOException {
int image_size = in.readInt();
if (image_size == 0) {
......@@ -306,14 +319,15 @@ public class Index {
}
// //////////////////////////////////////////////
// Annotations
// Annotations (TTT)
// //////////////////////////////////////////////
// displaying annotations on thumbnails
static final public int PAINT_ALL_ANNOTATIONS = 0;
static final public int PAINT_NO_ANNOTATIONS = 1;
static final public int PAINT_NO_HIGHLIGHT_ANNOTATIONS = 2;
int annotationsPaintMode = PAINT_ALL_ANNOTATIONS;
// disabled because not working yet
int annotationsPaintMode = PAINT_NO_ANNOTATIONS;
public int getAnnotationsPaintMode() {
return annotationsPaintMode;
......@@ -323,8 +337,9 @@ public class Index {
this.annotationsPaintMode = annotationsPaintMode;
}
// gather annotations for each index entry
// useful for annotated thumbnails and script
/**
* Method for extract Annotations(TTT)
*/
public void extractAnnotations() {
// Buffer for annotations
ArrayList<Annotation> annotations = new ArrayList<Annotation>();
......@@ -409,11 +424,9 @@ public class Index {
// //////////////////////////////////////////////////////////////////
/**
* Actually computes the Screenshots
* Create Thumnails for each index entry, time is set, and the bitmap
* created in graphicsContext
*
* @param mode
* @param batch
* @param ShowProgressMonitor
* @return
* @throws IOException
*/
......@@ -446,135 +459,13 @@ public class Index {
return isCanceled == false;
}
// //////////////////////////////////////////////////////////////////
// keyframes
// //////////////////////////////////////////////////////////////////
static final int PAINT_TO_OFFSCREEN_IMAGE = 0;
static final int RAW_IN_ARRAY = 2;
static final int RAW_IN_OFFSCREEN_IMAGE = 3;
static final int COLLECT_MESSAGES = 4;
public void computeKeyframes(int mode) {
// disable painting, because it's slow
recording.graphicsContext().enableRefresh(false);
// recording.graphicsContext().paint_to_offscreen_image = mode ==
// PAINT_TO_OFFSCREEN_IMAGE;
long t = System.currentTimeMillis();
if (mode == COLLECT_MESSAGES)
collectMessagesForKeyframes2();
else {
int nextIndex = 0;
for (int i = 0; i < recording.getMessages().size(); i++) {
Message message = recording.getMessages().get(i);
// if(i%1000==0) System.out.print(".");
if (message.getTimestamp() > index.get(nextIndex)
.getTimestamp()) {
switch (mode) {
case RAW_IN_OFFSCREEN_IMAGE:
recording
.graphicsContext()
.handleUpdatedPixels(
0,
0,
recording.getProtocolPreferences().framebufferWidth,
recording.getProtocolPreferences().framebufferHeight);
case PAINT_TO_OFFSCREEN_IMAGE:
// index.get(nextIndex).setKeyframe(
// recording.graphicsContext().getScreenshotOld());
break;
case RAW_IN_ARRAY:
int[] pixels = new int[recording.graphicsContext()
.getPixels().length];
System.arraycopy(recording.graphicsContext()
.getPixels(), 0, pixels, 0, pixels.length);
// index.get(nextIndex).setKeyframe(pixels);
break;
default:
break;
}
// System.out.println("write " + nextIndex);
// ImageCreator.writeImage(index.get(nextIndex-1).getKeyframe(),"/netzlaufwerk/frame"+nextIndex);
nextIndex++;
if (nextIndex == index.size())
break;
}
// recording.deliverMessage(message);
message.paint(recording.graphicsContext());
}
}
t = System.currentTimeMillis() - t;
// recording.graphicsContext().paint_to_offscreen_image = true;
recording.graphicsContext().enableRefresh(true);
}
private void collectMessagesForKeyframes2() {
boolean[][] set = new boolean[recording.getProtocolPreferences().framebufferWidth][recording
.getProtocolPreferences().framebufferHeight];
int setCount = 0;
int full = recording.getProtocolPreferences().framebufferWidth
* recording.getProtocolPreferences().framebufferHeight;
ArrayList<Message> collected = new ArrayList<Message>();
// TODO: what if index is empty??
int previousIndexNumber = index.size() - 1;
int previousIndexTime = index.get(previousIndexNumber--).getTimestamp();
int count = 0;
for (int i = recording.getMessages().size() - 1; i >= 0; i--) {
Message message = recording.getMessages().get(i);
count++;
if (message instanceof FramebufferUpdateMessage) {
if (previousIndexTime > message.getTimestamp()) {