|
1 /* |
|
2 * Copyright (C) 2010 The Android Open Source Project |
|
3 * |
|
4 * Licensed under the Apache License, Version 2.0 (the "License"); |
|
5 * you may not use this file except in compliance with the License. |
|
6 * You may obtain a copy of the License at |
|
7 * |
|
8 * http://www.apache.org/licenses/LICENSE-2.0 |
|
9 * |
|
10 * Unless required by applicable law or agreed to in writing, software |
|
11 * distributed under the License is distributed on an "AS IS" BASIS, |
|
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
13 * See the License for the specific language governing permissions and |
|
14 * limitations under the License. |
|
15 */ |
|
16 |
|
17 package org.mozilla.gecko.toolbar; |
|
18 |
|
19 import android.content.Context; |
|
20 import android.graphics.Canvas; |
|
21 import android.graphics.Rect; |
|
22 import android.graphics.drawable.Drawable; |
|
23 import android.os.Build; |
|
24 import android.os.Handler; |
|
25 import android.os.Message; |
|
26 import android.util.AttributeSet; |
|
27 import android.widget.ImageView; |
|
28 import android.view.View; |
|
29 import android.view.animation.Animation; |
|
30 |
|
31 /** |
|
32 * Progress view used for page loads. |
|
33 * |
|
34 * Because we're given limited information about the page load progress, the |
|
35 * bar also includes incremental animation between each step to improve |
|
36 * perceived performance. |
|
37 */ |
|
38 public class ToolbarProgressView extends ImageView { |
|
39 private static final int MAX_PROGRESS = 10000; |
|
40 private static final int MSG_UPDATE = 0; |
|
41 private static final int MSG_HIDE = 1; |
|
42 private static final int STEPS = 10; |
|
43 private static final int DELAY = 40; |
|
44 |
|
45 private static final boolean PRE_HONEYCOMB = Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB; |
|
46 |
|
47 private int mTargetProgress; |
|
48 private int mIncrement; |
|
49 private Rect mBounds; |
|
50 private Handler mHandler; |
|
51 private int mCurrentProgress; |
|
52 |
|
53 public ToolbarProgressView(Context context, AttributeSet attrs, int defStyle) { |
|
54 super(context, attrs, defStyle); |
|
55 init(context); |
|
56 } |
|
57 |
|
58 public ToolbarProgressView(Context context, AttributeSet attrs) { |
|
59 super(context, attrs); |
|
60 init(context); |
|
61 } |
|
62 |
|
63 public ToolbarProgressView(Context context) { |
|
64 super(context); |
|
65 init(context); |
|
66 } |
|
67 |
|
68 private void init(Context ctx) { |
|
69 mBounds = new Rect(0,0,0,0); |
|
70 mTargetProgress = 0; |
|
71 |
|
72 mHandler = new Handler() { |
|
73 @Override |
|
74 public void handleMessage(Message msg) { |
|
75 switch (msg.what) { |
|
76 case MSG_UPDATE: |
|
77 mCurrentProgress = Math.min(mTargetProgress, mCurrentProgress + mIncrement); |
|
78 |
|
79 updateBounds(); |
|
80 |
|
81 if (mCurrentProgress < mTargetProgress) { |
|
82 final int delay = (mTargetProgress < MAX_PROGRESS) ? DELAY : DELAY / 4; |
|
83 sendMessageDelayed(mHandler.obtainMessage(msg.what), delay); |
|
84 } else if (mCurrentProgress == MAX_PROGRESS) { |
|
85 sendMessageDelayed(mHandler.obtainMessage(MSG_HIDE), DELAY); |
|
86 } |
|
87 break; |
|
88 |
|
89 case MSG_HIDE: |
|
90 setVisibility(View.GONE); |
|
91 break; |
|
92 } |
|
93 } |
|
94 |
|
95 }; |
|
96 } |
|
97 |
|
98 @Override |
|
99 public void setVisibility(int visibility) { |
|
100 // On GB/Froyo, setting the visibility to GONE/HIDDEN alone does not |
|
101 // work with translations. Calling clearAnimation acts as a workaround. |
|
102 if (PRE_HONEYCOMB && visibility != VISIBLE) { |
|
103 clearAnimation(); |
|
104 } |
|
105 |
|
106 super.setVisibility(visibility); |
|
107 } |
|
108 |
|
109 @Override |
|
110 public void setAnimation(Animation animation) { |
|
111 // On GB/Froyo, setting the animation after hiding the view causes it |
|
112 // to reappear. As a workaround, disallow setAnimation from being |
|
113 // called if the view is not shown. |
|
114 if (PRE_HONEYCOMB && isShown()) { |
|
115 super.setAnimation(animation); |
|
116 } |
|
117 } |
|
118 |
|
119 @Override |
|
120 public void onLayout(boolean f, int l, int t, int r, int b) { |
|
121 mBounds.left = 0; |
|
122 mBounds.right = (r - l) * mCurrentProgress / MAX_PROGRESS; |
|
123 mBounds.top = 0; |
|
124 mBounds.bottom = b - t; |
|
125 } |
|
126 |
|
127 @Override |
|
128 public void onDraw(Canvas canvas) { |
|
129 final Drawable d = getDrawable(); |
|
130 d.setBounds(mBounds); |
|
131 d.draw(canvas); |
|
132 } |
|
133 |
|
134 /** |
|
135 * Immediately sets the progress bar to the given progress percentage. |
|
136 * |
|
137 * @param progress Percentage (0-100) to which progress bar should be set |
|
138 */ |
|
139 void setProgress(int progressPercentage) { |
|
140 mCurrentProgress = mTargetProgress = getAbsoluteProgress(progressPercentage); |
|
141 updateBounds(); |
|
142 |
|
143 clearMessages(); |
|
144 } |
|
145 |
|
146 /** |
|
147 * Animates the progress bar from the current progress value to the given |
|
148 * progress percentage. |
|
149 * |
|
150 * @param progress Percentage (0-100) to which progress bar should be animated |
|
151 */ |
|
152 void animateProgress(int progressPercentage) { |
|
153 final int absoluteProgress = getAbsoluteProgress(progressPercentage); |
|
154 if (absoluteProgress <= mTargetProgress) { |
|
155 // After we manually click stop, we can still receive page load |
|
156 // events (e.g., DOMContentLoaded). Updating for other updates |
|
157 // after a STOP event can freeze the progress bar, so guard against |
|
158 // that here. |
|
159 return; |
|
160 } |
|
161 |
|
162 mTargetProgress = absoluteProgress; |
|
163 mIncrement = (mTargetProgress - mCurrentProgress) / STEPS; |
|
164 |
|
165 clearMessages(); |
|
166 mHandler.sendEmptyMessage(MSG_UPDATE); |
|
167 } |
|
168 |
|
169 private void clearMessages() { |
|
170 mHandler.removeMessages(MSG_UPDATE); |
|
171 mHandler.removeMessages(MSG_HIDE); |
|
172 } |
|
173 |
|
174 private int getAbsoluteProgress(int progressPercentage) { |
|
175 if (progressPercentage < 0) { |
|
176 return 0; |
|
177 } |
|
178 |
|
179 if (progressPercentage > 100) { |
|
180 return 100; |
|
181 } |
|
182 |
|
183 return progressPercentage * MAX_PROGRESS / 100; |
|
184 } |
|
185 |
|
186 private void updateBounds() { |
|
187 mBounds.right = getWidth() * mCurrentProgress / MAX_PROGRESS; |
|
188 invalidate(); |
|
189 } |
|
190 } |