1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/mobile/android/base/toolbar/ToolbarProgressView.java Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,190 @@ 1.4 +/* 1.5 + * Copyright (C) 2010 The Android Open Source Project 1.6 + * 1.7 + * Licensed under the Apache License, Version 2.0 (the "License"); 1.8 + * you may not use this file except in compliance with the License. 1.9 + * You may obtain a copy of the License at 1.10 + * 1.11 + * http://www.apache.org/licenses/LICENSE-2.0 1.12 + * 1.13 + * Unless required by applicable law or agreed to in writing, software 1.14 + * distributed under the License is distributed on an "AS IS" BASIS, 1.15 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1.16 + * See the License for the specific language governing permissions and 1.17 + * limitations under the License. 1.18 + */ 1.19 + 1.20 +package org.mozilla.gecko.toolbar; 1.21 + 1.22 +import android.content.Context; 1.23 +import android.graphics.Canvas; 1.24 +import android.graphics.Rect; 1.25 +import android.graphics.drawable.Drawable; 1.26 +import android.os.Build; 1.27 +import android.os.Handler; 1.28 +import android.os.Message; 1.29 +import android.util.AttributeSet; 1.30 +import android.widget.ImageView; 1.31 +import android.view.View; 1.32 +import android.view.animation.Animation; 1.33 + 1.34 +/** 1.35 + * Progress view used for page loads. 1.36 + * 1.37 + * Because we're given limited information about the page load progress, the 1.38 + * bar also includes incremental animation between each step to improve 1.39 + * perceived performance. 1.40 + */ 1.41 +public class ToolbarProgressView extends ImageView { 1.42 + private static final int MAX_PROGRESS = 10000; 1.43 + private static final int MSG_UPDATE = 0; 1.44 + private static final int MSG_HIDE = 1; 1.45 + private static final int STEPS = 10; 1.46 + private static final int DELAY = 40; 1.47 + 1.48 + private static final boolean PRE_HONEYCOMB = Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB; 1.49 + 1.50 + private int mTargetProgress; 1.51 + private int mIncrement; 1.52 + private Rect mBounds; 1.53 + private Handler mHandler; 1.54 + private int mCurrentProgress; 1.55 + 1.56 + public ToolbarProgressView(Context context, AttributeSet attrs, int defStyle) { 1.57 + super(context, attrs, defStyle); 1.58 + init(context); 1.59 + } 1.60 + 1.61 + public ToolbarProgressView(Context context, AttributeSet attrs) { 1.62 + super(context, attrs); 1.63 + init(context); 1.64 + } 1.65 + 1.66 + public ToolbarProgressView(Context context) { 1.67 + super(context); 1.68 + init(context); 1.69 + } 1.70 + 1.71 + private void init(Context ctx) { 1.72 + mBounds = new Rect(0,0,0,0); 1.73 + mTargetProgress = 0; 1.74 + 1.75 + mHandler = new Handler() { 1.76 + @Override 1.77 + public void handleMessage(Message msg) { 1.78 + switch (msg.what) { 1.79 + case MSG_UPDATE: 1.80 + mCurrentProgress = Math.min(mTargetProgress, mCurrentProgress + mIncrement); 1.81 + 1.82 + updateBounds(); 1.83 + 1.84 + if (mCurrentProgress < mTargetProgress) { 1.85 + final int delay = (mTargetProgress < MAX_PROGRESS) ? DELAY : DELAY / 4; 1.86 + sendMessageDelayed(mHandler.obtainMessage(msg.what), delay); 1.87 + } else if (mCurrentProgress == MAX_PROGRESS) { 1.88 + sendMessageDelayed(mHandler.obtainMessage(MSG_HIDE), DELAY); 1.89 + } 1.90 + break; 1.91 + 1.92 + case MSG_HIDE: 1.93 + setVisibility(View.GONE); 1.94 + break; 1.95 + } 1.96 + } 1.97 + 1.98 + }; 1.99 + } 1.100 + 1.101 + @Override 1.102 + public void setVisibility(int visibility) { 1.103 + // On GB/Froyo, setting the visibility to GONE/HIDDEN alone does not 1.104 + // work with translations. Calling clearAnimation acts as a workaround. 1.105 + if (PRE_HONEYCOMB && visibility != VISIBLE) { 1.106 + clearAnimation(); 1.107 + } 1.108 + 1.109 + super.setVisibility(visibility); 1.110 + } 1.111 + 1.112 + @Override 1.113 + public void setAnimation(Animation animation) { 1.114 + // On GB/Froyo, setting the animation after hiding the view causes it 1.115 + // to reappear. As a workaround, disallow setAnimation from being 1.116 + // called if the view is not shown. 1.117 + if (PRE_HONEYCOMB && isShown()) { 1.118 + super.setAnimation(animation); 1.119 + } 1.120 + } 1.121 + 1.122 + @Override 1.123 + public void onLayout(boolean f, int l, int t, int r, int b) { 1.124 + mBounds.left = 0; 1.125 + mBounds.right = (r - l) * mCurrentProgress / MAX_PROGRESS; 1.126 + mBounds.top = 0; 1.127 + mBounds.bottom = b - t; 1.128 + } 1.129 + 1.130 + @Override 1.131 + public void onDraw(Canvas canvas) { 1.132 + final Drawable d = getDrawable(); 1.133 + d.setBounds(mBounds); 1.134 + d.draw(canvas); 1.135 + } 1.136 + 1.137 + /** 1.138 + * Immediately sets the progress bar to the given progress percentage. 1.139 + * 1.140 + * @param progress Percentage (0-100) to which progress bar should be set 1.141 + */ 1.142 + void setProgress(int progressPercentage) { 1.143 + mCurrentProgress = mTargetProgress = getAbsoluteProgress(progressPercentage); 1.144 + updateBounds(); 1.145 + 1.146 + clearMessages(); 1.147 + } 1.148 + 1.149 + /** 1.150 + * Animates the progress bar from the current progress value to the given 1.151 + * progress percentage. 1.152 + * 1.153 + * @param progress Percentage (0-100) to which progress bar should be animated 1.154 + */ 1.155 + void animateProgress(int progressPercentage) { 1.156 + final int absoluteProgress = getAbsoluteProgress(progressPercentage); 1.157 + if (absoluteProgress <= mTargetProgress) { 1.158 + // After we manually click stop, we can still receive page load 1.159 + // events (e.g., DOMContentLoaded). Updating for other updates 1.160 + // after a STOP event can freeze the progress bar, so guard against 1.161 + // that here. 1.162 + return; 1.163 + } 1.164 + 1.165 + mTargetProgress = absoluteProgress; 1.166 + mIncrement = (mTargetProgress - mCurrentProgress) / STEPS; 1.167 + 1.168 + clearMessages(); 1.169 + mHandler.sendEmptyMessage(MSG_UPDATE); 1.170 + } 1.171 + 1.172 + private void clearMessages() { 1.173 + mHandler.removeMessages(MSG_UPDATE); 1.174 + mHandler.removeMessages(MSG_HIDE); 1.175 + } 1.176 + 1.177 + private int getAbsoluteProgress(int progressPercentage) { 1.178 + if (progressPercentage < 0) { 1.179 + return 0; 1.180 + } 1.181 + 1.182 + if (progressPercentage > 100) { 1.183 + return 100; 1.184 + } 1.185 + 1.186 + return progressPercentage * MAX_PROGRESS / 100; 1.187 + } 1.188 + 1.189 + private void updateBounds() { 1.190 + mBounds.right = getWidth() * mCurrentProgress / MAX_PROGRESS; 1.191 + invalidate(); 1.192 + } 1.193 +}