1e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling/*
2e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling * Copyright (C) 2013 The Android Open Source Project
3e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling *
4e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling * Licensed under the Apache License, Version 2.0 (the "License");
5e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling * you may not use this file except in compliance with the License.
6e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling * You may obtain a copy of the License at
7e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling *
8e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling *      http://www.apache.org/licenses/LICENSE-2.0
9e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling *
10e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling * Unless required by applicable law or agreed to in writing, software
11e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling * distributed under the License is distributed on an "AS IS" BASIS,
12e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling * See the License for the specific language governing permissions and
14e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling * limitations under the License.
15e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling */
16e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling
17e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberlingpackage com.android.camera.ui;
18e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling
19e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberlingimport android.content.Context;
20e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberlingimport android.graphics.Canvas;
21e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberlingimport android.graphics.Color;
22e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberlingimport android.graphics.Paint;
23e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberlingimport android.graphics.RectF;
245ce035e98ca289b0b0ca884c4d2bb2fd43d8c187Erin Dahlgrenimport android.view.View;
25e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling
26e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberlingimport com.android.camera2.R;
27e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling
28e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling/**
29e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling * Renders a circular progress bar on the screen.
30e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling */
31e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberlingpublic class ProgressRenderer {
32e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling    private final int mProgressRadius;
33e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling    private final Paint mProgressBasePaint;
34e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling    private final Paint mProgressPaint;
35e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling
36e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling    private RectF mArcBounds = new RectF(0, 0, 1, 1);
37e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling    private int mProgressAngleDegrees = 270;
38e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling    private boolean mVisible = false;
3990f158340db39bca9ee5da4cf1d246adbcb03453Sascha Haeberling    private final View mParentView;
4090f158340db39bca9ee5da4cf1d246adbcb03453Sascha Haeberling    private final Runnable mInvalidateParentViewRunnable = new Runnable() {
4190f158340db39bca9ee5da4cf1d246adbcb03453Sascha Haeberling        @Override
4290f158340db39bca9ee5da4cf1d246adbcb03453Sascha Haeberling        public void run() {
4390f158340db39bca9ee5da4cf1d246adbcb03453Sascha Haeberling            mParentView.invalidate();
4490f158340db39bca9ee5da4cf1d246adbcb03453Sascha Haeberling        }
4590f158340db39bca9ee5da4cf1d246adbcb03453Sascha Haeberling    };
46b7b73ec15e05605db6cc2b7f42bbc61d441da1d2Sascha Haeberling
47b7b73ec15e05605db6cc2b7f42bbc61d441da1d2Sascha Haeberling    /**
4849ea51ab31f8e39fd48577b704695cb437f644afSascha Haeberling     * After we reach 100%, keep on painting the progress for another x milliseconds
49b7b73ec15e05605db6cc2b7f42bbc61d441da1d2Sascha Haeberling     * before hiding it.
50b7b73ec15e05605db6cc2b7f42bbc61d441da1d2Sascha Haeberling     */
5149ea51ab31f8e39fd48577b704695cb437f644afSascha Haeberling    private static final int SHOW_PROGRESS_X_ADDITIONAL_MS = 100;
5249ea51ab31f8e39fd48577b704695cb437f644afSascha Haeberling
535ce035e98ca289b0b0ca884c4d2bb2fd43d8c187Erin Dahlgren    public ProgressRenderer(Context context, View parent) {
545ce035e98ca289b0b0ca884c4d2bb2fd43d8c187Erin Dahlgren        mParentView = parent;
55e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling        mProgressRadius = context.getResources().getDimensionPixelSize(R.dimen.pie_progress_radius);
56e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling        int pieProgressWidth = context.getResources().getDimensionPixelSize(
57e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling                R.dimen.pie_progress_width);
58e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling        mProgressBasePaint = createProgressPaint(pieProgressWidth, 0.2f);
59e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling        mProgressPaint = createProgressPaint(pieProgressWidth, 1.0f);
60e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling    }
61e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling
62b7b73ec15e05605db6cc2b7f42bbc61d441da1d2Sascha Haeberling    /**
63e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling     * Shows a progress indicator. If the progress is '100', the progress
64e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling     * indicator will be hidden.
6590f158340db39bca9ee5da4cf1d246adbcb03453Sascha Haeberling     * <p>
6690f158340db39bca9ee5da4cf1d246adbcb03453Sascha Haeberling     * Can be called from any thread.
67e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling     *
68e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling     * @param percent the progress in percent (0-100).
69e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling     */
70e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling    public void setProgress(int percent) {
71e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling        // Clamp the value.
72e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling        percent = Math.min(100, Math.max(percent, 0));
73e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling        mProgressAngleDegrees = (int) ((360f / 100) * percent);
74e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling
75b7b73ec15e05605db6cc2b7f42bbc61d441da1d2Sascha Haeberling        // We hide the progress once we drew the 100% state once.
76b7b73ec15e05605db6cc2b7f42bbc61d441da1d2Sascha Haeberling        if (percent < 100) {
77b7b73ec15e05605db6cc2b7f42bbc61d441da1d2Sascha Haeberling            mVisible = true;
78b7b73ec15e05605db6cc2b7f42bbc61d441da1d2Sascha Haeberling        }
7990f158340db39bca9ee5da4cf1d246adbcb03453Sascha Haeberling        mParentView.post(mInvalidateParentViewRunnable);
80e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling    }
81e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling
82e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling    /**
83e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling     * Draw the current progress (if < 100%) centered at the given location.
84e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling     */
85e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling    public void onDraw(Canvas canvas, int centerX, int centerY) {
86e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling        if (!mVisible) {
87e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling            return;
88e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling        }
89e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling        mArcBounds = new RectF(centerX - mProgressRadius, centerY - mProgressRadius, centerX
90e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling                + mProgressRadius,
91e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling                centerY + mProgressRadius);
92e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling
93e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling        canvas.drawCircle(centerX, centerY, mProgressRadius, mProgressBasePaint);
94e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling        canvas.drawArc(mArcBounds, -90, mProgressAngleDegrees, false, mProgressPaint);
95b7b73ec15e05605db6cc2b7f42bbc61d441da1d2Sascha Haeberling
96b7b73ec15e05605db6cc2b7f42bbc61d441da1d2Sascha Haeberling        // After we reached 100%, we paint the progress renderer for another x
9749ea51ab31f8e39fd48577b704695cb437f644afSascha Haeberling        // milliseconds until we hide it.
985ce035e98ca289b0b0ca884c4d2bb2fd43d8c187Erin Dahlgren        if (mProgressAngleDegrees == 360) {
9949ea51ab31f8e39fd48577b704695cb437f644afSascha Haeberling            mVisible = false;
1005ce035e98ca289b0b0ca884c4d2bb2fd43d8c187Erin Dahlgren            mParentView.postDelayed(
1015ce035e98ca289b0b0ca884c4d2bb2fd43d8c187Erin Dahlgren                new Runnable() {
1025ce035e98ca289b0b0ca884c4d2bb2fd43d8c187Erin Dahlgren                    @Override
1035ce035e98ca289b0b0ca884c4d2bb2fd43d8c187Erin Dahlgren                    public void run() {
1045ce035e98ca289b0b0ca884c4d2bb2fd43d8c187Erin Dahlgren                        mParentView.invalidate();
1055ce035e98ca289b0b0ca884c4d2bb2fd43d8c187Erin Dahlgren                    }
1065ce035e98ca289b0b0ca884c4d2bb2fd43d8c187Erin Dahlgren                }, SHOW_PROGRESS_X_ADDITIONAL_MS);
107b7b73ec15e05605db6cc2b7f42bbc61d441da1d2Sascha Haeberling        }
108b7b73ec15e05605db6cc2b7f42bbc61d441da1d2Sascha Haeberling    }
109b7b73ec15e05605db6cc2b7f42bbc61d441da1d2Sascha Haeberling
110b7b73ec15e05605db6cc2b7f42bbc61d441da1d2Sascha Haeberling    /**
111b7b73ec15e05605db6cc2b7f42bbc61d441da1d2Sascha Haeberling     * @return Whether the progress renderer is visible.
112b7b73ec15e05605db6cc2b7f42bbc61d441da1d2Sascha Haeberling     */
113b7b73ec15e05605db6cc2b7f42bbc61d441da1d2Sascha Haeberling    public boolean isVisible() {
114b7b73ec15e05605db6cc2b7f42bbc61d441da1d2Sascha Haeberling        return mVisible;
115b7b73ec15e05605db6cc2b7f42bbc61d441da1d2Sascha Haeberling    }
116b7b73ec15e05605db6cc2b7f42bbc61d441da1d2Sascha Haeberling
117b7b73ec15e05605db6cc2b7f42bbc61d441da1d2Sascha Haeberling    private static Paint createProgressPaint(int width, float alpha) {
118b7b73ec15e05605db6cc2b7f42bbc61d441da1d2Sascha Haeberling        Paint paint = new Paint();
119b7b73ec15e05605db6cc2b7f42bbc61d441da1d2Sascha Haeberling        paint.setAntiAlias(true);
120b7b73ec15e05605db6cc2b7f42bbc61d441da1d2Sascha Haeberling        // 20% alpha.
121b7b73ec15e05605db6cc2b7f42bbc61d441da1d2Sascha Haeberling        paint.setColor(Color.argb((int) (alpha * 255), 255, 255, 255));
122b7b73ec15e05605db6cc2b7f42bbc61d441da1d2Sascha Haeberling        paint.setStrokeWidth(width);
123b7b73ec15e05605db6cc2b7f42bbc61d441da1d2Sascha Haeberling        paint.setStyle(Paint.Style.STROKE);
124b7b73ec15e05605db6cc2b7f42bbc61d441da1d2Sascha Haeberling        return paint;
125e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling    }
126e0ecc64979a29e5bbdd1084712b231070b1d57bfSascha Haeberling}
127