mirror of
https://github.com/bitwarden/android.git
synced 2024-12-25 02:18:27 +03:00
Fix Clipboard clear after time on iOS (#1679)
* Fixed Clipboard clear after x seconds depending on what the user set. Also refactored a bit to make the Clipboard a custom service to provide a better way to handle this situation #1464 * Clear some usings #1464
This commit is contained in:
parent
23a164b245
commit
705b8ac12b
17 changed files with 157 additions and 131 deletions
|
@ -149,6 +149,7 @@
|
|||
<Compile Include="Utilities\ThemeHelpers.cs" />
|
||||
<Compile Include="WebAuthCallbackActivity.cs" />
|
||||
<Compile Include="Renderers\SelectableLabelRenderer.cs" />
|
||||
<Compile Include="Services\ClipboardService.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidAsset Include="Assets\FontAwesome.ttf" />
|
||||
|
|
|
@ -34,9 +34,7 @@ namespace Bit.Droid
|
|||
private IBroadcasterService _broadcasterService;
|
||||
private IUserService _userService;
|
||||
private IAppIdService _appIdService;
|
||||
private IStorageService _storageService;
|
||||
private IEventService _eventService;
|
||||
private PendingIntent _clearClipboardPendingIntent;
|
||||
private PendingIntent _eventUploadPendingIntent;
|
||||
private AppOptions _appOptions;
|
||||
private string _activityKey = $"{nameof(MainActivity)}_{Java.Lang.JavaSystem.CurrentTimeMillis().ToString()}";
|
||||
|
@ -48,9 +46,6 @@ namespace Bit.Droid
|
|||
var eventUploadIntent = new Intent(this, typeof(EventUploadReceiver));
|
||||
_eventUploadPendingIntent = PendingIntent.GetBroadcast(this, 0, eventUploadIntent,
|
||||
PendingIntentFlags.UpdateCurrent);
|
||||
var clearClipboardIntent = new Intent(this, typeof(ClearClipboardAlarmReceiver));
|
||||
_clearClipboardPendingIntent = PendingIntent.GetBroadcast(this, 0, clearClipboardIntent,
|
||||
PendingIntentFlags.UpdateCurrent);
|
||||
|
||||
var policy = new StrictMode.ThreadPolicy.Builder().PermitAll().Build();
|
||||
StrictMode.SetThreadPolicy(policy);
|
||||
|
@ -60,7 +55,6 @@ namespace Bit.Droid
|
|||
_broadcasterService = ServiceContainer.Resolve<IBroadcasterService>("broadcasterService");
|
||||
_userService = ServiceContainer.Resolve<IUserService>("userService");
|
||||
_appIdService = ServiceContainer.Resolve<IAppIdService>("appIdService");
|
||||
_storageService = ServiceContainer.Resolve<IStorageService>("storageService");
|
||||
_eventService = ServiceContainer.Resolve<IEventService>("eventService");
|
||||
|
||||
TabLayoutResource = Resource.Layout.Tabbar;
|
||||
|
@ -108,10 +102,6 @@ namespace Bit.Droid
|
|||
{
|
||||
ExitApp();
|
||||
}
|
||||
else if (message.Command == "copiedToClipboard")
|
||||
{
|
||||
var task = ClearClipboardAlarmAsync(message.Data as Tuple<string, int?, bool>);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -388,30 +378,6 @@ namespace Bit.Droid
|
|||
Java.Lang.JavaSystem.Exit(0);
|
||||
}
|
||||
|
||||
private async Task ClearClipboardAlarmAsync(Tuple<string, int?, bool> data)
|
||||
{
|
||||
if (data.Item3)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var clearMs = data.Item2;
|
||||
if (clearMs == null)
|
||||
{
|
||||
var clearSeconds = await _storageService.GetAsync<int?>(Constants.ClearClipboardKey);
|
||||
if (clearSeconds != null)
|
||||
{
|
||||
clearMs = clearSeconds.Value * 1000;
|
||||
}
|
||||
}
|
||||
if (clearMs == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var triggerMs = Java.Lang.JavaSystem.CurrentTimeMillis() + clearMs.Value;
|
||||
var alarmManager = GetSystemService(AlarmService) as AlarmManager;
|
||||
alarmManager.Set(AlarmType.Rtc, triggerMs, _clearClipboardPendingIntent);
|
||||
}
|
||||
|
||||
private void StartEventAlarm()
|
||||
{
|
||||
var alarmManager = GetSystemService(AlarmService) as AlarmManager;
|
||||
|
|
|
@ -113,6 +113,7 @@ namespace Bit.Droid
|
|||
ServiceContainer.Register<ICryptoPrimitiveService>("cryptoPrimitiveService", cryptoPrimitiveService);
|
||||
ServiceContainer.Register<IStorageService>("storageService", mobileStorageService);
|
||||
ServiceContainer.Register<IStorageService>("secureStorageService", secureStorageService);
|
||||
ServiceContainer.Register<IClipboardService>("clipboardService", new ClipboardService(mobileStorageService));
|
||||
ServiceContainer.Register<IDeviceActionService>("deviceActionService", deviceActionService);
|
||||
ServiceContainer.Register<IPlatformUtilsService>("platformUtilsService", platformUtilsService);
|
||||
ServiceContainer.Register<IBiometricService>("biometricService", biometricService);
|
||||
|
|
57
src/Android/Services/ClipboardService.cs
Normal file
57
src/Android/Services/ClipboardService.cs
Normal file
|
@ -0,0 +1,57 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Android.App;
|
||||
using Android.Content;
|
||||
using Bit.Core;
|
||||
using Bit.Core.Abstractions;
|
||||
using Bit.Droid.Receivers;
|
||||
using Plugin.CurrentActivity;
|
||||
using Xamarin.Essentials;
|
||||
|
||||
namespace Bit.Droid.Services
|
||||
{
|
||||
public class ClipboardService : IClipboardService
|
||||
{
|
||||
private readonly IStorageService _storageService;
|
||||
private readonly Lazy<PendingIntent> _clearClipboardPendingIntent;
|
||||
|
||||
public ClipboardService(IStorageService storageService)
|
||||
{
|
||||
_storageService = storageService;
|
||||
|
||||
_clearClipboardPendingIntent = new Lazy<PendingIntent>(() =>
|
||||
PendingIntent.GetBroadcast(CrossCurrentActivity.Current.Activity,
|
||||
0,
|
||||
new Intent(CrossCurrentActivity.Current.Activity, typeof(ClearClipboardAlarmReceiver)),
|
||||
PendingIntentFlags.UpdateCurrent));
|
||||
}
|
||||
|
||||
public async Task CopyTextAsync(string text, int expiresInMs = -1)
|
||||
{
|
||||
await Clipboard.SetTextAsync(text);
|
||||
|
||||
await ClearClipboardAlarmAsync(expiresInMs);
|
||||
}
|
||||
|
||||
private async Task ClearClipboardAlarmAsync(int expiresInMs = -1)
|
||||
{
|
||||
var clearMs = expiresInMs;
|
||||
if (clearMs < 0)
|
||||
{
|
||||
// if not set then we need to check if the user set this config
|
||||
var clearSeconds = await _storageService.GetAsync<int?>(Constants.ClearClipboardKey);
|
||||
if (clearSeconds != null)
|
||||
{
|
||||
clearMs = clearSeconds.Value * 1000;
|
||||
}
|
||||
}
|
||||
if (clearMs < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var triggerMs = Java.Lang.JavaSystem.CurrentTimeMillis() + clearMs;
|
||||
var alarmManager = CrossCurrentActivity.Current.Activity.GetSystemService(Context.AlarmService) as AlarmManager;
|
||||
alarmManager.Set(AlarmType.Rtc, triggerMs, _clearClipboardPendingIntent.Value);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,6 +12,7 @@ namespace Bit.App.Pages
|
|||
{
|
||||
private readonly IPlatformUtilsService _platformUtilsService;
|
||||
private readonly IPasswordGenerationService _passwordGenerationService;
|
||||
private readonly IClipboardService _clipboardService;
|
||||
|
||||
private bool _showNoData;
|
||||
|
||||
|
@ -20,6 +21,7 @@ namespace Bit.App.Pages
|
|||
_platformUtilsService = ServiceContainer.Resolve<IPlatformUtilsService>("platformUtilsService");
|
||||
_passwordGenerationService = ServiceContainer.Resolve<IPasswordGenerationService>(
|
||||
"passwordGenerationService");
|
||||
_clipboardService = ServiceContainer.Resolve<IClipboardService>("clipboardService");
|
||||
|
||||
PageTitle = AppResources.PasswordHistory;
|
||||
History = new ExtendedObservableCollection<GeneratedPasswordHistory>();
|
||||
|
@ -51,7 +53,7 @@ namespace Bit.App.Pages
|
|||
|
||||
private async void CopyAsync(GeneratedPasswordHistory ph)
|
||||
{
|
||||
await _platformUtilsService.CopyToClipboardAsync(ph.Password);
|
||||
await _clipboardService.CopyTextAsync(ph.Password);
|
||||
_platformUtilsService.ShowToast("info", null,
|
||||
string.Format(AppResources.ValueHasBeenCopied, AppResources.Password));
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ namespace Bit.App.Pages
|
|||
{
|
||||
private readonly IPasswordGenerationService _passwordGenerationService;
|
||||
private readonly IPlatformUtilsService _platformUtilsService;
|
||||
private readonly IClipboardService _clipboardService;
|
||||
|
||||
private PasswordGenerationOptions _options;
|
||||
private PasswordGeneratorPolicyOptions _enforcedPolicyOptions;
|
||||
|
@ -38,6 +39,8 @@ namespace Bit.App.Pages
|
|||
_passwordGenerationService = ServiceContainer.Resolve<IPasswordGenerationService>(
|
||||
"passwordGenerationService");
|
||||
_platformUtilsService = ServiceContainer.Resolve<IPlatformUtilsService>("platformUtilsService");
|
||||
_clipboardService = ServiceContainer.Resolve<IClipboardService>("clipboardService");
|
||||
|
||||
PageTitle = AppResources.PasswordGenerator;
|
||||
TypeOptions = new List<string> { AppResources.Password, AppResources.Passphrase };
|
||||
}
|
||||
|
@ -305,7 +308,7 @@ namespace Bit.App.Pages
|
|||
|
||||
public async Task CopyAsync()
|
||||
{
|
||||
await _platformUtilsService.CopyToClipboardAsync(Password);
|
||||
await _clipboardService.CopyTextAsync(Password);
|
||||
_platformUtilsService.ShowToast("success", null,
|
||||
string.Format(AppResources.ValueHasBeenCopied, AppResources.Password));
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ namespace Bit.App.Pages
|
|||
private readonly IPolicyService _policyService;
|
||||
private readonly ILocalizeService _localizeService;
|
||||
private readonly IKeyConnectorService _keyConnectorService;
|
||||
private readonly IClipboardService _clipboardService;
|
||||
|
||||
private const int CustomVaultTimeoutValue = -100;
|
||||
|
||||
|
@ -78,6 +79,7 @@ namespace Bit.App.Pages
|
|||
_policyService = ServiceContainer.Resolve<IPolicyService>("policyService");
|
||||
_localizeService = ServiceContainer.Resolve<ILocalizeService>("localizeService");
|
||||
_keyConnectorService = ServiceContainer.Resolve<IKeyConnectorService>("keyConnectorService");
|
||||
_clipboardService = ServiceContainer.Resolve<IClipboardService>("clipboardService");
|
||||
|
||||
GroupedItems = new ExtendedObservableCollection<SettingsPageListGroup>();
|
||||
PageTitle = AppResources.Settings;
|
||||
|
@ -135,7 +137,7 @@ namespace Bit.App.Pages
|
|||
AppResources.Close);
|
||||
if (copy)
|
||||
{
|
||||
await _platformUtilsService.CopyToClipboardAsync(debugText);
|
||||
await _clipboardService.CopyTextAsync(debugText);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ namespace Bit.App.Pages
|
|||
{
|
||||
private readonly IPlatformUtilsService _platformUtilsService;
|
||||
private readonly ICipherService _cipherService;
|
||||
private readonly IClipboardService _clipboardService;
|
||||
|
||||
private bool _showNoData;
|
||||
|
||||
|
@ -19,6 +20,7 @@ namespace Bit.App.Pages
|
|||
{
|
||||
_platformUtilsService = ServiceContainer.Resolve<IPlatformUtilsService>("platformUtilsService");
|
||||
_cipherService = ServiceContainer.Resolve<ICipherService>("cipherService");
|
||||
_clipboardService = ServiceContainer.Resolve<IClipboardService>("clipboardService");
|
||||
|
||||
PageTitle = AppResources.PasswordHistory;
|
||||
History = new ExtendedObservableCollection<PasswordHistoryView>();
|
||||
|
@ -45,7 +47,7 @@ namespace Bit.App.Pages
|
|||
|
||||
private async void CopyAsync(PasswordHistoryView ph)
|
||||
{
|
||||
await _platformUtilsService.CopyToClipboardAsync(ph.Password);
|
||||
await _clipboardService.CopyTextAsync(ph.Password);
|
||||
_platformUtilsService.ShowToast("info", null,
|
||||
string.Format(AppResources.ValueHasBeenCopied, AppResources.Password));
|
||||
}
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
using Bit.App.Abstractions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Bit.App.Abstractions;
|
||||
using Bit.App.Resources;
|
||||
using Bit.App.Utilities;
|
||||
using Bit.Core.Abstractions;
|
||||
|
@ -6,10 +10,6 @@ using Bit.Core.Enums;
|
|||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Models.View;
|
||||
using Bit.Core.Utilities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace Bit.App.Pages
|
||||
|
@ -26,6 +26,8 @@ namespace Bit.App.Pages
|
|||
private readonly IEventService _eventService;
|
||||
private readonly IPasswordRepromptService _passwordRepromptService;
|
||||
private readonly ILocalizeService _localizeService;
|
||||
private readonly IClipboardService _clipboardService;
|
||||
|
||||
private CipherView _cipher;
|
||||
private List<ViewPageFieldViewModel> _fields;
|
||||
private bool _canAccessPremium;
|
||||
|
@ -54,6 +56,8 @@ namespace Bit.App.Pages
|
|||
_eventService = ServiceContainer.Resolve<IEventService>("eventService");
|
||||
_passwordRepromptService = ServiceContainer.Resolve<IPasswordRepromptService>("passwordRepromptService");
|
||||
_localizeService = ServiceContainer.Resolve<ILocalizeService>("localizeService");
|
||||
_clipboardService = ServiceContainer.Resolve<IClipboardService>("clipboardService");
|
||||
|
||||
CopyCommand = new Command<string>((id) => CopyAsync(id, null));
|
||||
CopyUriCommand = new Command<LoginUriView>(CopyUri);
|
||||
CopyFieldCommand = new Command<FieldView>(CopyField);
|
||||
|
@ -653,7 +657,7 @@ namespace Bit.App.Pages
|
|||
|
||||
if (text != null)
|
||||
{
|
||||
await _platformUtilsService.CopyToClipboardAsync(text);
|
||||
await _clipboardService.CopyTextAsync(text);
|
||||
if (!string.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
_platformUtilsService.ShowToast("info", null, string.Format(AppResources.ValueHasBeenCopied, name));
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
using Bit.App.Abstractions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Bit.App.Abstractions;
|
||||
using Bit.App.Models;
|
||||
using Bit.App.Resources;
|
||||
using Bit.Core.Abstractions;
|
||||
using Plugin.Fingerprint;
|
||||
using Plugin.Fingerprint.Abstractions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Xamarin.Essentials;
|
||||
using Xamarin.Forms;
|
||||
|
||||
|
@ -21,6 +21,7 @@ namespace Bit.App.Services
|
|||
private readonly IDeviceActionService _deviceActionService;
|
||||
private readonly IMessagingService _messagingService;
|
||||
private readonly IBroadcasterService _broadcasterService;
|
||||
|
||||
private readonly Dictionary<int, Tuple<TaskCompletionSource<bool>, DateTime>> _showDialogResolves =
|
||||
new Dictionary<int, Tuple<TaskCompletionSource<bool>, DateTime>>();
|
||||
|
||||
|
@ -201,17 +202,6 @@ namespace Bit.App.Services
|
|||
return false;
|
||||
}
|
||||
|
||||
public async Task CopyToClipboardAsync(string text, Dictionary<string, object> options = null)
|
||||
{
|
||||
var clearMs = options != null && options.ContainsKey("clearMs") ? (int?)options["clearMs"] : null;
|
||||
var clearing = options != null && options.ContainsKey("clearing") ? (bool)options["clearing"] : false;
|
||||
await Clipboard.SetTextAsync(text);
|
||||
if (!clearing)
|
||||
{
|
||||
_messagingService.Send("copiedToClipboard", new Tuple<string, int?, bool>(text, clearMs, clearing));
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<string> ReadFromClipboardAsync(Dictionary<string, object> options = null)
|
||||
{
|
||||
return await Clipboard.GetTextAsync();
|
||||
|
|
|
@ -27,6 +27,8 @@ namespace Bit.App.Utilities
|
|||
var platformUtilsService = ServiceContainer.Resolve<IPlatformUtilsService>("platformUtilsService");
|
||||
var eventService = ServiceContainer.Resolve<IEventService>("eventService");
|
||||
var vaultTimeoutService = ServiceContainer.Resolve<IVaultTimeoutService>("vaultTimeoutService");
|
||||
var clipboardService = ServiceContainer.Resolve<IClipboardService>("clipboardService");
|
||||
|
||||
var options = new List<string> { AppResources.View };
|
||||
if (!cipher.IsDeleted)
|
||||
{
|
||||
|
@ -92,7 +94,7 @@ namespace Bit.App.Utilities
|
|||
}
|
||||
else if (selection == AppResources.CopyUsername)
|
||||
{
|
||||
await platformUtilsService.CopyToClipboardAsync(cipher.Login.Username);
|
||||
await clipboardService.CopyTextAsync(cipher.Login.Username);
|
||||
platformUtilsService.ShowToast("info", null,
|
||||
string.Format(AppResources.ValueHasBeenCopied, AppResources.Username));
|
||||
}
|
||||
|
@ -100,7 +102,7 @@ namespace Bit.App.Utilities
|
|||
{
|
||||
if (cipher.Reprompt == CipherRepromptType.None || await passwordRepromptService.ShowPasswordPromptAsync())
|
||||
{
|
||||
await platformUtilsService.CopyToClipboardAsync(cipher.Login.Password);
|
||||
await clipboardService.CopyTextAsync(cipher.Login.Password);
|
||||
platformUtilsService.ShowToast("info", null,
|
||||
string.Format(AppResources.ValueHasBeenCopied, AppResources.Password));
|
||||
var task = eventService.CollectAsync(Core.Enums.EventType.Cipher_ClientCopiedPassword, cipher.Id);
|
||||
|
@ -114,7 +116,7 @@ namespace Bit.App.Utilities
|
|||
var totp = await totpService.GetCodeAsync(cipher.Login.Totp);
|
||||
if (!string.IsNullOrWhiteSpace(totp))
|
||||
{
|
||||
await platformUtilsService.CopyToClipboardAsync(totp);
|
||||
await clipboardService.CopyTextAsync(totp);
|
||||
platformUtilsService.ShowToast("info", null,
|
||||
string.Format(AppResources.ValueHasBeenCopied, AppResources.VerificationCodeTotp));
|
||||
}
|
||||
|
@ -128,7 +130,7 @@ namespace Bit.App.Utilities
|
|||
{
|
||||
if (cipher.Reprompt == CipherRepromptType.None || await passwordRepromptService.ShowPasswordPromptAsync())
|
||||
{
|
||||
await platformUtilsService.CopyToClipboardAsync(cipher.Card.Number);
|
||||
await clipboardService.CopyTextAsync(cipher.Card.Number);
|
||||
platformUtilsService.ShowToast("info", null,
|
||||
string.Format(AppResources.ValueHasBeenCopied, AppResources.Number));
|
||||
}
|
||||
|
@ -137,7 +139,7 @@ namespace Bit.App.Utilities
|
|||
{
|
||||
if (cipher.Reprompt == CipherRepromptType.None || await passwordRepromptService.ShowPasswordPromptAsync())
|
||||
{
|
||||
await platformUtilsService.CopyToClipboardAsync(cipher.Card.Code);
|
||||
await clipboardService.CopyTextAsync(cipher.Card.Code);
|
||||
platformUtilsService.ShowToast("info", null,
|
||||
string.Format(AppResources.ValueHasBeenCopied, AppResources.SecurityCode));
|
||||
var task = eventService.CollectAsync(Core.Enums.EventType.Cipher_ClientCopiedCardCode, cipher.Id);
|
||||
|
@ -145,7 +147,7 @@ namespace Bit.App.Utilities
|
|||
}
|
||||
else if (selection == AppResources.CopyNotes)
|
||||
{
|
||||
await platformUtilsService.CopyToClipboardAsync(cipher.Notes);
|
||||
await clipboardService.CopyTextAsync(cipher.Notes);
|
||||
platformUtilsService.ShowToast("info", null,
|
||||
string.Format(AppResources.ValueHasBeenCopied, AppResources.Notes));
|
||||
}
|
||||
|
@ -200,7 +202,8 @@ namespace Bit.App.Utilities
|
|||
return;
|
||||
}
|
||||
var platformUtilsService = ServiceContainer.Resolve<IPlatformUtilsService>("platformUtilsService");
|
||||
await platformUtilsService.CopyToClipboardAsync(GetSendUrl(send));
|
||||
var clipboardService = ServiceContainer.Resolve<IClipboardService>("clipboardService");
|
||||
await clipboardService.CopyTextAsync(GetSendUrl(send));
|
||||
platformUtilsService.ShowToast("info", null,
|
||||
string.Format(AppResources.ValueHasBeenCopied, AppResources.SendLink));
|
||||
}
|
||||
|
|
16
src/Core/Abstractions/IClipboardService.cs
Normal file
16
src/Core/Abstractions/IClipboardService.cs
Normal file
|
@ -0,0 +1,16 @@
|
|||
using System.Threading.Tasks;
|
||||
|
||||
namespace Bit.Core.Abstractions
|
||||
{
|
||||
public interface IClipboardService
|
||||
{
|
||||
/// <summary>
|
||||
/// Copies the <paramref name="text"/> to the Clipboard.
|
||||
/// If <paramref name="expiresInMs"/> is set > 0 then the Clipboard will be cleared after this time in milliseconds.
|
||||
/// if less than 0 then it takes the configuration that the user set in Options.
|
||||
/// </summary>
|
||||
/// <param name="text">Text to be copied to the Clipboard</param>
|
||||
/// <param name="expiresInMs">Expiration time in milliseconds of the copied text</param>
|
||||
Task CopyTextAsync(string text, int expiresInMs = -1);
|
||||
}
|
||||
}
|
|
@ -9,7 +9,6 @@ namespace Bit.Core.Abstractions
|
|||
{
|
||||
string IdentityClientId { get; }
|
||||
|
||||
Task CopyToClipboardAsync(string text, Dictionary<string, object> options = null);
|
||||
string GetApplicationVersion();
|
||||
DeviceType GetDevice();
|
||||
string GetDeviceString();
|
||||
|
|
40
src/iOS.Core/Services/ClipboardService.cs
Normal file
40
src/iOS.Core/Services/ClipboardService.cs
Normal file
|
@ -0,0 +1,40 @@
|
|||
using System.Threading.Tasks;
|
||||
using Bit.Core.Abstractions;
|
||||
using Foundation;
|
||||
using MobileCoreServices;
|
||||
using UIKit;
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace Bit.iOS.Core.Services
|
||||
{
|
||||
public class ClipboardService : IClipboardService
|
||||
{
|
||||
private readonly IStorageService _storageService;
|
||||
|
||||
public ClipboardService(IStorageService storageService)
|
||||
{
|
||||
_storageService = storageService;
|
||||
}
|
||||
|
||||
public async Task CopyTextAsync(string text, int expiresInMs = -1)
|
||||
{
|
||||
int clearSeconds = -1;
|
||||
if (expiresInMs < 0)
|
||||
{
|
||||
clearSeconds = await _storageService.GetAsync<int?>(Bit.Core.Constants.ClearClipboardKey) ?? -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
clearSeconds = expiresInMs * 1000;
|
||||
}
|
||||
|
||||
var dictArr = new NSDictionary<NSString, NSObject>[1];
|
||||
dictArr[0] = new NSDictionary<NSString, NSObject>(new NSString(UTType.UTF8PlainText), new NSString(text));
|
||||
Device.BeginInvokeOnMainThread(() => UIPasteboard.General.SetItems(dictArr, new UIPasteboardOptions
|
||||
{
|
||||
LocalOnly = true,
|
||||
ExpirationDate = clearSeconds > 0 ? NSDate.FromTimeIntervalSinceNow(clearSeconds) : null
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -52,6 +52,7 @@ namespace Bit.iOS.Core.Utilities
|
|||
var cryptoPrimitiveService = new CryptoPrimitiveService();
|
||||
var mobileStorageService = new MobileStorageService(preferencesStorage, liteDbStorage);
|
||||
var deviceActionService = new DeviceActionService(mobileStorageService, messagingService);
|
||||
var clipboardService = new ClipboardService(mobileStorageService);
|
||||
var platformUtilsService = new MobilePlatformUtilsService(deviceActionService, messagingService,
|
||||
broadcasterService);
|
||||
var biometricService = new BiometricService(mobileStorageService);
|
||||
|
@ -67,6 +68,7 @@ namespace Bit.iOS.Core.Utilities
|
|||
ServiceContainer.Register<IStorageService>("storageService", mobileStorageService);
|
||||
ServiceContainer.Register<IStorageService>("secureStorageService", secureStorageService);
|
||||
ServiceContainer.Register<IDeviceActionService>("deviceActionService", deviceActionService);
|
||||
ServiceContainer.Register<IClipboardService>("clipboardService", clipboardService);
|
||||
ServiceContainer.Register<IPlatformUtilsService>("platformUtilsService", platformUtilsService);
|
||||
ServiceContainer.Register<IBiometricService>("biometricService", biometricService);
|
||||
ServiceContainer.Register<ICryptoFunctionService>("cryptoFunctionService", cryptoFunctionService);
|
||||
|
|
|
@ -191,6 +191,7 @@
|
|||
<Compile Include="Views\Toast.cs" />
|
||||
<Compile Include="Renderers\SelectableLabelRenderer.cs" />
|
||||
<Compile Include="Effects\ScrollEnabledEffect.cs" />
|
||||
<Compile Include="Services\ClipboardService.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\App\App.csproj">
|
||||
|
|
|
@ -71,14 +71,6 @@ namespace Bit.iOS
|
|||
iOSCoreHelpers.AppearanceAdjustments();
|
||||
});
|
||||
}
|
||||
else if (message.Command == "copiedToClipboard")
|
||||
{
|
||||
|
||||
Device.BeginInvokeOnMainThread(() =>
|
||||
{
|
||||
var task = ClearClipboardTimerAsync(message.Data as Tuple<string, int?, bool>);
|
||||
});
|
||||
}
|
||||
else if (message.Command == "listenYubiKeyOTP")
|
||||
{
|
||||
iOSCoreHelpers.ListenYubiKey((bool)message.Data, _deviceActionService, _nfcSession, _nfcDelegate);
|
||||
|
@ -329,61 +321,6 @@ namespace Bit.iOS
|
|||
"pushNotificationService", iosPushNotificationService);
|
||||
}
|
||||
|
||||
private async Task ClearClipboardTimerAsync(Tuple<string, int?, bool> data)
|
||||
{
|
||||
if (data.Item3)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var clearMs = data.Item2;
|
||||
if (clearMs == null)
|
||||
{
|
||||
var clearSeconds = await _storageService.GetAsync<int?>(Constants.ClearClipboardKey);
|
||||
if (clearSeconds != null)
|
||||
{
|
||||
clearMs = clearSeconds.Value * 1000;
|
||||
}
|
||||
}
|
||||
if (clearMs == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (_clipboardBackgroundTaskId > 0)
|
||||
{
|
||||
UIApplication.SharedApplication.EndBackgroundTask(_clipboardBackgroundTaskId);
|
||||
_clipboardBackgroundTaskId = 0;
|
||||
}
|
||||
_clipboardBackgroundTaskId = UIApplication.SharedApplication.BeginBackgroundTask(() =>
|
||||
{
|
||||
UIApplication.SharedApplication.EndBackgroundTask(_clipboardBackgroundTaskId);
|
||||
_clipboardBackgroundTaskId = 0;
|
||||
});
|
||||
_clipboardTimer?.Invalidate();
|
||||
_clipboardTimer?.Dispose();
|
||||
_clipboardTimer = null;
|
||||
var lastClipboardChangeCount = UIPasteboard.General.ChangeCount;
|
||||
var clearMsSpan = TimeSpan.FromMilliseconds(clearMs.Value);
|
||||
_clipboardTimer = NSTimer.CreateScheduledTimer(clearMsSpan, timer =>
|
||||
{
|
||||
Device.BeginInvokeOnMainThread(() =>
|
||||
{
|
||||
var changeNow = UIPasteboard.General.ChangeCount;
|
||||
if (changeNow == 0 || lastClipboardChangeCount == changeNow)
|
||||
{
|
||||
UIPasteboard.General.String = string.Empty;
|
||||
}
|
||||
_clipboardTimer?.Invalidate();
|
||||
_clipboardTimer?.Dispose();
|
||||
_clipboardTimer = null;
|
||||
if (_clipboardBackgroundTaskId > 0)
|
||||
{
|
||||
UIApplication.SharedApplication.EndBackgroundTask(_clipboardBackgroundTaskId);
|
||||
_clipboardBackgroundTaskId = 0;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private void ShowAppExtension(ExtensionPageViewModel extensionPageViewModel)
|
||||
{
|
||||
var itemProvider = new NSItemProvider(new NSDictionary(), Core.Constants.UTTypeAppExtensionSetup);
|
||||
|
|
Loading…
Reference in a new issue