Open local pdf file in Xamarin Forms - xamarin.forms

i'm triying to open a local pdf file in xamarin forms, my code:
var context = Forms.Context;
Java.IO.File javaFile = new Java.IO.File(filePath);
Android.Net.Uri uri = FileProvider.GetUriForFile(context, "myAuth.fileprovider", javaFile);
context.GrantUriPermission(context.PackageName, uri, ActivityFlags.GrantReadUriPermission);
Intent intent = new Intent(Intent.ActionView);
intent.SetDataAndType(uri, "application/pdf");
intent.SetFlags(ActivityFlags.ClearWhenTaskReset | ActivityFlags.NewTask);
Xamarin.Forms.Forms.Context.StartActivity(intent);
i followed several tutorials like this: How to get actual path from Uri xamarin android
But now my problem is that i don't know if the uri is getting the real path for the file:
i got this :
javaFile = "/storage/emulated/0/Download/myReport.pdf" (checked and exist)
uri =
"content://myAuth.fileprovider/external_files/Download/myReport.pdf"
But i got this error on my pdf app "this file cannot be accessed". What i need to change to take the real path of the file? i think the problem is here:
Android.Net.Uri uri = FileProvider.GetUriForFile(context, "myAuth.fileprovider", javaFile);
But don't know what more change in order to work. Thx a lot!

You should set the FileProvider in the application tag of AndroidManifest.xml.
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.companyname.boxviewcolordemo" android:installLocation="auto">
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="28" />
<application android:label="BoxViewColorDemo.Android">
<provider android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths"></meta-data>
</provider>
</application>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
</manifest>
Then create file_paths.xml in the xml folder.
file_paths.xml add following code.
<?xml version="1.0" encoding="utf-8" ?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path
name="external"
path="." />
<external-files-path
name="external_files"
path="." />
<cache-path
name="cache"
path="." />
<external-cache-path
name="external_cache"
path="." />
<files-path
name="files"
path="." />
</paths>
Then in your dependenceService achievement, you should use following code. Note: FileProvider.GetUriForFile(context, context.ApplicationContext.PackageName + ".fileprovider", file); the second attribute is you package name and ".fileprovider"
[assembly: Dependency(typeof(OpenPDF))]
namespace BoxViewColorDemo.Droid
{
public class OpenPDF : IOpenFile
{
public void OpenPDf(string filePath)
{
var rs = System.IO.File.Exists(filePath);
if (rs)
{
var context = Android.App.Application.Context;
var file = new Java.IO.File(filePath);
var uri = FileProvider.GetUriForFile(context, context.ApplicationContext.PackageName + ".fileprovider", file);
try
{
var intent = new Intent(Intent.ActionView);
intent.AddCategory(Intent.CategoryDefault);
intent.AddFlags(ActivityFlags.GrantReadUriPermission);
intent.AddFlags(ActivityFlags.ClearWhenTaskReset | ActivityFlags.NewTask);
intent.SetDataAndType(uri, "application/pdf");
context.StartActivity(intent);
}
catch (Exception e)
{
Toast.MakeText(context, e.Message, ToastLength.Long).Show();
}
}
}
}
}
And do not forget to grand the read/write permission at the runtime. For testing, you can add following code to the OnCreate method of MainActivity.cs.
if (ContextCompat.CheckSelfPermission(this, Manifest.Permission.WriteExternalStorage) != (int)Permission.Granted)
{
RequestPermissions(new string[] { Manifest.Permission.ReadExternalStorage, Manifest.Permission.WriteExternalStorage }, 0);
}
I put the pdf file to the Download folder, my filePath is DependencyService.Get<IOpenFile>().OpenPDf("/storage/emulated/0/Download/test.pdf");

If someone has follow the steps before and still does not works, and the problem continues in the line var uri = FileProvider.GetUriForFile(context, context.ApplicationContext.PackageName + ".fileprovider", file);. Check this too:
1 - Check if it's into Application tag
2 - Check the autority, usually you will use "${applicationId}.provider", but if not works, use a literal, for example myAuth.fileprovider
<application>
...
<provider ..android:authorities="myAuth.fileprovider" ..>
<meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="#xml/file_paths"></meta-data>
</provider>
</application>
3 - Check the context, var context = Android.App.Application.Context; it's the usually, but if this one does not works, you can try MainActivity.Current, but you need to create first a static var into the MainActivity Class, something like this: public static MainActivity Current = null; and initialize into the OnCreate Method Current = this;. That's was my problem
4 - Check the type of the MimeType of the data, intent.SetDataAndType(uri, "application/pdf");
Thanks again to Leon Lu - MSFT for the answer, this is just an extension for anyone facing the same problem as me.

Related

Use Custom DLLs into Progress

I'm having some issues while loading my custom DLL to OpenEdge Enviroment.
I've already copied my DLL to an PROPATH value and imported the DLL inside ProAsmRef.exe (The DLL is in the same folder as ProAsmRef and assemblies.xml)
The problem is, when I try to load my custom file inside a procedure, it sends me this current error:
**Unknown table name PCControl. (200)
I've already imported the DLL on my definition block with:
USING PCControl.*.
My DLL depends on another DLL (System.DirectoryServices.dll) but is already on assemblies.xml.
I can't figure it out why PCControl isn't importing, because I already have another two DLL's and they are working just fine...
Thanks for the help!
My DLL Code:
using System;
using System.DirectoryServices;
using System.Runtime.InteropServices;
using Microsoft.Office.Interop.Outlook;
namespace PCControl{
public class PCC{
public static string AzureLogin(string user, string password) {
string status;
try {
DirectoryEntry entry = new DirectoryEntry("LDAP://AUTOEXPR.COM", user, password) {
AuthenticationType = AuthenticationTypes.Secure,
Username = user,
Password = password
};
DirectorySearcher _searcher = new DirectorySearcher(entry);
_searcher.Filter = "(objectclass=user)";
SearchResult _sr = _searcher.FindOne();
string? _name = _sr.Properties["displayname"][0].ToString();
status = "SUCCESS - User " + user + " has logged in.";
} catch (System.Exception e) {
status = "ERROR - While logging in: " + e.ToString();
}
return status;
}
}
}
My XML:
<?xml version="1.0" encoding="utf-8"?>
<references xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<assembly name="ClassADT, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<assembly name="ClassOPC, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<assembly name="PCControl, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<assembly name="System.DirectoryServices, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
</references>
My login.p (resumed):
&ANALYZE-SUSPEND _UIB-CODE-BLOCK _PROCEDURE Login C-Win
PROCEDURE Login :
/*------------------------------------------------------------------------------
Purpose:
Parameters: <none>
Notes:
------------------------------------------------------------------------------*/
DEF VAR lSuccess AS CHAR NO-UNDO.
lSuccess = PCControl.PCC:AzureLogin("arorap1", "12345").
MESSAGE lSuccess
VIEW-AS ALERT-BOX INFO
TITLE "ok".
END PROCEDURE.
/* _UIB-CODE-BLOCK-END */
&ANALYZE-RESUME
This issue is not related to my code into DLL... I've added the function in my co-worker's DLL and it works perfectly:
USING ClassADT.*.
DEFINE VARIABLE LSuccess AS CHAR NO-UNDO.
IF AVAIL usr_param AND usr_param.usr_ativo EQ TRUE THEN
lSuccess = ClassADT.MyAdt:MyLogin(txtUser:SCREEN-VALUE, txtPassword:SCREEN-VALUE).
It is not required and not advised to have your custom .NET Assembly and the assemblies.xml file in the c:\dlc117\bin folder at all.
Also your first assumption that those need to be in the PROPATH is not correct.
Progress provides the -assemblies startup parameter which can be used to point to the folder that contains you assemblies.xml file along with the custom .NET Assemblies (.dll files).

How to get associations from the data list by using WebScript?

In the Alfresco One 5.x Developer's Guide there is an example of the data list.
This functionality I would like to use in my project. For example, there are some business process for which performers are predefined. Each Department has its own set of business processes. It's possible to read the metadata of the incoming contract (from email or scanner - is not important) and automatically run a business process, depending on the Department. The concept of data lists seems to me appropriate...
The problem is that I can't obtain associations. In my case, this is the type cm:person.
For example, data list model definition described as follows:
<?xml version="1.0" encoding="UTF-8"?>
<model name="mspdl:MSpredefinedAssigneesDataListModel" xmlns="http://www.alfresco.org/model/dictionary/1.0">
<description>...</description>
<author>...</author>
<version>...</version>
<imports>
<import uri="http://www.alfresco.org/model/dictionary/1.0" prefix="d"/>
<import uri="http://www.alfresco.org/model/content/1.0" prefix="cm"/>
<import uri="http://www.alfresco.org/model/datalist/1.0" prefix="dl" />
</imports>
<namespaces>
<namespace uri="http://www.....com/model/datalist/3.0" prefix="mspdl"/>
</namespaces>
<types>
<type name="mspdl:assigneesListItem">
<title>...</title>
<parent>dl:dataListItem</parent>
<properties>
<property name="mspdl:serviceName">
<type>d:text</type>
<mandatory>true</mandatory>
</property>
</properties>
<associations>
<association name="mspdl:projectMember1">
<source>
<mandatory>true</mandatory>
<many>false</many>
</source>
<target>
<class>cm:person</class>
<mandatory>true</mandatory>
<many>false</many>
</target>
</association>
<association name="mspdl:projectMember2">
<source>
<mandatory>true</mandatory>
<many>false</many>
</source>
<target>
<class>cm:person</class>
<mandatory>true</mandatory>
<many>false</many>
</target>
</association>
...
<association name="mspdl:projectMemberN">
<source>
<mandatory>true</mandatory>
<many>false</many>
</source>
<target>
<class>cm:person</class>
<mandatory>true</mandatory>
<many>false</many>
</target>
</association>
</associations>
</type>
</types>
</model>
The web script where I'm trying to retrieve association:
public class DataListAssignmentsRetriever extends DeclarativeWebScript {
private final String DATA_LIST_SITE_CONTAINER = "dataLists";
private final String NAMESPACE_URI = "http://www.......com/model/datalist/3.0";
#Override
protected Map<String, Object> executeImpl(WebScriptRequest req, Status status) {
QName ASSOC_NAME_PROJECT_MEMBER_1 = QName.createQName(NAMESPACE_URI, "projectMember1");
List<AssociationRef> temp00List = serviceRegistry.getNodeService().getSourceAssocs(dataListNodeRef, ASSOC_NAME_PROJECT_MEMBER_1);
// temp00List.size() == 0 ???
List<AssociationRef> temp01List = serviceRegistry.getNodeService().getTargetAssocs(dataListNodeRef, ASSOC_NAME_PROJECT_MEMBER_1);
// temp01List.size() == 0 ???
List<ChildAssociationRef> temp02List = serviceRegistry.getNodeService().getChildAssocs(dataListNodeRef);
// temp02List == 1 < -- Allows to find just only the property 'serviceName'.
List<ChildAssociationRef> temp03List =
serviceRegistry.getNodeService().getChildAssocs(dataListNodeRef, RegexQNamePattern.MATCH_ALL, ASSOC_NAME_PROJECT_MEMBER_1);
// temp03List.size() == 0 ???
List<AssociationRef> temp04List.size() =
serviceRegistry.getNodeService().getSourceAssocs(dataListNodeRef, RegexQNamePattern.MATCH_ALL);
// temp04List.size() == 0 ???
List<AssociationRef> temp05List = serviceRegistry.getNodeService().getTargetAssocs(nodeRef, RegexQNamePattern.MATCH_ALL);
// temp05List.size() == 0 ???
...
}
}
Service serviceRegistry is injected correctly.
What I'm doing wrong?. How to get associations from the data list?.
I would be very grateful for the information. Thanks to all.
Updated.
NodeRef of my data list is workspace://SpacesStore/b136bebc-fe2c-40fb-aec6-93d9fd22533d. When I searching it in the Node Browser, I get the following:
Hence, I go through the link and see the following: associations is missing.
Then I go through the reference to the child element (showing at the top of the screenshot) and see the following:
And when I go via this link, I see my associations:
Updated.
Thanks for the consulting, Gagravarr and ratik.singhal _. By using the following code I can get the reference to the data list item:
List<ChildAssociationRef> childAssociationRefs = serviceRegistry.getNodeService().getChildAssocs(
dataListNodeRef,
ContentModel.ASSOC_CONTAINS,
RegexQNamePattern.MATCH_ALL
);
NodeRef dataListItemNodeRef = childAssociationRefs.get(0).getChildRef();
Here I can see the properties and associations:
Properties:
Associations:
I can access the properties using the following code:
Map<QName, Serializable> properties = serviceRegistry.getNodeService().getProperties(dataListItemNodeRef);
Iterator iterator = properties.entrySet().iterator();
while(iterator.hasNext()) {
Map.Entry keyValuePairs = (Map.Entry)iterator.next();
Object key = keyValuePairs.getKey();
Object value = keyValuePairs.getValue();
...
}
But how to obtain associations?...
Angel Borroy gave an excellent example that helped me:
alfresco-datalist-constraints
And of course, Gagravarr gave a great example:
DataListDownloadWebScript
The solution may look like the following:
...
NodeRef dataListContainer =
siteService.getContainer("contracts-site", "dataLists");
List<ChildAssociationRef> dataListsNodes =
nodeService.getChildAssocs(dataListContainer);
for(ChildAssociationRef dataList : dataListsNodes) {
if (dataList.getTypeQName().isMatch(ContentModel.ASSOC_CONTAINS)) {
if(nodeService.getProperty(
dataList.getChildRef(),
ContentModel.PROP_TITLE).toString().equals("Data list title here")) {
List<ChildAssociationRef> childAssocsRef =
nodeService.getChildAssocs(dataList.getChildRef());
for(ChildAssociationRef childAssocRef : childAssocsRef) {
List<AssociationRef> customAssocs = nodeService.getTargetAssocs(
childAssocRef.getChildRef(),
QName.createQName(DATALIST_MODEL_URI, "projectMember1"));
NodeRef nodeRef = customAssocs.get(0).getTargetRef();
if(ContentModel.TYPE_PERSON.equals(nodeService.getType(nodeRef))) {
nodeService.getProperty(nodeRef, ContentModel.PROP_USERNAME);
}
...
}
} else continue;
}
}
...
This solved my issue.

Acces-Control-Allow-Origin works with Web.config (IIS7) but not with (WebApiConfig.cs) ASP.NET Cross Origin support

For a project i want to load and view a pdf file with angular-pdfjs. The team uses ASP.net Cross Origin, to Allow-Acces-Control, Headers, Credentials etc.
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Replace the default implementation of the ITraceWriter with our custom logger.
config.Services.Replace(typeof (ITraceWriter), new GlobalTraceLogger());
// Replace the default exception logger to be able to log exceptions with NLog
config.Services.Replace(typeof (IExceptionLogger), new GlobalExceptionLogger());
// Replace the default exceptionhandler to be able to handle exceptions globally
config.Services.Replace(typeof (IExceptionHandler), new GlobalExceptionHandler());
// We must enable cors, because otherwise we are not able to commuincate with a java script client
// TODO: We need to restirct the requested resource. Do not allow every origin!
// Do not run this in prodocutive environment
var cors = new EnableCorsAttribute("*", "*", "*", "*");
cors.SupportsCredentials = true;
config.EnableCors(cors);
config.MapHttpAttributeRoutes();
// Make the default return type JSON
var appXmlType =
config.Formatters.XmlFormatter.SupportedMediaTypes.FirstOrDefault(t => t.MediaType == "application/xml");
config.Formatters.XmlFormatter.SupportedMediaTypes.Remove(appXmlType);
This works good so far, but if i want to load my pdf file with angular-pdfjs, i get a Cross Origin Error, because Allow-Acces-Control-Origin "*" didn't works for my pdf-url.
(https://img3.picload.org/image/roirrgcw/corsworksnot.png)
But if i using instead of ASP.net Cross Origin Support the Allow-Access-Control of IIS7 in Web.config:
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Headers" value="Origin, X-Requested- With, Content-Type, Accept" />
<add name="Access-Control-Allow-Methods" value="GET,POST,PUT,DELETE,OPTIONS" />
<add name="Access-Control-Allow-Credentials" value="true" />
</customHeaders>
</httpProtocol>
it works and the pdf will be loaded correctly.
(https://picload.org/image/roirrgci/corsworks.jpg)
But the problem is, at the moment the page is loaded via "file://" and so i get
an error because there is no Access-Control-Allow-Origin for 'null'. That means, my pdf is loading correctly this way, but the login, pictures... won't be loaded anymore. So my question is, if someone knows how i can change the WebApiConfig-Implementation that my pdf-file get an Access-Controll-Allow as well. Or maybe can someone tell where the error could be.
For information:
Thats the way i'm loading the pdf with angular-pdfjs:
<!---------------------------THE PDF VIEWER DIRECTIVE------------------------->
<div pdf-viewer="options" pdf-url="pdfUrl" id="my-viewer" class="col col-lg-10"></div>
<!---------------------------THE PDF VIEWER DIRECTIVE------------------------->
and thats the url, i'm using:
function PdfviewController(ebmGuideLineService, mediaService, $scope, $window) {
var vm = this;
$scope.pdfUrl = 'http://localhost:3787/NCCN_Evidence_Blocks_Melanoma.pdf';
$scope.options = { mouseZoom: false, mousePan: false };
Please tell me, if you need more informations and thank you for your help.

GCMRegistrar Crash with ECPN plugin for unity android

I encountered a severe problem with the ECPN plugin (push notification) for android. As client needs it these days and push notification is my last hurdle......
OK, I changed your plugin quite a bit, just to work with my own purpose. It seems that my Samsung S4 and Sony Xperia got crash whenever gcm.jar is used, for example:
#Override
public void onCreate(Bundle savedInstance) {
super.onCreate(savedInstance);
Intent i = getIntent();
Boolean isRegistration = getIntent().getExtras().getBoolean("isRegistration ");
/*
if(!isRegistration) {
// Unregister device
GCMRegistrar.unregister(this);
} else {
// Carry on with registration
String SENDER_ID = i.getStringExtra("senderID");
// Checking device and manifest dependencies
*/
GCMRegistrar.checkDevice(this);
// GCMRegistrar.checkManifest(this);
// Get GCM registration id
//final String regId = GCMRegistrar.getRegistrationId(this);
/*
// Check if regid already presents
if (regId.equals("")) {
// Registration is not present, register now with GCM
GCMRegistrar.register(this, SENDER_ID);
} else {
// Send ID to Unity
sendConfirmRegistration(regId);
// if registeredOnServer flag is not set, send info to Unity
if (!GCMRegistrar.isRegisteredOnServer(this)) {
GCMRegistrar.setRegisteredOnServer(this, true);
}
}
}
*/
finish();
return;
}
The procedure crashes at the bold line. Any idea why it is so ?
My bundleID is com.redcross.redcross, below is my manifest file for GCM portion.
<!-- GCM java -->
<activity
android:name="com.redcross.redcross.GCMJava"
android:label="#string/app_name" > <!-- android:name must coincide with GCMJava package name + .GCMJava-->
</activity>
<receiver android:name="com.google.android.gcm.GCMBroadcastR eceiver" androidermission="com.google.android.c2dm.permission.SEND " >
<intent-filter>
<!-- Receives the actual messages. -->
<action android:name="com.google.android.c2dm.intent.RECEI VE" />
<!-- Receives the registration id. -->
<action android:name="com.google.android.c2dm.intent.REGIS TRATION" />
<category android:name="com.redcross.redcross" /> <!-- android:name must coincide with GCMJava package name -->
</intent-filter> </receiver>
<service android:name="com.redcross.redcross.GCMIntentServi ce" /> <!-- android:name must coincide with GCMJava package name + .GCMIntentService-->
<!-- end -->
And I tried putting classes.jar, gcm.jar and android.jar around in unity asset folder => plugins => android and referenced inside or outside GCMJava.jar, it simply doesn't work out... Worked two whole days already...
Really appreciate your help ...

Basic Auth for WSO2 EI API service

I am using WSO2-EI 6.4.0. I have tried this development with link. It work for me. But I need to get user name and password from other back end service. In this example was showed the hard corded user and password. I have added that code for your reference. Please help me to get those user name and password from property file.
public boolean processSecurity(String credentials) {
String decodedCredentials = new String(new Base64().decode(credentials.getBytes()));
String usernName = decodedCredentials.split(":")[0];
String password = decodedCredentials.split(":")[1];
if ("admin".equals(username) && "admin".equals(password)) {
return true;
} else {
return false;
}
}
I have added WSO2 EI handler like following. I need to pass the value from back service or call other sequence and load.
<api context="/test">
<resource methods="POST">
<inSequence>
................
</inSequence>
<outSequence>
................
</outSequence>
</resource>
<handlers>
<handler class="rezg.ride.common.BasicAuthHandler">
<property name="cm_password" value="admin"/>
<property name="cm_userName" value="admin"/>
</handler>
</handlers>
</api>
When we run the above API, handlers are running first and then running in and out sequences. So I need to get user name and password calling Sequence or any other method before run this BasicAuthHandler.
If you need to read the property file from the class mediator it's just straight forward java property file reading. Please refer the following call sample of reading a property file. In this scenario, Just read the carbon.properties file exists in the conf directory.
public boolean mediate(MessageContext context) {
String passwordFileLocation = System.getProperty("conf.location")+"/carbon.properties";
try (FileInputStream input = new FileInputStream(passwordFileLocation)) {
Properties prop = new Properties();
// load a properties file
prop.load(input);
log.info("------org.wso2.CipherTransformation : " + prop.getProperty("org.wso2.CipherTransformation"));
} catch (IOException ex) {
ex.printStackTrace();
}
return true;
}
To get the server location and the conf locating, There are JAVA system properties are set at the time wso2 server starts. Following are some of the useful System system properties.
carbon.local.ip
carbon.home
conf.location

Resources