package de.tu.darmstadt.seemoo.ansian.drawables; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import de.tu.darmstadt.seemoo.ansian.control.DataHandler; import de.tu.darmstadt.seemoo.ansian.control.StateHandler; import de.tu.darmstadt.seemoo.ansian.model.FFTDrawData; import de.tu.darmstadt.seemoo.ansian.model.FFTSample; import de.tu.darmstadt.seemoo.ansian.model.WaterfallColorMap; import de.tu.darmstadt.seemoo.ansian.model.preferences.ColorPreference; import de.tu.darmstadt.seemoo.ansian.model.preferences.GuiPreferences; import de.tu.darmstadt.seemoo.ansian.model.preferences.MiscPreferences; import de.tu.darmstadt.seemoo.ansian.model.preferences.Preferences; /** * Drawable which takes care of the waterfall drawing below the FFT spectrum * */ public class WaterfallDrawable extends MyDrawable { MiscPreferences preferences; GuiPreferences guiPreferences; Bitmap[] waterfallLines; private int waterfallLinesTopIndex; private int rowHeight = 1; private int yPos; private int width; private int height; private String LOGTAG = "WaterfallDrawable"; private long lastFrequecy = Preferences.GUI_PREFERENCE.getFrequency(); public WaterfallDrawable(int yPos, int width, int height) { preferences = Preferences.MISC_PREFERENCE; guiPreferences = Preferences.GUI_PREFERENCE; rowHeight = guiPreferences.getWaterfallRowHeight(); this.yPos = yPos; this.width = width; this.height = height; createWaterfallLineBitmaps(); } /** * Will initialize the waterfallLines array for the given width and height * of the waterfall plot. If the array is not null, it will be recycled * first. */ public void createWaterfallLineBitmaps() { // Recycle bitmaps if not null: if (waterfallLines != null) { for (Bitmap b : this.waterfallLines) b.recycle(); } // Create new array: waterfallLinesTopIndex = 0; waterfallLines = new Bitmap[height]; for (int i = 0; i < waterfallLines.length; i++) waterfallLines[i] = Bitmap.createBitmap(width, 1, Bitmap.Config.ARGB_8888); } public void setDimensions(int yPos, int width, int height) { // remove old waterfall bitmaps if display width changed if (this.width != width || this.height != height || this.yPos != yPos) { waterfallLines = null; this.yPos = yPos; this.width = width; this.height = height; createWaterfallLineBitmaps(); } } private boolean isChanged() { if (lastFrequecy != Preferences.GUI_PREFERENCE.getFrequency()) { lastFrequecy = Preferences.GUI_PREFERENCE.getFrequency(); return true; } else return false; } @Override public void draw(Canvas canvas) { if (Preferences.GUI_PREFERENCE.isWaterfallPaused() && StateHandler.isPaused()) { if (isChanged()) { FFTSample[] ffts = DataHandler.getInstance().getSamples(height - yPos); for (FFTSample fft : ffts) if (fft != null) drawNewWaterfallLine(fft.getDrawData(width)); } else drawOldWaterfallBitmaps(canvas); } else { drawOldWaterfallBitmaps(canvas); FFTDrawData fftDrawData; if (StateHandler.isScanning()) { fftDrawData = DataHandler.getInstance().getScannerDrawData(width); } else { fftDrawData = DataHandler.getInstance().getWaterfallDrawData(width); } drawNewWaterfallLine(fftDrawData); } } private void drawOldWaterfallBitmaps(Canvas canvas) { int tempYPos = yPos; // draw the bitmaps on the canvas: for (int i = 0; i < waterfallLines.length; i++) { int idx = (waterfallLinesTopIndex + i) % waterfallLines.length; canvas.drawBitmap(waterfallLines[idx], 0, tempYPos, ColorPreference.DEFAULT_PAINT); tempYPos += rowHeight; } } private void drawNewWaterfallLine(FFTDrawData fftDrawData) { int startX = 0; float[] magnitudes = null; if (fftDrawData != null) { startX = fftDrawData.getStart(); magnitudes = fftDrawData.getValues(); } if (magnitudes != null) { // Log.d(LOGTAG, "drawing waterfall. mag length: " + // magnitudes.length); Canvas newline = new Canvas(waterfallLines[waterfallLinesTopIndex]); newline.drawColor(Color.BLACK); // move the array index (note that we have to decrement in order to // do // it correctly) waterfallLinesTopIndex--; if (waterfallLinesTopIndex < 0) { waterfallLinesTopIndex += waterfallLines.length; } float minDB = Preferences.GUI_PREFERENCE.getCurMinDB(); float maxDB = Preferences.GUI_PREFERENCE.getCurMaxDB(); float dbDiff = maxDB - minDB; WaterfallColorMap colormap = Preferences.GUI_PREFERENCE.getWaterfallColorMap(); float scale = colormap.getLength() / dbDiff; int px = startX; for (int magPos = 0; magPos < magnitudes.length; magPos++) { // Waterfall: if (magnitudes[magPos] <= minDB) ColorPreference.WATERFALL_LINE_PAINT.setColor(colormap.getColor(0)); else if (magnitudes[magPos] >= maxDB) ColorPreference.WATERFALL_LINE_PAINT.setColor(colormap.getColor(colormap.getLength() - 1)); else ColorPreference.WATERFALL_LINE_PAINT .setColor(colormap.getColor((int) ((magnitudes[magPos] - minDB) * scale))); newline.drawPoint(px++, 0, ColorPreference.WATERFALL_LINE_PAINT); } } } }