Android 10 - unable to take PersistableUriPermission on a file that I created in getExternalFilesDir() - uri

Using the below code snippet, we created a file in Android 10, in a sub-folder under getExternalFilesDir(). However, immediately after creation, if we try to take persistableUriPermission, it throws an exception "No such permission exists....".
We need that check to know if that file will be available for read later in a common utility, else we have to make a copy. Please let us know what we might be doing wrong and how to fix this. Appreciate your help.
ParcelFileDescriptor filePFD =
cxt.getContentResolver().openFileDescriptor(Uri.parse(pathFileToSend), "r");
FileDescriptor fd = filePFD.getFileDescriptor();
FileInputStream fIn = new FileInputStream(fd);
File fileBaseFolder = new File(Utils.GetRootDirectory().getAbsolutePath(), Utils.DESTINATION);
if (!fileBaseFolder.exists())
fileBaseFolder.mkdirs();
if (fileBaseFolder.exists()) {
File copyFile = new File(fileBaseFolder.getAbsolutePath(), nameOfFile);
FileOutputStream fOut = new FileOutputStream(copyFile);
byte data[] = new byte[4096];
long total = 0;
int count;
while ((count = fIn.read(data)) != -1) {
total += count;
fOut.write(data, 0, count);
}
fOut.close();
Uri copiedFileUri =
FileProvider.getUriForFile(cxt,
cxt.getString(R.string.file_provider_authority),
copyFile);
if (null != copiedFileUri)
{
try {
/*At this line, an exception is thrown - No persistable permissions exist.. */
cxt.getContentResolver().takePersistableUriPermission(copiedFileUri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
} catch (Exception e) {
e.printStackTrace();
}
}

takePersistableUriPermission() is for Uri values that you get from the Storage Access Framework (e.g., ACTION_OPEN_DOCUMENT). It will not work for FileProvider. And, you do not need permissions to work with getExternalFilesDir() on Android 4.4 and higher.

Related

What is the necessary call to send data over COM port using OpenNETCF Port class?

I am trying to retrieve a value from a Zebra printer by interrogating it with this code:
public static string GetSettingFromPrinter(string cmd)
{
string setting = string.Empty;
try
{
BasicPortSettings bps = new BasicPortSettings();
bps.BaudRate = BaudRates.CBR_19200;
bps.Parity = OpenNETCF.IO.Serial.Parity.none;
bps.StopBits = OpenNETCF.IO.Serial.StopBits.one;
Port serialPort = new Port("COM1:", bps);
serialPort.Open();
byte[] sendBytes = Encoding.ASCII.GetBytes(cmd);
MessageBox.Show(Encoding.ASCII.GetString(sendBytes, 0, sendBytes.Length));
serialPort.Output = sendBytes;
serialPort.Query(); // <= this is new
byte[] responseBytes = serialPort.Input;
setting = GetString(responseBytes);
serialPort.Close();
return setting;
}
catch (Exception x)
{
MessageBox.Show(x.ToString());
return setting;
}
}
However, I don't see where the Output is actually sent, or how to do that. My best guess was calling the Port.Query() method, but that doesn't work, either - at least there is nothing in setting / the Port.Input value after doing so.
I have successfully passed commands to the printer using the older SerialPort class:
public static bool SendCommandToPrinter(string cmd)
{
bool success; // init'd to false by default
try
{
SerialPort serialPort = new SerialPort();
serialPort.BaudRate = 19200;
serialPort.Handshake = Handshake.XOnXOff;
serialPort.Open();
serialPort.Write(cmd);
serialPort.Close();
success = true;
}
catch // may not need a try/catch block, as success defaults to false
{
success = false;
}
return success;
}
...but was advised not to use that due to its longness of tooth.
I would revert back to this snaggletooth if I knew how to read from the old SerialPort class. Does anybody know what I need to do to send sendBytes (and receive responseBytes)?
UPDATE
I tested "COM1" instead of "COM1:" (I used the latter because there is a post that says the colon is necessary (<= not medical advice, although that is doubtless true in that sense, too), but sans the ":" made no noticeable difference.
I then tried "string.Empty" in place of giving it a name, and got, "OpenNETCF.IO.Serial.CommPortException: CreateFileFailed 2 ..."
Onward...or is it Sideward...
FWIW, setting the Output property immediately sends the data on the wire. No additional call is necessary.

Asynchronous multipart uploads to Amazon S3 with ASP.NET

I am able to initiate asynchronous uploads to S3, however they are somehow not ending up as a file inside my S3 bucket and I see an error 'WithPartETags cannot be empty'. Here is the complete code
InitiateMultipartUploadRequest initRequest =
new InitiateMultipartUploadRequest()
.WithBucketName(existingBucketName)
.WithKey(Path.Combine(S3Path + "/", finfo.Name));
InitiateMultipartUploadResponse initResponse =
s3Client.InitiateMultipartUpload(initRequest);
// 2. Upload Parts.
long contentLength = finfo.Length;
long partSize = 15728640;//52428800-50MB 104857600- 100 MB - 5242880 - 5 MB
try
{
long filePosition = 0;
for (int i = 1; filePosition < contentLength; i++)
{
// Create request to upload a part.
UploadPartRequest uploadRequest = new UploadPartRequest()
.WithBucketName(existingBucketName)
.WithKey(Path.Combine(S3Path + "/", finfo.Name))
.WithUploadId(initResponse.UploadId)
.WithPartNumber(i)
.WithPartSize(partSize)
.WithFilePosition(filePosition)
.WithFilePath(finfo.FullName);
// Upload part and add response to our list.
//uploadResponses.Add(s3Client.UploadPart(uploadRequest));
IAsyncResult ar = s3Client.BeginUploadPart(uploadRequest, null, null);
ListObj.Add(new ThreadList() { _iasyncResult = ar });
filePosition += partSize;
Console.WriteLine("Length Written - " + filePosition + " .Content Length - " + contentLength);
}
bool uploadsComplete = false;
while (!uploadsComplete)
{
bool individualuploadscomplete = true;
foreach (var obj in ListObj)
{
if (!obj._iasyncResult.IsCompleted)
{
individualuploadscomplete = false;
break;
}
}
if (individualuploadscomplete)
{
uploadsComplete = true;
}
}
foreach (var obj in ListObj)
{
s3Client.EndUploadPart(obj._iasyncResult);
}
//// Step 3: complete.
CompleteMultipartUploadRequest compRequest =
new CompleteMultipartUploadRequest()
.WithBucketName(existingBucketName)
.WithKey(Path.Combine(S3Path + "/", finfo.Name))
.WithUploadId(initResponse.UploadId);
//.WithPartETags(uploadResponses);
CompleteMultipartUploadResponse completeUploadResponse =
s3Client.CompleteMultipartUpload(compRequest);
Not sure why you have the setting of the PartETags commented out for the complete multipart upload call but you need to add that code back in. Also when you are calling the EndUploadPart method you need to capture that UploadResponse that comes back from that.
You also might want to look into the TransferUtility found in the Amazon.S3.Transfer namespace. Its upload methods are designed to handle what you are attempting to accomplish for large objects, see Using the High-Level .NET API for Multipart Upload for details and example snippets.

Setting default TWAIN data source without using API UI menu

Using the twaindotnet library in C#, I'm wondering if there's a way to set the default datasource using the library.
As a feeble attempt, I've tried adding a SetDefault method to the DataSource class of twaindonet, like this
public static void SetDefault(Identity applicationId, IWindowsMessageHook messageHook, DataSource newDataSource)
{
var defaultSourceId = newDataSource.SourceId;
// Attempt to get information about the system default source
var result = Twain32Native.DsmIdentity(
applicationId,
IntPtr.Zero,
DataGroup.Control,
DataArgumentType.Identity,
Message.Set,
defaultSourceId);
if (result != TwainResult.Success)
{
var status = DataSourceManager.GetConditionCode(applicationId, null);
throw new TwainException("Error getting information about the default source: " + result, result, status);
}
}
which is called from the DataSourceManage class like this
public void SelectSource(DataSource dataSource)
{
DataSource.Dispose();
DataSource.SetDefault(ApplicationId, _messageHook, dataSource);
}
But when I try to use SetDefault, Twain32Native.DsmIdentity always results in Failure being returned.
I basically copied from SetDefault the setDefaultDataSource method from TWAIN sample Data Source and Application
pTW_IDENTITY TwainApp::setDefaultDataSource(unsigned int _index)
{
if(m_DSMState < 3)
{
cout << "You need to open the DSM first." << endl;
return NULL;
}
else if(m_DSMState > 3)
{
PrintCMDMessage("A source has already been opened, please close it first\n");
return NULL;
}
if(_index >= 0 && _index < m_DataSources.size())
{
m_pDataSource = &(m_DataSources[_index]);
// set the specific data source
TW_UINT16 twrc;
twrc = _DSM_Entry(
&m_MyInfo,
0,
DG_CONTROL,
DAT_IDENTITY,
MSG_SET,
(TW_MEMREF) m_pDataSource);
switch (twrc)
{
case TWRC_SUCCESS:
break;
case TWRC_FAILURE:
printError(0, "Failed to get the data source info!");
break;
}
}
else
{
return NULL;
}
return m_pDataSource;
}
Any help would be greatly appreciated.
The possible cause is that the version of your TWAIN DSM is too low. Only DSM 2.0 or above supports setting default TWAIN data source.

MethodAccessException when updating a record in sqlite db

I encounter this exception when I try to updating a record with following statement.
UPDATE GroupTable SET groupId=100 WHERE groupId=101
I tested the statement under SQLite Manager of Firefox plug-in, and it works.
The error message is as following image. It crashed at the os_win_c.cs, the method named getTempname().
Well, I modified the original codes and fixed this bug.
The Path.GetTempPath() doesn't work because the sandbox enviroment. It has no access right.
I fixed by following codes. And it works now.
static int getTempname(int nBuf, StringBuilder zBuf)
{
const string zChars = "abcdefghijklmnopqrstuvwxyz0123456789";
StringBuilder zRandom = new StringBuilder(20);
i64 iRandom = 0;
for (int i = 0; i < 20; i++)
{
sqlite3_randomness(1, ref iRandom);
zRandom.Append((char)zChars[(int)(iRandom % (zChars.Length - 1))]);
}
//! Modified by Toro, 2011,05,10
string tmpDir = "tmpDir";
IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication();
store.CreateDirectory(tmpDir);
//zBuf.Append(Path.GetTempPath() + SQLITE_TEMP_FILE_PREFIX + zRandom.ToString());
zBuf.Append(tmpDir + "/" + SQLITE_TEMP_FILE_PREFIX + zRandom.ToString());
return SQLITE_OK;
}
The above patch will result in an extra folder tmpDir in the isolatedstorage, and the temp files won't be deleted automatically, so it needs to be delete by self. I tried to delete those files in tmpDir in the method of winClose inside os_win_c.cs, and I found it will result in crash when I do VACUUM. Finally, I delete those tmp files when I closed the database. The following is a Dispose method in SQLiteConnection class.
public void Dispose()
{
if (_open)
{
// Original codes for close sqlite database
Sqlite3.sqlite3_close(_db);
_db = null;
_open = false;
// Clear tmp files in tmpDir, added by Toro 2011,05,13
IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication();
string tmpDir = "tmpDir";
if (store.DirectoryExists(tmpDir) == false) return;
string searchPath = System.IO.Path.Combine(tmpDir, "*.*");
foreach (string file in store.GetFileNames(searchPath)) {
store.DeleteFile(System.IO.Path.Combine(tmpDir, file));
}
}
}

ASP.NET Backgroundworkers for spreadsheet creation: multiple ones interfering with each other?

I am writing an ASP.NET application in which i need to create multiple excel reports. the report creation is pretty time-consuming (up to ten seconds for each) so i am using backgroundworkers to create them simultaneously.
My code looks a bit like this:
if (condition1)
{
excel_file_name = "TRANSFER";
BackgroundWorker worker_t = new BackgroundWorker();
worker_t.DoWork += new DoWorkEventHandler(DoWork);
worker_t.WorkerReportsProgress = false;
worker_t.WorkerSupportsCancellation = true;
worker_t.RunWorkerCompleted +=
new RunWorkerCompletedEventHandler(WorkerCompleted);
worker_t.RunWorkerAsync(excel_file_name);
}
if (Condition2)
{
excel_file_name = "NEFT";
BackgroundWorker worker_n = new BackgroundWorker();
worker_n.DoWork += new DoWorkEventHandler(DoWork);
worker_n.WorkerReportsProgress = false;
worker_n.WorkerSupportsCancellation = true;
worker_n.RunWorkerCompleted +=
new RunWorkerCompletedEventHandler(WorkerCompleted);
worker_n.RunWorkerAsync(excel_file_name);
}
there are more conditions but i haven't written them, since they are all similar. the only difference is the Excel_File_Name
the DoWork even then calls a class to create the excel files with the given name.
When condition1 and condition2 are both true, Here is the issue:
1. if i run this slowly using breakpoints during debugging, both files (TRANSFER and NEFT) are created.
2. if, however, i run it without breakpoints like a normal application, only the last file (NEFT in this example) is created.
What can be the issue?
Thanks
PS: For further information, here is the important code from the class that creates the excel file:
private static string placeDataInTemplate(string destFilePath, DataRow dr, bool isCoverLetter)
{
int loop = 0;
ExcelNamespace.Application excelApplication = new ExcelNamespace.Application();
ExcelNamespace.Workbook workbook = excelApplication.Workbooks.Open(destFilePath, 0, false, 5,
"", "", true, ExcelNamespace.XlPlatform.xlWindows, "\t", false, false, 0, true, true, false);
ExcelNamespace.Worksheet workSheet = (ExcelNamespace.Worksheet)workbook.Sheets[sheet_no];
try
{
string value;
string replicate;
string replicate_end;
// get data for Place Holders
sDataTable dtPlaceHolderData = getPlaceHolderData(dr);
//make Display Alerts False
excelApplication.DisplayAlerts = false;
if (dtPlaceHolderData != null && dtPlaceHolderData.Rows.Count > 0)
{
int rowCntDt = 0; //Which row will be used for data?
int i = 1;
Excel.Range Find = (ExcelNamespace.Range)workSheet.Cells.Find("#",
(ExcelNamespace.Range)workSheet.Cells[1, 1],
Excel.XlFindLookIn.xlValues,
Excel.XlLookAt.xlPart,
Excel.XlSearchOrder.xlByRows,
Excel.XlSearchDirection.xlNext,
false,
false,
Missing.Value);
while (Find != null && loop <= 200)
{
loop++;
value = Find.Value2.ToString();
if (condition)
//VERY long if...else if
}
string approveDirPath = destFilePath.Replace(Path.GetFileName(destFilePath), string.Empty);
workbook.Close(true, destFilePath, Type.Missing);
excelApplication.Quit();
string filepath = destFilePath.Split('-')[0];
string approval_id = dr[0].ToString();
return destFilePath;
}
return string.Empty;
}
catch (Exception ex)
{
//do something
}
finally
{
//release resources
}
NOTE: I have removed a lot of needless code. I can paste it if needed. Thank you
Most likely cause is some shared state between two threads - shared state may include excel application and workbooks. So you need to inspect your code for the same.
On the side note, instead of using Excel Automation to generate excel files, you may consider using some in-process library which would be perhaps more scalable and void of such issues. Have a look at one such free basic library at code project

Resources