From d9265653586397adc07af3d78894f6e1fb9fac78 Mon Sep 17 00:00:00 2001 From: Matt Portune <59324545+mportune-bw@users.noreply.github.com> Date: Wed, 31 Mar 2021 10:19:05 -0400 Subject: [PATCH] Share-to-Send for Android (#1343) * Android implementation * remove iOS attempt for now --- src/Android/MainActivity.cs | 54 ++++++++++++++++++- src/Android/Services/DeviceActionService.cs | 11 ++++ src/App/Abstractions/IDeviceActionService.cs | 1 + src/App/App.xaml.cs | 13 ++++- src/App/Models/AppOptions.cs | 5 +- src/App/Pages/Send/SendAddEditPage.xaml | 5 +- src/App/Pages/Send/SendAddEditPage.xaml.cs | 36 ++++++++++++- .../Pages/Send/SendAddEditPageViewModel.cs | 42 ++++++++++++--- .../SendGroupingsPage.xaml.cs | 37 ++++++------- .../SendGroupingsPageViewModel.cs | 2 +- src/App/Pages/Send/SendsPageViewModel.cs | 2 +- src/App/Pages/TabsPage.cs | 11 +++- src/App/Resources/AppResources.Designer.cs | 6 +++ src/App/Resources/AppResources.resx | 4 ++ src/App/Utilities/AppHelpers.cs | 7 ++- src/iOS.Core/Services/DeviceActionService.cs | 5 ++ 16 files changed, 203 insertions(+), 38 deletions(-) diff --git a/src/Android/MainActivity.cs b/src/Android/MainActivity.cs index 7cbdfee21..3a691a6c9 100644 --- a/src/Android/MainActivity.cs +++ b/src/Android/MainActivity.cs @@ -30,6 +30,16 @@ namespace Bit.Droid ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.Keyboard | ConfigChanges.KeyboardHidden | ConfigChanges.Navigation)] + [IntentFilter( + new[] { Intent.ActionSend }, + Categories = new[] { Intent.CategoryDefault }, + DataMimeTypes = new[] + { + @"application/*", + @"image/*", + @"video/*", + @"text/*" + })] [Register("com.x8bit.bitwarden.MainActivity")] public class MainActivity : Xamarin.Forms.Platform.Android.FormsAppCompatActivity { @@ -169,7 +179,7 @@ namespace Bit.Droid _appOptions.GeneratorTile = true; } } - if (intent.GetBooleanExtra("myVaultTile", false)) + else if (intent.GetBooleanExtra("myVaultTile", false)) { _messagingService.Send("popAllAndGoToTabMyVault"); if (_appOptions != null) @@ -177,6 +187,14 @@ namespace Bit.Droid _appOptions.MyVaultTile = true; } } + else if (intent.Action == Intent.ActionSend && intent.Type != null) + { + if (_appOptions != null) + { + _appOptions.CreateSend = GetCreateSendRequest(intent); + } + _messagingService.Send("popAllAndGoToTabSend"); + } else { ParseYubiKey(intent.DataString); @@ -298,7 +316,8 @@ namespace Bit.Droid Uri = Intent.GetStringExtra("uri") ?? Intent.GetStringExtra("autofillFrameworkUri"), MyVaultTile = Intent.GetBooleanExtra("myVaultTile", false), GeneratorTile = Intent.GetBooleanExtra("generatorTile", false), - FromAutofillFramework = Intent.GetBooleanExtra("autofillFramework", false) + FromAutofillFramework = Intent.GetBooleanExtra("autofillFramework", false), + CreateSend = GetCreateSendRequest(Intent) }; var fillType = Intent.GetIntExtra("autofillFrameworkFillType", 0); if (fillType > 0) @@ -320,6 +339,37 @@ namespace Bit.Droid return options; } + private Tuple GetCreateSendRequest(Intent intent) + { + if (intent.Action == Intent.ActionSend && intent.Type != null) + { + var type = intent.Type; + if (type.Contains("text/")) + { + var subject = intent.GetStringExtra(Intent.ExtraSubject); + var text = intent.GetStringExtra(Intent.ExtraText); + return new Tuple(SendType.Text, subject, null, text); + } + else + { + var data = intent.ClipData?.GetItemAt(0); + var uri = data?.Uri; + var filename = AndroidHelpers.GetFileName(ApplicationContext, uri); + try + { + using (var stream = ContentResolver.OpenInputStream(uri)) + using (var memoryStream = new MemoryStream()) + { + stream.CopyTo(memoryStream); + return new Tuple(SendType.File, filename, memoryStream.ToArray(), null); + } + } + catch (Java.IO.FileNotFoundException) { } + } + } + return null; + } + private void ParseYubiKey(string data) { if (data == null) diff --git a/src/Android/Services/DeviceActionService.cs b/src/Android/Services/DeviceActionService.cs index 7585bf2e1..9afbcba7d 100644 --- a/src/Android/Services/DeviceActionService.cs +++ b/src/Android/Services/DeviceActionService.cs @@ -760,6 +760,17 @@ namespace Bit.Droid.Services // ref: https://developer.android.com/reference/android/os/SystemClock#elapsedRealtime() return SystemClock.ElapsedRealtime(); } + + public void CloseMainApp() + { + var activity = (MainActivity)CrossCurrentActivity.Current.Activity; + if (activity == null) + { + return; + } + activity.Finish(); + _messagingService.Send("finishMainActivity"); + } private bool DeleteDir(Java.IO.File dir) { diff --git a/src/App/Abstractions/IDeviceActionService.cs b/src/App/Abstractions/IDeviceActionService.cs index c1795685f..8f1b03e64 100644 --- a/src/App/Abstractions/IDeviceActionService.cs +++ b/src/App/Abstractions/IDeviceActionService.cs @@ -44,5 +44,6 @@ namespace Bit.App.Abstractions void OpenAutofillSettings(); bool UsingDarkTheme(); long GetActiveTime(); + void CloseMainApp(); } } diff --git a/src/App/App.xaml.cs b/src/App/App.xaml.cs index 15563b45f..c2d424380 100644 --- a/src/App/App.xaml.cs +++ b/src/App/App.xaml.cs @@ -131,7 +131,8 @@ namespace Bit.App await SetMainPageAsync(); } else if (message.Command == "popAllAndGoToTabGenerator" || - message.Command == "popAllAndGoToTabMyVault") + message.Command == "popAllAndGoToTabMyVault" || + message.Command == "popAllAndGoToTabSend") { Device.BeginInvokeOnMainThread(async () => { @@ -146,11 +147,15 @@ namespace Bit.App Options.MyVaultTile = false; tabsPage.ResetToVaultPage(); } - else + else if (message.Command == "popAllAndGoToTabGenerator") { Options.GeneratorTile = false; tabsPage.ResetToGeneratorPage(); } + else if (message.Command == "popAllAndGoToTabSend") + { + tabsPage.ResetToSendPage(); + } } }); } @@ -274,6 +279,10 @@ namespace Bit.App { Current.MainPage = new NavigationPage(new AutofillCiphersPage(Options)); } + else if (Options.CreateSend != null) + { + Current.MainPage = new NavigationPage(new SendAddEditPage(Options)); + } else { Current.MainPage = new TabsPage(Options); diff --git a/src/App/Models/AppOptions.cs b/src/App/Models/AppOptions.cs index 564ab5704..a28a76855 100644 --- a/src/App/Models/AppOptions.cs +++ b/src/App/Models/AppOptions.cs @@ -1,4 +1,5 @@ -using Bit.Core.Enums; +using System; +using Bit.Core.Enums; namespace Bit.App.Models { @@ -19,6 +20,7 @@ namespace Bit.App.Models public string SaveCardExpYear { get; set; } public string SaveCardCode { get; set; } public bool IosExtension { get; set; } + public Tuple CreateSend { get; set; } public void SetAllFrom(AppOptions o) { @@ -41,6 +43,7 @@ namespace Bit.App.Models SaveCardExpYear = o.SaveCardExpYear; SaveCardCode = o.SaveCardCode; IosExtension = o.IosExtension; + CreateSend = o.CreateSend; } } } diff --git a/src/App/Pages/Send/SendAddEditPage.xaml b/src/App/Pages/Send/SendAddEditPage.xaml index 98adc268b..21b9b2bad 100644 --- a/src/App/Pages/Send/SendAddEditPage.xaml +++ b/src/App/Pages/Send/SendAddEditPage.xaml @@ -117,7 +117,7 @@ + IsVisible="{Binding ShowTypeButtons}">