1ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi/*
21910b08fe7305339a8bd87d4eb7bc6e56abbfa29Shih-chia Cheng
3f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang * Copyright (C) 2011 The Android Open Source Project
4ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi *
5ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi * Licensed under the Apache License, Version 2.0 (the "License");
6ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi * you may not use this file except in compliance with the License.
7ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi * You may obtain a copy of the License at
8ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi *
9ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi *      http://www.apache.org/licenses/LICENSE-2.0
10ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi *
11ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi * Unless required by applicable law or agreed to in writing, software
12ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi * distributed under the License is distributed on an "AS IS" BASIS,
13ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi * See the License for the specific language governing permissions and
15ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi * limitations under the License.
16ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi */
17ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
1881393d6dc5767f7784a00958095614a37bf1a91aGil Dobjanschipackage com.android.videoeditor.widgets;
19ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
2081393d6dc5767f7784a00958095614a37bf1a91aGil Dobjanschiimport com.android.videoeditor.service.ApiService;
2181393d6dc5767f7784a00958095614a37bf1a91aGil Dobjanschiimport com.android.videoeditor.service.MovieMediaItem;
2281393d6dc5767f7784a00958095614a37bf1a91aGil Dobjanschiimport com.android.videoeditor.R;
23ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
24ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschiimport android.content.Context;
25ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschiimport android.graphics.Bitmap;
26ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschiimport android.graphics.Canvas;
271910b08fe7305339a8bd87d4eb7bc6e56abbfa29Shih-chia Chengimport android.graphics.Color;
281910b08fe7305339a8bd87d4eb7bc6e56abbfa29Shih-chia Chengimport android.graphics.Paint;
29ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschiimport android.graphics.Point;
30ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschiimport android.graphics.Rect;
31ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschiimport android.graphics.drawable.Drawable;
32ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschiimport android.util.AttributeSet;
33ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschiimport android.util.DisplayMetrics;
34ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschiimport android.util.Log;
35f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Changimport android.util.LruCache;
36ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschiimport android.view.Display;
37ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschiimport android.view.GestureDetector;
38ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschiimport android.view.MotionEvent;
39ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschiimport android.view.View;
40ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschiimport android.view.WindowManager;
41ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
42f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Changimport java.util.ArrayList;
43f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Changimport java.util.HashSet;
44f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Changimport java.util.Map;
45f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang
46ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi/**
471910b08fe7305339a8bd87d4eb7bc6e56abbfa29Shih-chia Cheng * Media item preview view on the timeline. This class assumes the media item is always put on a
481910b08fe7305339a8bd87d4eb7bc6e56abbfa29Shih-chia Cheng * MediaLinearLayout and is wrapped with a timeline scroll view.
49ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi */
50ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschipublic class MediaItemView extends View {
51ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    private static final String TAG = "MediaItemView";
52ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
53f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    // Static variables
54f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    private static Drawable sAddTransitionDrawable;
55f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    private static Drawable sEmptyFrameDrawable;
56f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    private static ThumbnailCache sThumbnailCache;
57ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
588f2abc8e2ffffd37487a6baae568bd7e11da9439Chih-Chung Chang    // Because MediaItemView may be recreated for the same MediaItem (it happens
598f2abc8e2ffffd37487a6baae568bd7e11da9439Chih-Chung Chang    // when the device orientation is changed), we use a globally unique
608f2abc8e2ffffd37487a6baae568bd7e11da9439Chih-Chung Chang    // generation counter to reject thumbnail results (passed to setBitmap())
618f2abc8e2ffffd37487a6baae568bd7e11da9439Chih-Chung Chang    // requested by a previous incarnation of MediaItemView.
628f2abc8e2ffffd37487a6baae568bd7e11da9439Chih-Chung Chang    private static int sGenerationCounter;
638f2abc8e2ffffd37487a6baae568bd7e11da9439Chih-Chung Chang
64ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    // Instance variables
65ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    private final GestureDetector mGestureDetector;
66ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    private final ScrollViewListener mScrollListener;
6724318ced8e2cae0f300bd4360b8bf25d322a0b1cShih-chia Cheng    private final Rect mGeneratingEffectProgressDestRect;
68ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
69ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    private boolean mIsScrolling;
70ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    private boolean mIsPlaying;
71ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
7224318ced8e2cae0f300bd4360b8bf25d322a0b1cShih-chia Cheng    // Progress of generation of the effect applied on this media item view.
7324318ced8e2cae0f300bd4360b8bf25d322a0b1cShih-chia Cheng    // -1 indicates the generation is not in progress. 0-100 indicates the
7424318ced8e2cae0f300bd4360b8bf25d322a0b1cShih-chia Cheng    // generation is in progress. Currently only Ken Burns effect is used with
7524318ced8e2cae0f300bd4360b8bf25d322a0b1cShih-chia Cheng    // the progress bar.
7624318ced8e2cae0f300bd4360b8bf25d322a0b1cShih-chia Cheng    private int mGeneratingEffectProgress;
7724318ced8e2cae0f300bd4360b8bf25d322a0b1cShih-chia Cheng
7824318ced8e2cae0f300bd4360b8bf25d322a0b1cShih-chia Cheng    // The scrolled left pixels of this view.
79f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    private int mScrollX;
80ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
81f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    private String mProjectPath;
82f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    private MovieMediaItem mMediaItem;
831910b08fe7305339a8bd87d4eb7bc6e56abbfa29Shih-chia Cheng    // Convenient handle to the parent timeline scroll view.
841910b08fe7305339a8bd87d4eb7bc6e56abbfa29Shih-chia Cheng    private TimelineHorizontalScrollView mScrollView;
851910b08fe7305339a8bd87d4eb7bc6e56abbfa29Shih-chia Cheng    // Convenient handle to the parent timeline linear layout.
861910b08fe7305339a8bd87d4eb7bc6e56abbfa29Shih-chia Cheng    private MediaLinearLayout mTimeline;
87f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    private ItemSimpleGestureListener mGestureListener;
88f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    private int[] mLeftState, mRightState;
89ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
9024318ced8e2cae0f300bd4360b8bf25d322a0b1cShih-chia Cheng    private int mScreenWidth;
91f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    private int mThumbnailWidth, mThumbnailHeight;
92f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    private int mNumberOfThumbnails;
93f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    private long mBeginTimeMs, mEndTimeMs;
94ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
95f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    private int mGeneration;
96f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    private HashSet<Integer> mPending;
97f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    private ArrayList<Integer> mWantThumbnails;
98ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
99f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    public MediaItemView(Context context, AttributeSet attrs) {
100f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        this(context, attrs, 0);
101f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    }
102ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
103f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    public MediaItemView(Context context) {
104f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        this(context, null, 0);
105ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
106ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
107ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    public MediaItemView(Context context, AttributeSet attrs, int defStyle) {
108ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        super(context, attrs, defStyle);
109ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
110f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        // Initialize static data
111f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        if (sAddTransitionDrawable == null) {
112f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            sAddTransitionDrawable = getResources().getDrawable(
113f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                    R.drawable.add_transition_selector);
114f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            sEmptyFrameDrawable = getResources().getDrawable(
115f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                    R.drawable.timeline_loading);
116ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
117f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            // Initialize the thumbnail cache, limit the memory usage to 3MB
118f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            sThumbnailCache = new ThumbnailCache(3*1024*1024);
119f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        }
120ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
121f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        // Get the screen width
122f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        final Display display = ((WindowManager)context.getSystemService(
123f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                Context.WINDOW_SERVICE)).getDefaultDisplay();
124f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        final DisplayMetrics metrics = new DisplayMetrics();
125f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        display.getMetrics(metrics);
126f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        mScreenWidth = metrics.widthPixels;
12777a3d89eaf839df50c2f3b4ddb0819ed974726b6Gil Dobjanschi
128f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        // Setup our gesture detector and scroll listener
129f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        mGestureDetector = new GestureDetector(context, new MyGestureListener());
130f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        mScrollListener = new MyScrollViewListener();
131ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
132f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        // Prepare the progress bar rectangles
133ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        final ProgressBar progressBar = ProgressBar.getProgressBar(context);
134f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        final int layoutHeight = (int)(
135f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                getResources().getDimension(R.dimen.media_layout_height) -
136f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                getResources().getDimension(R.dimen.media_layout_padding));
13724318ced8e2cae0f300bd4360b8bf25d322a0b1cShih-chia Cheng        mGeneratingEffectProgressDestRect = new Rect(getPaddingLeft(),
138ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi                layoutHeight - progressBar.getHeight() - getPaddingBottom(), 0,
139ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi                layoutHeight - getPaddingBottom());
140ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
141ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        // Initialize the progress value
14224318ced8e2cae0f300bd4360b8bf25d322a0b1cShih-chia Cheng        mGeneratingEffectProgress = -1;
143ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
144f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        // Initialize the "Add transition" indicators state
145f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        mLeftState = View.EMPTY_STATE_SET;
146f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        mRightState = View.EMPTY_STATE_SET;
147ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
148f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        // Initialize the thumbnail indices we want to request
149f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        mWantThumbnails = new ArrayList<Integer>();
15077a3d89eaf839df50c2f3b4ddb0819ed974726b6Gil Dobjanschi
151f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        // Initialize the set of indices we are waiting
152f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        mPending = new HashSet<Integer>();
1538f2abc8e2ffffd37487a6baae568bd7e11da9439Chih-Chung Chang
1548f2abc8e2ffffd37487a6baae568bd7e11da9439Chih-Chung Chang        // Initialize the generation number
1558f2abc8e2ffffd37487a6baae568bd7e11da9439Chih-Chung Chang        mGeneration = sGenerationCounter++;
156f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    }
157ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
158f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    private class MyGestureListener extends GestureDetector.SimpleOnGestureListener {
159f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        @Override
160f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        public boolean onSingleTapConfirmed(MotionEvent e) {
161f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            if (mGestureListener == null) {
162f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                return false;
163f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            }
164ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
165f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            int tappedArea = ItemSimpleGestureListener.CENTER_AREA;
166f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang
16724318ced8e2cae0f300bd4360b8bf25d322a0b1cShih-chia Cheng            if (hasSpaceForAddTransitionIcons()) {
168f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                if (mMediaItem.getBeginTransition() == null &&
169f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                        e.getX() < sAddTransitionDrawable.getIntrinsicWidth() +
170f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                        getPaddingLeft()) {
171f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                    tappedArea = ItemSimpleGestureListener.LEFT_AREA;
172f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                } else if (mMediaItem.getEndTransition() == null &&
173f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                        e.getX() >= getWidth() - getPaddingRight() -
174f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                        sAddTransitionDrawable.getIntrinsicWidth()) {
175f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                    tappedArea = ItemSimpleGestureListener.RIGHT_AREA;
176f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                }
177f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            }
178f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            return mGestureListener.onSingleTapConfirmed(
179f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                    MediaItemView.this, tappedArea, e);
180f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        }
181ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
182f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        @Override
183f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        public void onLongPress(MotionEvent e) {
184f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            if (mGestureListener != null) {
185f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                mGestureListener.onLongPress(MediaItemView.this, e);
186f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            }
187f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        }
188ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
189ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
190f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    private class MyScrollViewListener implements ScrollViewListener {
191f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        @Override
192f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        public void onScrollBegin(View view, int scrollX, int scrollY, boolean appScroll) {
193f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            mIsScrolling = true;
194f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        }
195f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang
196f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        @Override
197f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        public void onScrollProgress(View view, int scrollX, int scrollY, boolean appScroll) {
198f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            mScrollX = scrollX;
199f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            invalidate();
200f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        }
201f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang
202f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        @Override
203f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        public void onScrollEnd(View view, int scrollX, int scrollY, boolean appScroll) {
204f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            mIsScrolling = false;
205f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            mScrollX = scrollX;
206f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            invalidate();
207f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        }
208ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
209ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
210ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    @Override
211ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    protected void onAttachedToWindow() {
2121910b08fe7305339a8bd87d4eb7bc6e56abbfa29Shih-chia Cheng        mMediaItem = (MovieMediaItem) getTag();
2131910b08fe7305339a8bd87d4eb7bc6e56abbfa29Shih-chia Cheng
2141910b08fe7305339a8bd87d4eb7bc6e56abbfa29Shih-chia Cheng        mScrollView = (TimelineHorizontalScrollView) getRootView().findViewById(
2151910b08fe7305339a8bd87d4eb7bc6e56abbfa29Shih-chia Cheng                R.id.timeline_scroller);
2161910b08fe7305339a8bd87d4eb7bc6e56abbfa29Shih-chia Cheng        mScrollView.addScrollListener(mScrollListener);
217ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        // Add the horizontal scroll view listener
2181910b08fe7305339a8bd87d4eb7bc6e56abbfa29Shih-chia Cheng        mScrollX = mScrollView.getScrollX();
2191910b08fe7305339a8bd87d4eb7bc6e56abbfa29Shih-chia Cheng
2201910b08fe7305339a8bd87d4eb7bc6e56abbfa29Shih-chia Cheng        mTimeline = (MediaLinearLayout) getRootView().findViewById(R.id.timeline_media);
221ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
222ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
223ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    @Override
224ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    protected void onDetachedFromWindow() {
2251910b08fe7305339a8bd87d4eb7bc6e56abbfa29Shih-chia Cheng        mScrollView.removeScrollListener(mScrollListener);
226f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        // Release the cached bitmaps
227f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        releaseBitmapsAndClear();
228ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
229ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
230ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    /**
231ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * @return The shadow builder
232ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     */
233ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    public DragShadowBuilder getShadowBuilder() {
234ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        return new MediaItemShadowBuilder(this);
235ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
236ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
237ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    /**
238f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang     * Shadow builder for the media item
239f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang     */
240f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    private class MediaItemShadowBuilder extends DragShadowBuilder {
241f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        private final Drawable mFrame;
242f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang
243f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        public MediaItemShadowBuilder(View view) {
244f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            super(view);
245f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            mFrame = view.getContext().getResources().getDrawable(
246f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                    R.drawable.timeline_item_pressed);
247f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        }
248f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang
249f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        @Override
250f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        public void onProvideShadowMetrics(Point shadowSize, Point shadowTouchPoint) {
251f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            shadowSize.set(getShadowWidth(), getShadowHeight());
252f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            shadowTouchPoint.set(shadowSize.x / 2, shadowSize.y);
253f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        }
254f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang
255f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        @Override
256f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        public void onDrawShadow(Canvas canvas) {
257f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            mFrame.setBounds(0, 0, getShadowWidth(), getShadowHeight());
258f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            mFrame.draw(canvas);
259f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang
260f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            Bitmap bitmap = getOneThumbnail();
261f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            if (bitmap != null) {
262f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                final View view = getView();
263f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                canvas.drawBitmap(bitmap, view.getPaddingLeft(),
264f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                        view.getPaddingTop(), null);
265f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            }
266f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        }
267f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    }
268f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang
269f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    /**
270ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * @return The shadow width
271ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     */
272f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    private int getShadowWidth() {
273ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        final int thumbnailHeight = getHeight() - getPaddingTop() - getPaddingBottom();
274f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        final int thumbnailWidth = (thumbnailHeight * mMediaItem.getWidth()) /
275f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            mMediaItem.getHeight();
276ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        return thumbnailWidth + getPaddingLeft() + getPaddingRight();
277ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
278ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
279ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    /**
280ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * @return The shadow height
281ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     */
282f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    private int getShadowHeight() {
283ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        return getHeight();
284ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
285ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
286f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    private Bitmap getOneThumbnail() {
287f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        ThumbnailKey key = new ThumbnailKey();
288f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        key.mediaItemId = mMediaItem.getId();
289f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang
290f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        // Find any one cached thumbnail
291f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        for (int i = 0; i < mNumberOfThumbnails; i++) {
292f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            key.index = i;
293f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            Bitmap bitmap = sThumbnailCache.get(key);
294f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            if (bitmap != null) {
295f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                return bitmap;
296f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            }
297f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        }
298f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang
299f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        return null;
300f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    }
301f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang
302ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    /**
303ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * @param projectPath The project path
304ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     */
305ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    public void setProjectPath(String projectPath) {
306ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        mProjectPath = projectPath;
307ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
308ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
309ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    /**
310ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * @param listener The gesture listener
311ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     */
312ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    public void setGestureListener(ItemSimpleGestureListener listener) {
313ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        mGestureListener = listener;
314ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
315ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
316ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    /**
317f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang     * A view enters or exits the playback mode
31803699548e6f627af79aac4fd0d233f10e53841d0Gil Dobjanschi     *
319f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang     * @param playback true if playback is in progress
320ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     */
321f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    public void setPlaybackMode(boolean playback) {
322f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        mIsPlaying = playback;
323f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        invalidate();
324f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    }
325ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
326f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    /**
32724318ced8e2cae0f300bd4360b8bf25d322a0b1cShih-chia Cheng     * Resets the effect generation progress status.
32824318ced8e2cae0f300bd4360b8bf25d322a0b1cShih-chia Cheng     */
32924318ced8e2cae0f300bd4360b8bf25d322a0b1cShih-chia Cheng    public void resetGeneratingEffectProgress() {
33024318ced8e2cae0f300bd4360b8bf25d322a0b1cShih-chia Cheng        setGeneratingEffectProgress(-1);
33124318ced8e2cae0f300bd4360b8bf25d322a0b1cShih-chia Cheng    }
33224318ced8e2cae0f300bd4360b8bf25d322a0b1cShih-chia Cheng
33324318ced8e2cae0f300bd4360b8bf25d322a0b1cShih-chia Cheng    /**
33424318ced8e2cae0f300bd4360b8bf25d322a0b1cShih-chia Cheng     * Sets the effect generation progress of this view.
335ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     */
33624318ced8e2cae0f300bd4360b8bf25d322a0b1cShih-chia Cheng    public void setGeneratingEffectProgress(int progress) {
337ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        if (progress == 0) {
33824318ced8e2cae0f300bd4360b8bf25d322a0b1cShih-chia Cheng            mGeneratingEffectProgress = progress;
339ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            // Release the current set of bitmaps. New content is being generated.
340ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            releaseBitmapsAndClear();
341ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        } else if (progress == 100) {
34224318ced8e2cae0f300bd4360b8bf25d322a0b1cShih-chia Cheng            mGeneratingEffectProgress = -1;
343ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        } else {
34424318ced8e2cae0f300bd4360b8bf25d322a0b1cShih-chia Cheng            mGeneratingEffectProgress = progress;
345ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        }
346ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
347ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        invalidate();
348ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
349ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
350ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    /**
35124318ced8e2cae0f300bd4360b8bf25d322a0b1cShih-chia Cheng     * The view has been layout out.
352ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     *
353f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang     * @param oldLeft The old left position
354f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang     * @param oldRight The old right position
355ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     */
356f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    public void onLayoutPerformed(int oldLeft, int oldRight) {
357f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        // Compute the thumbnail width and height
358f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        mThumbnailHeight = getHeight() - getPaddingTop() - getPaddingBottom();
359f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        mThumbnailWidth = (mThumbnailHeight * mMediaItem.getWidth()) / mMediaItem.getHeight();
360ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
361b05b86bc5ac360df08b1951998a8f3540e3cae4fChih-Chung Chang        // We are not able to display a bitmap with width or height > 2048.
362b05b86bc5ac360df08b1951998a8f3540e3cae4fChih-Chung Chang        while (mThumbnailWidth > 2048 || mThumbnailHeight > 2048) {
363b05b86bc5ac360df08b1951998a8f3540e3cae4fChih-Chung Chang            mThumbnailHeight /= 2;
364b05b86bc5ac360df08b1951998a8f3540e3cae4fChih-Chung Chang            mThumbnailWidth /= 2;
365b05b86bc5ac360df08b1951998a8f3540e3cae4fChih-Chung Chang        }
366b05b86bc5ac360df08b1951998a8f3540e3cae4fChih-Chung Chang
367f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        int usableWidth = getWidth() - getPaddingLeft() - getPaddingRight();
36824318ced8e2cae0f300bd4360b8bf25d322a0b1cShih-chia Cheng        // Compute the ceiling of (usableWidth / mThumbnailWidth).
369f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        mNumberOfThumbnails = (usableWidth + mThumbnailWidth - 1) / mThumbnailWidth;
370f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        mBeginTimeMs = mMediaItem.getAppBoundaryBeginTime();
371f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        mEndTimeMs = mMediaItem.getAppBoundaryEndTime();
372ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
373f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        releaseBitmapsAndClear();
374f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        invalidate();
375ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
376ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
377ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    /**
37824318ced8e2cae0f300bd4360b8bf25d322a0b1cShih-chia Cheng     * @return True if the effect generation is in progress
379ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     */
38024318ced8e2cae0f300bd4360b8bf25d322a0b1cShih-chia Cheng    public boolean isGeneratingEffect() {
38124318ced8e2cae0f300bd4360b8bf25d322a0b1cShih-chia Cheng        return (mGeneratingEffectProgress >= 0);
382f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    }
383ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
384f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    public boolean setBitmap(Bitmap bitmap, int index, int token) {
385f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        // Ignore results from previous requests
386f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        if (token != mGeneration) {
387ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            return false;
388f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        }
389f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        if (!mPending.contains(index)) {
390f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            Log.e(TAG, "received unasked bitmap, index = " + index);
391ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            return false;
392ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        }
393f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        if (bitmap == null) {
394f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            Log.w(TAG, "receive null bitmap for index = " + index);
395f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            // We keep this request in mPending, so we won't request it again.
396f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            return false;
397ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        }
398f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        mPending.remove(index);
399f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        ThumbnailKey key = new ThumbnailKey(mMediaItem.getId(), index);
400f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        sThumbnailCache.put(key, bitmap);
401ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
402ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        invalidate();
403ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        return true;
404ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
405ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
406ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    @Override
407ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    protected void onDraw(Canvas canvas) {
408ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        super.onDraw(canvas);
40924318ced8e2cae0f300bd4360b8bf25d322a0b1cShih-chia Cheng        if (mGeneratingEffectProgress >= 0) {
410f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            ProgressBar.getProgressBar(getContext()).draw(
41124318ced8e2cae0f300bd4360b8bf25d322a0b1cShih-chia Cheng                    canvas, mGeneratingEffectProgress, mGeneratingEffectProgressDestRect,
412f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                    getPaddingLeft(), getWidth() - getPaddingRight());
413f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        } else {
414ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            // Do not draw in the padding area
415f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            canvas.clipRect(getPaddingLeft(), getPaddingTop(),
416f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                    getWidth() - getPaddingRight(),
417ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi                    getHeight() - getPaddingBottom());
418ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
419f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            // Draw thumbnails
420f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            drawThumbnails(canvas);
421ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
422f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            // Draw the "Add transition" indicators
423ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            if (isSelected()) {
42424318ced8e2cae0f300bd4360b8bf25d322a0b1cShih-chia Cheng                drawAddTransitionIcons(canvas);
4251910b08fe7305339a8bd87d4eb7bc6e56abbfa29Shih-chia Cheng            } else if (mTimeline.hasItemSelected()) {
4261910b08fe7305339a8bd87d4eb7bc6e56abbfa29Shih-chia Cheng                // Dim myself if some view on the timeline is selected but not me
4271910b08fe7305339a8bd87d4eb7bc6e56abbfa29Shih-chia Cheng                // by drawing a transparent black overlay.
4281910b08fe7305339a8bd87d4eb7bc6e56abbfa29Shih-chia Cheng                final Paint paint = new Paint();
4291910b08fe7305339a8bd87d4eb7bc6e56abbfa29Shih-chia Cheng                paint.setColor(Color.BLACK);
4301910b08fe7305339a8bd87d4eb7bc6e56abbfa29Shih-chia Cheng                paint.setAlpha(192);
4311910b08fe7305339a8bd87d4eb7bc6e56abbfa29Shih-chia Cheng                canvas.drawPaint(paint);
432ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            }
433ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
434f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            // Request thumbnails if things are not moving
4351910b08fe7305339a8bd87d4eb7bc6e56abbfa29Shih-chia Cheng            boolean isBusy = mIsPlaying || mTimeline.isTrimming() || mIsScrolling;
436f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            if (!isBusy && !mWantThumbnails.isEmpty()) {
437f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                requestThumbnails();
438ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            }
439ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        }
440ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
441ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
442f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    // Draws the thumbnails, also put unavailable thumbnail indices in
443f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    // mWantThumbnails.
44477a3d89eaf839df50c2f3b4ddb0819ed974726b6Gil Dobjanschi    private void drawThumbnails(Canvas canvas) {
445f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        mWantThumbnails.clear();
446f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang
447f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        // The screen coordinate of the left edge of the usable area.
448f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        int left = getLeft() + getPaddingLeft() - mScrollX;
449f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        // The screen coordinate of the right edge of the usable area.
450f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        int right = getRight() - getPaddingRight() - mScrollX;
451f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        // Return if the usable area is not on screen.
452f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        if (left >= mScreenWidth || right <= 0 || left >= right) {
453ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            return;
454ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        }
455ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
456f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        // Map [0, mScreenWidth - 1] to the indices of the thumbnail.
457f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        int startIdx = (0 - left) / mThumbnailWidth;
458f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        int endIdx = (mScreenWidth - 1 - left) / mThumbnailWidth;
459ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
460f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        startIdx = clamp(startIdx, 0, mNumberOfThumbnails - 1);
461f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        endIdx = clamp(endIdx, 0, mNumberOfThumbnails - 1);
462ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
463f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        // Prepare variables used in the loop
464f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        ThumbnailKey key = new ThumbnailKey();
465f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        key.mediaItemId = mMediaItem.getId();
466f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        int x = getPaddingLeft() + startIdx * mThumbnailWidth;
467f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        int y = getPaddingTop();
46877a3d89eaf839df50c2f3b4ddb0819ed974726b6Gil Dobjanschi
469b05b86bc5ac360df08b1951998a8f3540e3cae4fChih-Chung Chang        // Center the thumbnail vertically
470b05b86bc5ac360df08b1951998a8f3540e3cae4fChih-Chung Chang        int spacing = (getHeight() - getPaddingTop() - getPaddingBottom() -
471b05b86bc5ac360df08b1951998a8f3540e3cae4fChih-Chung Chang                mThumbnailHeight) / 2;
472b05b86bc5ac360df08b1951998a8f3540e3cae4fChih-Chung Chang        y += spacing;
473b05b86bc5ac360df08b1951998a8f3540e3cae4fChih-Chung Chang
474f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        // Loop through the thumbnails on screen and draw it
475f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        for (int i = startIdx; i <= endIdx; i++) {
476f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            key.index = i;
477f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            Bitmap bitmap = sThumbnailCache.get(key);
478f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            if (bitmap == null) {
47977a3d89eaf839df50c2f3b4ddb0819ed974726b6Gil Dobjanschi                // Draw a frame placeholder
480f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                sEmptyFrameDrawable.setBounds(
481f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                        x, y, x + mThumbnailWidth, y + mThumbnailHeight);
482f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                sEmptyFrameDrawable.draw(canvas);
483f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                if (!mPending.contains(i)) {
484f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                    mWantThumbnails.add(Integer.valueOf(i));
48577a3d89eaf839df50c2f3b4ddb0819ed974726b6Gil Dobjanschi                }
486f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            } else {
487f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                canvas.drawBitmap(bitmap, x, y, null);
48877a3d89eaf839df50c2f3b4ddb0819ed974726b6Gil Dobjanschi            }
489f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            x += mThumbnailWidth;
490ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        }
491ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
492ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
493ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    /**
49424318ced8e2cae0f300bd4360b8bf25d322a0b1cShih-chia Cheng     * Draws the "Add transition" icons at the beginning and end of the media item.
495ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     *
49624318ced8e2cae0f300bd4360b8bf25d322a0b1cShih-chia Cheng     * @param canvas Canvas to be drawn
497ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     */
49824318ced8e2cae0f300bd4360b8bf25d322a0b1cShih-chia Cheng    private void drawAddTransitionIcons(Canvas canvas) {
49924318ced8e2cae0f300bd4360b8bf25d322a0b1cShih-chia Cheng        if (hasSpaceForAddTransitionIcons()) {
500f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            if (mMediaItem.getBeginTransition() == null) {
501f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                sAddTransitionDrawable.setState(mLeftState);
502f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                sAddTransitionDrawable.setBounds(getPaddingLeft(), getPaddingTop(),
503f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                        sAddTransitionDrawable.getIntrinsicWidth() + getPaddingLeft(),
504f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                        getPaddingTop() + sAddTransitionDrawable.getIntrinsicHeight());
505f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                sAddTransitionDrawable.draw(canvas);
506ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            }
507ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
508f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            if (mMediaItem.getEndTransition() == null) {
509f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                sAddTransitionDrawable.setState(mRightState);
510f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                sAddTransitionDrawable.setBounds(
511ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi                        getWidth() - getPaddingRight() -
512f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                        sAddTransitionDrawable.getIntrinsicWidth(),
513ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi                        getPaddingTop(), getWidth() - getPaddingRight(),
514f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                        getPaddingTop() + sAddTransitionDrawable.getIntrinsicHeight());
515f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                sAddTransitionDrawable.draw(canvas);
516ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            }
517ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        }
518ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
519ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
520ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    /**
52124318ced8e2cae0f300bd4360b8bf25d322a0b1cShih-chia Cheng     * @return true if the visible area of this view is big enough to display
52224318ced8e2cae0f300bd4360b8bf25d322a0b1cShih-chia Cheng     *      "add transition" icons on both sides; false otherwise.
523ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     */
52424318ced8e2cae0f300bd4360b8bf25d322a0b1cShih-chia Cheng    private boolean hasSpaceForAddTransitionIcons() {
5251910b08fe7305339a8bd87d4eb7bc6e56abbfa29Shih-chia Cheng        if (mTimeline.isTrimming()) {
526ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            return false;
527ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        }
528ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
529ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        return (getWidth() - getPaddingLeft() - getPaddingRight() >=
530f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                2 * sAddTransitionDrawable.getIntrinsicWidth());
531f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    }
532f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang
53324318ced8e2cae0f300bd4360b8bf25d322a0b1cShih-chia Cheng    /**
53424318ced8e2cae0f300bd4360b8bf25d322a0b1cShih-chia Cheng     * Clamps the input value v to the range [low, high].
53524318ced8e2cae0f300bd4360b8bf25d322a0b1cShih-chia Cheng     */
536f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    private static int clamp(int v, int low, int high) {
537f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        return Math.min(Math.max(v, low), high);
538f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    }
539f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang
54024318ced8e2cae0f300bd4360b8bf25d322a0b1cShih-chia Cheng    /**
54124318ced8e2cae0f300bd4360b8bf25d322a0b1cShih-chia Cheng     * Requests the thumbnails in mWantThumbnails (which is filled by onDraw).
54224318ced8e2cae0f300bd4360b8bf25d322a0b1cShih-chia Cheng     */
543f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    private void requestThumbnails() {
544f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        // Copy mWantThumbnails to an array
545f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        int indices[] = new int[mWantThumbnails.size()];
546f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        for (int i = 0; i < mWantThumbnails.size(); i++) {
547f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            indices[i] = mWantThumbnails.get(i);
548f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        }
549f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang
550f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        // Put them in the pending set
551f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        mPending.addAll(mWantThumbnails);
552f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang
553f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        ApiService.getMediaItemThumbnails(getContext(), mProjectPath,
554f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                mMediaItem.getId(), mThumbnailWidth, mThumbnailHeight,
555f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                mBeginTimeMs, mEndTimeMs, mNumberOfThumbnails, mGeneration,
556f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                indices);
557ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
558ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
559ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    @Override
560ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    public boolean onTouchEvent(MotionEvent ev) {
561ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        // Let the gesture detector inspect all events.
562ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        mGestureDetector.onTouchEvent(ev);
563ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        super.onTouchEvent(ev);
564ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
565ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        switch (ev.getAction()) {
566ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            case MotionEvent.ACTION_DOWN: {
567f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                mLeftState = View.EMPTY_STATE_SET;
568f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                mRightState = View.EMPTY_STATE_SET;
56924318ced8e2cae0f300bd4360b8bf25d322a0b1cShih-chia Cheng                if (isSelected() && hasSpaceForAddTransitionIcons()) {
570f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                    if (ev.getX() < sAddTransitionDrawable.getIntrinsicWidth() +
571ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi                            getPaddingLeft()) {
572f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                        if (mMediaItem.getBeginTransition() == null) {
573ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi                            mLeftState = View.PRESSED_WINDOW_FOCUSED_STATE_SET;
574ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi                        }
575ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi                    } else if (ev.getX() >= getWidth() - getPaddingRight() -
576f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                            sAddTransitionDrawable.getIntrinsicWidth()) {
577f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                        if (mMediaItem.getEndTransition() == null) {
578ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi                            mRightState = View.PRESSED_WINDOW_FOCUSED_STATE_SET;
579ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi                        }
580ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi                    }
581ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi                }
582ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi                invalidate();
583ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi                break;
584ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            }
585ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
586ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            case MotionEvent.ACTION_UP:
587ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            case MotionEvent.ACTION_CANCEL: {
588ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi                mRightState = View.EMPTY_STATE_SET;
589ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi                mLeftState = View.EMPTY_STATE_SET;
590ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi                invalidate();
591ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi                break;
592ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            }
593ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
594ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            default: {
595ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi                break;
596ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            }
597ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        }
598ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
599ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        return true;
600ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
601ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
602f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    private void releaseBitmapsAndClear() {
603f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        sThumbnailCache.clearForMediaItemId(mMediaItem.getId());
604f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        mPending.clear();
6058f2abc8e2ffffd37487a6baae568bd7e11da9439Chih-Chung Chang        mGeneration = sGenerationCounter++;
606f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    }
607f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang}
608ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
609f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Changclass ThumbnailKey {
610f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    public String mediaItemId;
611f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    public int index;
612ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
613f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    public ThumbnailKey() {
614f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    }
615ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
616f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    public ThumbnailKey(String id, int idx) {
617f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        mediaItemId = id;
618f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        index = idx;
619f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    }
620ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
621f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    @Override
622f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    public boolean equals(Object o) {
623f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        if (!(o instanceof ThumbnailKey)) {
624f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            return false;
625ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        }
626f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        ThumbnailKey key = (ThumbnailKey) o;
627f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        return index == key.index && mediaItemId.equals(key.mediaItemId);
628f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    }
629ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
630f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    @Override
631f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    public int hashCode() {
632f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        return mediaItemId.hashCode() ^ index;
633f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    }
634f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang}
635ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
636f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Changclass ThumbnailCache {
637f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    private LruCache<ThumbnailKey, Bitmap> mCache;
638ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
639f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    public ThumbnailCache(int size) {
64024318ced8e2cae0f300bd4360b8bf25d322a0b1cShih-chia Cheng        mCache = new LruCache<ThumbnailKey, Bitmap>(size) {
64124318ced8e2cae0f300bd4360b8bf25d322a0b1cShih-chia Cheng            @Override
642f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            protected int sizeOf(ThumbnailKey key, Bitmap value) {
643f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                return value.getByteCount();
644ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            }
645f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        };
646ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
647ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
648f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    void put(ThumbnailKey key, Bitmap value) {
649f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        mCache.put(key, value);
650ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
651ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
652f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    Bitmap get(ThumbnailKey key) {
653f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        return mCache.get(key);
654f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    }
655ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
656f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    void clearForMediaItemId(String id) {
657f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        Map<ThumbnailKey, Bitmap> map = mCache.snapshot();
658f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        for (ThumbnailKey key : map.keySet()) {
659f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            if (key.mediaItemId.equals(id)) {
660f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                mCache.remove(key);
661ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            }
662ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        }
663ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
664ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi}
665