Respect the global animator duration scale setting

This changes the way the TOTP progress bar works, so that we can respect the
global animator duration scale setting.
This commit is contained in:
Alexander Bakker 2020-06-07 17:00:56 +02:00
parent 626995ec91
commit 98a38b03e4
10 changed files with 102 additions and 103 deletions

View file

@ -1,10 +1,8 @@
package com.beemdevelopment.aegis.ui;
import android.animation.ValueAnimator;
import android.content.Intent;
import android.content.res.Configuration;
import android.os.Bundle;
import android.provider.Settings;
import android.view.WindowManager;
import android.widget.Toast;
@ -47,9 +45,6 @@ public abstract class AegisActivity extends AppCompatActivity implements AegisAp
getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE);
}
// apply a dirty hack to make progress bars work even if animations are disabled
setGlobalAnimationDurationScale();
// register a callback to listen for lock events
_app.registerLockListener(this);
}
@ -152,17 +147,6 @@ public abstract class AegisActivity extends AppCompatActivity implements AegisAp
return !(this instanceof MainActivity) && _app.isVaultLocked();
}
private void setGlobalAnimationDurationScale() {
float durationScale = Settings.Global.getFloat(getContentResolver(), Settings.Global.ANIMATOR_DURATION_SCALE, 0);
if (durationScale != 1) {
try {
ValueAnimator.class.getMethod("setDurationScale", float.class).invoke(null, 1f);
} catch (Throwable t) {
Toast.makeText(this, R.string.progressbar_error, Toast.LENGTH_SHORT).show();
}
}
}
protected Theme getCurrentTheme() {
return _currentTheme;
}

View file

@ -224,7 +224,7 @@ public class EntryAdapter extends RecyclerView.Adapter<EntryHolder> implements I
notifyDataSetChanged();
} else {
for (EntryHolder holder : _holders) {
holder.refreshCode();
holder.refresh();
}
}
}

View file

@ -45,7 +45,7 @@ public class EntryHolder extends RecyclerView.ViewHolder {
private boolean _hidden;
private PeriodProgressBar _progressBar;
private TotpProgressBar _progressBar;
private View _view;
private UiRefresher _refresher;
@ -84,8 +84,6 @@ public class EntryHolder extends RecyclerView.ViewHolder {
if (!_hidden) {
refreshCode();
}
_progressBar.refresh();
}
@Override
@ -199,10 +197,17 @@ public class EntryHolder extends RecyclerView.ViewHolder {
public void startRefreshLoop() {
_refresher.start();
_progressBar.start();
}
public void stopRefreshLoop() {
_refresher.stop();
_progressBar.stop();
}
public void refresh() {
_progressBar.restart();
refreshCode();
}
public void refreshCode() {

View file

@ -23,8 +23,6 @@ import com.beemdevelopment.aegis.R;
import com.beemdevelopment.aegis.SortCategory;
import com.beemdevelopment.aegis.ViewMode;
import com.beemdevelopment.aegis.helpers.SimpleItemTouchHelperCallback;
import com.beemdevelopment.aegis.helpers.UiRefresher;
import com.beemdevelopment.aegis.otp.TotpInfo;
import com.beemdevelopment.aegis.vault.VaultEntry;
import com.bumptech.glide.Glide;
import com.bumptech.glide.ListPreloader;
@ -46,13 +44,11 @@ public class EntryListView extends Fragment implements EntryAdapter.Listener {
private RecyclerView _recyclerView;
private RecyclerView.ItemDecoration _dividerDecoration;
private ViewPreloadSizeProvider<VaultEntry> _preloadSizeProvider;
private PeriodProgressBar _progressBar;
private TotpProgressBar _progressBar;
private boolean _showProgress;
private ViewMode _viewMode;
private LinearLayout _emptyStateView;
private UiRefresher _refresher;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@ -97,19 +93,6 @@ public class EntryListView extends Fragment implements EntryAdapter.Listener {
int resId = R.anim.layout_animation_fall_down;
LayoutAnimationController animation = AnimationUtils.loadLayoutAnimation(getContext(), resId);
_recyclerView.setLayoutAnimation(animation);
_refresher = new UiRefresher(new UiRefresher.Listener() {
@Override
public void onRefresh() {
refresh(false);
}
@Override
public long getMillisTillNextRefresh() {
return TotpInfo.getMillisTillNextRotation(_adapter.getMostFrequentPeriod());
}
});
_emptyStateView = view.findViewById(R.id.vEmptyList);
return view;
@ -121,7 +104,6 @@ public class EntryListView extends Fragment implements EntryAdapter.Listener {
@Override
public void onDestroyView() {
_refresher.destroy();
super.onDestroyView();
}
@ -175,8 +157,9 @@ public class EntryListView extends Fragment implements EntryAdapter.Listener {
public void refresh(boolean hard) {
if (_showProgress) {
_progressBar.refresh();
_progressBar.restart();
}
_adapter.refresh(hard);
}
@ -224,13 +207,12 @@ public class EntryListView extends Fragment implements EntryAdapter.Listener {
public void onPeriodUniformityChanged(boolean isUniform, int period) {
setShowProgress(isUniform);
if (_showProgress) {
_refresher.stop();
_progressBar.setVisibility(View.VISIBLE);
_progressBar.setPeriod(period);
_refresher.start();
_progressBar.start();
} else {
_progressBar.setVisibility(View.GONE);
_refresher.stop();
_progressBar.stop();
}
}

View file

@ -1,54 +0,0 @@
package com.beemdevelopment.aegis.ui.views;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.os.Build;
import android.util.AttributeSet;
import android.view.animation.LinearInterpolator;
import android.widget.ProgressBar;
import com.beemdevelopment.aegis.otp.TotpInfo;
import androidx.annotation.RequiresApi;
public class PeriodProgressBar extends ProgressBar {
private int _period;
public PeriodProgressBar(Context context) {
super(context);
}
public PeriodProgressBar(Context context, AttributeSet attrs) {
super(context, attrs);
}
public PeriodProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public PeriodProgressBar(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
public void setPeriod(int period) {
_period = period;
}
public void refresh() {
// reset the progress bar
int maxProgress = getMax();
setProgress(maxProgress);
// calculate the progress the bar should start at
long millisTillRotation = TotpInfo.getMillisTillNextRotation(_period);
long period = _period * maxProgress;
int currentProgress = maxProgress - (int) ((((double) period - millisTillRotation) / period) * maxProgress);
// start progress animation
ObjectAnimator animation = ObjectAnimator.ofInt(this, "progress", currentProgress, 0);
animation.setDuration(millisTillRotation);
animation.setInterpolator(new LinearInterpolator());
animation.start();
}
}

View file

@ -0,0 +1,82 @@
package com.beemdevelopment.aegis.ui.views;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.os.Build;
import android.os.Handler;
import android.provider.Settings;
import android.util.AttributeSet;
import android.view.animation.LinearInterpolator;
import android.widget.ProgressBar;
import androidx.annotation.RequiresApi;
import com.beemdevelopment.aegis.otp.TotpInfo;
public class TotpProgressBar extends ProgressBar {
private int _period = 30;
private Handler _handler;
private float _animDurationScale;
public TotpProgressBar(Context context) {
super(context);
}
public TotpProgressBar(Context context, AttributeSet attrs) {
super(context, attrs);
}
public TotpProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public TotpProgressBar(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
public void setPeriod(int period) {
_period = period;
}
public void start() {
stop();
_handler = new Handler();
_animDurationScale = Settings.Global.getFloat(getContext().getContentResolver(), Settings.Global.ANIMATOR_DURATION_SCALE, 1.0f);
refresh();
}
public void stop() {
if (_handler != null) {
_handler.removeCallbacksAndMessages(null);
_handler = null;
}
}
public void restart() {
stop();
start();
}
private void refresh() {
// calculate the current progress the bar should start at
int maxProgress = getMax();
long millisTillRotation = TotpInfo.getMillisTillNextRotation(_period);
int currentProgress = (int) (maxProgress * ((float) millisTillRotation / (_period * 1000)));
// start progress animation, compensating for any changes to the animator duration scale settings
int animPart = maxProgress / _period;
int animEnd = (currentProgress / animPart) * animPart;
int animPartDuration = (int) (1000 / _animDurationScale);
float animDurationFraction = (float) (currentProgress - animEnd) / animPart;
int realAnimDuration = (int) (1000 * animDurationFraction);
int animDuration = (int) (animPartDuration * animDurationFraction);
ObjectAnimator animation = ObjectAnimator.ofInt(this, "progress", currentProgress, animEnd);
animation.setDuration(animDuration);
animation.setInterpolator(new LinearInterpolator());
animation.start();
// the animation only lasts for (less than) one second, so restart it after that
_handler.postDelayed(this::refresh, realAnimDuration);
}
}

View file

@ -152,12 +152,12 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.beemdevelopment.aegis.ui.views.PeriodProgressBar
<com.beemdevelopment.aegis.ui.views.TotpProgressBar
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="wrap_content"
android:layout_height="4dp"
android:id="@+id/progressBar"
android:max="1000"
android:max="5000"
android:layout_weight="1"/>
</LinearLayout>

View file

@ -151,7 +151,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.beemdevelopment.aegis.ui.views.PeriodProgressBar
<com.beemdevelopment.aegis.ui.views.TotpProgressBar
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="wrap_content"
android:layout_height="3dp"

View file

@ -150,7 +150,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.beemdevelopment.aegis.ui.views.PeriodProgressBar
<com.beemdevelopment.aegis.ui.views.TotpProgressBar
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="wrap_content"
android:layout_height="3dp"

View file

@ -6,14 +6,14 @@
android:background="?attr/background"
android:orientation="vertical">
<com.beemdevelopment.aegis.ui.views.PeriodProgressBar
<com.beemdevelopment.aegis.ui.views.TotpProgressBar
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="4dp"
android:progressDrawable="@drawable/progress_horizontal"
android:id="@+id/progressBar"
android:visibility="gone"
android:max="1000"/>
android:max="5000"/>
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"