1a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling/*
2a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling * Copyright (C) 2013 The Android Open Source Project
3a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling *
4a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling * Licensed under the Apache License, Version 2.0 (the "License");
5a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling * you may not use this file except in compliance with the License.
6a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling * You may obtain a copy of the License at
7a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling *
8a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling *      http://www.apache.org/licenses/LICENSE-2.0
9a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling *
10a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling * Unless required by applicable law or agreed to in writing, software
11a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling * distributed under the License is distributed on an "AS IS" BASIS,
12a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling * See the License for the specific language governing permissions and
14a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling * limitations under the License.
15a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling */
16a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling
17a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberlingpackage com.android.camera.tinyplanet;
18a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling
19a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberlingimport android.content.Context;
20a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberlingimport android.graphics.Bitmap;
21a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberlingimport android.graphics.Canvas;
22a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberlingimport android.graphics.Paint;
23a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberlingimport android.util.AttributeSet;
24a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberlingimport android.view.View;
25a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling
26a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberlingimport java.util.concurrent.locks.Lock;
27a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling
28a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling/**
29a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling * Shows a preview of the TinyPlanet on the screen while editing.
30a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling */
31a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberlingpublic class TinyPlanetPreview extends View {
32a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling    /**
33a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling     * Classes implementing this interface get informed about changes to the
34a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling     * preview size.
35a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling     */
36a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling    public static interface PreviewSizeListener {
37a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling        /**
38a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling         * Called when the preview size has changed.
39a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling         *
40a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling         * @param sizePx the size in pixels of the square preview area
41a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling         */
42a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling        public void onSizeChanged(int sizePx);
43a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling    }
44a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling
45a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling    private Paint mPaint = new Paint();
46a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling    private Bitmap mPreview;
47a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling    private Lock mLock;
48a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling    private PreviewSizeListener mPreviewSizeListener;
49a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling    private int mSize = 0;
50a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling
51a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling    public TinyPlanetPreview(Context context) {
52a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling        super(context);
53a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling    }
54a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling
55a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling    public TinyPlanetPreview(Context context, AttributeSet attrs) {
56a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling        super(context, attrs);
57a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling    }
58a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling
59a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling    public TinyPlanetPreview(Context context, AttributeSet attrs, int defStyle) {
60a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling        super(context, attrs, defStyle);
61a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling    }
62a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling
63a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling    /**
64a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling     * Sets the bitmap and waits for a draw to happen before returning.
65a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling     */
66a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling    public void setBitmap(Bitmap preview, Lock lock) {
67a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling        mPreview = preview;
68a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling        mLock = lock;
69a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling        invalidate();
70a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling    }
71a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling
72a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling    public void setPreviewSizeChangeListener(PreviewSizeListener listener) {
73a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling        mPreviewSizeListener = listener;
74a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling        if (mSize > 0) {
75a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling            mPreviewSizeListener.onSizeChanged(mSize);
76a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling        }
77a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling    }
78a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling
79a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling    @Override
80a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling    protected void onDraw(Canvas canvas) {
81a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling        super.onDraw(canvas);
826100053eea36f0258091ee12be5f72c501209ad0Sascha Haeberling        if (mLock != null && mLock.tryLock()) {
83a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling            try {
846100053eea36f0258091ee12be5f72c501209ad0Sascha Haeberling                if (mPreview != null && !mPreview.isRecycled()) {
856100053eea36f0258091ee12be5f72c501209ad0Sascha Haeberling                    canvas.drawBitmap(mPreview, 0, 0, mPaint);
866100053eea36f0258091ee12be5f72c501209ad0Sascha Haeberling                }
87a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling            } finally {
88a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling                mLock.unlock();
89a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling            }
90a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling        }
91a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling    }
92a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling
93a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling    @Override
94a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
95a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
96a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling
97a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling        // Make sure the view is square
98a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling        int size = Math.min(getMeasuredWidth(), getMeasuredHeight());
99a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling        setMeasuredDimension(size, size);
100a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling    }
101a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling
102a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling    @Override
103a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
104a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling        super.onLayout(changed, left, top, right, bottom);
105a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling        if (changed && mPreviewSizeListener != null) {
106a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling            int width = right - left;
107a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling            int height = bottom - top;
108a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling
109a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling            // These should be the same as we enforce a square layout, but let's
110a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling            // be safe.
111a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling            int mSize = Math.min(width, height);
112a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling
113a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling            // Tell the listener about our new size so the renderer can adapt.
114a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling            if (mSize > 0 && mPreviewSizeListener != null) {
115a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling                mPreviewSizeListener.onSizeChanged(mSize);
116a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling            }
117a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling        }
118a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling    }
119a5a08d7642a1fdf961b057cc90e76c4c93103c15Sascha Haeberling}
120