Advertisement
Guest User

Untitled

a guest
Nov 26th, 2012
572
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 26.08 KB | None | 0 0
  1. /*
  2. * Copyright (C) 2008 Google Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16.  
  17. package cap.shot;
  18.  
  19. import android.content.Context;
  20. import android.graphics.Bitmap;
  21. import android.graphics.Canvas;
  22. import android.graphics.Matrix;
  23. import android.graphics.Paint;
  24. import android.graphics.Rect;
  25. import android.graphics.RectF;
  26. import android.graphics.Typeface;
  27. import android.graphics.drawable.BitmapDrawable;
  28. import android.net.Uri;
  29. import android.text.TextUtils;
  30. import android.util.AttributeSet;
  31. import android.util.Log;
  32. import android.view.MotionEvent;
  33. import android.widget.ImageView;
  34.  
  35.  
  36. /**
  37. * Lolcat-specific subclass of ImageView, which manages the various
  38. * scaled-down Bitmaps and knows how to render and manipulate the
  39. * image captions.
  40. */
  41. public class LolcatView extends ImageView {
  42. private static final String TAG = "LolcatView";
  43.  
  44.  
  45. // Standard lolcat size is 500x375. (But to preserve the original
  46. // image's aspect ratio, we rescale so that the larger dimension ends
  47. // up being 500 pixels.)
  48. private static final float SCALED_IMAGE_MAX_DIMENSION = 500f;
  49.  
  50. // Other standard lolcat image parameters
  51. private static final int FONT_SIZE = 44;
  52.  
  53. private Bitmap mScaledBitmap; // The photo picked by the user, scaled-down
  54. private Bitmap mWorkingBitmap; // The Bitmap we render the caption text into
  55.  
  56. // Current state of the captions.
  57. // TODO: This array currently has a hardcoded length of 2 (for "top"
  58. // and "bottom" captions), but eventually should support as many
  59. // captions as the user wants to add.
  60. private final Caption[] mCaptions = new Caption[] { new Caption(), new Caption() };
  61.  
  62. // State used while dragging a caption around
  63. private boolean mDragging;
  64. private int mDragCaptionIndex; // index of the caption (in mCaptions[]) that's being dragged
  65. private int mTouchDownX, mTouchDownY;
  66. private final Rect mInitialDragBox = new Rect();
  67. private final Rect mCurrentDragBox = new Rect();
  68. private final RectF mCurrentDragBoxF = new RectF(); // used in onDraw()
  69. private final RectF mTransformedDragBoxF = new RectF(); // used in onDraw()
  70. private final Rect mTmpRect = new Rect();
  71.  
  72. public LolcatView(Context context) {
  73. super(context);
  74. }
  75.  
  76. public LolcatView(Context context, AttributeSet attrs) {
  77. super(context, attrs);
  78. }
  79.  
  80. public LolcatView(Context context, AttributeSet attrs, int defStyle) {
  81. super(context, attrs, defStyle);
  82. }
  83.  
  84. public Bitmap getWorkingBitmap() {
  85. return mWorkingBitmap;
  86. }
  87.  
  88. public String getTopCaption() {
  89. return mCaptions[0].caption;
  90. }
  91.  
  92. public String getBottomCaption() {
  93. return mCaptions[1].caption;
  94. }
  95.  
  96. /**
  97. * @return true if the user has set caption(s) for this LolcatView.
  98. */
  99. public boolean hasValidCaption() {
  100. return !TextUtils.isEmpty(mCaptions[0].caption)
  101. || !TextUtils.isEmpty(mCaptions[1].caption);
  102. }
  103.  
  104. public void clear() {
  105. mScaledBitmap = null;
  106. mWorkingBitmap = null;
  107. setImageDrawable(null);
  108.  
  109. // TODO: Anything else we need to do here to release resources
  110. // associated with this object, like maybe the Bitmap that got
  111. // created by the previous setImageURI() call?
  112. }
  113.  
  114. public void loadFromUri(Uri uri) {
  115. // For now, directly load the specified Uri.
  116. setImageURI(uri);
  117.  
  118. // TODO: Rather than calling setImageURI() with the URI of
  119. // the (full-size) photo, it would be better to turn the URI into
  120. // a scaled-down Bitmap right here, and load *that* into ourself.
  121. // I'd do that basically the same way that ImageView.setImageURI does it:
  122. // [ . . . ]
  123. // android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
  124. // android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:304)
  125. // android.graphics.drawable.Drawable.createFromStream(Drawable.java:635)
  126. // android.widget.ImageView.resolveUri(ImageView.java:477)
  127. // android.widget.ImageView.setImageURI(ImageView.java:281)
  128. // [ . . . ]
  129. // But for now let's let ImageView do the work: we call setImageURI (above)
  130. // and immediately pull out a Bitmap (below).
  131.  
  132. // Stash away a scaled-down bitmap.
  133. // TODO: is it safe to assume this will always be a BitmapDrawable?
  134. BitmapDrawable drawable = (BitmapDrawable) getDrawable();
  135. Log.i(TAG, "===> current drawable: " + drawable);
  136.  
  137. Bitmap fullSizeBitmap = drawable.getBitmap();
  138. Log.i(TAG, "===> fullSizeBitmap: " + fullSizeBitmap
  139. + " dimensions: " + fullSizeBitmap.getWidth()
  140. + " x " + fullSizeBitmap.getHeight());
  141.  
  142. Bitmap.Config config = fullSizeBitmap.getConfig();
  143. Log.i(TAG, " - config = " + config);
  144.  
  145. // Standard lolcat size is 500x375. But we don't want to distort
  146. // the image if it isn't 4x3, so let's just set the larger
  147. // dimension to 500 pixels and preserve the source aspect ratio.
  148.  
  149. float origWidth = fullSizeBitmap.getWidth();
  150. float origHeight = fullSizeBitmap.getHeight();
  151. float aspect = origWidth / origHeight;
  152. Log.i(TAG, " - aspect = " + aspect + "(" + origWidth + " x " + origHeight + ")");
  153.  
  154. float scaleFactor = ((aspect > 1.0) ? origWidth : origHeight) / SCALED_IMAGE_MAX_DIMENSION;
  155. int scaledWidth = Math.round(origWidth / scaleFactor);
  156. int scaledHeight = Math.round(origHeight / scaleFactor);
  157.  
  158. mScaledBitmap = Bitmap.createScaledBitmap(fullSizeBitmap,
  159. scaledWidth,
  160. scaledHeight,
  161. true /* filter */);
  162. Log.i(TAG, " ===> mScaledBitmap: " + mScaledBitmap
  163. + " dimensions: " + mScaledBitmap.getWidth()
  164. + " x " + mScaledBitmap.getHeight());
  165. Log.i(TAG, " isMutable = " + mScaledBitmap.isMutable());
  166. }
  167.  
  168. /**
  169. * Sets the captions for this LolcatView.
  170. */
  171. public void setCaptions(String topCaption, String bottomCaption) {
  172. Log.i(TAG, "setCaptions: '" + topCaption + "', '" + bottomCaption + "'");
  173. if (topCaption == null) topCaption = "";
  174. if (bottomCaption == null) bottomCaption = "";
  175.  
  176. mCaptions[0].caption = topCaption;
  177. mCaptions[1].caption = bottomCaption;
  178.  
  179. // If the user clears a caption, reset its position (so that it'll
  180. // come back in the default position if the user re-adds it.)
  181. if (TextUtils.isEmpty(mCaptions[0].caption)) {
  182. Log.i(TAG, "- invalidating position of caption 0...");
  183. mCaptions[0].positionValid = false;
  184. }
  185. if (TextUtils.isEmpty(mCaptions[1].caption)) {
  186. Log.i(TAG, "- invalidating position of caption 1...");
  187. mCaptions[1].positionValid = false;
  188. }
  189.  
  190. // And *any* time the captions change, blow away the cached
  191. // caption bounding boxes to make sure we'll recompute them in
  192. // renderCaptions().
  193. mCaptions[0].captionBoundingBox = null;
  194. mCaptions[1].captionBoundingBox = null;
  195.  
  196. renderCaptions(mCaptions);
  197. }
  198.  
  199. /**
  200. * Clears the captions for this LolcatView.
  201. */
  202. public void clearCaptions() {
  203. setCaptions("", "");
  204. }
  205.  
  206. /**
  207. * Renders this LolcatView's current image captions into our
  208. * underlying ImageView.
  209. *
  210. * We start with a scaled-down version of the photo originally chosed
  211. * by the user (mScaledBitmap), make a mutable copy (mWorkingBitmap),
  212. * render the specified strings into the bitmap, and show the
  213. * resulting image onscreen.
  214. * @return
  215. */
  216. public void renderCaptions(Caption[] captions) {
  217.  
  218. // TODO: handle an arbitrary array of strings, rather than
  219. // assuming "top" and "bottom" captions.
  220.  
  221. String topString = captions[0].caption;
  222. boolean topStringValid = !TextUtils.isEmpty(topString);
  223.  
  224. String bottomString = captions[1].caption;
  225. boolean bottomStringValid = !TextUtils.isEmpty(bottomString);
  226.  
  227. Log.i(TAG, "renderCaptions: '" + topString + "', '" + bottomString + "'");
  228.  
  229. if (mScaledBitmap == null) return;
  230.  
  231. // Make a fresh (mutable) copy of the scaled-down photo Bitmap,
  232. // and render the desired text into it.
  233.  
  234. Bitmap.Config config = mScaledBitmap.getConfig();
  235. Log.i(TAG, " - mScaledBitmap config = " + config);
  236.  
  237. mWorkingBitmap = mScaledBitmap.copy(config, true /* isMutable */);
  238. Log.i(TAG, " ===> mWorkingBitmap: " + mWorkingBitmap
  239. + " dimensions: " + mWorkingBitmap.getWidth()
  240. + " x " + mWorkingBitmap.getHeight());
  241. Log.i(TAG, " isMutable = " + mWorkingBitmap.isMutable());
  242.  
  243. Canvas canvas = new Canvas(mWorkingBitmap);
  244. Log.i(TAG, "- Canvas: " + canvas
  245. + " dimensions: " + canvas.getWidth() + " x " + canvas.getHeight());
  246.  
  247. Paint textPaint = new Paint();
  248. textPaint.setAntiAlias(true);
  249. textPaint.setTextSize(FONT_SIZE);
  250. textPaint.setColor(0xFFFFFFFF);
  251. Log.i(TAG, "- Paint: " + textPaint);
  252.  
  253. Typeface face = textPaint.getTypeface();
  254. Log.i(TAG, "- default typeface: " + face);
  255.  
  256. // The most standard font for lolcat captions is Impact. (Arial
  257. // Black is also common.) Unfortunately we don't have either of
  258. // these on the device by default; the closest we can do is
  259. // DroidSans-Bold:
  260.  
  261. Typeface mFace = Typeface.createFromAsset(getContext().getAssets(),"fonts/impact.ttf");
  262. Paint mPaint = new Paint ();
  263. mPaint.setTypeface(mFace);
  264. Log.i(TAG, "- new face: " + face);
  265. textPaint.setTypeface(mFace);
  266.  
  267. // Look up the positions of the captions, or if this is our very
  268. // first time rendering them, initialize the positions to default
  269. // values.
  270.  
  271. final int edgeBorder = 20;
  272. final int fontHeight = textPaint.getFontMetricsInt(null);
  273. Log.i(TAG, "- fontHeight: " + fontHeight);
  274.  
  275. Log.i(TAG, "- Caption positioning:");
  276. int topX = 0;
  277. int topY = 0;
  278. if (topStringValid) {
  279. if (mCaptions[0].positionValid) {
  280. topX = mCaptions[0].xpos;
  281. topY = mCaptions[0].ypos;
  282. Log.i(TAG, " - TOP: already had a valid position: " + topX + ", " + topY);
  283. } else {
  284. // Start off with the "top" caption at the upper-left:
  285. topX = edgeBorder;
  286. topY = edgeBorder + (fontHeight * 3 / 4);
  287. mCaptions[0].setPosition(topX, topY);
  288. Log.i(TAG, " - TOP: initializing to default position: " + topX + ", " + topY);
  289. }
  290. }
  291.  
  292. int bottomX = 0;
  293. int bottomY = 0;
  294. if (bottomStringValid) {
  295. if (mCaptions[1].positionValid) {
  296. bottomX = mCaptions[1].xpos;
  297. bottomY = mCaptions[1].ypos;
  298. Log.i(TAG, " - Bottom: already had a valid position: "
  299. + bottomX + ", " + bottomY);
  300. } else {
  301. // Start off with the "bottom" caption at the lower-right:
  302. final int bottomTextWidth = (int) textPaint.measureText(bottomString);
  303. Log.i(TAG, "- bottomTextWidth (" + bottomString + "): " + bottomTextWidth);
  304. bottomX = canvas.getWidth() - edgeBorder - bottomTextWidth;
  305. bottomY = canvas.getHeight() - edgeBorder;
  306. mCaptions[1].setPosition(bottomX, bottomY);
  307. Log.i(TAG, " - BOTTOM: initializing to default position: "
  308. + bottomX + ", " + bottomY);
  309. }
  310. }
  311.  
  312. // Finally, render the text.
  313.  
  314. // Standard lolcat captions are drawn in white with a heavy black
  315. // outline (i.e. white fill, black stroke). Our Canvas APIs can't
  316. // do this exactly, though.
  317. // We *could* get something decent-looking using a regular
  318. // drop-shadow, like this:
  319. // textPaint.setShadowLayer(3.0f, 3, 3, 0xff000000);
  320. // but instead let's simulate the "outline" style by drawing the
  321. // text 4 separate times, with the shadow in a different direction
  322. // each time.
  323. // (TODO: This is a hack, and still doesn't look as good
  324. // as a real "white fill, black stroke" style.)
  325.  
  326. final float shadowRadius = 2.0f;
  327. final int shadowOffset = 2;
  328. final int shadowColor = 0xff000000;
  329.  
  330. // TODO: Right now we use offsets of 2,2 / -2,2 / 2,-2 / -2,-2 .
  331. // But 2,0 / 0,2 / -2,0 / 0,-2 might look better.
  332.  
  333. textPaint.setShadowLayer(shadowRadius, shadowOffset, shadowOffset, shadowColor);
  334. if (topStringValid) canvas.drawText(topString, topX, topY, textPaint);
  335. if (bottomStringValid) canvas.drawText(bottomString, bottomX, bottomY, textPaint);
  336. //
  337. textPaint.setShadowLayer(shadowRadius, -shadowOffset, shadowOffset, shadowColor);
  338. if (topStringValid) canvas.drawText(topString, topX, topY, textPaint);
  339. if (bottomStringValid) canvas.drawText(bottomString, bottomX, bottomY, textPaint);
  340. //
  341. textPaint.setShadowLayer(shadowRadius, shadowOffset, -shadowOffset, shadowColor);
  342. if (topStringValid) canvas.drawText(topString, topX, topY, textPaint);
  343. if (bottomStringValid) canvas.drawText(bottomString, bottomX, bottomY, textPaint);
  344. //
  345. textPaint.setShadowLayer(shadowRadius, -shadowOffset, -shadowOffset, shadowColor);
  346. if (topStringValid) canvas.drawText(topString, topX, topY, textPaint);
  347. if (bottomStringValid) canvas.drawText(bottomString, bottomX, bottomY, textPaint);
  348.  
  349. // Stash away bounding boxes for the captions if this
  350. // is our first time rendering them.
  351. // Watch out: the x/y position we use for drawing the text is
  352. // actually the *lower* left corner of the bounding box...
  353.  
  354. int textWidth, textHeight;
  355.  
  356. if (topStringValid && mCaptions[0].captionBoundingBox == null) {
  357. Log.i(TAG, "- Computing initial bounding box for top caption...");
  358. textPaint.getTextBounds(topString, 0, topString.length(), mTmpRect);
  359. textWidth = mTmpRect.width();
  360. textHeight = mTmpRect.height();
  361. Log.i(TAG, "- text dimensions: " + textWidth + " x " + textHeight);
  362. mCaptions[0].captionBoundingBox = new Rect(topX, topY - textHeight,
  363. topX + textWidth, topY);
  364. Log.i(TAG, "- RESULTING RECT: " + mCaptions[0].captionBoundingBox);
  365. }
  366. if (bottomStringValid && mCaptions[1].captionBoundingBox == null) {
  367. Log.i(TAG, "- Computing initial bounding box for bottom caption...");
  368. textPaint.getTextBounds(bottomString, 0, bottomString.length(), mTmpRect);
  369. textWidth = mTmpRect.width();
  370. textHeight = mTmpRect.height();
  371. Log.i(TAG, "- text dimensions: " + textWidth + " x " + textHeight);
  372. mCaptions[1].captionBoundingBox = new Rect(bottomX, bottomY - textHeight,
  373. bottomX + textWidth, bottomY);
  374. Log.i(TAG, "- RESULTING RECT: " + mCaptions[1].captionBoundingBox);
  375. }
  376.  
  377. // Finally, display the new Bitmap to the user:
  378. setImageBitmap(mWorkingBitmap);
  379. }
  380.  
  381. @Override
  382. protected void onDraw(Canvas canvas) {
  383. Log.i(TAG, "onDraw: " + canvas);
  384. super.onDraw(canvas);
  385.  
  386. if (mDragging) {
  387. Log.i(TAG, "- dragging! Drawing box at " + mCurrentDragBox);
  388.  
  389. // mCurrentDragBox is in the coordinate system of our bitmap;
  390. // need to convert it into the coordinate system of the
  391. // overall LolcatView.
  392. //
  393. // To transform between coordinate systems we need to apply the
  394. // transformation described by the ImageView's matrix *and* also
  395. // account for our left and top padding.
  396.  
  397. Matrix m = getImageMatrix();
  398.  
  399. mCurrentDragBoxF.set(mCurrentDragBox);
  400. m.mapRect(mTransformedDragBoxF, mCurrentDragBoxF);
  401. mTransformedDragBoxF.offset(getPaddingLeft(), getPaddingTop());
  402.  
  403. Paint p = new Paint();
  404. p.setColor(0xFFFFFFFF);
  405. p.setStyle(Paint.Style.STROKE);
  406. p.setStrokeWidth(2f);
  407. Log.i(TAG, "- Paint: " + p);
  408.  
  409. canvas.drawRect(mTransformedDragBoxF, p);
  410. }
  411. }
  412.  
  413. @Override
  414. public boolean onTouchEvent(MotionEvent ev) {
  415. Log.i(TAG, "onTouchEvent: " + ev);
  416.  
  417. // Watch out: ev.getX() and ev.getY() are in the
  418. // coordinate system of the entire LolcatView, although
  419. // all the positions and rects we use here (like
  420. // mCaptions[].captionBoundingBox) are relative to the bitmap
  421. // that's drawn inside the LolcatView.
  422. //
  423. // To transform between coordinate systems we need to apply the
  424. // transformation described by the ImageView's matrix *and* also
  425. // account for our left and top padding.
  426.  
  427. Matrix m = getImageMatrix();
  428.  
  429. Matrix invertedMatrix = new Matrix();
  430. m.invert(invertedMatrix);
  431.  
  432. float[] pointArray = new float[] { ev.getX() - getPaddingLeft(),
  433. ev.getY() - getPaddingTop() };
  434. Log.i(TAG, " - BEFORE: pointArray = " + pointArray[0] + ", " + pointArray[1]);
  435.  
  436. // Transform the X/Y position of the DOWN event back into bitmap coords
  437. invertedMatrix.mapPoints(pointArray);
  438. Log.i(TAG, " - AFTER: pointArray = " + pointArray[0] + ", " + pointArray[1]);
  439.  
  440. int eventX = (int) pointArray[0];
  441. int eventY = (int) pointArray[1];
  442.  
  443. int action = ev.getAction();
  444. switch (action) {
  445. case MotionEvent.ACTION_DOWN:
  446. if (mDragging) {
  447. Log.w(TAG, "Got an ACTION_DOWN, but we were already dragging!");
  448. mDragging = false; // and continue as if we weren't already dragging...
  449. }
  450. if (!hasValidCaption()) {
  451. Log.w(TAG, "No caption(s) yet; ignoring this ACTION_DOWN event.");
  452. return true;
  453. }
  454.  
  455. // See if this DOWN event hit one of the caption bounding
  456. // boxes. If so, start dragging!
  457. for (int i = 0; i < mCaptions.length; i++) {
  458. Rect boundingBox = mCaptions[i].captionBoundingBox;
  459. Log.i(TAG, " - boundingBox #" + i + ": " + boundingBox + "...");
  460.  
  461. if (boundingBox != null) {
  462. // Expand the bounding box by a fudge factor to make it
  463. // easier to hit (since touch accuracy is pretty poor on a
  464. // real device, and the captions are fairly small...)
  465. mTmpRect.set(boundingBox);
  466.  
  467. final int touchPositionSlop = 40; // pixels
  468. mTmpRect.inset(-touchPositionSlop, -touchPositionSlop);
  469.  
  470. Log.i(TAG, " - Checking expanded bounding box #" + i
  471. + ": " + mTmpRect + "...");
  472. if (mTmpRect.contains(eventX, eventY)) {
  473. Log.i(TAG, " - Hit! " + mCaptions[i]);
  474. mDragging = true;
  475. mDragCaptionIndex = i;
  476. break;
  477. }
  478. }
  479. }
  480. if (!mDragging) {
  481. Log.i(TAG, "- ACTION_DOWN event didn't hit any captions; ignoring.");
  482. return true;
  483. }
  484.  
  485. mTouchDownX = eventX;
  486. mTouchDownY = eventY;
  487.  
  488. mInitialDragBox.set(mCaptions[mDragCaptionIndex].captionBoundingBox);
  489. mCurrentDragBox.set(mCaptions[mDragCaptionIndex].captionBoundingBox);
  490.  
  491. invalidate();
  492.  
  493. return true;
  494.  
  495. case MotionEvent.ACTION_MOVE:
  496. if (!mDragging) {
  497. return true;
  498. }
  499.  
  500. int displacementX = eventX - mTouchDownX;
  501. int displacementY = eventY - mTouchDownY;
  502.  
  503. mCurrentDragBox.set(mInitialDragBox);
  504. mCurrentDragBox.offset(displacementX, displacementY);
  505.  
  506. invalidate();
  507.  
  508. return true;
  509.  
  510. case MotionEvent.ACTION_UP:
  511. if (!mDragging) {
  512. return true;
  513. }
  514.  
  515. mDragging = false;
  516.  
  517. // Reposition the selected caption!
  518. Log.i(TAG, "- Done dragging! Repositioning caption #" + mDragCaptionIndex + ": "
  519. + mCaptions[mDragCaptionIndex]);
  520.  
  521. int offsetX = eventX - mTouchDownX;
  522. int offsetY = eventY - mTouchDownY;
  523. Log.i(TAG, " - OFFSET: " + offsetX + ", " + offsetY);
  524.  
  525. // Reposition the the caption we just dragged, and blow
  526. // away the cached bounding box to make sure it'll get
  527. // recomputed in renderCaptions().
  528. mCaptions[mDragCaptionIndex].xpos += offsetX;
  529. mCaptions[mDragCaptionIndex].ypos += offsetY;
  530. mCaptions[mDragCaptionIndex].captionBoundingBox = null;
  531.  
  532. Log.i(TAG, " - Updated caption: " + mCaptions[mDragCaptionIndex]);
  533.  
  534. // Finally, refresh the screen.
  535. renderCaptions(mCaptions);
  536. return true;
  537.  
  538. // This case isn't expected to happen.
  539. case MotionEvent.ACTION_CANCEL:
  540. if (!mDragging) {
  541. return true;
  542. }
  543.  
  544. mDragging = false;
  545. // Refresh the screen.
  546. renderCaptions(mCaptions);
  547. return true;
  548.  
  549. default:
  550. return super.onTouchEvent(ev);
  551. }
  552. }
  553.  
  554. /**
  555. * Returns an array containing the xpos/ypos of each Caption in our
  556. * array of captions. (This method and setCaptionPositions() are used
  557. * by LolcatActivity to save and restore the activity state across
  558. * orientation changes.)
  559. */
  560. public int[] getCaptionPositions() {
  561. // TODO: mCaptions currently has a hardcoded length of 2 (for
  562. // "top" and "bottom" captions).
  563. int[] captionPositions = new int[4];
  564.  
  565. if (mCaptions[0].positionValid) {
  566. captionPositions[0] = mCaptions[0].xpos;
  567. captionPositions[1] = mCaptions[0].ypos;
  568. } else {
  569. captionPositions[0] = -1;
  570. captionPositions[1] = -1;
  571. }
  572.  
  573. if (mCaptions[1].positionValid) {
  574. captionPositions[2] = mCaptions[1].xpos;
  575. captionPositions[3] = mCaptions[1].ypos;
  576. } else {
  577. captionPositions[2] = -1;
  578. captionPositions[3] = -1;
  579. }
  580.  
  581. Log.i(TAG, "getCaptionPositions: returning " + captionPositions);
  582. return captionPositions;
  583. }
  584.  
  585. /**
  586. * Sets the xpos and ypos values of each Caption in our array based on
  587. * the specified values. (This method and getCaptionPositions() are
  588. * used by LolcatActivity to save and restore the activity state
  589. * across orientation changes.)
  590. */
  591. public void setCaptionPositions(int[] captionPositions) {
  592. // TODO: mCaptions currently has a hardcoded length of 2 (for
  593. // "top" and "bottom" captions).
  594.  
  595. Log.i(TAG, "setCaptionPositions(" + captionPositions + ")...");
  596.  
  597. if (captionPositions[0] < 0) {
  598. mCaptions[0].positionValid = false;
  599. Log.i(TAG, "- TOP caption: no valid position");
  600. } else {
  601. mCaptions[0].setPosition(captionPositions[0], captionPositions[1]);
  602. Log.i(TAG, "- TOP caption: got valid position: "
  603. + mCaptions[0].xpos + ", " + mCaptions[0].ypos);
  604. }
  605.  
  606. if (captionPositions[2] < 0) {
  607. mCaptions[1].positionValid = false;
  608. Log.i(TAG, "- BOTTOM caption: no valid position");
  609. } else {
  610. mCaptions[1].setPosition(captionPositions[2], captionPositions[3]);
  611. Log.i(TAG, "- BOTTOM caption: got valid position: "
  612. + mCaptions[1].xpos + ", " + mCaptions[1].ypos);
  613. }
  614.  
  615. // Finally, refresh the screen.
  616. renderCaptions(mCaptions);
  617. }
  618.  
  619. /**
  620. * Structure used to hold the entire state of a single caption.
  621. */
  622. class Caption {
  623. public String caption;
  624. public Rect captionBoundingBox; // updated by renderCaptions()
  625. public int xpos, ypos;
  626. public boolean positionValid;
  627.  
  628. public void setPosition(int x, int y) {
  629. positionValid = true;
  630. xpos = x;
  631. ypos = y;
  632. // Also blow away the cached bounding box, to make sure it'll
  633. // get recomputed in renderCaptions().
  634. captionBoundingBox = null;
  635. }
  636.  
  637. @Override
  638. public String toString() {
  639. return "Caption['" + caption + "'; bbox " + captionBoundingBox
  640. + "; pos " + xpos + ", " + ypos + "; posValid = " + positionValid + "]";
  641. }
  642. }
  643.  
  644. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement