1c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu/*
2c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu * Copyright (C) 2013 The Android Open Source Project
3c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu *
4c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu * Licensed under the Apache License, Version 2.0 (the "License");
5c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu * you may not use this file except in compliance with the License.
6c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu * You may obtain a copy of the License at
7c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu *
8c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu *      http://www.apache.org/licenses/LICENSE-2.0
9c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu *
10c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu * Unless required by applicable law or agreed to in writing, software
11c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu * distributed under the License is distributed on an "AS IS" BASIS,
12c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu * See the License for the specific language governing permissions and
14c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu * limitations under the License.
15c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu */
16c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu
17c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescupackage com.android.gallery3d.ingest.ui;
18c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu
19f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescuimport com.android.gallery3d.R;
20f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescuimport com.android.gallery3d.ingest.data.BitmapWithMetadata;
21f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescuimport com.android.gallery3d.ingest.data.IngestObjectInfo;
22f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescuimport com.android.gallery3d.ingest.data.MtpBitmapFetch;
23f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescuimport com.android.gallery3d.ingest.data.MtpDeviceIndex;
24f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
25c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescuimport android.content.Context;
26f349b1b2b2d3a1c024a979328e89c112d3e2cf25Bobby Georgescuimport android.graphics.Canvas;
27573dfae59a96663b6ff6e47b4c7db326c651a3cfBobby Georgescuimport android.graphics.Matrix;
28f349b1b2b2d3a1c024a979328e89c112d3e2cf25Bobby Georgescuimport android.graphics.drawable.Drawable;
29c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescuimport android.mtp.MtpDevice;
3037faa3150feebccecd8872658af32bd88a0d2073Bobby Georgescuimport android.os.Handler;
3137faa3150feebccecd8872658af32bd88a0d2073Bobby Georgescuimport android.os.HandlerThread;
3237faa3150feebccecd8872658af32bd88a0d2073Bobby Georgescuimport android.os.Looper;
3337faa3150feebccecd8872658af32bd88a0d2073Bobby Georgescuimport android.os.Message;
34c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescuimport android.util.AttributeSet;
35c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescuimport android.widget.ImageView;
36c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu
3737faa3150feebccecd8872658af32bd88a0d2073Bobby Georgescuimport java.lang.ref.WeakReference;
38c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu
39f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu/**
40f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu * View for images from an MTP devices
41f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu */
4237faa3150feebccecd8872658af32bd88a0d2073Bobby Georgescupublic class MtpImageView extends ImageView {
43f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  // We will use the thumbnail for images larger than this threshold
44f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private static final int MAX_FULLSIZE_PREVIEW_SIZE = 8388608; // 8 megabytes
45baa68886db66f4beb6a07e4441b122975b778f1cBobby Georgescu
46f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private int mObjectHandle;
47f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private int mGeneration;
48c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu
49f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private WeakReference<MtpImageView> mWeakReference = new WeakReference<MtpImageView>(this);
50f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private Object mFetchLock = new Object();
51f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private boolean mFetchPending = false;
52f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private IngestObjectInfo mFetchObjectInfo;
53f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private MtpDevice mFetchDevice;
54f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private Object mFetchResult;
55f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private Drawable mOverlayIcon;
56f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private boolean mShowOverlayIcon;
5737faa3150feebccecd8872658af32bd88a0d2073Bobby Georgescu
58f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private static final FetchImageHandler sFetchHandler = FetchImageHandler.createOnNewThread();
59f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private static final ShowImageHandler sFetchCompleteHandler = new ShowImageHandler();
6037faa3150feebccecd8872658af32bd88a0d2073Bobby Georgescu
61f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private void init() {
62f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    showPlaceholder();
63f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
64c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu
65f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  public MtpImageView(Context context) {
66f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    super(context);
67f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    init();
68f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
69c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu
70f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  public MtpImageView(Context context, AttributeSet attrs) {
71f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    super(context, attrs);
72f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    init();
73f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
74c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu
75f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  public MtpImageView(Context context, AttributeSet attrs, int defStyle) {
76f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    super(context, attrs, defStyle);
77f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    init();
78f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
79c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu
80f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private void showPlaceholder() {
81f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    setImageResource(android.R.color.transparent);
82f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
83c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu
84f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  public void setMtpDeviceAndObjectInfo(MtpDevice device, IngestObjectInfo object, int gen) {
85f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    int handle = object.getObjectHandle();
86f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    if (handle == mObjectHandle && gen == mGeneration) {
87f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      return;
88f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    }
89f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    cancelLoadingAndClear();
90f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    showPlaceholder();
91f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    mGeneration = gen;
92f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    mObjectHandle = handle;
93f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    mShowOverlayIcon = MtpDeviceIndex.SUPPORTED_VIDEO_FORMATS.contains(object.getFormat());
94f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    if (mShowOverlayIcon && mOverlayIcon == null) {
95f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      mOverlayIcon = getResources().getDrawable(R.drawable.ic_control_play);
96f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      updateOverlayIconBounds();
97c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu    }
98f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    synchronized (mFetchLock) {
99f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      mFetchObjectInfo = object;
100f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      mFetchDevice = device;
101f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      if (mFetchPending) {
102f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        return;
103f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      }
104f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      mFetchPending = true;
105f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      sFetchHandler.sendMessage(
106f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu          sFetchHandler.obtainMessage(0, mWeakReference));
107f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    }
108f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
109c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu
110f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  protected Object fetchMtpImageDataFromDevice(MtpDevice device, IngestObjectInfo info) {
111f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    if (info.getCompressedSize() <= MAX_FULLSIZE_PREVIEW_SIZE
112f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        && MtpDeviceIndex.SUPPORTED_IMAGE_FORMATS.contains(info.getFormat())) {
113f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      return MtpBitmapFetch.getFullsize(device, info);
114f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    } else {
115f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      return new BitmapWithMetadata(MtpBitmapFetch.getThumbnail(device, info), 0);
116c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu    }
117f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
118c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu
119f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private float mLastBitmapWidth;
120f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private float mLastBitmapHeight;
121f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private int mLastRotationDegrees;
122f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private Matrix mDrawMatrix = new Matrix();
123573dfae59a96663b6ff6e47b4c7db326c651a3cfBobby Georgescu
124f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private void updateDrawMatrix() {
125f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    mDrawMatrix.reset();
126f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    float dwidth;
127f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    float dheight;
128f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    float vheight = getHeight();
129f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    float vwidth = getWidth();
130f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    float scale;
131f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    boolean rotated90 = (mLastRotationDegrees % 180 != 0);
132f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    if (rotated90) {
133f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      dwidth = mLastBitmapHeight;
134f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      dheight = mLastBitmapWidth;
135f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    } else {
136f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      dwidth = mLastBitmapWidth;
137f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      dheight = mLastBitmapHeight;
138f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    }
139f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    if (dwidth <= vwidth && dheight <= vheight) {
140f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      scale = 1.0f;
141f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    } else {
142f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      scale = Math.min(vwidth / dwidth, vheight / dheight);
143f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    }
144f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    mDrawMatrix.setScale(scale, scale);
145f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    if (rotated90) {
146f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      mDrawMatrix.postTranslate(-dheight * scale * 0.5f,
147f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu          -dwidth * scale * 0.5f);
148f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      mDrawMatrix.postRotate(mLastRotationDegrees);
149f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      mDrawMatrix.postTranslate(dwidth * scale * 0.5f,
150f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu          dheight * scale * 0.5f);
151573dfae59a96663b6ff6e47b4c7db326c651a3cfBobby Georgescu    }
152f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    mDrawMatrix.postTranslate((vwidth - dwidth * scale) * 0.5f,
153f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        (vheight - dheight * scale) * 0.5f);
154f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    if (!rotated90 && mLastRotationDegrees > 0) {
155f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      // rotated by a multiple of 180
156f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      mDrawMatrix.postRotate(mLastRotationDegrees, vwidth / 2, vheight / 2);
157f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    }
158f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    setImageMatrix(mDrawMatrix);
159f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
160573dfae59a96663b6ff6e47b4c7db326c651a3cfBobby Georgescu
161f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private static final int OVERLAY_ICON_SIZE_DENOMINATOR = 4;
162f349b1b2b2d3a1c024a979328e89c112d3e2cf25Bobby Georgescu
163f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private void updateOverlayIconBounds() {
164f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    int iheight = mOverlayIcon.getIntrinsicHeight();
165f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    int iwidth = mOverlayIcon.getIntrinsicWidth();
166f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    int vheight = getHeight();
167f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    int vwidth = getWidth();
168f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    float scaleHeight = ((float) vheight) / (iheight * OVERLAY_ICON_SIZE_DENOMINATOR);
169f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    float scaleWidth = ((float) vwidth) / (iwidth * OVERLAY_ICON_SIZE_DENOMINATOR);
170f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    if (scaleHeight >= 1f && scaleWidth >= 1f) {
171f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      mOverlayIcon.setBounds((vwidth - iwidth) / 2,
172f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu          (vheight - iheight) / 2,
173f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu          (vwidth + iwidth) / 2,
174f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu          (vheight + iheight) / 2);
175f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    } else {
176f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      float scale = Math.min(scaleHeight, scaleWidth);
177f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      mOverlayIcon.setBounds((int) (vwidth - scale * iwidth) / 2,
178f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu          (int) (vheight - scale * iheight) / 2,
179f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu          (int) (vwidth + scale * iwidth) / 2,
180f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu          (int) (vheight + scale * iheight) / 2);
181f349b1b2b2d3a1c024a979328e89c112d3e2cf25Bobby Georgescu    }
182f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
183f349b1b2b2d3a1c024a979328e89c112d3e2cf25Bobby Georgescu
184f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  @Override
185f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
186f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    super.onLayout(changed, left, top, right, bottom);
187f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    if (changed && getScaleType() == ScaleType.MATRIX) {
188f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      updateDrawMatrix();
189f349b1b2b2d3a1c024a979328e89c112d3e2cf25Bobby Georgescu    }
190f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    if (mShowOverlayIcon && changed && mOverlayIcon != null) {
191f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      updateOverlayIconBounds();
192573dfae59a96663b6ff6e47b4c7db326c651a3cfBobby Georgescu    }
193f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
194573dfae59a96663b6ff6e47b4c7db326c651a3cfBobby Georgescu
195f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  @Override
196f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  protected void onDraw(Canvas canvas) {
197f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    super.onDraw(canvas);
198f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    if (mShowOverlayIcon && mOverlayIcon != null) {
199f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      mOverlayIcon.draw(canvas);
200c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu    }
201f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
202c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu
203f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  protected void onMtpImageDataFetchedFromDevice(Object result) {
204f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    BitmapWithMetadata bitmapWithMetadata = (BitmapWithMetadata) result;
205f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    if (getScaleType() == ScaleType.MATRIX) {
206f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      mLastBitmapHeight = bitmapWithMetadata.bitmap.getHeight();
207f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      mLastBitmapWidth = bitmapWithMetadata.bitmap.getWidth();
208f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      mLastRotationDegrees = bitmapWithMetadata.rotationDegrees;
209f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      updateDrawMatrix();
210f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    } else {
211f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      setRotation(bitmapWithMetadata.rotationDegrees);
21237faa3150feebccecd8872658af32bd88a0d2073Bobby Georgescu    }
213f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    setAlpha(0f);
214f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    setImageBitmap(bitmapWithMetadata.bitmap);
215f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    animate().alpha(1f);
216f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
217c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu
218f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  protected void cancelLoadingAndClear() {
219f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    synchronized (mFetchLock) {
220f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      mFetchDevice = null;
221f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      mFetchObjectInfo = null;
222f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      mFetchResult = null;
22337faa3150feebccecd8872658af32bd88a0d2073Bobby Georgescu    }
224f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    animate().cancel();
225f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    setImageResource(android.R.color.transparent);
226f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
22737faa3150feebccecd8872658af32bd88a0d2073Bobby Georgescu
228f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  @Override
229f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  public void onDetachedFromWindow() {
230f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    cancelLoadingAndClear();
231f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    super.onDetachedFromWindow();
232f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
233c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu
234f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private static class FetchImageHandler extends Handler {
235f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    public FetchImageHandler(Looper l) {
236f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      super(l);
237f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    }
238c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu
239f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    public static FetchImageHandler createOnNewThread() {
240f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      HandlerThread t = new HandlerThread("MtpImageView Fetch");
241f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      t.start();
242f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      return new FetchImageHandler(t.getLooper());
243c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu    }
244c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu
245f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    @Override
246f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    public void handleMessage(Message msg) {
247f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      @SuppressWarnings("unchecked")
248f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      MtpImageView parent = ((WeakReference<MtpImageView>) msg.obj).get();
249f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      if (parent == null) {
250f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        return;
251f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      }
252f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      IngestObjectInfo objectInfo;
253f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      MtpDevice device;
254f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      synchronized (parent.mFetchLock) {
255f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        parent.mFetchPending = false;
256f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        device = parent.mFetchDevice;
257f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        objectInfo = parent.mFetchObjectInfo;
258f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      }
259f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      if (device == null) {
260f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        return;
261f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      }
262f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      Object result = parent.fetchMtpImageDataFromDevice(device, objectInfo);
263f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      if (result == null) {
264f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        return;
265f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      }
266f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      synchronized (parent.mFetchLock) {
267f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        if (parent.mFetchObjectInfo != objectInfo) {
268f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu          return;
269c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu        }
270f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        parent.mFetchResult = result;
271f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        parent.mFetchDevice = null;
272f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        parent.mFetchObjectInfo = null;
273f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        sFetchCompleteHandler.sendMessage(
274f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu            sFetchCompleteHandler.obtainMessage(0, parent.mWeakReference));
275f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      }
276f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    }
277f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
278f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
279f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private static class ShowImageHandler extends Handler {
280f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    @Override
281f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    public void handleMessage(Message msg) {
282f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      @SuppressWarnings("unchecked")
283f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      MtpImageView parent = ((WeakReference<MtpImageView>) msg.obj).get();
284f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      if (parent == null) {
285f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        return;
286f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      }
287f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      Object result;
288f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      synchronized (parent.mFetchLock) {
289f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        result = parent.mFetchResult;
290f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      }
291f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      if (result == null) {
292f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        return;
293f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      }
294f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      parent.onMtpImageDataFetchedFromDevice(result);
295c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu    }
296f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
297c8a9e86919dca8938948f97efc3dcbe143e806bfBobby Georgescu}
298