/// <summary> /// liefert das DocumentFile für eine Datei oder ein Verzeichnis (API level 14) /// <para>Wenn das Objekt noch nicht ex., wird es erzeugt. Auch ein notwendiger Pfad wird vollständig erzeugt.</para> /// </summary> /// <param name="storagename">z.B. "primary" oder "19F4-0903"</param> /// <param name="volpath">abs. Pfad im Volume</param> /// <param name="isDirectory">Pfad bezieht sich auf eine Datei oder ein Verzeichnis</param> /// <returns></returns> public DocumentFile GetDocumentFile(string storagename, string volpath, bool isDirectory) { global::Android.Net.Uri rooturi = GetTreeDocumentUri(storagename); DocumentFile document = DocumentFile.FromTreeUri(Activity.ApplicationContext, rooturi); string[] pathelems = volpath.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; document != null && i < pathelems.Length; i++) { DocumentFile nextDocument = document.FindFile(pathelems[i]); if (nextDocument == null) { if ((i < pathelems.Length - 1) || isDirectory) { nextDocument = document.CreateDirectory(pathelems[i]); } else { nextDocument = document.CreateFile("", pathelems[i]); } } document = nextDocument; } System.Diagnostics.Debug.WriteLine("AndroidGetDocumentFile(" + storagename + ", " + volpath + ", " + isDirectory.ToString() + ") = " + (document != null && (isDirectory == document.IsDirectory)).ToString()); return(document != null ? (isDirectory == document.IsDirectory ? document : null) : null); }
private async Task <RestoreResult> RestoreFromDir(Uri destUri) { if (!HasPersistablePermissionsAtUri(destUri)) { throw new InvalidOperationException("No permission at URI"); } var directory = DocumentFile.FromTreeUri(_context, destUri); var files = directory.ListFiles(); var mostRecentBackup = files .Where(f => f.IsFile && f.Type == Backup.MimeType && f.Name.EndsWith(Backup.FileExtension) && f.Length() > 0 && f.CanRead()) .OrderByDescending(f => f.LastModified()) .FirstOrDefault(); if (mostRecentBackup == null || mostRecentBackup.LastModified() <= _preferences.MostRecentBackupModifiedAt) { return(new RestoreResult()); } _preferences.MostRecentBackupModifiedAt = mostRecentBackup.LastModified(); var password = await GetBackupPassword(); if (password == null) { throw new InvalidOperationException("No password defined."); } var data = await FileUtil.ReadFile(_context, mostRecentBackup.Uri); var backup = Backup.FromBytes(data, password); return(await _restoreService.RestoreAndUpdateAsync(backup)); }
public async Task <bool> RemoveFileIfExists(ContentType accessType, string filename, string storageLocationBase) { var fileIfExists = GetPathIfFileExists(accessType, filename, storageLocationBase); if (!fileIfExists.Exists) { return(false); } switch (accessType) { case ContentType.DirectAccess: File.Delete(fileIfExists.Path); await Task.Delay(50); return(true); case ContentType.StorageFramework: var doc = DocumentsContract.BuildDocumentUriUsingTree(Uri.Parse(storageLocationBase), fileIfExists.Path); DocumentFile file = DocumentFile.FromTreeUri(Android.App.Application.Context, doc); await Task.Delay(50); return(file.Delete()); default: throw new ArgumentOutOfRangeException(nameof(accessType), accessType, null); } }
private async Task <RestoreResult> RestoreFromDir(Uri destUri) { if (!HasPersistablePermissionsAtUri(destUri)) { throw new Exception("No permission at URI"); } var directory = DocumentFile.FromTreeUri(_context, destUri); var files = directory.ListFiles(); var mostRecentBackup = files .Where(f => f.IsFile && f.Type == Backup.MimeType && f.Name.EndsWith(Backup.FileExtension) && f.Length() > 0 && f.CanRead()) .OrderByDescending(f => f.LastModified()) .FirstOrDefault(); if (mostRecentBackup == null || mostRecentBackup.LastModified() <= _preferences.MostRecentBackupModifiedAt) { return(new RestoreResult()); } _preferences.MostRecentBackupModifiedAt = mostRecentBackup.LastModified(); var password = await SecureStorageWrapper.GetAutoBackupPassword(); if (password == null) { throw new Exception("No password defined."); } var data = await FileUtil.ReadFile(_context, mostRecentBackup.Uri); var backup = Backup.FromBytes(data, password); var(authsAdded, authsUpdated) = await _authSource.AddOrUpdateMany(backup.Authenticators); var categoriesAdded = backup.Categories != null ? await _categorySource.AddMany(backup.Categories) : 0; if (backup.AuthenticatorCategories != null) { await _authSource.AddOrUpdateManyCategoryBindings(backup.AuthenticatorCategories); } var customIconsAdded = backup.CustomIcons != null ? await _customIconSource.AddMany(backup.CustomIcons) : 0; try { await _customIconSource.CullUnused(); } catch (Exception e) { // ignored Logger.Error(e); } return(new RestoreResult(authsAdded, authsUpdated, categoriesAdded, customIconsAdded)); }
internal SafFolder(Android.Net.Uri uri) : base(uri.Path ?? string.Empty) { _folderUri = uri ?? throw new ArgumentNullException(nameof(uri)); _directoryDocument = DocumentFile.FromTreeUri(Application.Context, uri); if (string.IsNullOrEmpty(Path)) { Path = _directoryDocument.Name; } }
private DocumentFile GetDocumentFile(string path) { if (path.Contains("://")) { return(DocumentFile.FromTreeUri(context, Android.Net.Uri.Parse(path))); } else { return(DocumentFile.FromFile(new Java.IO.File(path))); } }
private async Task <bool> WriteFileAsync(ContentType accessType, string filePath, string storageLocationBase, byte[] bytes) { switch (accessType) { case ContentType.DirectAccess: await File.WriteAllBytesAsync(filePath, bytes); return(true); case ContentType.StorageFramework: // check file exists var fileExistPath = this.GetPathIfFileExists(accessType, filePath, storageLocationBase); Uri contentPath; if (!fileExistPath.Exists) { var pathUri = Uri.Parse(storageLocationBase); //var treeId = DocumentsContract.GetTreeDocumentId(pathUri) + $"/{filePath}"; var treeId = DocumentsContract.GetTreeDocumentId(pathUri) + $"/{Path.GetDirectoryName(filePath)}"; var newPath = DocumentsContract.BuildDocumentUriUsingTree(pathUri, treeId); DocumentFile newFile = DocumentFile.FromTreeUri(Android.App.Application.Context, newPath); var documentFile = newFile.CreateFile("application/octet-stream", Path.GetFileName(filePath)); contentPath = documentFile.Uri; } else { var baseUriParse = Uri.Parse(storageLocationBase); contentPath = DocumentsContract.BuildDocumentUriUsingTree(baseUriParse, fileExistPath.Path); } var descriptor = AppContentResolver.OpenAssetFileDescriptor(contentPath !, "w"); if (descriptor == null) { throw new Exception($"File descriptor null, tried to open {contentPath}."); } var writeStream = descriptor.CreateOutputStream(); if (!writeStream.CanWrite) { throw new Exception("Cannot write the writeStream."); } await writeStream.WriteAsync(bytes); return(true); default: throw new ArgumentOutOfRangeException(nameof(accessType), accessType, null); } }
/// <summary> /// Handles the result from activities called with StartActivityForResult() /// </summary> /// <param name="requestCode"></param> /// <param name="resultCode"></param> /// <param name="data"></param> protected override void OnActivityResult(int requestCode, [GeneratedEnum] Result resultCode, Intent data) { try { base.OnActivityResult(requestCode, resultCode, data); if (resultCode == Result.Ok && data != null && requestCode == OPEN_DOCUMENT_TREE_ACTIVITY) { // keep track of the raw URI data returned from user selection // just in case we need it later? _userSelectedDirectory = data.Data; // keep track of the parent directory // this is used in building document URIs of the children // based on their id this._parentUri = DocumentsContract.BuildDocumentUriUsingTree( _userSelectedDirectory, DocumentsContract.GetTreeDocumentId(_userSelectedDirectory) ); // WARN: This is a little hacky, and might not be that robust // After creating the initial file strucutre at the location, // I would recommend commenting the below check/function call var dir = DocumentFile.FromTreeUri(this, _parentUri); if (dir.IsDirectory && dir.Length() == 0) { CreateTestFileStructureAtLocation(); } // persist permissions for this directory ContentResolver.TakePersistableUriPermission( _userSelectedDirectory, ActivityFlags.GrantReadUriPermission | ActivityFlags.GrantWriteUriPermission ); data.AddFlags(ActivityFlags.GrantWriteUriPermission); data.AddFlags(ActivityFlags.GrantReadUriPermission); data.AddFlags(ActivityFlags.GrantPrefixUriPermission); data.AddFlags(ActivityFlags.GrantPersistableUriPermission); } } catch (Exception ex) { var timeElapsedTV = FindViewById <TextView>(Resource.Id.timeElapsedTV); SetTextViewOnError(timeElapsedTV, ex); } }
/// <summary> /// liefert das DocumentFile für eine Datei oder ein Verzeichnis, wenn es existiert (sonst null) (API level 14) /// </summary> /// <param name="storagename">z.B. "primary" oder "19F4-0903"</param> /// <param name="volpath">abs. Pfad im Volume</param> /// <returns></returns> public DocumentFile GetExistingDocumentFile(string storagename, string volpath) { global::Android.Net.Uri rooturi = GetTreeDocumentUri(storagename); DocumentFile document = DocumentFile.FromTreeUri(Activity.ApplicationContext, rooturi); string[] pathelems = volpath.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; document != null && i < pathelems.Length; i++) { DocumentFile nextDocument = document.FindFile(pathelems[i]); document = nextDocument; } System.Diagnostics.Debug.WriteLine("AndroidGetExistingDocumentFile(" + storagename + ", " + volpath + ") = " + (document != null).ToString()); return(document); }
/// <summary> /// Called when activity started with StartActivityForResult() returns. /// </summary> /// <param name="requestCode">request code used in StartActivityForResult()</param> /// <param name="resultCode">result code</param> /// <param name="data">intent data from folder picking</param> protected override void OnActivityResult(int requestCode, [GeneratedEnum] Result resultCode, Intent data) { base.OnActivityResult(requestCode, resultCode, data); if (resultCode == Result.Canceled) { // Notify user folder picking was cancelled. OnFolderPickCancelled(); this.Finish(); } else { try { if (data?.Data == null) { throw new Exception("Folder picking returned no valid data"); } System.Diagnostics.Debug.Write(data.Data); //var uri = data.Data; //Android.Net.Uri testURI = Android.Net.Uri.Parse(uri); var documentFile = DocumentFile.FromTreeUri(this, data.Data); OnFolderPicked(new FolderPickerEventArgs(documentFile.Name, documentFile.Uri.ToString())); } catch (Exception readEx) { System.Diagnostics.Debug.Write(readEx); // Notify user folder picking failed. FolderPickCancelled?.Invoke( this, new FolderPickerCancelledEventArgs { Exception = readEx }); } finally { this.Finish(); } } }
protected override void OnActivityResult(int requestCode, [GeneratedEnum] Result resultCode, Intent data) { AndroidApplication.Logger.Debug(() => $"MainActivity:OnActivityResult {requestCode}, {resultCode}"); base.OnActivityResult(requestCode, resultCode, data); if (!resultCode.Equals(Result.Ok)) { return; } AndroidApplication.Logger.Debug(() => $"MainActivity:OnActivityResult {data.Data.ToString()}"); switch (requestCode) { // we asked for manage storage access in SDK30+ case PermissionRequester.REQUEST_CODE_WRITE_EXTERNAL_STORAGE_PERMISSION: SelectFile(); break; case REQUEST_SELECT_FILE: ToastMessage("OK"); AndroidApplication.ControlFile = OpenControlFile(data.Data); if (AndroidApplication.ControlFile != null) { PreferencesProvider.SetPreferenceString(ApplicationContext.GetString(Resource.String.prefs_control_uri_key), data.Data.ToString()); ApplicationContext.ContentResolver.TakePersistableUriPermission(data.Data, ActivityFlags.GrantReadUriPermission); } break; case REQUEST_SELECT_FOLDER: ToastMessage("OK"); SetTextViewText(Resource.Id.txtRoot, $"{data.Data.ToString()}"); //Android.Net.Uri uri = data.Data; //Android.Net.Uri docUri = DocumentsContract.BuildDocumentUriUsingTree(uri,DocumentsContract.GetTreeDocumentId(uri)); // TODO - write GetRealPathFromUri() // see https://stackoverflow.com/questions/29713587/how-to-get-the-real-path-with-action-open-document-tree-intent //String path = GetRealPathFromURI(uri); DocumentFile file = DocumentFile.FromTreeUri(ApplicationContext, data.Data); AndroidApplication.Logger.Debug(() => $"MainActivity:OnActivityResult {file.Uri.Path}"); SetTextViewText(Resource.Id.txtRoot, $"{file.Uri.Path}"); break; } }
private async Task <BackupResult> BackupToDir(Uri destUri) { var auths = (await _authenticatorRepository.GetAllAsync()).ToImmutableArray(); if (!auths.Any()) { return(new BackupResult()); } if (!HasPersistablePermissionsAtUri(destUri)) { throw new InvalidOperationException("No permission at URI"); } var password = await GetBackupPassword(); if (password == null) { throw new InvalidOperationException("No password defined"); } var backup = new Backup( auths, await _categoryRepository.GetAllAsync(), await _authenticatorCategoryRepository.GetAllAsync(), await _customIconRepository.GetAllAsync() ); var dataToWrite = backup.ToBytes(password); var directory = DocumentFile.FromTreeUri(_context, destUri); var file = directory.CreateFile(Backup.MimeType, FormattableString.Invariant($"backup-{DateTime.Now:yyyy-MM-dd_HHmmss}.{Backup.FileExtension}")); if (file == null) { throw new Exception("File creation failed, got null."); } await FileUtil.WriteFile(_context, file.Uri, dataToWrite); return(new BackupResult(file.Name)); }
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data) { if (requestCode == 10001 && _currentRequest != null) { if (resultCode == Result.Ok) { ContentResolver.TakePersistableUriPermission(data.Data, ActivityFlags.GrantWriteUriPermission); var documentFile = DocumentFile.FromTreeUri(this, data.Data); _currentRequest.AcceptRequest(documentFile); } else { _currentRequest.RejectRequest(); } _currentRequest = null; } }
private async Task <BackupResult> BackupToDir(Uri destUri) { if (!_authSource.GetAll().Any()) { return(new BackupResult()); } if (!HasPersistablePermissionsAtUri(destUri)) { throw new Exception("No permission at URI"); } var password = await SecureStorageWrapper.GetAutoBackupPassword(); if (password == null) { throw new Exception("No password defined."); } var backup = new Backup( _authSource.GetAll(), _categorySource.GetAll(), _authSource.CategoryBindings, _customIconSource.GetAll() ); var dataToWrite = backup.ToBytes(password); var directory = DocumentFile.FromTreeUri(_context, destUri); var file = directory.CreateFile(Backup.MimeType, $"backup-{DateTime.Now:yyyy-MM-dd_HHmmss}.{Backup.FileExtension}"); if (file == null) { throw new Exception("File creation failed, got null."); } await FileUtil.WriteFile(_context, file.Uri, dataToWrite); return(new BackupResult(file.Name)); }
/// <inheritdoc/> public async Task <bool> TrySaveFileToPickedFolder(string fileName, byte[] content) { if (_pickedUri == null) { return(false); } try { DocumentFile folder = DocumentFile.FromTreeUri(_context, _pickedUri); string mimeType = URLConnection.GuessContentTypeFromName(fileName); DocumentFile file = folder.CreateFile(mimeType, fileName); using (Stream stream = _context.ContentResolver.OpenOutputStream(file.Uri, "w")) { await stream.WriteAsync(content, 0, content.Length); return(true); } } catch (Exception ex) { return(false); } }
/// <summary> /// Calls ScanFilesInSelectedFolder to begin scanning the initial directory /// </summary> /// <param name="folder">location chosen by user</param> /// <returns>Hashset of all the files in given location</returns> internal void GetFilesFromSelectedFolder() { ScanFilesInSelectedFolder( DocumentFile.FromTreeUri(this, _userSelectedDirectory) ); }
public Task <bool> SavePhoto(byte[] image, string destination, bool external) { var taskCompletionSource = new TaskCompletionSource <bool>(); Task.Run(async() => { try { var contentResolver = MainActivity.Instance.ContentResolver; var currentTimeSeconds = JavaSystem.CurrentTimeMillis() / 1000; if (external) { var externalPicturesDir = MainActivity.Instance.GetExternalFilesDirs(Environment.DirectoryPictures).ElementAt(1).AbsolutePath; var newFilePath = Path.Combine(externalPicturesDir, currentTimeSeconds + ".jpg"); using (var stream = new FileStream(newFilePath, FileMode.CreateNew)) { using (var bitmap = BitmapFactory.DecodeByteArray(image, 0, image.Length)) { await bitmap.CompressAsync(Bitmap.CompressFormat.Jpeg, 100, stream); } } using (var file = new Java.IO.File(newFilePath)) { MainActivity.Instance.SendBroadcast(new Intent(Intent.ActionMediaScannerScanFile, Uri.FromFile(file))); } } else { Uri destinationFinalUri; if (destination != null) { var pickedDir = DocumentFile.FromTreeUri(MainActivity.Instance, Uri.Parse(destination)); var newFile = pickedDir.CreateFile("image/jpeg", currentTimeSeconds + ".jpg"); if (newFile == null) { throw new DirectoryNotFoundException(); } destinationFinalUri = newFile.Uri; } else { var values = new ContentValues(); values.Put(MediaStore.Images.Media.InterfaceConsts.MimeType, "image/jpeg"); values.Put(MediaStore.Images.Media.InterfaceConsts.DateAdded, currentTimeSeconds); values.Put(MediaStore.Images.Media.InterfaceConsts.DateModified, currentTimeSeconds); destinationFinalUri = contentResolver.Insert(MediaStore.Images.Media.ExternalContentUri, values); } using (var stream = contentResolver.OpenOutputStream(destinationFinalUri)) { using (var bitmap = BitmapFactory.DecodeByteArray(image, 0, image.Length)) { await bitmap.CompressAsync(Bitmap.CompressFormat.Jpeg, 100, stream); } } MainActivity.Instance.SendBroadcast(new Intent(Intent.ActionMediaScannerScanFile, destinationFinalUri)); } taskCompletionSource.SetResult(true); } catch (Exception e) { taskCompletionSource.SetException(e); } }); return(taskCompletionSource.Task); }
protected override void OnActivityResult(int requestCode, Android.App.Result resultCode, Intent data) { switch ((ActivityRequest)requestCode) { case ActivityRequest.RequestDevelopmentSettings: UpdateDisplay(); break; case ActivityRequest.RequestOpenDocumentTreeToApp: if (data != null && resultCode == Android.App.Result.Ok) { Android.Net.Uri treeUri = data.Data; if (treeUri != null) { _instanceData.CopyToAppSrcUri = treeUri.ToString(); if (!string.IsNullOrEmpty(_instanceData.CopyToAppSrcUri)) { SelectCopyAppDir(false); } } } break; case ActivityRequest.RequestOpenDocumentTreeFromApp: if (data != null && resultCode == Android.App.Result.Ok) { Android.Net.Uri treeUri = data.Data; if (treeUri != null) { _instanceData.CopyFromAppDstUri = treeUri.ToString(); if (!string.IsNullOrEmpty(_instanceData.CopyFromAppSrcPath) && !string.IsNullOrEmpty(_instanceData.CopyFromAppDstUri)) { try { DocumentFile srcDir = DocumentFile.FromFile(new Java.IO.File(_instanceData.CopyFromAppSrcPath)); DocumentFile dstDir = DocumentFile.FromTreeUri(this, Android.Net.Uri.Parse(_instanceData.CopyFromAppDstUri)); if (_activityCommon.RequestCopyDocumentsThread(srcDir, dstDir, (result, aborted) => { })) { ActivityCommon.CopyFromAppSrc = _instanceData.CopyFromAppSrcPath; ActivityCommon.CopyFromAppDst = _instanceData.CopyFromAppDstUri; } } catch (Exception) { // ignored } } } } break; case ActivityRequest.RequestSelDirToApp: if (data != null && resultCode == Android.App.Result.Ok) { _instanceData.CopyToAppDstPath = data.Extras?.GetString(FilePickerActivity.ExtraFileName); if (!string.IsNullOrEmpty(_instanceData.CopyToAppSrcUri) && !string.IsNullOrEmpty(_instanceData.CopyToAppDstPath)) { try { DocumentFile srcDir = DocumentFile.FromTreeUri(this, Android.Net.Uri.Parse(_instanceData.CopyToAppSrcUri)); DocumentFile dstDir = DocumentFile.FromFile(new Java.IO.File(_instanceData.CopyToAppDstPath)); if (_activityCommon.RequestCopyDocumentsThread(srcDir, dstDir, (result, aborted) => { })) { ActivityCommon.CopyToAppDst = _instanceData.CopyToAppDstPath; ActivityCommon.CopyFromAppDst = _instanceData.CopyFromAppDstUri; } } catch (Exception) { // ignored } } } break; case ActivityRequest.RequestSelDirFromApp: if (data != null && resultCode == Android.App.Result.Ok) { _instanceData.CopyFromAppSrcPath = data.Extras?.GetString(FilePickerActivity.ExtraFileName); if (!string.IsNullOrEmpty(_instanceData.CopyFromAppSrcPath)) { SelectCopyDocumentTree(true); } } break; case ActivityRequest.RequestSelDirDelApp: if (data != null && resultCode == Android.App.Result.Ok) { string delPath = data.Extras?.GetString(FilePickerActivity.ExtraFileName); if (!string.IsNullOrEmpty(delPath)) { try { DocumentFile delDir = DocumentFile.FromFile(new Java.IO.File(delPath)); _activityCommon.RequestDeleteDocumentsThread(delDir, (result, aborted) => { }); } catch (Exception) { // ignored } } } break; } }
public Task <bool> SaveFileInFolder(FileData fileToSave, FolderData folder, bool shouldOverWrite) { var uniqueId = Guid.NewGuid(); var next = new TaskCompletionSource <bool>(uniqueId); // Interlocked.CompareExchange(ref object location1, object value, object comparand) // Compare location1 with comparand. // If equal replace location1 by value. // Returns the original value of location1. // --- // In this context, tcs is compared to null, if equal tcs is replaced by next, // and original tcs is returned. // We then compare original tcs with null, if not null it means that a task was // already started. if (Interlocked.CompareExchange(ref tcs_bool_as_int, next, null) != null) { return(Task.FromResult <bool>(false)); } EventHandler <PermissionRequestEventArgs> handler = null; weakContext.TryGetTarget(out Context newContext); var requestPermissionIntent = new Intent(newContext, typeof(RequestPermissionActivity)); requestPermissionIntent.SetFlags(ActivityFlags.NewTask); requestPermissionIntent.PutExtra(RequestPermissionActivity.RequestedPermission, Manifest.Permission.WriteExternalStorage); handler = (sender, e) => { // Interlocaked.Exchange(ref object location1, object value) // Sets an object to a specified value and returns a reference to the original object. // --- // In this context, sets tcs to null and returns it. var task = Interlocked.Exchange(ref tcs_bool_as_int, null); RequestPermissionActivity.OnPermissionGranted -= handler; if (e.success) { try { var test = Android.Net.Uri.Parse(folder.FolderPath);// + "/test.pdf"); var documentFile = DocumentFile.FromTreeUri(newContext, test); DocumentFile newFile = documentFile.FindFile(fileToSave.FileName); if (newFile != null) { if (shouldOverWrite) { newFile.Delete(); } else { //supposed to create uniuqe name in this case var purefilename = Path.GetFileNameWithoutExtension(fileToSave.FileName); var fileextention = Path.GetExtension(fileToSave.FileName); fileToSave.FileName = purefilename + "_" + Path.GetRandomFileName() + fileextention; } } documentFile.CreateFile("*/*", fileToSave.FileName); //var documentFile = DocumentFile.FromTreeUri(activity, test); var outputstream = newContext.ContentResolver.OpenOutputStream(newFile.Uri); fileToSave.GetStream().CopyTo(outputstream); outputstream.Flush(); outputstream.Close(); task.SetResult(e.success); } catch (Exception ex) { Debug.WriteLine(ex.Message); task.SetCanceled(); } } }; RequestPermissionActivity.OnPermissionGranted += handler; //proably need a try statement here newContext.StartActivity(requestPermissionIntent); return(tcs_bool_as_int.Task); }