mirror of
https://github.com/beemdevelopment/Aegis.git
synced 2025-06-28 11:49:55 +00:00
Merge pull request #1599 from michaelschattgen/feature/haptic-feedback
Add haptic feedback toggle for code refresh
This commit is contained in:
commit
6f270144e2
10 changed files with 144 additions and 9 deletions
|
@ -4,6 +4,7 @@
|
|||
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
|
||||
<!-- NOTE: Disabled for now. See issue: #1047
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||
|
|
|
@ -94,6 +94,10 @@ public class Preferences {
|
|||
return _prefs.getBoolean("pref_highlight_entry", false);
|
||||
}
|
||||
|
||||
public boolean isHapticFeedbackEnabled() {
|
||||
return _prefs.getBoolean("pref_haptic_feedback", true);
|
||||
}
|
||||
|
||||
public boolean isPauseFocusedEnabled() {
|
||||
boolean dependenciesEnabled = isTapToRevealEnabled() || isEntryHighlightEnabled();
|
||||
if (!dependenciesEnabled) return false;
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
package com.beemdevelopment.aegis;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class VibrationPatterns {
|
||||
public static final long[] EXPIRING = {475, 20, 5, 20, 965, 20, 5, 20, 965, 20, 5, 20, 420};
|
||||
public static final long[] REFRESH_CODE = {0, 100};
|
||||
|
||||
public static long getLengthInMillis(long[] pattern) {
|
||||
return Arrays.stream(pattern).sum();
|
||||
}
|
||||
}
|
|
@ -2,6 +2,8 @@ package com.beemdevelopment.aegis.helpers;
|
|||
|
||||
import android.os.Handler;
|
||||
|
||||
import com.beemdevelopment.aegis.VibrationPatterns;
|
||||
|
||||
public class UiRefresher {
|
||||
private boolean _running;
|
||||
private Listener _listener;
|
||||
|
@ -23,7 +25,6 @@ public class UiRefresher {
|
|||
}
|
||||
_running = true;
|
||||
|
||||
_listener.onRefresh();
|
||||
_handler.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
@ -31,6 +32,27 @@ public class UiRefresher {
|
|||
_handler.postDelayed(this, _listener.getMillisTillNextRefresh());
|
||||
}
|
||||
}, _listener.getMillisTillNextRefresh());
|
||||
|
||||
_handler.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
_listener.onExpiring();
|
||||
_handler.postDelayed(this, getNextRun());
|
||||
}
|
||||
}, getInitialRun());
|
||||
}
|
||||
|
||||
private long getInitialRun() {
|
||||
long sum = _listener.getMillisTillNextRefresh() - VibrationPatterns.getLengthInMillis(VibrationPatterns.EXPIRING);
|
||||
if (sum < 0) {
|
||||
return getNextRun();
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
private long getNextRun() {
|
||||
return (_listener.getMillisTillNextRefresh() + _listener.getPeriodMillis()) - VibrationPatterns.getLengthInMillis(VibrationPatterns.EXPIRING);
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
|
@ -40,6 +62,8 @@ public class UiRefresher {
|
|||
|
||||
public interface Listener {
|
||||
void onRefresh();
|
||||
void onExpiring();
|
||||
long getMillisTillNextRefresh();
|
||||
long getPeriodMillis();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
package com.beemdevelopment.aegis.helpers;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.os.VibrationEffect;
|
||||
import android.os.Vibrator;
|
||||
import android.os.VibratorManager;
|
||||
|
||||
import com.beemdevelopment.aegis.Preferences;
|
||||
|
||||
public class VibrationHelper {
|
||||
private Preferences _preferences;
|
||||
|
||||
public VibrationHelper(Context context) {
|
||||
_preferences = new Preferences(context);
|
||||
}
|
||||
|
||||
public void vibratePattern(Context context, long[] pattern) {
|
||||
if (!isHapticFeedbackEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
VibratorManager vibratorManager = (VibratorManager) context.getSystemService(Context.VIBRATOR_MANAGER_SERVICE);
|
||||
if (vibratorManager != null) {
|
||||
Vibrator vibrator = vibratorManager.getDefaultVibrator();
|
||||
VibrationEffect effect = VibrationEffect.createWaveform(pattern, -1);
|
||||
vibrator.vibrate(effect);
|
||||
}
|
||||
} else {
|
||||
Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
|
||||
if (vibrator != null) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
VibrationEffect effect = VibrationEffect.createWaveform(pattern, -1);
|
||||
vibrator.vibrate(effect);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isHapticFeedbackEnabled() {
|
||||
return _preferences.isHapticFeedbackEnabled();
|
||||
}
|
||||
}
|
|
@ -890,6 +890,13 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
super.onStop();
|
||||
|
||||
_entryListView.onRefreshStop();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStart() {
|
||||
super.onStart();
|
||||
|
@ -941,10 +948,14 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
|
|||
|
||||
// refresh all codes to prevent showing old ones
|
||||
_entryListView.refresh(false);
|
||||
|
||||
_entryListView.onRefreshStart();
|
||||
} else {
|
||||
loadEntries();
|
||||
checkTimeSyncSetting();
|
||||
checkIconOptimization();
|
||||
|
||||
_entryListView.onRefreshStart();
|
||||
}
|
||||
|
||||
_lockBackPressHandler.setEnabled(
|
||||
|
|
|
@ -67,7 +67,6 @@ public class EntryHolder extends RecyclerView.ViewHolder {
|
|||
|
||||
private boolean _hidden;
|
||||
private boolean _paused;
|
||||
|
||||
private TotpProgressBar _progressBar;
|
||||
private MaterialCardView _view;
|
||||
|
||||
|
@ -111,14 +110,22 @@ public class EntryHolder extends RecyclerView.ViewHolder {
|
|||
refreshCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onExpiring() { }
|
||||
|
||||
@Override
|
||||
public long getMillisTillNextRefresh() {
|
||||
return ((TotpInfo) _entry.getInfo()).getMillisTillNextRotation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getPeriodMillis() {
|
||||
return ((TotpInfo) _entry.getInfo()).getPeriod() * 1000L;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void setData(VaultEntry entry, Preferences.CodeGrouping groupSize, ViewMode viewMode, AccountNamePosition accountNamePosition, boolean showIcon, boolean showProgress, boolean hidden, boolean paused, boolean dimmed, boolean showExpirationState, boolean showNextCode) {
|
||||
public void setData(VaultEntry entry, Preferences.CodeGrouping groupSize, ViewMode viewMode, AccountNamePosition accountNamePosition, boolean showIcon, boolean nonUniform, boolean hidden, boolean paused, boolean dimmed, boolean showExpirationState, boolean showNextCode) {
|
||||
_entry = entry;
|
||||
_hidden = hidden;
|
||||
_paused = paused;
|
||||
|
@ -140,7 +147,7 @@ public class EntryHolder extends RecyclerView.ViewHolder {
|
|||
_favoriteIndicator.setVisibility(_entry.isFavorite() ? View.VISIBLE : View.INVISIBLE);
|
||||
|
||||
// only show the progress bar if there is no uniform period and the entry type is TotpInfo
|
||||
setShowProgress(showProgress);
|
||||
setShowProgress(nonUniform);
|
||||
|
||||
// only show the button if this entry is of type HotpInfo
|
||||
_buttonRefresh.setVisibility(entry.getInfo() instanceof HotpInfo ? View.VISIBLE : View.GONE);
|
||||
|
|
|
@ -33,11 +33,13 @@ import com.beemdevelopment.aegis.CopyBehavior;
|
|||
import com.beemdevelopment.aegis.Preferences;
|
||||
import com.beemdevelopment.aegis.R;
|
||||
import com.beemdevelopment.aegis.SortCategory;
|
||||
import com.beemdevelopment.aegis.VibrationPatterns;
|
||||
import com.beemdevelopment.aegis.ViewMode;
|
||||
import com.beemdevelopment.aegis.helpers.AnimationsHelper;
|
||||
import com.beemdevelopment.aegis.helpers.MetricsHelper;
|
||||
import com.beemdevelopment.aegis.helpers.SimpleItemTouchHelperCallback;
|
||||
import com.beemdevelopment.aegis.helpers.UiRefresher;
|
||||
import com.beemdevelopment.aegis.helpers.VibrationHelper;
|
||||
import com.beemdevelopment.aegis.otp.TotpInfo;
|
||||
import com.beemdevelopment.aegis.ui.glide.GlideHelper;
|
||||
import com.beemdevelopment.aegis.ui.models.ErrorCardInfo;
|
||||
|
@ -66,13 +68,13 @@ public class EntryListView extends Fragment implements EntryAdapter.Listener {
|
|||
private Listener _listener;
|
||||
private SimpleItemTouchHelperCallback _touchCallback;
|
||||
private ItemTouchHelper _touchHelper;
|
||||
private VibrationHelper _vibrationHelper;
|
||||
|
||||
private RecyclerView _recyclerView;
|
||||
private RecyclerView.ItemDecoration _itemDecoration;
|
||||
private ViewPreloadSizeProvider<VaultEntry> _preloadSizeProvider;
|
||||
private TotpProgressBar _progressBar;
|
||||
private boolean _showProgress;
|
||||
private boolean _showExpirationState;
|
||||
private ViewMode _viewMode;
|
||||
private LinearLayout _emptyStateView;
|
||||
|
||||
|
@ -95,6 +97,7 @@ public class EntryListView extends Fragment implements EntryAdapter.Listener {
|
|||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
View view = inflater.inflate(R.layout.fragment_entry_list_view, container, false);
|
||||
_progressBar = view.findViewById(R.id.progressBar);
|
||||
_vibrationHelper = new VibrationHelper(getContext());
|
||||
|
||||
// set up the recycler view
|
||||
_recyclerView = view.findViewById(R.id.rvKeyProfiles);
|
||||
|
@ -144,12 +147,23 @@ public class EntryListView extends Fragment implements EntryAdapter.Listener {
|
|||
@Override
|
||||
public void onRefresh() {
|
||||
refresh(false);
|
||||
_vibrationHelper.vibratePattern(getContext(), VibrationPatterns.REFRESH_CODE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onExpiring() {
|
||||
_vibrationHelper.vibratePattern(getContext(), VibrationPatterns.EXPIRING);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getMillisTillNextRefresh() {
|
||||
return TotpInfo.getMillisTillNextRotation(_adapter.getMostFrequentPeriod());
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getPeriodMillis() {
|
||||
return _adapter.getMostFrequentPeriod() * 1000L;
|
||||
}
|
||||
});
|
||||
|
||||
final int rvInitialPaddingLeft = _recyclerView.getPaddingLeft();
|
||||
|
@ -191,6 +205,16 @@ public class EntryListView extends Fragment implements EntryAdapter.Listener {
|
|||
super.onDestroyView();
|
||||
}
|
||||
|
||||
public void onRefreshStop() {
|
||||
_refresher.stop();
|
||||
}
|
||||
|
||||
public void onRefreshStart() {
|
||||
if (_adapter.getMostFrequentPeriod() != -1){
|
||||
_refresher.start();
|
||||
}
|
||||
}
|
||||
|
||||
public void setGroups(Collection<VaultGroup> groups) {
|
||||
_adapter.setGroups(groups);
|
||||
updateDividerDecoration();
|
||||
|
@ -355,11 +379,11 @@ public class EntryListView extends Fragment implements EntryAdapter.Listener {
|
|||
_progressBar.setVisibility(View.VISIBLE);
|
||||
_progressBar.setPeriod(period);
|
||||
_progressBar.start();
|
||||
_refresher.start();
|
||||
onRefreshStart();
|
||||
} else {
|
||||
_progressBar.setVisibility(View.GONE);
|
||||
_progressBar.stop();
|
||||
_refresher.stop();
|
||||
onRefreshStop();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -391,7 +415,6 @@ public class EntryListView extends Fragment implements EntryAdapter.Listener {
|
|||
}
|
||||
|
||||
public void setShowExpirationState(boolean showExpirationState) {
|
||||
_showExpirationState = showExpirationState;
|
||||
_adapter.setShowExpirationState(showExpirationState);
|
||||
}
|
||||
|
||||
|
|
|
@ -373,6 +373,8 @@
|
|||
<string name="note" comment="Users can add a note to an entry">Note</string>
|
||||
<string name="clear">Clear</string>
|
||||
|
||||
<string name="pref_haptic_feedback_summary">Make your device vibrate when codes are refreshing</string>
|
||||
<string name="pref_haptic_feedback_title">Haptic feedback</string>
|
||||
<string name="pref_highlight_entry_title">Highlight tokens when tapped</string>
|
||||
<string name="pref_highlight_entry_summary">Make tokens easier to distinguish from each other by temporarily highlighting them when tapped</string>
|
||||
<string name="pref_groups_multiselect_title">Multiselect groups</string>
|
||||
|
|
|
@ -26,6 +26,13 @@
|
|||
android:title="@string/pref_copy_behavior_title"
|
||||
app:iconSpaceReserved="false"/>
|
||||
|
||||
<androidx.preference.SwitchPreferenceCompat
|
||||
android:defaultValue="true"
|
||||
android:key="pref_haptic_feedback"
|
||||
android:title="@string/pref_haptic_feedback_title"
|
||||
android:summary="@string/pref_haptic_feedback_summary"
|
||||
app:iconSpaceReserved="false"/>
|
||||
|
||||
<androidx.preference.SwitchPreferenceCompat
|
||||
android:defaultValue="false"
|
||||
android:key="pref_groups_multiselect"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue