Commit be157c0e by Thomas Krex

haptisches feedback bei longclick

bei löschen eines feeds werden alle feeditems+folder gelöscht
parent 18f4ba66
......@@ -9,6 +9,8 @@
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" >
</uses-permission>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.VIBRATE" >
</uses-permission>
<uses-sdk
android:minSdkVersion="9"
......
......@@ -9,6 +9,8 @@
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" >
</uses-permission>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.VIBRATE" >
</uses-permission>
<uses-sdk
android:minSdkVersion="9"
......
......@@ -18,6 +18,7 @@
android:id="@+id/playerView_fullscreen"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/black"
android:scaleType="centerInside" />
</LinearLayout>
......
......@@ -9,13 +9,14 @@
android:layout_height="wrap_content"
android:layout_weight="4"
android:gravity="center_vertical"
android:textAppearance="?android:attr/textAppearanceMedium" />
android:textAppearance="?android:attr/textAppearanceLarge" />
<ImageView
android:id="@+id/statusIcon"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:src="?android:attr/textCheckMark" />
android:src="@drawable/ic_action_download" >
</ImageView>
</LinearLayout>
\ No newline at end of file
......@@ -8,7 +8,7 @@
android:title="Search"/>
<item
android:id="@+id/extend"
android:icon="@android:drawable/ic_input_add"
android:icon="@drawable/ic_action_return_from_full_screen"
android:showAsAction="always">
</item>
......
......@@ -10,5 +10,11 @@
<string name="port">Port</string>
<string name="prompt_title">Connect to a Lecture</string>
<string name="multicast">Enabling Multicast</string>
<string name="confirm_download">Do you want to download this Lecture?\nThis could take some time and can\'t be canceled</string>
<string name="yes">Yes</string>
<string name="cancel">Cancel</string>
<string name="inet_needed">Internet Connection needed</string>
<string name="not_found">File was not found</string>
<string name="deleted">File was deleted</string>
</resources>
\ No newline at end of file
......@@ -2,6 +2,7 @@ package tttclient.activities;
import tttclient.models.Feed;
import tttclient.models.FeedDbManager;
import tttclient.models.FeedItemDbManager;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
......@@ -9,6 +10,7 @@ import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.os.Bundle;
import android.os.Vibrator;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
......@@ -29,13 +31,14 @@ public class FeedActivity extends Activity implements OnItemClickListener,
private SimpleCursorAdapter adapter;
private String feedUrl;
private String feedName;
private String feedId;
private int feedId;
private Vibrator myVib;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.feed_activity);
myVib = (Vibrator) this.getSystemService(VIBRATOR_SERVICE);
ListView feedList = (ListView) findViewById(R.id.feed_list);
FeedDbManager fManager = new FeedDbManager(this);
......@@ -43,11 +46,12 @@ public class FeedActivity extends Activity implements OnItemClickListener,
adapter = new SimpleCursorAdapter(this,
android.R.layout.simple_list_item_2, cursor,
new String[] { FeedDbManager.COLUMN_NAME,
FeedDbManager.COLUMN_FEEDURL },
new int[] { android.R.id.text1 });
FeedDbManager.COLUMN_FEEDURL }, new int[] {
android.R.id.text1, android.R.id.text2 });
feedList.setAdapter(adapter);
feedList.setOnItemClickListener(this);
feedList.setOnItemLongClickListener(this);
}
......@@ -109,9 +113,10 @@ public class FeedActivity extends Activity implements OnItemClickListener,
// click on feed in list
if (position != -1) {
Cursor c = (Cursor) av.getAdapter().getItem(position);
feedUrl = c.getString(c.getColumnIndex("feedUrl"));
feedName = c.getString(c.getColumnIndex("name"));
feedId = c.getString(c.getColumnIndex("_id"));
feedUrl = c.getString(c
.getColumnIndex(FeedDbManager.COLUMN_FEEDURL));
feedName = c.getString(c.getColumnIndex(FeedDbManager.COLUMN_NAME));
feedId = c.getInt(c.getColumnIndex("_id"));
}
Intent intent = new Intent(this, FeedDetailActivity.class);
......@@ -127,6 +132,7 @@ public class FeedActivity extends Activity implements OnItemClickListener,
if (id == -1) {
return false;
}
myVib.vibrate(50);
// confirm delete
DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
......@@ -136,19 +142,21 @@ public class FeedActivity extends Activity implements OnItemClickListener,
// delete feed from list, refresh feed list
Cursor c = (Cursor) av.getAdapter().getItem(position);
int _id = c.getInt(c.getColumnIndex(FeedDbManager.COLUMN_ID));
feedId = c.getInt(c.getColumnIndex("_id"));
FeedDbManager fm = new FeedDbManager(av.getContext());
fm.deleteFromDb(_id);
FeedItemDbManager fim = new FeedItemDbManager(av.getContext());
// delete all childs and their folders
fim.deleteFromDb(feedId);
fm.deleteFromDb(feedId);
adapter.changeCursor(fm.getAllFromDB());
}
};
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("Do you want to delete this feed?");
builder.setMessage("Do you want to delete this feed? All Lectures saved on this devices will be deleted");
builder.setPositiveButton("delete", listener);
builder.setNegativeButton("cancel", null);
builder.show();
return false;
return true;
}
}
......@@ -116,7 +116,7 @@ public class PlayerActivity extends Activity implements MediaPlayerControl {
protected void onPostExecute(Void result) {
dialog.dismiss();
audioController.show();
audioController.show(5000);
}
};
......@@ -130,7 +130,7 @@ public class PlayerActivity extends Activity implements MediaPlayerControl {
// update display if recording is not playing
// if (!recording.isPlaying())
recording.graphicsContext().updateCanvas();
recording.graphicsContext().updateView();
}
......@@ -254,13 +254,13 @@ public class PlayerActivity extends Activity implements MediaPlayerControl {
switchLayout(1);
// switchSurface(1);
item.setIcon(getResources().getDrawable(
android.R.drawable.ic_input_delete));
R.drawable.ic_action_full_screen));
isExtendend = true;
} else if (isExtendend) {
switchLayout(0);
// switchSurface(0);
item.setIcon(getResources().getDrawable(
android.R.drawable.ic_input_add));
R.drawable.ic_action_return_from_full_screen));
isExtendend = false;
}
......@@ -286,7 +286,8 @@ public class PlayerActivity extends Activity implements MediaPlayerControl {
if (index == 1) {
imgV = (ImageView) findViewById(R.id.playerView_extended);
recording.graphicsContext().setImageView(imgV);
recording.graphicsContext().refresh();
recording.graphicsContext().updateView();
switcher.setDisplayedChild(1);
}
......
......@@ -78,48 +78,6 @@ public abstract class Message {
// /////////////////////////////////////////////////
abstract public void paint(GraphicsContext graphicsContext);
// /////////////////////////////////////////////////
// write message
// /////////////////////////////////////////////////
static final public int NO_TIMESTAMP = -1;
static final public int TIMESTAMP_OF_MESSAGE = -2;
// write message to TTT output stream
// abstract public void write(DataOutputStream out, int writeTimestamp)
// throws IOException;
//
// // helper method to write message header, because it's the same for all
// // messages
// final void writeHeader(DataOutputStream out, int writeTimestamp)
// throws IOException {
// switch (writeTimestamp) {
// case NO_TIMESTAMP:
// // size of message
// out.writeInt(getSize());
// // encoding without timestamp
// out.writeByte(getEncoding());
// break;
//
// case TIMESTAMP_OF_MESSAGE:
// // size of message
// out.writeInt(getSize() + 4);
// // encoding and timestamp
// out.writeByte(getEncoding() | Constants.EncodingFlagTimestamp);
// out.writeInt(getTimestamp());
// break;
//
// default:
// // size of message
// out.writeInt(getSize() + 4);
// // encoding and timestamp
// out.writeByte(getEncoding() | Constants.EncodingFlagTimestamp);
// out.writeInt(writeTimestamp);
//
// break;
// }
// }
// return size of message in bytes (if written to stream)
abstract public int getSize();
......
......@@ -51,6 +51,7 @@ public class WhiteboardMessage extends FramebufferUpdateMessage {
@Override
public void paint(GraphicsContext graphicsContext) {
graphicsContext.setWhiteboardPage(pageNumber);
}
public boolean isWhiteboardEnabled() {
......@@ -70,14 +71,4 @@ public class WhiteboardMessage extends FramebufferUpdateMessage {
+ " at (" + x + "," + y + ")";
}
/*******************************************************************************************************************
* write message
******************************************************************************************************************/
// return size of message in bytes (if written to stream)
@Override
public int getSize() {
return 2;
}
}
......@@ -52,7 +52,7 @@ public class DeleteAnnotation extends Annotation {
@Override
public void paint(GraphicsContext graphicsContext) {
graphicsContext.removeAnnotationsAt(x, y);
graphicsContext.refresh();
graphicsContext.updateView();
}
@Override
......
package tttclient.models;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import org.apache.commons.io.FileUtils;
import tttclient.utils.DBManager;
import android.content.Context;
import android.database.Cursor;
......@@ -34,7 +38,7 @@ public class FeedItemDbManager {
db.execSQL(TABLE_CREATE);
}
public Cursor getAllFromDB() {
public Cursor getAllFromDB(int feedid) {
// Log.d("SQL", "SELECT " + COLUMN_TITLE + ", " + COLUMN_ID +
// " as _id , "
......@@ -43,8 +47,8 @@ public class FeedItemDbManager {
// + " FROM " + TABLE_FEEDITEMS + " ORDER BY " + COLUMN_PUBDATE);
return db
.rawQuery(
"SELECT title, id as _id , feedId, link, description, pubDate, path, status FROM feedItems ORDER BY pubDate",
null);
"SELECT title, id as _id , feedId, link, description, pubDate, path, status FROM feedItems WHERE feedId = ? ORDER BY title DESC",
new String[] { String.valueOf(feedid) });
}
......@@ -81,7 +85,7 @@ public class FeedItemDbManager {
}
public void insertintoDB(ArrayList<FeedItem> itemList, String feedId)
public void insertintoDB(ArrayList<FeedItem> itemList, int feedId)
throws Exception {
for (FeedItem item : itemList) {
......@@ -94,13 +98,15 @@ public class FeedItemDbManager {
// if
// so
if (!c.moveToNext()) {
db.execSQL("INSERT INTO " + TABLE_FEEDITEMS + " ("
+ COLUMN_TITLE + ", " + COLUMN_FEEDID + ", "
+ COLUMN_LINK + ", " + COLUMN_DESCRIPTION + ", "
+ COLUMN_PUBDATE + ", " + COLUMN_STATUS
+ ") VALUES ( ? , ? , ? , ? , ?," + 0 + " )",
new String[] { item.getTitle(), feedId, item.getLink(),
item.getDescription(), item.getPupDate() });
db.execSQL(
"INSERT INTO " + TABLE_FEEDITEMS + " (" + COLUMN_TITLE
+ ", " + COLUMN_FEEDID + ", " + COLUMN_LINK
+ ", " + COLUMN_DESCRIPTION + ", "
+ COLUMN_PUBDATE + ", " + COLUMN_STATUS
+ ") VALUES ( ? , ? , ? , ? , ?," + 0 + " )",
new String[] { item.getTitle(), String.valueOf(feedId),
item.getLink(), item.getDescription(),
item.getPupDate() });
}
......@@ -117,6 +123,26 @@ public class FeedItemDbManager {
}
public void deleteFromDb(int feedId) {
// delete all folders belonging to a certain lecture
Cursor cursor = db.rawQuery(
"Select path from feedItems WHERE feedid = ?",
new String[] { String.valueOf(feedId) });
while (cursor.moveToNext()) {
String path = cursor.getString(cursor.getColumnIndex(COLUMN_PATH));
if (path != null) {
File dir = new File(path);
if (dir.exists())
try {
FileUtils.deleteDirectory(dir);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
// delete the entries from the feedItems table
db.execSQL("DELETE FROM feedItems WHERE feedId = ?",
new String[] { String.valueOf(feedId) });
}
......
/**
*
* @author Thomas Krex
*
* All Lectures are stored in the /mnt/sdcard/ttt directory Every
* lecture got it's onw folder, named after it The folder contains the
* .ttt and .mp3 The zip file is stored at the same spot, but will be
* deleted after unzipping
*
*/
package tttclient.services;
import java.io.File;
......@@ -9,18 +19,14 @@ import java.net.HttpURLConnection;
import java.net.URL;
import tttclient.utils.UnzipManager;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.IntentService;
import android.app.ProgressDialog;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.os.ResultReceiver;
import android.util.Log;
import android.widget.Toast;
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public class DownloadService extends IntentService {
public DownloadService() {
......@@ -30,6 +36,7 @@ public class DownloadService extends IntentService {
public static final String BROADCAST_NAME = "com.example.services.downloadService";
private int result = Activity.RESULT_CANCELED;
public static int PROGRESS_UPDATE = 1234;
public static int UNZIPPING = 666;
public static String PROGRESS_RECEIVER = "progress_update";
public static String FILE_URL = "url";
public static String FILE_NAME = "name";
......@@ -107,7 +114,6 @@ public class DownloadService extends IntentService {
}
output.write(data, 0, count);
// Log.d("DownloadService", total + " bytes downloaded");
}
......@@ -115,16 +121,23 @@ public class DownloadService extends IntentService {
+ ".zip");
if (zipFile.exists()) {
result = Activity.RESULT_OK;
Log.d("DownloadService", " sucessful");
Toast.makeText(getApplicationContext(), "unzipping file ...",
Toast.LENGTH_LONG);
// show unzipping message in Dialog
Bundle unzipProgress = new Bundle();
unzipProgress.putBoolean("progress", true);
receiver.send(UNZIPPING, unzipProgress);
UnzipManager unzip = new UnzipManager(
zipFile.getAbsolutePath(), lectureDir.getAbsolutePath());
unzip.unzip();
unzipProgress = new Bundle();
// dismiss dialog
unzipProgress.putBoolean("progress", false);
receiver.send(UNZIPPING, unzipProgress);
zipFile.delete();
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
try {
......
......@@ -15,6 +15,7 @@ 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.media.Image;
import android.os.Handler;
......@@ -72,15 +73,12 @@ public class GraphicsContext implements MessageConsumer {
this.bitmapContainer = new BitmapContainer(Bitmap.createBitmap(
prefs.framebufferWidth, prefs.framebufferHeight,
Config.ARGB_8888));
Config.ARGB_4444));
// canvas to Bitmap
this.canvas = new Canvas(bitmapContainer.getBimap());
this.pixels = bitmapContainer.getPixels();
Log.d("Bitmap", "size: " + bitmapContainer.getBimap().getHeight()
+ bitmapContainer.getBimap().getWidth());
hextile_bg_encoded = new byte[prefs.bytesPerPixel];
hextile_fg_encoded = new byte[prefs.bytesPerPixel];
......@@ -93,7 +91,9 @@ public class GraphicsContext implements MessageConsumer {
// Gets the image task from the incoming Message object.
Bitmap bitmap = (Bitmap) inputMessage.obj;
paintAnnotations(canvas);
if (isWhiteboardEnabled())
paintWhiteboard();
paintAnnotations();
recording.highlightSearchResults(canvas);
imgView.setImageBitmap(bitmap);
......@@ -201,7 +201,7 @@ public class GraphicsContext implements MessageConsumer {
// TODO welche Methoden werden wann benötigt
// draw Canvas on current Bitmap
public void updateCanvas() {
public void updateView() {
if (refreshEnabled) {
android.os.Message message = viewHandler.obtainMessage(0,
bitmapContainer.getBimap());
......@@ -217,14 +217,6 @@ public class GraphicsContext implements MessageConsumer {
}
}
public void refresh() {
bitmapContainer.getBimap().setPixels(pixels, 0, prefs.framebufferWidth,
0, 0, prefs.framebufferWidth, prefs.framebufferHeight);
updateView(bitmapContainer.getBimap());
}
public int decodeColor(byte[] colorField) {
int color = (colorField[1] & 0xFF) << 8 | (colorField[0] & 0xFF);
......@@ -259,7 +251,8 @@ public class GraphicsContext implements MessageConsumer {
message.paint(this);
// TODO hier zeichnen oder wo anders???
if (message instanceof Annotation)
updateCanvas();
updateView();
}
public void handleUpdatedPixels(int[] pixel) {
......@@ -269,7 +262,7 @@ public class GraphicsContext implements MessageConsumer {
}
public void handleUpdatedPixels(int x, int y, int w, int h) {
// TODO
// if recording is adjusting, messages are not painted one by one but
// only the final image
if (!recording.adjusting) {
......@@ -277,10 +270,6 @@ public class GraphicsContext implements MessageConsumer {
x + y * prefs.framebufferWidth, prefs.framebufferWidth, x,
y, w, h);
// bitmapContainer.getBimap().setPixels(pixels, 0,
// prefs.framebufferWidth, 0, 0, prefs.framebufferWidth,
// prefs.framebufferHeight);
updateView(bitmapContainer.getBimap());
}
}
......@@ -347,7 +336,7 @@ public class GraphicsContext implements MessageConsumer {
}
// display all annotations
synchronized public void paintAnnotations(Canvas canvas) {
synchronized public void paintAnnotations() {
for (int i = 0; i < currentAnnotations.size(); i++) {
currentAnnotations.get(i).paint(canvas);
......@@ -358,28 +347,35 @@ public class GraphicsContext implements MessageConsumer {
public Bitmap getScreenshotWithoutAnnotations() {
Bitmap screenshot;
screenshot = Bitmap.createBitmap(pixels, prefs.framebufferWidth,
prefs.framebufferHeight, Config.ARGB_8888);
Bitmap scaledScreenshot = Bitmap.createScaledBitmap(screenshot,
prefs.framebufferWidth / 3, prefs.framebufferHeight / 3, true);
screenshot.recycle();
// show blank page if whiteboard activated
if (isWhiteboardEnabled()) {
int[] whitePixels = new int[prefs.framebufferWidth / 3
* prefs.framebufferWidth / 3];
int[] whitePixels = new int[(int) (prefs.framebufferWidth * Index.THUMBNAIL_SCALE_FACTOR)
* (int) (prefs.framebufferWidth * Index.THUMBNAIL_SCALE_FACTOR)];
for (int i = 0; i < whitePixels.length; i++) {
whitePixels[i] = Color.WHITE;
}
Bitmap whiteboard = Bitmap.createBitmap(whitePixels,
prefs.framebufferWidth / 3, prefs.framebufferHeight / 3,
Config.ARGB_8888);
Bitmap whiteboard = Bitmap
.createBitmap(
whitePixels,
(int) (prefs.framebufferWidth * Index.THUMBNAIL_SCALE_FACTOR),
(int) (prefs.framebufferHeight * Index.THUMBNAIL_SCALE_FACTOR),
Config.ARGB_4444);
return whiteboard;
} else {
screenshot = Bitmap.createBitmap(pixels, prefs.framebufferWidth,
prefs.framebufferHeight, Config.ARGB_4444);
Bitmap scaledScreenshot = Bitmap
.createScaledBitmap(
screenshot,
(int) (prefs.framebufferWidth * Index.THUMBNAIL_SCALE_FACTOR),
(int) (prefs.framebufferHeight * Index.THUMBNAIL_SCALE_FACTOR),
true);
screenshot.recycle();
return scaledScreenshot;
}
return scaledScreenshot;
}
// ////////////////////////////////////////////////////////////////
......@@ -397,7 +393,7 @@ public class GraphicsContext implements MessageConsumer {
public void setWhiteboardPage(int whiteboardPage) {
this.whiteboardPage = whiteboardPage;
clearAnnotations();
refresh();
updateView();
}
// updates for late comers and recorders
......@@ -405,6 +401,23 @@ public class GraphicsContext implements MessageConsumer {
return new WhiteboardMessage(0, whiteboardPage, prefs);
}
public void paintWhiteboard() {
int[] whitePixel = new int[prefs.framebufferHeight
* prefs.framebufferWidth];
for (int i = 0; i < whitePixel.length; i++) {
whitePixel[i] = Color.WHITE;
}
bitmapContainer.getBimap().setPixels(whitePixel, 0,
prefs.framebufferWidth, 0, 0, prefs.framebufferWidth,
prefs.framebufferHeight);
canvas.drawText("#" + whiteboardPage, prefs.framebufferWidth - 30, 20,
new Paint(Color.BLACK));
}
// ////////////////////////////////////////////////////////////////
// Cursor
// ////////////////////////////////////////////////////////////////
......@@ -433,7 +446,7 @@ public class GraphicsContext implements MessageConsumer {
// refresh(old_cursorX - hotX, old_cursorY - hotY, cursorWidth,
// cursorHeight);
// refresh(x - hotX, y - hotY, cursorWidth, cursorHeight);
refresh();
updateView();
} else {
// just set new position
cursorX = x;
......@@ -452,7 +465,7 @@ public class GraphicsContext implements MessageConsumer {
// refresh(cursorX - hotX, cursorY - hotY, cursorWidth,
// cursorHeight);
refresh();
updateView();
}
}
......@@ -463,7 +476,8 @@ public class GraphicsContext implements MessageConsumer {
showSoftCursor = true;
// refresh(cursorX - hotX, cursorY - hotY, cursorWidth,
// cursorHeight);
refresh();
updateView();
;
}
} else {
......@@ -472,7 +486,7 @@ public class GraphicsContext implements MessageConsumer {
showSoftCursor = false;
// refresh(cursorX - hotX, cursorY - hotY, cursorWidth,
// cursorHeight);
refresh();
updateView();
}
}
}
......
......@@ -459,13 +459,6 @@ public class Index {
// create screenshot
Bitmap screenshot = recording.graphicsContext()
.getScreenshotWithoutAnnotations();
// int scaledWidth = (int) (screenshot.getWidth() *
// THUMBNAIL_SCALE_FACTOR);
// int scaledHeight = (int) (screenshot.getHeight() *
// THUMBNAIL_SCALE_FACTOR);
// Bitmap scaled = Bitmap.createScaledBitmap(screenshot,
// scaledWidth,
// scaledHeight, true);
indexEntry.setThumbnail(screenshot);
......
......@@ -13,6 +13,7 @@ import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.os.Build;
import android.view.View;
import android.widget.ImageButton;
......@@ -222,20 +223,17 @@ public class IndexEntry extends ImageButton {
p.setStyle(Paint.Style.STROKE);
// scale shape for thumbnails
// RectF scaledRect = new RectF(
// (float) (shape.rectangle.left *
// Index.THUMBNAIL_SCALE_FACTOR),
// (float) (shape.rectangle.top * Index.THUMBNAIL_SCALE_FACTOR),
// (float) (shape.rectangle.right *
// Index.THUMBNAIL_SCALE_FACTOR),
// (float) (shape.rectangle.bottom *
// Index.THUMBNAIL_SCALE_FACTOR));
RectF scaledRect = new RectF(
(float) (shape.rectangle.left * Index.THUMBNAIL_SCALE_FACTOR),
(float) (shape.rectangle.top * Index.THUMBNAIL_SCALE_FACTOR),
(float) (shape.rectangle.right * Index.THUMBNAIL_SCALE_FACTOR),
(float) (shape.rectangle.bottom * Index.THUMBNAIL_SCALE_FACTOR));
// thumbail is inmutable --> create mutable one
Bitmap copy = thumbnail.copy(Config.ARGB_8888, true);
Canvas searchCanvas = new Canvas(copy);