boost::filesystem::wpath on Android - android

boost::filesystem provides many interesting functions, for example, we can use boost::filesystem::exists to check whether one file exists or not. I am now using this functionality in Android. It succeeds in the following program:
int main()
{
using namespace std;
string file_name="/data/local/tmp/abc/def.txt";
boost::filesystem::path dddddd(file_name);
if(boost::filesystem.exists(dddddd))
{
std::cout<<"Succeed"<<std::endl;
}
else
{
std::cout<<"Failed"<<std::endl;
}
return 0;
}
However, if I use wstring instead:
int main()
{
using namespace std;
wstring file_name=L"/data/local/tmp/abc/def.txt";
boost::filesystem::wpath dddddd(file_name);
if(boost::filesystem.exists(dddddd))
{
std::cout<<"Succeed"<<std::endl;
}
else
{
std::cout<<"Failed"<<std::endl;
}
return 0;
}
It will fail. It seems to me that the reason is because Android does not handle wstring very well. Any idea how I can change in order to make sure boost::filesystem::wpath can work on Android?

Related

Define and implement HIDL interface

For test purposes I want to create a HIDL interface + implementation and run the combination as a system service. For that I defined the IGuotie.hal interface:
package android.hardware.guotie#2.0;
interface IGuotie {
add(int32_t i, int32_t k) generates (int32_t result);
};
The following files are used to implement the interface
Guotie.h
#pragma once
#include <android/hardware/guotie/2.0/IGuotie.h>
#include <hidl/MQDescriptor.h>
#include <hidl/Status.h>
namespace android {
namespace hardware {
namespace guotie {
namespace V2_0 {
namespace implementation {
using ::android::hardware::hidl_array;
using ::android::hardware::hidl_memory;
using ::android::hardware::hidl_string;
using ::android::hardware::hidl_vec;
using ::android::hardware::Return;
using ::android::hardware::Void;
using ::android::sp;
struct Guotie : public IGuotie {
// Methods from ::android::hardware::guotie::V2_0::IGuotie follow.
Return<int32_t> add(int32_t i, int32_t k) override;
// Methods from ::android::hidl::base::V1_0::IBase follow.
static IGuotie* getInstance(void);
};
} // namespace implementation
} // namespace V2_0
} // namespace guotie
} // namespace hardware
}
Guotie.cpp
#include "Guotie.h"
namespace android {
namespace hardware {
namespace guotie {
namespace V2_0 {
namespace implementation {
// Methods from ::android::hardware::guotie::V2_0::IGuotie follow.
Return<int32_t> Guotie::add(int32_t i, int32_t k) {
return i + k;
}
IGuotie *Guotie::getInstance(void) {
return new Guotie();
}
} // namespace implementation
} // namespace V2_0
} // namespace guotie
} // namespace hardware
}
service.cpp
#define LOG_TAG "android.hardware.graphics.allocator#2.0-service"
#include <android/hardware/guotie/2.0/IGuotie.h>
#include <hidl/LegacySupport.h>
#include "Guotie.h"
using android::hardware::guotie::V2_0::IGuotie;
using android::hardware::guotie::V2_0::implementation::Guotie;
using android::hardware::configureRpcThreadpool;
using android::hardware::joinRpcThreadpool;
using android::sp;
int main() {
int res;
android::sp<IGuotie> ser = Guotie::getInstance();
ALOGE("simp main");
configureRpcThreadpool(1, true /*callerWillJoin*/);
if (ser != nullptr) {
res = ser->registerAsService();
if(res != 0)
ALOGE("Can't register instance of GuotieHardware, nullptr");
} else {
ALOGE("Can't create instance of GuotieHardware, nullptr");
}
joinRpcThreadpool();
return 0; // should never get here
}
android.hardware.guotie#2.0-service.rc
service guotieserver /vendor/bin/hw/android.hardware.guotie#2.0-service
class hal
user root
group root
seclabel u:r:su:s0
Android.bp
hidl_interface {
name: "android.hardware.guotie#2.0",
root: "android.hardware",
vndk: {
enabled: true,
},
srcs: [
"IGuotie.hal",
],
interfaces: [
"android.hidl.base#1.0",
],
gen_java: true,
}
Building results in following error message
FAILED: out/target/product/generic/obj/PACKAGING/vndk_intermediates/check-list-timestamp
/bin/bash -c "(( diff --old-line-format=\"Removed %L\" --new-line-format=\"Added %L\" --unchanged-line-format=\"\" build/make/target/product/gsi/29.txt out/target/product/generic/obj/PACKAGING/vndk_intermediates/libs.txt || ( echo -e \" error: VNDK library list has been changed.\\n\" \" Changing the VNDK library list is not allowed in API locked branches.\"; exit 1 )) ) && (mkdir -p out/target/product/generic/obj/PACKAGING/vndk_intermediates/ ) && (touch out/target/product/generic/obj/PACKAGING/vndk_intermediates/check-list-timestamp )"
Removed VNDK-code: android.hardware.guotie#2.0.so
Added VNDK-core: android.hardware.guotie#2.0.so
error: VNDK library list has been changed.
Changing the VNDK library list is not allowed in API locked branches.
Some articles suggested to add (in my case) android.hardware.guotie#2.0.so to build/make/target/product/vndk/28.txt. However, the vndk folder does not exist. Instead I added it to build/make/target/product/gsi/29.txt and current.txt but the build still fails (I added it in alphabetical order). Any suggestions?
Adding an interface to android.hardware is usually only done by Google itself. Vendor HIDL interfaces are not part of the VNDK.
You likely should consider yourself a vendor and just remove this part from your Android.bp:
vndk: {
enabled: true,
},
and change the namespace to vendor.<you>.guotie
For more information on what the VNDK is see the official documentation: https://source.android.com/devices/architecture/vndk.
I solved this build error when I was trying to make Khadas vim3 Android P.
Firstly please check if out/target/product/product_name/obj/PACKAGING/vndk_intermediates/libs.txt is same with build\make\target\product\vndk\28.txt and \current.txt.
Secondly please run make update-api.
This works for me and hope my sharing could help you.
You can see more detail and my console screenshot on my GitHub :)

Read value returned in CompletableFuture

A function from some SDK is returning me a CompletableFuture. How can I read the value properly once it's reached.
My Code:
CompletableFuture<Web3ClientVersion> web3clientCompletableFuture;
web3clientCompletableFuture = web3jNode.web3ClientVersion().sendAsync();
sendAsync() Code (In SDK):
public CompletableFuture<T> sendAsync() {
return web3jService.sendAsync(this, responseType);
}
I can access the returned data using get(), but that would make the whole process syncronus and block UI.
I've checked the functions signatures on Android API Reference, like:
thenApply(Function<? super T, ? extends U> fn)
handle(BiFunction<? super T, Throwable, ? extends U> fn)
But seems I require some code examples.
[Note: I'm not so familiar with lambda]
Here is a tutorial that has examples that show you how to use these powerful methods of CompletableFuture. You are right you want to use thenApply() if you have to return value after you process the future. But if you simply want to process the future and not return anything, you should use thenAccept() and thenRun(). There are other methods listed with examples as well.
Here is an example that simply returns a CompletableFuture of type integer:
CompletableFuture<Integer> mynumber = null;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
mynumber = CompletableFuture.supplyAsync(() -> {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
return 4 * 4;
});
}
Here arg is the result(CompletableFuture) from the above step, and in your case the data you are receiving from the SDK. You are attaching a callback method(thenApply()) and do what ever you would like to do with it. Depending on your implementation, you can attach multiple thenApply(). Here I am calling a method that will take the result and do some computation with it.
CompletableFuture<Integer> willdoStuff = null;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
willdoStuff = mynumber.thenApply(arg -> {
compute(arg);
return arg / 2;
});
}
public void compute(int someInt){
Toast.makeText(getApplicationContext(), "The result of the computation is" + someInt, Toast.LENGTH_LONG).show();
}
Just comment out the sleep code to execute this code in the main thread.
The Lambda function is simply input and output, the arguments before {} being the input and the statement within the {}, which is actually a function that does something with the arguments(input). You might want to ask different question in regards to that.

Xamarin - Does Android Drawable Exist?

In a Xamarin Forms (3.0) application, what method(s) would I use to tell if a drawable resource exists in my Android project from shared project code?
In iOS, I can use NSFileManager to see if the file exists in my iOS project's "Resources" folder:
#if __IOS__
private bool DoesImageExist(string image)
{
//WORKS
return Foundation.NSFileManager.DefaultManager.FileExists(image);
}
#endif
In Android, I thought it should be part of the Assembly Resources, but that just returns my App.xaml file.
#if __ANDROID__
private bool DoesImageExist(string image)
{
//DOES NOT WORK
if(MyApp.Current?.GetType() is Type type)
foreach (var res in Assembly.GetAssembly(type).GetManifestResourceNames())
{
if (res.Equals(image, StringComparison.CurrentCultureIgnoreCase))
return true;
}
return false;
}
#endif
How to specifically check if a drawable exists by name in android would work like something this:
#if __ANDROID__
public bool DoesImageExist(string image)
{
var context = Android.App.Application.Context;
var resources = context.Resources;
var name = Path.GetFileNameWithoutExtension(image);
int resourceId = resources.GetIdentifier(name, "drawable", context.PackageName);
return resourceId != 0;
}
#endif
If your code is in a pcl or .net standard assembly, you will have to create an abstraction. Some kind of Ioc library works well for this. You can also have Android or iOS implement the abstract interface and make that available as a singleton somewhere. It's not as elegant, but it would work.
Basically you would implement something like this:
public interface IDrawableManager
{
bool DoesImageExist(string path);
}
Then have two implementations:
public class DroidDrawableManager : IDrawableManager
{
var context = Android.App.Application.Context;
var resources = context.Resources;
var name = Path.GetFileNameWithoutExtension(image);
int resourceId = resources.GetIdentifier(name, "drawable", context.PackageName);
return resourceId != 0;
}
public class IOSDrawableManager : IDrawableManager
{
public bool DoesImageExist(string image)
{
return Foundation.NSFileManager.DefaultManager.FileExists(image);
}
}
I've uploaded a working sample to github:
https://github.com/curtisshipley/ResourceExists

Loading a Font with PdfSharp .Net Standard preview from Xamarin.Forms fails: No appropriate font found

I am currently assessing how to generate a PDF from Xamarin.Forms (currently running the app on Android, only) and checking the .NET Standard port of PdfSharp.
Drawing to the PDF and showing it works, but I'm having issues writing text to the document. When I am trying to load an XFont with the following code
var font = new XFont("sans-serif", 20);
it fails with the exception
System.InvalidOperationException: No appropriate font found.
According to these samples, it is supposed to work this way, but they are for PdfSharp.Xamarin and not the PdfSharp .NET Standard. According to this answer the "sans-serif" font family should be correct, but I've desperately tried other options, like "Roboto", but to no avail.
Is PdfSharp for .NET Standard compatible with Xamarin at all? (It lists PdfSharp.Xamarin as a source it has been created from, hence I assumed it.) Is there anything else I have missed?
EDIT
I tried PdfSharp.Xamarin and it did work. Obviously this is an issue with the .NET Standard port.
I had similar issue and i resolved it by writing my own implementation of IFontResolver and assigning it to GlobalFontSettings.FontResolver.
public class FileFontResolver : IFontResolver // FontResolverBase
{
public string DefaultFontName => throw new NotImplementedException();
public byte[] GetFont(string faceName)
{
using (var ms = new MemoryStream())
{
using (var fs = File.Open(faceName, FileMode.Open))
{
fs.CopyTo(ms);
ms.Position = 0;
return ms.ToArray();
}
}
}
public FontResolverInfo ResolveTypeface(string familyName, bool isBold, bool isItalic)
{
if (familyName.Equals("Verdana", StringComparison.CurrentCultureIgnoreCase))
{
if (isBold && isItalic)
{
return new FontResolverInfo("Fonts/Verdana-BoldItalic.ttf");
}
else if (isBold)
{
return new FontResolverInfo("Fonts/Verdana-Bold.ttf");
}
else if (isItalic)
{
return new FontResolverInfo("Fonts/Verdana-Italic.ttf");
}
else
{
return new FontResolverInfo("Fonts/Verdana-Regular.ttf");
}
}
return null;
}
}
Then tell PDFSharp to use it:
GlobalFontSettings.FontResolver = new FileFontResolver();

How to convert const char* to KString in Kotlin/Native?

In a C++ file, I want to convert a const char* to KString, so that I can then pass the KString to a Kotlin file using Kotlin/Native.
I believe the answer lies in the function
OBJ_GETTER(utf8ToUtf16, const char* rawString, size_t rawStringLength)
that I found in KString.cpp. But even though I discovered the used define statements in Memory.h, I have not yet managed to properly call the function utf8ToUtf16 from my own C++ file to get a KString. Any help is appreciated.
It depends on how you want to interact with Kotlin code. If you produce dynamic library with -produce dynamic, then string are converted automatically, see for example https://github.com/JetBrains/kotlin-native/blob/adf8614889e8cf5038a79960aa9651ca7d45e409/samples/python_extension/src/main/c/kotlin_bridge.c#L72.
So no additional magic is required at all. Same with Objective-C strings and -produce framework. And for other cases, there shall be no need to pass strings C -> Kotlin (callbacks produced with staticCFunction also do autoconversion).
I ended up taking the pieces to write my own function:
KString getKString(const char* rawString) {
size_t rawStringLength = strlen(rawString);
ObjHeader** OBJ_RESULT;
uint32_t charCount = utf8::unchecked::distance(rawString, rawString + rawStringLength);
ArrayHeader* result = AllocArrayInstance(theStringTypeInfo, charCount, OBJ_RESULT)->array();
KChar* rawResult = CharArrayAddressOfElementAt(result, 0);
auto convertResult =
utf8::unchecked::utf8to16(rawString, rawString + rawStringLength, rawResult);
ObjHeader* obj = result->obj();
UpdateReturnRef(OBJ_RESULT, obj);
return (const ArrayHeader*)obj;
}
In my test code (C++), I use it like this:
...
RuntimeState* state = InitRuntime();
KString inMessage;
{
ObjHolder args;
inMessage = getKString("Hello from C++");
}
...
DeinitRuntime(state);
and include Memory.h, Natives.h, Runtime.h, KString.h, utf8.h, stdlib.h, and string. You may be able to get rid of some of these.
As a side remark, you may realize how AllocArrayInstance is used in the function. It would be nice, if one simply could do the same thing for getting a KString, something like:
ObjHeader** OBJ_RESULT;
KString kstr = utf8ToUtf16(rawString, rawStringLength, OBJ_RESULT);
This did not work from my function, since utf8ToUtf16 was not found. I believe the reason is, that (at the time of writing) the respective function in KString.cpp is inside a namespace {...} block, such that it cannot be used from another file. That's why I ended up mimicking the function as shown above.

Categories

Resources