diff options
author | Chris Craik <ccraik@google.com> | 2011-07-21 11:52:19 -0700 |
---|---|---|
committer | Chris Craik <ccraik@google.com> | 2011-07-21 14:22:55 -0700 |
commit | 21555abad7ba5f5377052e2644974d3ce8c37869 (patch) | |
tree | a19eedb1b8880e2f747f1adcc525c7fe03ff31f3 /tests/TileBenchmark/src/com/test/tilebenchmark | |
parent | d2ceb321ea38fb5df3a14746cf52c181f9679a45 (diff) | |
download | frameworks_base-21555abad7ba5f5377052e2644974d3ce8c37869.zip frameworks_base-21555abad7ba5f5377052e2644974d3ce8c37869.tar.gz frameworks_base-21555abad7ba5f5377052e2644974d3ce8c37869.tar.bz2 |
New log format, Manual log generation, plus logging of invalidates
bug:5062896
Added features to TileProfiler, updated jni interface to allow querying of
arbitrary log data via strings. Depends on the following webkit change:
https://android-git.corp.google.com/g/#change,122779
For new logging jni interface, and logging of invalidates.
Change-Id: I80ba6702b87e86ec76e5b0eafde45f4ef3a80ad3
Diffstat (limited to 'tests/TileBenchmark/src/com/test/tilebenchmark')
6 files changed, 270 insertions, 92 deletions
diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackActivity.java b/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackActivity.java index 5130f5d..36694a7 100644 --- a/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackActivity.java +++ b/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackActivity.java @@ -27,6 +27,7 @@ import android.widget.Button; import android.widget.SeekBar; import android.widget.SeekBar.OnSeekBarChangeListener; import android.widget.TextView; +import android.widget.Toast; import java.io.FileInputStream; import java.io.IOException; @@ -102,7 +103,10 @@ public class PlaybackActivity extends Activity { @Override protected void onPostExecute(TileData data[][]) { if (data == null) { - data = genTestPattern(); + Toast.makeText(getApplicationContext(), + getResources().getString(R.string.error_no_data), + Toast.LENGTH_LONG).show(); + return; } mPlaybackView.setData(data); @@ -166,23 +170,4 @@ public class PlaybackActivity extends Activity { new LoadFileTask().execute(ProfileActivity.TEMP_FILENAME); } - - private TileData[][] genTestPattern() { - final int XMAX = 5; - final int FRAMEMAX = 99; - - TileData example[][] = new TileData[FRAMEMAX][]; - for (int frame = 0; frame < FRAMEMAX; frame++) { - int numTiles = frame + 10; - - example[frame] = new TileData[numTiles]; - for (int t = 0; t < numTiles; t++) { - int x = t % XMAX; - int y = t / XMAX; - boolean isReady = y * 10 < frame; - example[frame][t] = new TileData(x, y, isReady, 0); - } - } - return example; - } } diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackGraphs.java b/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackGraphs.java index db4a341..35b1563 100644 --- a/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackGraphs.java +++ b/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackGraphs.java @@ -28,19 +28,17 @@ import java.util.ArrayList; import java.util.Arrays; public class PlaybackGraphs { - private static final int BAR_WIDTH = PlaybackView.TILEX * 3; + private static final int BAR_WIDTH = PlaybackView.TILE_SCALE * 3; private static final float CANVAS_SCALE = 0.2f; private static final double IDEAL_FRAMES = 60; private static final int LABELOFFSET = 100; private static Paint whiteLabels; - private static double viewportCoverage(int l, int b, int r, int t, - int tileIndexX, - int tileIndexY) { - if (tileIndexX * PlaybackView.TILEX < r - && (tileIndexX + 1) * PlaybackView.TILEX >= l - && tileIndexY * PlaybackView.TILEY < t - && (tileIndexY + 1) * PlaybackView.TILEY >= b) { + private static double viewportCoverage(TileData view, TileData tile) { + if (tile.left < view.right + && tile.right >= view.left + && tile.top < view.bottom + && tile.bottom >= view.top) { return 1.0f; } return 0.0f; @@ -76,13 +74,10 @@ public class PlaybackGraphs { // coverage graph @Override public double getValue(TileData[] frame) { - int l = frame[0].x, b = frame[0].y; - int r = frame[1].x, t = frame[1].y; double total = 0, totalCount = 0; - for (int tileID = 2; tileID < frame.length; tileID++) { + for (int tileID = 1; tileID < frame.length; tileID++) { TileData data = frame[tileID]; - double coverage = viewportCoverage(l, b, r, t, data.x, - data.y); + double coverage = viewportCoverage(frame[0], data); total += coverage * (data.isReady ? 1 : 0); totalCount += coverage; } @@ -158,7 +153,7 @@ public class PlaybackGraphs { public PlaybackGraphs() { whiteLabels = new Paint(); whiteLabels.setColor(Color.WHITE); - whiteLabels.setTextSize(PlaybackView.TILEY / 3); + whiteLabels.setTextSize(PlaybackView.TILE_SCALE / 3); } private ArrayList<ShapeDrawable> mShapes = new ArrayList<ShapeDrawable>(); @@ -177,11 +172,13 @@ public class PlaybackGraphs { int lastBar = 0; for (int frameIndex = 0; frameIndex < tileProfilingData.length; frameIndex++) { TileData frame[] = tileProfilingData[frameIndex]; - int newBar = (frame[0].y + frame[1].y) / 2; + int newBar = (frame[0].top + frame[0].bottom) / 2; MetricGen s = Metrics[metricIndex]; double absoluteValue = s.getValue(frame); double relativeValue = absoluteValue / s.getMax(); + relativeValue = Math.min(1,relativeValue); + relativeValue = Math.max(0,relativeValue); int rightPos = (int) (-BAR_WIDTH * metricIndex); int leftPos = (int) (-BAR_WIDTH * (metricIndex + relativeValue)); @@ -207,7 +204,7 @@ public class PlaybackGraphs { ArrayList<ShapeDrawable> shapes) { // Shapes drawn here are drawn relative to the viewRect Rect viewRect = shapes.get(shapes.size() - 1).getBounds(); - canvas.translate(0, 5 * PlaybackView.TILEY - viewRect.top); + canvas.translate(0, 5 * PlaybackView.TILE_SCALE - viewRect.top); for (ShapeDrawable shape : mShapes) { shape.draw(canvas); @@ -234,13 +231,15 @@ public class PlaybackGraphs { int yPos = LABELOFFSET; canvas.drawText(label, xPos, yPos, whiteLabels); for (int statIndex = 0; statIndex < Stats.length; statIndex++) { - label = resources.getString(R.string.format_stat, mStats[metricIndex][statIndex]); - yPos = LABELOFFSET + (1 + statIndex) * PlaybackView.TILEY / 2; + label = resources.getString(R.string.format_stat, + mStats[metricIndex][statIndex]); + yPos = LABELOFFSET + (1 + statIndex) * PlaybackView.TILE_SCALE + / 2; canvas.drawText(label, xPos, yPos, whiteLabels); } } for (int stringIndex = 0; stringIndex < strings.length; stringIndex++) { - int yPos = LABELOFFSET + stringIndex * PlaybackView.TILEY / 2; + int yPos = LABELOFFSET + stringIndex * PlaybackView.TILE_SCALE / 2; canvas.drawText(strings[stringIndex], 0, yPos, whiteLabels); } } diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackView.java b/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackView.java index f104eac..edc8643 100644 --- a/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackView.java +++ b/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackView.java @@ -16,6 +16,9 @@ package com.test.tilebenchmark; +import android.animation.ArgbEvaluator; +import android.animation.ObjectAnimator; +import android.animation.ValueAnimator; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; @@ -30,8 +33,9 @@ import android.view.View; import java.util.ArrayList; public class PlaybackView extends View { - public static final int TILEX = 300; - public static final int TILEY = 300; + public static final int TILE_SCALE = 300; + private static final int INVAL_FLAG = -2; + private static final int INVAL_CYCLE = 250; private Paint levelPaint = null, coordPaint = null, goldPaint = null; private PlaybackGraphs mGraphs; @@ -39,28 +43,46 @@ public class PlaybackView extends View { private ArrayList<ShapeDrawable> mTempShapes = new ArrayList<ShapeDrawable>(); private TileData mProfData[][] = null; private GestureDetector mGestureDetector = null; - private String mRenderStrings[] = new String[3]; + private String mRenderStrings[] = new String[4]; private class TileDrawable extends ShapeDrawable { TileData tile; + String label; - public TileDrawable(TileData t) { - int tileColorId = t.isReady ? R.color.ready_tile - : R.color.unready_tile; - getPaint().setColor(getResources().getColor(tileColorId)); - - setBounds(t.x * TILEX, t.y * TILEY, (t.x + 1) * TILEX, (t.y + 1) - * TILEY); + public TileDrawable(TileData t, int colorId) { this.tile = t; + getPaint().setColor(getResources().getColor(colorId)); + if (colorId == R.color.ready_tile + || colorId == R.color.unready_tile) { + + label = (int) (t.left / TILE_SCALE) + ", " + + (int) (t.top / TILE_SCALE); + // ignore scale value for tiles + setBounds(t.left, t.top, + t.right, t.bottom); + } else { + setBounds((int) (t.left * t.scale), + (int) (t.top * t.scale), + (int) (t.right * t.scale), + (int) (t.bottom * t.scale)); + } + } + + @SuppressWarnings("unused") + public void setColor(int color) { + getPaint().setColor(color); } @Override public void draw(Canvas canvas) { super.draw(canvas); - canvas.drawText(Integer.toString(tile.level), getBounds().left, - getBounds().bottom, levelPaint); - canvas.drawText(tile.x + "," + tile.y, getBounds().left, - ((getBounds().bottom + getBounds().top) / 2), coordPaint); + if (label != null) { + canvas.drawText(Integer.toString(tile.level), getBounds().left, + getBounds().bottom, levelPaint); + canvas.drawText(label, getBounds().left, + ((getBounds().bottom + getBounds().top) / 2), + coordPaint); + } } } @@ -92,10 +114,10 @@ public class PlaybackView extends View { private void init() { levelPaint = new Paint(); levelPaint.setColor(Color.WHITE); - levelPaint.setTextSize(TILEY / 2); + levelPaint.setTextSize(TILE_SCALE / 2); coordPaint = new Paint(); coordPaint.setColor(Color.BLACK); - coordPaint.setTextSize(TILEY / 3); + coordPaint.setTextSize(TILE_SCALE / 3); goldPaint = new Paint(); goldPaint.setColor(0xffa0e010); mGraphs = new PlaybackGraphs(); @@ -110,6 +132,7 @@ public class PlaybackView extends View { } mGraphs.draw(canvas, mTempShapes, mRenderStrings, getResources()); + invalidate(); // may have animations, force redraw } public int setFrame(int frame) { @@ -117,35 +140,66 @@ public class PlaybackView extends View { return 0; } - int readyTiles = 0, unreadyTiles = 0, unplacedTiles = 0; + int readyTiles = 0, unreadyTiles = 0, unplacedTiles = 0, numInvals = 0; mTempShapes.clear(); - // draw actual tiles - for (int tileID = 2; tileID < mProfData[frame].length; tileID++) { - TileData t = mProfData[frame][tileID]; - mTempShapes.add(new TileDrawable(t)); - if (t.isReady) { - readyTiles++; + // create tile shapes (as they're drawn on bottom) + for (TileData t : mProfData[frame]) { + if (t.level != INVAL_FLAG && t != mProfData[frame][0]) { + int colorId; + if (t.isReady) { + readyTiles++; + colorId = R.color.ready_tile; + } else { + unreadyTiles++; + colorId = R.color.unready_tile; + } + if (t.left < 0 || t.top < 0) { + unplacedTiles++; + } + mTempShapes.add(new TileDrawable(t, colorId)); } else { - unreadyTiles++; + numInvals++; } - if (t.x < 0 || t.y < 0) { - unplacedTiles++; + } + + // create invalidate shapes (drawn above tiles) + int invalId = 0; + for (TileData t : mProfData[frame]) { + if (t.level == INVAL_FLAG && t != mProfData[frame][0]) { + TileDrawable invalShape = new TileDrawable(t, + R.color.inval_region_start); + ValueAnimator tileAnimator = ObjectAnimator.ofInt(invalShape, + "color", + getResources().getColor(R.color.inval_region_start), + getResources().getColor(R.color.inval_region_stop)); + tileAnimator.setDuration(numInvals * INVAL_CYCLE); + tileAnimator.setEvaluator(new ArgbEvaluator()); + tileAnimator.setRepeatCount(ValueAnimator.INFINITE); + tileAnimator.setRepeatMode(ValueAnimator.RESTART); + float delay = (float) (invalId) * INVAL_CYCLE; + tileAnimator.setStartDelay((int) delay); + invalId++; + tileAnimator.start(); + + mTempShapes.add(invalShape); } } + mRenderStrings[0] = getResources().getString(R.string.format_stat_name, getResources().getString(R.string.ready_tiles), readyTiles); mRenderStrings[1] = getResources().getString(R.string.format_stat_name, getResources().getString(R.string.unready_tiles), unreadyTiles); mRenderStrings[2] = getResources().getString(R.string.format_stat_name, - getResources().getString(R.string.unplaced_tiles), unplacedTiles); - - // draw view rect (using first two TileData objects) - ShapeDrawable viewShape = new ShapeDrawable(); - viewShape.getPaint().setColor(0xff0000ff); - viewShape.setAlpha(64); - viewShape.setBounds(mProfData[frame][0].x, mProfData[frame][0].y, - mProfData[frame][1].x, mProfData[frame][1].y); + getResources().getString(R.string.unplaced_tiles), + unplacedTiles); + mRenderStrings[3] = getResources().getString(R.string.format_stat_name, + getResources().getString(R.string.number_invalidates), + numInvals); + + // draw view rect (using first TileData object, on top) + TileDrawable viewShape = new TileDrawable(mProfData[frame][0], + R.color.view); mTempShapes.add(viewShape); this.invalidate(); return frame; diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/ProfileActivity.java b/tests/TileBenchmark/src/com/test/tilebenchmark/ProfileActivity.java index 23b6275..1521807 100644 --- a/tests/TileBenchmark/src/com/test/tilebenchmark/ProfileActivity.java +++ b/tests/TileBenchmark/src/com/test/tilebenchmark/ProfileActivity.java @@ -38,6 +38,7 @@ import android.widget.EditText; import android.widget.Spinner; import android.widget.TextView; import android.widget.TextView.OnEditorActionListener; +import android.widget.ToggleButton; import java.io.FileOutputStream; import java.io.IOException; @@ -58,11 +59,24 @@ public class ProfileActivity extends Activity { // before test Button mInspectButton; + ToggleButton mCaptureButton; Spinner mVelocitySpinner; + Spinner mMovementSpinner; EditText mUrl; ProfiledWebView mWeb; ProfileCallback mCallback; + LoggingWebViewClient mLoggingWebViewClient = new LoggingWebViewClient(); + AutoLoggingWebViewClient mAutoLoggingWebViewClient = new AutoLoggingWebViewClient(); + + private enum TestingState { + NOT_TESTING, + PRE_TESTING, + START_TESTING, + STOP_TESTING, + SAVED_TESTING + }; + private class VelocitySelectedListener implements OnItemSelectedListener { @Override public void onItemSelected(AdapterView<?> parent, View view, @@ -77,6 +91,31 @@ public class ProfileActivity extends Activity { } } + private class MovementSelectedListener implements OnItemSelectedListener { + @Override + public void onItemSelected(AdapterView<?> parent, View view, + int position, long id) { + String movementStr = parent.getItemAtPosition(position).toString(); + if (movementStr == getResources().getString( + R.string.movement_auto_scroll) + || movementStr == getResources().getString( + R.string.movement_auto_fling)) { + mWeb.setWebViewClient(mAutoLoggingWebViewClient); + mCaptureButton.setEnabled(false); + mVelocitySpinner.setEnabled(true); + } else if (movementStr == getResources().getString( + R.string.movement_manual)) { + mWeb.setWebViewClient(mLoggingWebViewClient); + mCaptureButton.setEnabled(true); + mVelocitySpinner.setEnabled(false); + } + } + + @Override + public void onNothingSelected(AdapterView<?> parent) { + } + } + private class LoggingWebViewClient extends WebViewClient { @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { @@ -88,6 +127,9 @@ public class ProfileActivity extends Activity { super.onPageStarted(view, url, favicon); mUrl.setText(url); } + } + + private class AutoLoggingWebViewClient extends LoggingWebViewClient { @Override public void onPageFinished(WebView view, String url) { @@ -100,10 +142,16 @@ public class ProfileActivity extends Activity { @Override public void onFinish() { - mWeb.startScrollTest(mCallback); + startViewProfiling(true); } }.start(); } + + @Override + public void onPageStarted(WebView view, String url, Bitmap favicon) { + super.onPageStarted(view, url, favicon); + setTestingState(TestingState.PRE_TESTING); + } } private class StoreFileTask extends @@ -125,24 +173,65 @@ public class ProfileActivity extends Activity { @Override protected void onPostExecute(Void v) { - mUrl.setBackgroundResource(R.color.finished_url); + setTestingState(TestingState.SAVED_TESTING); } } + public void setTestingState(TestingState state) { + switch (state) { + case NOT_TESTING: + mUrl.setBackgroundResource(R.color.background_not_testing); + mInspectButton.setEnabled(true); + mMovementSpinner.setEnabled(true); + break; + case PRE_TESTING: + mInspectButton.setEnabled(false); + mMovementSpinner.setEnabled(false); + break; + case START_TESTING: + mUrl.setBackgroundResource(R.color.background_start_testing); + mInspectButton.setEnabled(false); + mMovementSpinner.setEnabled(false); + break; + case STOP_TESTING: + mUrl.setBackgroundResource(R.color.background_stop_testing); + break; + case SAVED_TESTING: + mInspectButton.setEnabled(true); + mMovementSpinner.setEnabled(true); + break; + } + } + + /** auto - automatically scroll. */ + private void startViewProfiling(boolean auto) { + if (!auto) { + // manual, toggle capture button to indicate capture state to user + mCaptureButton.setChecked(true); + } + mWeb.startScrollTest(mCallback, auto); + setTestingState(TestingState.START_TESTING); + } + /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); mInspectButton = (Button) findViewById(R.id.inspect); + mCaptureButton = (ToggleButton) findViewById(R.id.capture); mVelocitySpinner = (Spinner) findViewById(R.id.velocity); + mMovementSpinner = (Spinner) findViewById(R.id.movement); mUrl = (EditText) findViewById(R.id.url); mWeb = (ProfiledWebView) findViewById(R.id.web); mCallback = new ProfileCallback() { @SuppressWarnings("unchecked") @Override public void profileCallback(TileData[][] data) { - new StoreFileTask().execute(new Pair<String, TileData[][]>(TEMP_FILENAME, data)); + new StoreFileTask().execute(new Pair<String, TileData[][]>( + TEMP_FILENAME, data)); + mCaptureButton.setChecked(false); + setTestingState(TestingState.STOP_TESTING); } }; @@ -166,6 +255,33 @@ public class ProfileActivity extends Activity { new VelocitySelectedListener()); mVelocitySpinner.setSelection(3); + // Movement spinner + String content[] = { + getResources().getString(R.string.movement_auto_scroll), + getResources().getString(R.string.movement_auto_fling), + getResources().getString(R.string.movement_manual) + }; + adapter = new ArrayAdapter<CharSequence>(this, + android.R.layout.simple_spinner_item, content); + adapter.setDropDownViewResource( + android.R.layout.simple_spinner_dropdown_item); + mMovementSpinner.setAdapter(adapter); + mMovementSpinner.setOnItemSelectedListener( + new MovementSelectedListener()); + mMovementSpinner.setSelection(0); + + // Capture toggle button + mCaptureButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + if (mCaptureButton.isChecked()) { + startViewProfiling(false); + } else { + mWeb.stopScrollTest(); + } + } + }); + // Custom profiling WebView WebSettings settings = mWeb.getSettings(); settings.setJavaScriptEnabled(true); @@ -180,12 +296,13 @@ public class ProfileActivity extends Activity { public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { String url = mUrl.getText().toString(); - mUrl.setBackgroundResource(R.color.unfinished_url); mWeb.loadUrl(url); mWeb.requestFocus(); return true; } }); + + setTestingState(TestingState.NOT_TESTING); } public void setCallback(ProfileCallback callback) { diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/ProfiledWebView.java b/tests/TileBenchmark/src/com/test/tilebenchmark/ProfiledWebView.java index 6560624..d3941be 100644 --- a/tests/TileBenchmark/src/com/test/tilebenchmark/ProfiledWebView.java +++ b/tests/TileBenchmark/src/com/test/tilebenchmark/ProfiledWebView.java @@ -59,12 +59,13 @@ public class ProfiledWebView extends WebView { } /* - * Called once the page is loaded to start scrolling for evaluating tiles + * Called once the page is loaded to start scrolling for evaluating tiles. + * If autoScrolling isn't set, stop must be called manually. */ - public void startScrollTest(ProfileCallback callback) { - isScrolling = true; + public void startScrollTest(ProfileCallback callback, boolean autoScrolling) { + isScrolling = autoScrolling; mCallback = callback; - super.tileProfilingStart(); + tileProfilingStart(); invalidate(); } @@ -72,19 +73,31 @@ public class ProfiledWebView extends WebView { * Called once the page has stopped scrolling */ public void stopScrollTest() { - float testRatio = super.tileProfilingStop(); + super.tileProfilingStop(); + + if (mCallback == null) { + tileProfilingClear(); + return; + } TileData data[][] = new TileData[super.tileProfilingNumFrames()][]; for (int frame = 0; frame < data.length; frame++) { data[frame] = new TileData[ - super.tileProfilingNumTilesInFrame(frame)]; + tileProfilingNumTilesInFrame(frame)]; for (int tile = 0; tile < data[frame].length; tile++) { - int x = super.tileProfilingGetX(frame, tile); - int y = super.tileProfilingGetY(frame, tile); - boolean isReady = super.tileProfilingGetReady(frame, tile); - int level = super.tileProfilingGetLevel(frame, tile); + int left = tileProfilingGetInt(frame, tile, "left"); + int top = tileProfilingGetInt(frame, tile, "top"); + int right = tileProfilingGetInt(frame, tile, "right"); + int bottom = tileProfilingGetInt(frame, tile, "bottom"); + + boolean isReady = super.tileProfilingGetInt( + frame, tile, "isReady") == 1; + int level = tileProfilingGetInt(frame, tile, "level"); + + float scale = tileProfilingGetFloat(frame, tile, "scale"); - data[frame][tile] = new TileData(x, y, isReady, level); + data[frame][tile] = new TileData(left, top, right, bottom, + isReady, level, scale); } } super.tileProfilingClear(); diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/TileData.java b/tests/TileBenchmark/src/com/test/tilebenchmark/TileData.java index 7d4bb9f..3e729a6 100644 --- a/tests/TileBenchmark/src/com/test/tilebenchmark/TileData.java +++ b/tests/TileBenchmark/src/com/test/tilebenchmark/TileData.java @@ -19,14 +19,24 @@ package com.test.tilebenchmark; import java.io.Serializable; public class TileData implements Serializable { - public int x, y; + int left, top, right, bottom; public boolean isReady; public int level; + public float scale; - public TileData(int x, int y, boolean isReady, int level) { - this.x = x; - this.y = y; + public TileData(int left, int top, int right, int bottom, boolean isReady, + int level, float scale) { + this.left = left; + this.right = right; + this.top = top; + this.bottom = bottom; this.isReady = isReady; this.level = level; + this.scale = scale; + } + + public String toString() { + return "Tile (" + left + "," + top + ")->(" + + right + "," + bottom + ")"; } } |