mirror of
https://github.com/bitwarden/mobile
synced 2026-01-07 19:13:19 +00:00
Add support for camera for android choose file
This commit is contained in:
@@ -18,6 +18,7 @@ using Bit.App;
|
||||
using Android.Nfc;
|
||||
using Android.Views.InputMethods;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Bit.Android
|
||||
{
|
||||
@@ -211,8 +212,18 @@ namespace Bit.Android
|
||||
ParseYubiKey(intent.DataString);
|
||||
}
|
||||
|
||||
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults)
|
||||
public async override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults)
|
||||
{
|
||||
if(requestCode == Constants.SelectFilePermissionRequestCode)
|
||||
{
|
||||
if(grantResults.Any(r => r != Permission.Granted))
|
||||
{
|
||||
MessagingCenter.Send(Xamarin.Forms.Application.Current, "SelectFileCameraPermissionDenied");
|
||||
}
|
||||
await _deviceActionService.SelectFileAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
ZXing.Net.Mobile.Forms.Android.PermissionsHandler.OnRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
}
|
||||
|
||||
@@ -221,16 +232,32 @@ namespace Bit.Android
|
||||
if(requestCode == Constants.SelectFileRequestCode && resultCode == Result.Ok)
|
||||
{
|
||||
global::Android.Net.Uri uri = null;
|
||||
if(data != null)
|
||||
string fileName = null;
|
||||
if(data != null && data.Data != null)
|
||||
{
|
||||
uri = data.Data;
|
||||
using(var stream = ContentResolver.OpenInputStream(uri))
|
||||
using(var memoryStream = new MemoryStream())
|
||||
{
|
||||
stream.CopyTo(memoryStream);
|
||||
MessagingCenter.Send(Xamarin.Forms.Application.Current, "SelectFileResult",
|
||||
new Tuple<byte[], string>(memoryStream.ToArray(), Utilities.GetFileName(ApplicationContext, uri)));
|
||||
}
|
||||
fileName = Utilities.GetFileName(ApplicationContext, uri);
|
||||
}
|
||||
else
|
||||
{
|
||||
// camera
|
||||
var root = new Java.IO.File(global::Android.OS.Environment.ExternalStorageDirectory, "bitwarden");
|
||||
var file = new Java.IO.File(root, "temp_camera_photo.jpg");
|
||||
uri = global::Android.Net.Uri.FromFile(file);
|
||||
fileName = $"photo_{DateTime.UtcNow.ToString("yyyyMMddHHmmss")}.jpg";
|
||||
}
|
||||
|
||||
if(uri == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
using(var stream = ContentResolver.OpenInputStream(uri))
|
||||
using(var memoryStream = new MemoryStream())
|
||||
{
|
||||
stream.CopyTo(memoryStream);
|
||||
MessagingCenter.Send(Xamarin.Forms.Application.Current, "SelectFileResult",
|
||||
new Tuple<byte[], string>(memoryStream.ToArray(), fileName ?? "unknown_file_name"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.NFC" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
|
||||
<uses-permission android:name="com.samsung.android.providers.context.permission.WRITE_USE_APP_FEATURE_SURVEY" />
|
||||
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
|
||||
|
||||
@@ -7,14 +7,24 @@ using Plugin.CurrentActivity;
|
||||
using System.IO;
|
||||
using Android.Support.V4.Content;
|
||||
using Bit.App;
|
||||
using Bit.App.Resources;
|
||||
using Android.Provider;
|
||||
using System.Threading.Tasks;
|
||||
using Android.OS;
|
||||
using System.Collections.Generic;
|
||||
using Android;
|
||||
using Android.Content.PM;
|
||||
using Android.Support.V4.App;
|
||||
|
||||
namespace Bit.Android.Services
|
||||
{
|
||||
public class DeviceActionService : IDeviceActionService
|
||||
{
|
||||
private readonly IAppSettingsService _appSettingsService;
|
||||
private bool _cameraPermissionsDenied;
|
||||
|
||||
public DeviceActionService(IAppSettingsService appSettingsService)
|
||||
public DeviceActionService(
|
||||
IAppSettingsService appSettingsService)
|
||||
{
|
||||
_appSettingsService = appSettingsService;
|
||||
}
|
||||
@@ -124,12 +134,86 @@ namespace Bit.Android.Services
|
||||
}
|
||||
}
|
||||
|
||||
public void SelectFile()
|
||||
public Task SelectFileAsync()
|
||||
{
|
||||
var intent = new Intent(Intent.ActionOpenDocument);
|
||||
intent.AddCategory(Intent.CategoryOpenable);
|
||||
intent.SetType("*/*");
|
||||
CrossCurrentActivity.Current.Activity.StartActivityForResult(intent, Constants.SelectFileRequestCode);
|
||||
MessagingCenter.Unsubscribe<Application>(Application.Current, "SelectFileCameraPermissionDenied");
|
||||
|
||||
var hasStorageWritePermission = !_cameraPermissionsDenied && HasPermission(Manifest.Permission.WriteExternalStorage);
|
||||
var hasCameraPermission = !_cameraPermissionsDenied && HasPermission(Manifest.Permission.Camera);
|
||||
|
||||
if(!_cameraPermissionsDenied && !hasStorageWritePermission)
|
||||
{
|
||||
AskCameraPermission(Manifest.Permission.WriteExternalStorage);
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
if(!_cameraPermissionsDenied && !hasCameraPermission)
|
||||
{
|
||||
AskCameraPermission(Manifest.Permission.Camera);
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
var docIntent = new Intent(Intent.ActionOpenDocument);
|
||||
docIntent.AddCategory(Intent.CategoryOpenable);
|
||||
docIntent.SetType("*/*");
|
||||
|
||||
var chooserIntent = Intent.CreateChooser(docIntent, AppResources.FileSource);
|
||||
|
||||
if(!_cameraPermissionsDenied && hasCameraPermission && hasStorageWritePermission)
|
||||
{
|
||||
var root = new Java.IO.File(global::Android.OS.Environment.ExternalStorageDirectory, "bitwarden");
|
||||
var file = new Java.IO.File(root, "temp_camera_photo.jpg");
|
||||
if(!file.Exists())
|
||||
{
|
||||
var a = file.ParentFile.Mkdirs();
|
||||
var b = file.CreateNewFile();
|
||||
}
|
||||
var outputFileUri = global::Android.Net.Uri.FromFile(file);
|
||||
var additionalIntents = GetCameraIntents(outputFileUri);
|
||||
chooserIntent.PutExtra(Intent.ExtraInitialIntents, additionalIntents.ToArray());
|
||||
}
|
||||
|
||||
CrossCurrentActivity.Current.Activity.StartActivityForResult(chooserIntent, Constants.SelectFileRequestCode);
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
private List<IParcelable> GetCameraIntents(global::Android.Net.Uri outputUri)
|
||||
{
|
||||
var intents = new List<IParcelable>();
|
||||
var pm = CrossCurrentActivity.Current.Activity.PackageManager;
|
||||
var captureIntent = new Intent(MediaStore.ActionImageCapture);
|
||||
var listCam = pm.QueryIntentActivities(captureIntent, 0);
|
||||
foreach(var res in listCam)
|
||||
{
|
||||
var packageName = res.ActivityInfo.PackageName;
|
||||
var intent = new Intent(captureIntent);
|
||||
intent.SetComponent(new ComponentName(packageName, res.ActivityInfo.Name));
|
||||
intent.SetPackage(packageName);
|
||||
intent.PutExtra(MediaStore.ExtraOutput, outputUri);
|
||||
intents.Add(intent);
|
||||
}
|
||||
return intents;
|
||||
}
|
||||
|
||||
private bool HasPermission(string permission)
|
||||
{
|
||||
return ContextCompat.CheckSelfPermission(CrossCurrentActivity.Current.Activity, permission) == Permission.Granted;
|
||||
}
|
||||
|
||||
private void AskCameraPermission(string permission)
|
||||
{
|
||||
MessagingCenter.Subscribe<Application>(Application.Current, "SelectFileCameraPermissionDenied", (sender) =>
|
||||
{
|
||||
_cameraPermissionsDenied = true;
|
||||
});
|
||||
|
||||
AskPermission(permission);
|
||||
}
|
||||
|
||||
private void AskPermission(string permission)
|
||||
{
|
||||
ActivityCompat.RequestPermissions(CrossCurrentActivity.Current.Activity, new string[] { permission },
|
||||
Constants.SelectFilePermissionRequestCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Bit.App.Abstractions
|
||||
{
|
||||
@@ -7,7 +8,7 @@ namespace Bit.App.Abstractions
|
||||
void CopyToClipboard(string text);
|
||||
bool OpenFile(byte[] fileData, string id, string fileName);
|
||||
bool CanOpenFile(string fileName);
|
||||
void SelectFile();
|
||||
Task SelectFileAsync();
|
||||
void ClearCache();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,5 +35,6 @@
|
||||
public const string LastSync = "other:lastSync";
|
||||
|
||||
public const int SelectFileRequestCode = 42;
|
||||
public const int SelectFilePermissionRequestCode = 43;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ namespace Bit.App.Pages
|
||||
var selectButton = new ExtendedButton
|
||||
{
|
||||
Text = AppResources.ChooseFile,
|
||||
Command = new Command(() => _deviceActiveService.SelectFile()),
|
||||
Command = new Command(async () => await _deviceActiveService.SelectFileAsync()),
|
||||
Style = (Style)Application.Current.Resources["btn-primaryAccent"],
|
||||
FontSize = Device.GetNamedSize(NamedSize.Medium, typeof(Button))
|
||||
};
|
||||
|
||||
9
src/App/Resources/AppResources.Designer.cs
generated
9
src/App/Resources/AppResources.Designer.cs
generated
@@ -1051,6 +1051,15 @@ namespace Bit.App.Resources {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to File Source.
|
||||
/// </summary>
|
||||
public static string FileSource {
|
||||
get {
|
||||
return ResourceManager.GetString("FileSource", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Fingerprint.
|
||||
/// </summary>
|
||||
|
||||
@@ -983,4 +983,7 @@
|
||||
<data name="NoAttachments" xml:space="preserve">
|
||||
<value>There are no attachments.</value>
|
||||
</data>
|
||||
<data name="FileSource" xml:space="preserve">
|
||||
<value>File Source</value>
|
||||
</data>
|
||||
</root>
|
||||
BIN
src/iOS/Resources/photo.png
Normal file
BIN
src/iOS/Resources/photo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 434 B |
BIN
src/iOS/Resources/photo@2x.png
Normal file
BIN
src/iOS/Resources/photo@2x.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 685 B |
BIN
src/iOS/Resources/photo@3x.png
Normal file
BIN
src/iOS/Resources/photo@3x.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.2 KiB |
@@ -8,6 +8,7 @@ using Bit.App.Resources;
|
||||
using Xamarin.Forms;
|
||||
using Photos;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Bit.iOS.Services
|
||||
{
|
||||
@@ -89,12 +90,12 @@ namespace Bit.iOS.Services
|
||||
return tmp;
|
||||
}
|
||||
|
||||
public void SelectFile()
|
||||
public Task SelectFileAsync()
|
||||
{
|
||||
var controller = GetVisibleViewController();
|
||||
var picker = new UIDocumentMenuViewController(new string[] { UTType.Data }, UIDocumentPickerMode.Import);
|
||||
|
||||
picker.AddOption(AppResources.Camera, null, UIDocumentMenuOrder.First, () =>
|
||||
picker.AddOption(AppResources.Camera, UIImage.FromBundle("camera"), UIDocumentMenuOrder.First, () =>
|
||||
{
|
||||
var imagePicker = new UIImagePickerController { SourceType = UIImagePickerControllerSourceType.Camera };
|
||||
imagePicker.FinishedPickingMedia += ImagePicker_FinishedPickingMedia;
|
||||
@@ -102,7 +103,7 @@ namespace Bit.iOS.Services
|
||||
controller.PresentModalViewController(imagePicker, true);
|
||||
});
|
||||
|
||||
picker.AddOption(AppResources.Photos, null, UIDocumentMenuOrder.First, () =>
|
||||
picker.AddOption(AppResources.Photos, UIImage.FromBundle("photo"), UIDocumentMenuOrder.First, () =>
|
||||
{
|
||||
var imagePicker = new UIImagePickerController { SourceType = UIImagePickerControllerSourceType.PhotoLibrary };
|
||||
imagePicker.FinishedPickingMedia += ImagePicker_FinishedPickingMedia;
|
||||
@@ -117,6 +118,7 @@ namespace Bit.iOS.Services
|
||||
};
|
||||
|
||||
controller.PresentViewController(picker, true, null);
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
private void ImagePicker_FinishedPickingMedia(object sender, UIImagePickerMediaPickedEventArgs e)
|
||||
|
||||
@@ -758,6 +758,15 @@
|
||||
<ItemGroup>
|
||||
<BundleResource Include="Resources\camera%403x.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<BundleResource Include="Resources\photo.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<BundleResource Include="Resources\photo%402x.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<BundleResource Include="Resources\photo%403x.png" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildExtensionsPath)\Xamarin\iOS\Xamarin.iOS.CSharp.targets" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
|
||||
Reference in New Issue
Block a user