MediaItemView.java revision f6b29b560e55392015caebeffbe76f8a1d1ddeb4
1ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi/*
2f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang * Copyright (C) 2011 The Android Open Source Project
3ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi *
4ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi * Licensed under the Apache License, Version 2.0 (the "License");
5ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi * you may not use this file except in compliance with the License.
6ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi * You may obtain a copy of the License at
7ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi *
8ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi *      http://www.apache.org/licenses/LICENSE-2.0
9ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi *
10ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi * Unless required by applicable law or agreed to in writing, software
11ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi * distributed under the License is distributed on an "AS IS" BASIS,
12ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi * See the License for the specific language governing permissions and
14ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi * limitations under the License.
15ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi */
16ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
1781393d6dc5767f7784a00958095614a37bf1a91aGil Dobjanschipackage com.android.videoeditor.widgets;
18ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
1981393d6dc5767f7784a00958095614a37bf1a91aGil Dobjanschiimport com.android.videoeditor.service.ApiService;
2081393d6dc5767f7784a00958095614a37bf1a91aGil Dobjanschiimport com.android.videoeditor.service.MovieMediaItem;
2181393d6dc5767f7784a00958095614a37bf1a91aGil Dobjanschiimport com.android.videoeditor.R;
22ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
23ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschiimport android.content.Context;
24ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschiimport android.graphics.Bitmap;
25ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschiimport android.graphics.Canvas;
26ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschiimport android.graphics.Point;
27ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschiimport android.graphics.Rect;
28ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschiimport android.graphics.drawable.Drawable;
29ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschiimport android.util.AttributeSet;
30ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschiimport android.util.DisplayMetrics;
31ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschiimport android.util.Log;
32f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Changimport android.util.LruCache;
33ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschiimport android.view.Display;
34ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschiimport android.view.GestureDetector;
35ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschiimport android.view.MotionEvent;
36ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschiimport android.view.View;
37ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschiimport android.view.WindowManager;
38ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
39f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Changimport java.util.ArrayList;
40f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Changimport java.util.HashSet;
41f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Changimport java.util.Map;
42f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang
43ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi/**
44ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi * Media item preview view
45ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi */
46ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschipublic class MediaItemView extends View {
47ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    private static final String TAG = "MediaItemView";
48ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
49f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    // Static variables
50f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    private static Drawable sAddTransitionDrawable;
51f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    private static Drawable sEmptyFrameDrawable;
52f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    private static ThumbnailCache sThumbnailCache;
53ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
54ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    // Instance variables
55ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    private final GestureDetector mGestureDetector;
56ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    private final ScrollViewListener mScrollListener;
57ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    private final Rect mProgressDestRect;
58ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
59ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    private boolean mIsScrolling;
60ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    private boolean mIsTrimming;
61ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    private boolean mIsPlaying;
62f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    private int mProgress;  // -1: not in progress, 0-100: in progress
63ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
64f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    private static int mScreenWidth;
65f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    private int mScrollX;
66ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
67f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    private String mProjectPath;
68f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    private MovieMediaItem mMediaItem;
69f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    private ItemSimpleGestureListener mGestureListener;
70f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    private int[] mLeftState, mRightState;
71ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
72f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    private int mThumbnailWidth, mThumbnailHeight;
73f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    private int mNumberOfThumbnails;
74f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    private long mBeginTimeMs, mEndTimeMs;
75ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
76f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    private int mGeneration;
77f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    private HashSet<Integer> mPending;
78f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    private ArrayList<Integer> mWantThumbnails;
79ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
80f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    public MediaItemView(Context context, AttributeSet attrs) {
81f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        this(context, attrs, 0);
82f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    }
83ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
84f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    public MediaItemView(Context context) {
85f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        this(context, null, 0);
86ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
87ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
88ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    public MediaItemView(Context context, AttributeSet attrs, int defStyle) {
89ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        super(context, attrs, defStyle);
90ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
91f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        // Initialize static data
92f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        if (sAddTransitionDrawable == null) {
93f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            sAddTransitionDrawable = getResources().getDrawable(
94f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                    R.drawable.add_transition_selector);
95f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            sEmptyFrameDrawable = getResources().getDrawable(
96f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                    R.drawable.timeline_loading);
97ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
98f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            // Initialize the thumbnail cache, limit the memory usage to 3MB
99f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            sThumbnailCache = new ThumbnailCache(3*1024*1024);
100f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        }
101ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
102f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        // Get the screen width
103f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        final Display display = ((WindowManager)context.getSystemService(
104f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                Context.WINDOW_SERVICE)).getDefaultDisplay();
105f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        final DisplayMetrics metrics = new DisplayMetrics();
106f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        display.getMetrics(metrics);
107f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        mScreenWidth = metrics.widthPixels;
10877a3d89eaf839df50c2f3b4ddb0819ed974726b6Gil Dobjanschi
109f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        // Setup our gesture detector and scroll listener
110f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        mGestureDetector = new GestureDetector(context, new MyGestureListener());
111f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        mScrollListener = new MyScrollViewListener();
112ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
113f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        // Prepare the progress bar rectangles
114ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        final ProgressBar progressBar = ProgressBar.getProgressBar(context);
115f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        final int layoutHeight = (int)(
116f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                getResources().getDimension(R.dimen.media_layout_height) -
117f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                getResources().getDimension(R.dimen.media_layout_padding));
118ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        mProgressDestRect = new Rect(getPaddingLeft(),
119ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi                layoutHeight - progressBar.getHeight() - getPaddingBottom(), 0,
120ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi                layoutHeight - getPaddingBottom());
121ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
122ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        // Initialize the progress value
123ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        mProgress = -1;
124ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
125f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        // Initialize the "Add transition" indicators state
126f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        mLeftState = View.EMPTY_STATE_SET;
127f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        mRightState = View.EMPTY_STATE_SET;
128ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
129f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        // Initialize the thumbnail indices we want to request
130f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        mWantThumbnails = new ArrayList<Integer>();
13177a3d89eaf839df50c2f3b4ddb0819ed974726b6Gil Dobjanschi
132f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        // Initialize the set of indices we are waiting
133f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        mPending = new HashSet<Integer>();
134f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    }
135ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
136f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    private class MyGestureListener extends GestureDetector.SimpleOnGestureListener {
137f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        @Override
138f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        public boolean onSingleTapConfirmed(MotionEvent e) {
139f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            if (mGestureListener == null) {
140f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                return false;
141f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            }
142ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
143f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            int tappedArea = ItemSimpleGestureListener.CENTER_AREA;
144f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang
145f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            if (hasAddTransition()) {
146f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                if (mMediaItem.getBeginTransition() == null &&
147f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                        e.getX() < sAddTransitionDrawable.getIntrinsicWidth() +
148f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                        getPaddingLeft()) {
149f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                    tappedArea = ItemSimpleGestureListener.LEFT_AREA;
150f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                } else if (mMediaItem.getEndTransition() == null &&
151f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                        e.getX() >= getWidth() - getPaddingRight() -
152f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                        sAddTransitionDrawable.getIntrinsicWidth()) {
153f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                    tappedArea = ItemSimpleGestureListener.RIGHT_AREA;
154f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                }
155f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            }
156f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            return mGestureListener.onSingleTapConfirmed(
157f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                    MediaItemView.this, tappedArea, e);
158f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        }
159ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
160f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        @Override
161f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        public void onLongPress(MotionEvent e) {
162f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            if (mGestureListener != null) {
163f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                mGestureListener.onLongPress(MediaItemView.this, e);
164f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            }
165f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        }
166ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
167ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
168f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    private class MyScrollViewListener implements ScrollViewListener {
169f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        @Override
170f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        public void onScrollBegin(View view, int scrollX, int scrollY, boolean appScroll) {
171f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            mIsScrolling = true;
172f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        }
173f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang
174f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        @Override
175f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        public void onScrollProgress(View view, int scrollX, int scrollY, boolean appScroll) {
176f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            mScrollX = scrollX;
177f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            invalidate();
178f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        }
179f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang
180f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        @Override
181f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        public void onScrollEnd(View view, int scrollX, int scrollY, boolean appScroll) {
182f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            mIsScrolling = false;
183f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            mScrollX = scrollX;
184f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            invalidate();
185f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        }
186ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
187ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
188ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    @Override
189ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    protected void onAttachedToWindow() {
190f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        mMediaItem = (MovieMediaItem)getTag();
191ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        // Add the horizontal scroll view listener
192ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        final TimelineHorizontalScrollView scrollView =
193ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi                (TimelineHorizontalScrollView)((View)((View)getParent()).getParent()).getParent();
194f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        mScrollX = scrollView.getScrollX();
195ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        scrollView.addScrollListener(mScrollListener);
196ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
197ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
198ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    @Override
199ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    protected void onDetachedFromWindow() {
200ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        final TimelineHorizontalScrollView scrollView =
201f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                (TimelineHorizontalScrollView)((View)((View)getParent()).getParent()).getParent();
202ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        scrollView.removeScrollListener(mScrollListener);
203ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
204f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        // Release the cached bitmaps
205f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        releaseBitmapsAndClear();
206ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
207ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
208ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    /**
209ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * @return The shadow builder
210ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     */
211ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    public DragShadowBuilder getShadowBuilder() {
212ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        return new MediaItemShadowBuilder(this);
213ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
214ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
215ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    /**
216f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang     * Shadow builder for the media item
217f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang     */
218f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    private class MediaItemShadowBuilder extends DragShadowBuilder {
219f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        private final Drawable mFrame;
220f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang
221f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        public MediaItemShadowBuilder(View view) {
222f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            super(view);
223f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            mFrame = view.getContext().getResources().getDrawable(
224f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                    R.drawable.timeline_item_pressed);
225f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        }
226f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang
227f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        @Override
228f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        public void onProvideShadowMetrics(Point shadowSize, Point shadowTouchPoint) {
229f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            shadowSize.set(getShadowWidth(), getShadowHeight());
230f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            shadowTouchPoint.set(shadowSize.x / 2, shadowSize.y);
231f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        }
232f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang
233f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        @Override
234f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        public void onDrawShadow(Canvas canvas) {
235f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            mFrame.setBounds(0, 0, getShadowWidth(), getShadowHeight());
236f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            mFrame.draw(canvas);
237f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang
238f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            Bitmap bitmap = getOneThumbnail();
239f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            if (bitmap != null) {
240f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                final View view = getView();
241f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                canvas.drawBitmap(bitmap, view.getPaddingLeft(),
242f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                        view.getPaddingTop(), null);
243f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            }
244f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        }
245f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    }
246f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang
247f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    /**
248ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * @return The shadow width
249ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     */
250f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    private int getShadowWidth() {
251ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        final int thumbnailHeight = getHeight() - getPaddingTop() - getPaddingBottom();
252f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        final int thumbnailWidth = (thumbnailHeight * mMediaItem.getWidth()) /
253f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            mMediaItem.getHeight();
254ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        return thumbnailWidth + getPaddingLeft() + getPaddingRight();
255ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
256ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
257ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    /**
258ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * @return The shadow height
259ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     */
260f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    private int getShadowHeight() {
261ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        return getHeight();
262ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
263ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
264f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    private Bitmap getOneThumbnail() {
265f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        ThumbnailKey key = new ThumbnailKey();
266f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        key.mediaItemId = mMediaItem.getId();
267f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang
268f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        // Find any one cached thumbnail
269f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        for (int i = 0; i < mNumberOfThumbnails; i++) {
270f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            key.index = i;
271f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            Bitmap bitmap = sThumbnailCache.get(key);
272f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            if (bitmap != null) {
273f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                return bitmap;
274f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            }
275f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        }
276f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang
277f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        return null;
278f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    }
279f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang
280ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    /**
281ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * @param projectPath The project path
282ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     */
283ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    public void setProjectPath(String projectPath) {
284ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        mProjectPath = projectPath;
285ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
286ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
287ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    /**
288ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * @param listener The gesture listener
289ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     */
290ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    public void setGestureListener(ItemSimpleGestureListener listener) {
291ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        mGestureListener = listener;
292ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
293ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
294ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    /**
295f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang     * A view enters or exits the playback mode
29603699548e6f627af79aac4fd0d233f10e53841d0Gil Dobjanschi     *
297f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang     * @param playback true if playback is in progress
298ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     */
299f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    public void setPlaybackMode(boolean playback) {
300f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        mIsPlaying = playback;
301f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        invalidate();
302f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    }
303ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
304f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    /**
305f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang     * A view enters or exits the trimming mode
306f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang     *
307f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang     * @param trimmingView The view which is being trimmed
308f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang     * @param trimming true if trimming
309f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang     */
310f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    public void setTrimMode(View trimmingView, boolean trimming) {
311f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        mIsTrimming = trimming;
312f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        // Redraw the control to hide the "Add transition" areas
313f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        invalidate();
314ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
315ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
316ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    /**
317ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * @param progress The progress
318ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     */
319ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    public void setProgress(int progress) {
320ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        if (progress == 0) {
321ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            mProgress = progress;
322ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            // Release the current set of bitmaps. New content is being generated.
323ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            releaseBitmapsAndClear();
324ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        } else if (progress == 100) {
325ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            mProgress = -1;
326ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        } else {
327ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            mProgress = progress;
328ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        }
329ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
330ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        invalidate();
331ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
332ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
333ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    /**
334f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang     * The view has been layout out
335ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     *
336f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang     * @param oldLeft The old left position
337f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang     * @param oldRight The old right position
338ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     */
339f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    public void onLayoutPerformed(int oldLeft, int oldRight) {
340f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        // Compute the thumbnail width and height
341f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        mThumbnailHeight = getHeight() - getPaddingTop() - getPaddingBottom();
342f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        mThumbnailWidth = (mThumbnailHeight * mMediaItem.getWidth()) / mMediaItem.getHeight();
343ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
344f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        int usableWidth = getWidth() - getPaddingLeft() - getPaddingRight();
345f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        mNumberOfThumbnails = (usableWidth + mThumbnailWidth - 1) / mThumbnailWidth;
346f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        mBeginTimeMs = mMediaItem.getAppBoundaryBeginTime();
347f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        mEndTimeMs = mMediaItem.getAppBoundaryEndTime();
348ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
349f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        releaseBitmapsAndClear();
350f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        invalidate();
351ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
352ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
353ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    /**
354f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang     * @return True if generation is in progress
355ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     */
356f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    public boolean isInProgress() {
357f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        return (mProgress >= 0);
358f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    }
359ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
360f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    public boolean setBitmap(Bitmap bitmap, int index, int token) {
361f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        // Ignore results from previous requests
362f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        if (token != mGeneration) {
363ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            return false;
364f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        }
365f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        if (!mPending.contains(index)) {
366f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            Log.e(TAG, "received unasked bitmap, index = " + index);
367ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            return false;
368ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        }
369f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        if (bitmap == null) {
370f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            Log.w(TAG, "receive null bitmap for index = " + index);
371f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            // We keep this request in mPending, so we won't request it again.
372f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            return false;
373ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        }
374f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        mPending.remove(index);
375f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        ThumbnailKey key = new ThumbnailKey(mMediaItem.getId(), index);
376f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        sThumbnailCache.put(key, bitmap);
377ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
378ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        invalidate();
379ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        return true;
380ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
381ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
382ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    @Override
383ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    protected void onDraw(Canvas canvas) {
384ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        super.onDraw(canvas);
385ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        if (mProgress >= 0) {
386f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            ProgressBar.getProgressBar(getContext()).draw(
387f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                    canvas, mProgress, mProgressDestRect,
388f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                    getPaddingLeft(), getWidth() - getPaddingRight());
389f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        } else {
390ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            // Do not draw in the padding area
391f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            canvas.clipRect(getPaddingLeft(), getPaddingTop(),
392f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                    getWidth() - getPaddingRight(),
393ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi                    getHeight() - getPaddingBottom());
394ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
395f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            // Draw thumbnails
396f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            drawThumbnails(canvas);
397ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
398f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            // Draw the "Add transition" indicators
399ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            if (isSelected()) {
400ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi                drawAddTransitions(canvas);
401ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            }
402ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
403f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            // Request thumbnails if things are not moving
404f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            boolean isBusy = mIsPlaying || mIsTrimming || mIsScrolling;
405f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            if (!isBusy && !mWantThumbnails.isEmpty()) {
406f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                requestThumbnails();
407ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            }
408ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        }
409ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
410ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
411f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    // Draws the thumbnails, also put unavailable thumbnail indices in
412f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    // mWantThumbnails.
41377a3d89eaf839df50c2f3b4ddb0819ed974726b6Gil Dobjanschi    private void drawThumbnails(Canvas canvas) {
414f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        mWantThumbnails.clear();
415f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang
416f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        // The screen coordinate of the left edge of the usable area.
417f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        int left = getLeft() + getPaddingLeft() - mScrollX;
418f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        // The screen coordinate of the right edge of the usable area.
419f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        int right = getRight() - getPaddingRight() - mScrollX;
420f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        // Return if the usable area is not on screen.
421f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        if (left >= mScreenWidth || right <= 0 || left >= right) {
422ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            return;
423ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        }
424ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
425f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        // Map [0, mScreenWidth - 1] to the indices of the thumbnail.
426f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        int startIdx = (0 - left) / mThumbnailWidth;
427f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        int endIdx = (mScreenWidth - 1 - left) / mThumbnailWidth;
428ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
429f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        startIdx = clamp(startIdx, 0, mNumberOfThumbnails - 1);
430f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        endIdx = clamp(endIdx, 0, mNumberOfThumbnails - 1);
431ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
432f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        // Prepare variables used in the loop
433f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        ThumbnailKey key = new ThumbnailKey();
434f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        key.mediaItemId = mMediaItem.getId();
435f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        int x = getPaddingLeft() + startIdx * mThumbnailWidth;
436f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        int y = getPaddingTop();
43777a3d89eaf839df50c2f3b4ddb0819ed974726b6Gil Dobjanschi
438f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        // Loop through the thumbnails on screen and draw it
439f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        for (int i = startIdx; i <= endIdx; i++) {
440f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            key.index = i;
441f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            Bitmap bitmap = sThumbnailCache.get(key);
442f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            if (bitmap == null) {
44377a3d89eaf839df50c2f3b4ddb0819ed974726b6Gil Dobjanschi                // Draw a frame placeholder
444f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                sEmptyFrameDrawable.setBounds(
445f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                        x, y, x + mThumbnailWidth, y + mThumbnailHeight);
446f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                sEmptyFrameDrawable.draw(canvas);
447f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                if (!mPending.contains(i)) {
448f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                    mWantThumbnails.add(Integer.valueOf(i));
44977a3d89eaf839df50c2f3b4ddb0819ed974726b6Gil Dobjanschi                }
450f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            } else {
451f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                canvas.drawBitmap(bitmap, x, y, null);
45277a3d89eaf839df50c2f3b4ddb0819ed974726b6Gil Dobjanschi            }
453f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            x += mThumbnailWidth;
454ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        }
455ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
456ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
457ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    /**
458f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang     * Draw the "Add transition" area at the beginning and end of the media item
459ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     *
460ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * @param canvas Draw on this canvas
461ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     */
462ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    private void drawAddTransitions(Canvas canvas) {
463ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        if (hasAddTransition()) {
464f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            if (mMediaItem.getBeginTransition() == null) {
465f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                sAddTransitionDrawable.setState(mLeftState);
466f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                sAddTransitionDrawable.setBounds(getPaddingLeft(), getPaddingTop(),
467f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                        sAddTransitionDrawable.getIntrinsicWidth() + getPaddingLeft(),
468f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                        getPaddingTop() + sAddTransitionDrawable.getIntrinsicHeight());
469f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                sAddTransitionDrawable.draw(canvas);
470ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            }
471ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
472f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            if (mMediaItem.getEndTransition() == null) {
473f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                sAddTransitionDrawable.setState(mRightState);
474f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                sAddTransitionDrawable.setBounds(
475ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi                        getWidth() - getPaddingRight() -
476f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                        sAddTransitionDrawable.getIntrinsicWidth(),
477ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi                        getPaddingTop(), getWidth() - getPaddingRight(),
478f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                        getPaddingTop() + sAddTransitionDrawable.getIntrinsicHeight());
479f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                sAddTransitionDrawable.draw(canvas);
480ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            }
481ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        }
482ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
483ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
484ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    /**
485ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * @return true if the "Add transition" areas exist
486ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     */
487ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    private boolean hasAddTransition() {
488ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        if (mIsTrimming) {
489ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            return false;
490ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        }
491ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
492ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        return (getWidth() - getPaddingLeft() - getPaddingRight() >=
493f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                2 * sAddTransitionDrawable.getIntrinsicWidth());
494f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    }
495f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang
496f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    // clamp the input value v to the range [low, high]
497f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    private static int clamp(int v, int low, int high) {
498f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        return Math.min(Math.max(v, low), high);
499f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    }
500f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang
501f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    // Requests the thumbnails in mWantThumbnails (which is filled by onDraw)
502f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    private void requestThumbnails() {
503f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        // Copy mWantThumbnails to an array
504f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        int indices[] = new int[mWantThumbnails.size()];
505f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        for (int i = 0; i < mWantThumbnails.size(); i++) {
506f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            indices[i] = mWantThumbnails.get(i);
507f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        }
508f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang
509f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        // Put them in the pending set
510f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        mPending.addAll(mWantThumbnails);
511f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang
512f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        ApiService.getMediaItemThumbnails(getContext(), mProjectPath,
513f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                mMediaItem.getId(), mThumbnailWidth, mThumbnailHeight,
514f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                mBeginTimeMs, mEndTimeMs, mNumberOfThumbnails, mGeneration,
515f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                indices);
516ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
517ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
518ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    @Override
519ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    public boolean onTouchEvent(MotionEvent ev) {
520ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        // Let the gesture detector inspect all events.
521ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        mGestureDetector.onTouchEvent(ev);
522ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        super.onTouchEvent(ev);
523ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
524ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        switch (ev.getAction()) {
525ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            case MotionEvent.ACTION_DOWN: {
526f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                mLeftState = View.EMPTY_STATE_SET;
527f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                mRightState = View.EMPTY_STATE_SET;
528ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi                if (isSelected() && hasAddTransition()) {
529f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                    if (ev.getX() < sAddTransitionDrawable.getIntrinsicWidth() +
530ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi                            getPaddingLeft()) {
531f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                        if (mMediaItem.getBeginTransition() == null) {
532ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi                            mLeftState = View.PRESSED_WINDOW_FOCUSED_STATE_SET;
533ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi                        }
534ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi                    } else if (ev.getX() >= getWidth() - getPaddingRight() -
535f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                            sAddTransitionDrawable.getIntrinsicWidth()) {
536f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                        if (mMediaItem.getEndTransition() == null) {
537ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi                            mRightState = View.PRESSED_WINDOW_FOCUSED_STATE_SET;
538ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi                        }
539ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi                    }
540ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi                }
541ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi                invalidate();
542ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi                break;
543ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            }
544ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
545ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            case MotionEvent.ACTION_UP:
546ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            case MotionEvent.ACTION_CANCEL: {
547ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi                mRightState = View.EMPTY_STATE_SET;
548ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi                mLeftState = View.EMPTY_STATE_SET;
549ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi                invalidate();
550ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi                break;
551ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            }
552ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
553ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            default: {
554ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi                break;
555ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            }
556ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        }
557ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
558ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        return true;
559ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
560ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
561f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    private void releaseBitmapsAndClear() {
562f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        sThumbnailCache.clearForMediaItemId(mMediaItem.getId());
563f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        mPending.clear();
564f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        mGeneration++;
565f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    }
566f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang}
567ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
568f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Changclass ThumbnailKey {
569f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    public String mediaItemId;
570f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    public int index;
571ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
572f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    public ThumbnailKey() {
573f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    }
574ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
575f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    public ThumbnailKey(String id, int idx) {
576f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        mediaItemId = id;
577f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        index = idx;
578f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    }
579ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
580f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    @Override
581f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    public boolean equals(Object o) {
582f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        if (!(o instanceof ThumbnailKey)) {
583f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            return false;
584ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        }
585f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        ThumbnailKey key = (ThumbnailKey) o;
586f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        return index == key.index && mediaItemId.equals(key.mediaItemId);
587f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    }
588ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
589f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    @Override
590f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    public int hashCode() {
591f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        return mediaItemId.hashCode() ^ index;
592f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    }
593f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang}
594ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
595f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Changclass ThumbnailCache {
596f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    private LruCache<ThumbnailKey, Bitmap> mCache;
597ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
598f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    public ThumbnailCache(int size) {
599f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        mCache = new LruCache(size) {
600f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            protected int sizeOf(ThumbnailKey key, Bitmap value) {
601f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                return value.getByteCount();
602ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            }
603f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        };
604ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
605ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
606f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    void put(ThumbnailKey key, Bitmap value) {
607f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        mCache.put(key, value);
608ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
609ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
610f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    Bitmap get(ThumbnailKey key) {
611f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        return mCache.get(key);
612f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    }
613ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
614f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang    void clearForMediaItemId(String id) {
615f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        Map<ThumbnailKey, Bitmap> map = mCache.snapshot();
616f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang        for (ThumbnailKey key : map.keySet()) {
617f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang            if (key.mediaItemId.equals(id)) {
618f6b29b560e55392015caebeffbe76f8a1d1ddeb4Chih-Chung Chang                mCache.remove(key);
619ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            }
620ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        }
621ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
622ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi}
623