move TOTP field up in EntryActivity and add a progress bar to indicate the time left for using the TOTP

closes https://github.com/PhilippC/keepass2android/issues/2315
This commit is contained in:
Philipp Crocoll
2024-01-05 09:01:29 +01:00
parent e189776ba9
commit 4fea731c87
6 changed files with 132 additions and 11 deletions

View File

@@ -32,6 +32,7 @@ using Android.Text.Method;
using System.Globalization;
using System.IO;
using System.Net;
using System.Threading.Tasks;
using Android.Content.PM;
using Android.Webkit;
using Android.Graphics;
@@ -49,7 +50,9 @@ using PluginTOTP;
using File = Java.IO.File;
using Uri = Android.Net.Uri;
using keepass2android.fileselect;
using KeeTrayTOTP.Libraries;
using Boolean = Java.Lang.Boolean;
using Android.Util;
namespace keepass2android
{
@@ -286,6 +289,8 @@ namespace keepass2android
extraGroup.AddView(view.View);
}
SetPasswordStyle();
//update the Entry output in the App database and notify the CopyToClipboard service
if (App.Kp2a.LastOpenedEntry != null)
@@ -665,7 +670,7 @@ namespace keepass2android
EditModeBase editMode = new DefaultEdit();
if (KpEntryTemplatedEdit.IsTemplated(App.Kp2a.CurrentDb, this.Entry))
editMode = new KpEntryTemplatedEdit(App.Kp2a.CurrentDb, this.Entry);
foreach (var key in editMode.SortExtraFieldKeys(Entry.Strings.GetKeys().Where(key=> !PwDefs.IsStandardField(key))))
foreach (var key in editMode.SortExtraFieldKeys(Entry.Strings.GetKeys().Where(key=> !PwDefs.IsStandardField(key) && key != Kp2aTotp.TotpKey)))
{
if (editMode.IsVisible(key))
{
@@ -841,7 +846,7 @@ namespace keepass2android
{
if (!_showPassword.ContainsKey(protectedTextView))
{
_showPassword[protectedTextView] = fieldKey == UpdateTotpTimerTask.TotpKey ? _showTotpDefault : _showPasswordDefault;
_showPassword[protectedTextView] = fieldKey == Kp2aTotp.TotpKey ? _showTotpDefault : _showPasswordDefault;
}
var protectedTextviewGroup = new ProtectedTextviewGroup { ProtectedField = protectedTextView, VisibleProtectedField = visibleTextView};
_protectedTextViews.Add(protectedTextviewGroup);
@@ -947,11 +952,13 @@ namespace keepass2android
PopulateStandardText(Resource.Id.entry_user_name, Resource.Id.entryfield_container_username, PwDefs.UserNameField);
PopulateStandardText(Resource.Id.entry_url, Resource.Id.entryfield_container_url, PwDefs.UrlField);
PopulateStandardText(new List<int> { Resource.Id.entry_password, Resource.Id.entry_password_visible}, Resource.Id.entryfield_container_password, PwDefs.PasswordField);
PopulateStandardText(new List<int> { Resource.Id.entry_totp, Resource.Id.entry_totp_visible }, Resource.Id.entryfield_container_totp, Kp2aTotp.TotpKey);
PopulateStandardText(new List<int> { Resource.Id.entry_password, Resource.Id.entry_password_visible}, Resource.Id.entryfield_container_password, PwDefs.PasswordField);
RegisterProtectedTextView(PwDefs.PasswordField, FindViewById<TextView>(Resource.Id.entry_password), FindViewById<TextView>(Resource.Id.entry_password_visible));
RegisterProtectedTextView(Kp2aTotp.TotpKey, FindViewById<TextView>(Resource.Id.entry_totp), FindViewById<TextView>(Resource.Id.entry_totp_visible));
RegisterTextPopup(FindViewById<RelativeLayout> (Resource.Id.groupname_container),
RegisterTextPopup(FindViewById<RelativeLayout> (Resource.Id.groupname_container),
FindViewById (Resource.Id.entry_group_name), KeyGroupFullPath);
RegisterTextPopup(FindViewById<RelativeLayout>(Resource.Id.username_container),
@@ -962,9 +969,11 @@ namespace keepass2android
.Add(new GotoUrlMenuItem(this, PwDefs.UrlField));
RegisterTextPopup(FindViewById<RelativeLayout>(Resource.Id.password_container),
FindViewById(Resource.Id.password_vdots), PwDefs.PasswordField);
RegisterTextPopup(FindViewById<RelativeLayout>(Resource.Id.totp_container),
FindViewById(Resource.Id.totp_vdots), Kp2aTotp.TotpKey);
PopulateText(Resource.Id.entry_created, Resource.Id.entryfield_container_created, getDateTime(Entry.CreationTime));
PopulateText(Resource.Id.entry_created, Resource.Id.entryfield_container_created, getDateTime(Entry.CreationTime));
PopulateText(Resource.Id.entry_modified, Resource.Id.entryfield_container_modified, getDateTime(Entry.LastModificationTime));
if (Entry.Expires)
@@ -991,6 +1000,40 @@ namespace keepass2android
SetPasswordStyle();
}
private async Task UpdateTotpCountdown()
{
if (App.Kp2a.LastOpenedEntry == null)
return;
var totpData = new Kp2aTotp().TryGetTotpData(App.Kp2a.LastOpenedEntry);
if (totpData == null || !totpData.IsTotpEntry)
return;
var totpProvider = new TOTPProvider(totpData);
var progressBar = FindViewById<ProgressBar>(Resource.Id.TotpCountdownProgressBar);
int lastSecondsLeft = -1;
while (!isPaused && progressBar != null)
{
int secondsLeft = totpProvider.Timer;
if (secondsLeft != lastSecondsLeft)
{
lastSecondsLeft = secondsLeft;
// Update the progress bar on the UI thread
RunOnUiThread(() =>
{
progressBar.Progress = secondsLeft;
progressBar.Max = totpProvider.Duration;
});
}
await Task.Delay(1000);
}
}
private void PopulatePreviousVersions()
{
@@ -1043,7 +1086,7 @@ namespace keepass2android
}
private List<IPopupMenuItem> RegisterTextPopup(View container, View anchor, string fieldKey)
{
return RegisterTextPopup(container, anchor, fieldKey, Entry.Strings.GetSafe(fieldKey).IsProtected);
return RegisterTextPopup(container, anchor, fieldKey, Entry.Strings.GetSafe(fieldKey).IsProtected || fieldKey == Kp2aTotp.TotpKey);
}
private List<IPopupMenuItem> RegisterTextPopup(View container, View anchor, string fieldKey, bool isProtected)
@@ -1056,7 +1099,12 @@ namespace keepass2android
popupItems.Add(new CopyToClipboardPopupMenuIcon(this, _stringViews[fieldKey], isProtected));
if (isProtected)
{
var valueView = container.FindViewById<TextView>(fieldKey == PwDefs.PasswordField ? Resource.Id.entry_password : Resource.Id.entry_extra);
var valueView = container.FindViewById<TextView>(fieldKey switch
{
PwDefs.PasswordField => Resource.Id.entry_password,
Kp2aTotp.TotpKey => Resource.Id.entry_totp,
_ => Resource.Id.entry_extra
});
popupItems.Add(new ToggleVisibilityPopupMenuItem(this, valueView));
}
@@ -1283,11 +1331,16 @@ namespace keepass2android
return base.OnPrepareOptionsMenu(menu);
}
bool isPaused = false;
protected override void OnPause()
{
base.OnPause();
isPaused = true;
}
private void UpdateTogglePasswordMenu()
private void UpdateTogglePasswordMenu()
{
IMenuItem togglePassword = _menu.FindItem(Resource.Id.menu_toggle_pass);
if (_showPassword.Values.All(x => x))
@@ -1324,7 +1377,9 @@ namespace keepass2android
ClearCache();
base.OnResume();
_activityDesign.ReapplyTheme();
}
isPaused = false;
Task.Run(UpdateTotpCountdown);
}
public void ClearCache()
{

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

View File

@@ -184,6 +184,68 @@
</RelativeLayout>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/entryfield_container_totp"
style="@style/EntryEditSingleLine_container">
<ImageView
style="@style/EntryEditSingleLine_ImageView"
android:src="@drawable/ic_entry_totp" />
<LinearLayout
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:orientation="vertical">
<!-- TOTP -->
<TextView
android:id="@+id/entry_totp_label"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/TOTP"
style="@style/EntryFieldHeader" />
<RelativeLayout
android:id="@+id/totp_container"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:orientation="horizontal"
android:clickable="true"
android:background="?android:attr/selectableItemBackground">
<ImageView
android:id="@+id/totp_vdots"
android:layout_width="wrap_content"
android:layout_height="15dp"
android:src="@drawable/vdots"
android:gravity="right|bottom"
android:layout_alignParentRight="true" />
<TextView
android:id="@+id/entry_totp"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:password="true"
android:typeface="monospace"
android:layout_toLeftOf="@id/totp_vdots"
style="@style/EntryItem" />
<TextView
android:id="@+id/entry_totp_visible"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_toLeftOf="@id/totp_vdots"
style="@style/EntryItem" />
</RelativeLayout>
<ProgressBar
android:id="@+id/TotpCountdownProgressBar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignParentBottom="true"
android:layout_marginRight="30dp" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/entryfield_container_comment"
style="@style/EntryEditSingleLine_container">

View File

@@ -599,6 +599,7 @@
<string name="CouldntLoadChalAuxFile_Hint">Please use the KeeChallenge plugin in KeePass 2.x (PC) to configure your database for use with challenge-response!</string>
<string name="ErrorUpdatingChalAuxFile">Error updating OTP auxiliary file!</string>
<string name="TrayTotp_SeedField_title">TOTP Seed field name</string>
<string name="TOTP">TOTP</string>
<string name="TrayTotp_SeedField_summary">If you are using the Keepass 2 plugin "TrayTotp" with non-default settings, enter the field name for the seed field here according to the settings on the PC.</string>
<string name="TrayTotp_SettingsField_title">TOTP Settings field name</string>
<string name="TrayTotp_SettingsField_summary">Enter the field name of the settings field for TrayTotp here.</string>

View File

@@ -1985,6 +1985,9 @@
<ItemGroup>
<AndroidResource Include="Resources\drawable-mdpi\ic_storage_pcloudall.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xhdpi\ic_entry_totp.png" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.