I have been implemented this project: https://github.com/yaylas/AndroidFaceRecognizer into Android Studio. I included OpenCV using tutorial: https://www.youtube.com/watch?v=OTw_GIQNbD8 (this is static initialization). Moreover, I set in Android Studio settings proper NDK location.
Problem is that, if I add this Class:
package com.yaylas.sytech.facerecognizer;
import java.util.Vector;
import org.opencv.core.Mat;
import org.opencv.core.MatOfRect;
import android.widget.Toast;
public class DetectionBasedTracker
{
public DetectionBasedTracker(String cascadeName, int minFaceSize, boolean isFaceDetector) {
mNativeObj = nativeCreateObject(cascadeName, minFaceSize, isFaceDetector);
}
public long getNativeObj(){
return mNativeObj;
}
public void setMinFaceSize(int size) {
nativeSetFaceSize(mNativeObj, size);
}
public void detect(Mat imageGray, MatOfRect faces) {
nativeDetect(mNativeObj, imageGray.getNativeObjAddr(), faces.getNativeObjAddr());
}
public void release() {
nativeDestroyObject(mNativeObj);
mNativeObj = 0;
}
public static Vector<Mat> imageVector = new Vector<Mat>();
public static void addElement(Mat m){
imageVector.add(m);
System.out.println("--------------------------------- elementAdded: "+imageVector.size());
}
public static long getElementAt(int index){
if(index >= imageVector.size() || index < 0){
return 0;
}
System.out.println("-------------------------***** get element: "+imageVector.size()+" index: "+index);
return imageVector.elementAt(index).getNativeObjAddr();
}
public static int getImageCount(){
return imageVector.size();
}
private long mNativeObj = 0;
private static native long nativeCreateObject(String cascadeName, int minFaceSize, boolean faceDetection);
private static native void nativeDestroyObject(long thiz);
private static native void nativeStart(long thiz);
private static native void nativeStop(long thiz);
private static native void nativeSetFaceSize(long thiz, int size);
private static native void nativeDetect(long thiz, long inputImage, long faces);
}
An error is returned:
Cannot resolve corresponding JNI function
I tried everything, but the error still is there. I would like to ask, where can be a problem?
There are several reasons why the runtime might not be able to resolve the JNI function. Test these hypotheses:
The native code library didn't get bundled into your APK. Look inside the APK for it.
The native code library is in the wrong directory of the APK. Again, look and see.
The Java class got mangled by ProGuard so the names no longer match with the native library. Try turning off ProGuard. It should be off for debug builds.
If your native code library is compiled for ARM but you're running in an x86 based Android emulator (or vice versa), it won't be able to load that library.
Think of more hypotheses, then test them.
The page http://opencv.org/platforms/android.html has lots of info about OpenCV on Android, including links to tutorials.
Related
I am not sure of the terminology for what I'm looking to do, so sorry in advance!
I've found a FilePicker plugin for Xamarin.Forms (https://github.com/Studyxnet/FilePicker-Plugin-for-Xamarin-and-Windows) that implements device-specific functionality for selecting files via the CrossFilePicker class.
The way to use leverage this functionality would be something like
CrossFilePicker.Current.OpenFile("Filename.txt");
The most important part of this for me is that CrossFilePicker.Current is static and can be accessible from anywhere in the shared layer of my Xamarin.Forms app.
I need to implement a class with the same characteristics. I want to leverage device Accessibility functionality (i.e. determining if a screen reader is enabled) and I need to be able to do so with a static class.
My eventual plan is to then wrap this static class so that I can use it for unit tests too.
I don't want to import device libraries into my shared project.
TLDR: I need a static class that implements device-specific functionality.
Any help would be greatly appreciated! Thank you :)
EDIT:
Here are the files I have currently implemented in my project
IAccessibilityService Located in the shared .NET project
namespace Bitspace.Services
{
public interface IAccessibilityService
{
public bool IsScreenReaderEnabled();
public void Announcement(string message);
public void NavigationAnnouncement(string message);
}
}
DeviceAccessibility.cs Located in the shared .NET project
using System;
namespace Bitspace.Services
{
public class DeviceAccessibility
{
private static Lazy<IAccessibilityService> Implementation = new Lazy<IAccessibilityService>(() => CreateAccessibilityService(), System.Threading.LazyThreadSafetyMode.PublicationOnly);
public static IAccessibilityService Current
{
get
{
var curr = Implementation.Value;
if (curr == null)
{
throw new Exception();
}
return curr;
}
}
private static IAccessibilityService CreateAccessibilityService()
{
return new DeviceAccessibilityImplementation();
}
}
}
DeviceAccessibilityImplementation.cs Located in the Android project
using Android.Runtime;
namespace Bitspace.Services
{
[Preserve (AllMembers = true)]
public class DeviceAccessibilityImplementation : IAccessibilityService
{
public bool IsScreenReaderEnabled()
{
return true;
}
public void Announcement(string message)
{
}
public void NavigationAnnouncement(string message)
{
}
}
}
If I try to build the project, I get an error on the return new DeviceAccessibilityImplementation(); line in DeviceAccessibility.cs that says DeviceAccessibility.cs(25, 24): [CS0246] The type or namespace name 'DeviceAccessibilityImplementation' could not be found (are you missing a using directive or an assembly reference?)
However, CTRL Clicking on that line takes me to the DeviceAccessibilityImplementation.cs
I just tested out proguard to obfuscate my android app.
But decompiling the apk shows that obfuscated functions have a weird annotation on top of them that displays the real function name, the real class name AND the real file name. How is that possible? Why is this happening?
The decompiled code looks like this,
#f(c = "com.my.app.package.Classname", f = "Classname.kt", l = {49, 51}, m = "RealFunctionName")
public static final class b extends i.b0.j.a.d {
public /* synthetic */ Object s;
public int t;
public final /* synthetic */ Classname u;
public Object v;
public Object w;
public Object x;
/* JADX INFO: super call moved to the top of the method (can break code semantics) */
public b(Classname classname, i.b0.d dVar) {
super(dVar);
this.u = classname;
}
#Override // i.b0.j.a.a
public final Object l(Object obj) {
this.s = obj;
this.t |= Integer.MIN_VALUE;
return this.u.c(this);
}
}
This happens even if I remove ALL proguard rules to make it obfuscate everything without any exceptions. So where does this annotation come from? And why does it happen? Any help would be appreciated!
I have an app that run as a launcher, in Android 4 in work great but in Android 7 and 8 the select launcher dialog not appear
//
// Decompiled by Procyon v0.5.36
//
package com.r7developers.unityplugin;
import android.os.Build;
import android.annotation.TargetApi;
import android.os.Process;
import android.app.AppOpsManager;
import android.content.Intent;
import com.rvalerio.fgchecker.AppChecker;
import android.content.Context;
public class Plugin
{
static Context mContext;
static String mBundleIdentifier;
static AppChecker mAppChecker;
public static void init(final Context context, final String bundleIdentifier) {
Plugin.mContext = context;
Plugin.mBundleIdentifier = bundleIdentifier;
}
public static void start() {
Plugin.mAppChecker = new AppChecker();
Plugin.mAppChecker.other((AppChecker.Listener)new AppChecker.Listener() {
public void onForeground(final String packageName) {
if (packageName != null && !packageName.contains(Plugin.mBundleIdentifier)) {
final Intent startHomescreen = new Intent("android.intent.action.MAIN");
startHomescreen.addCategory("android.intent.category.HOME");
startHomescreen.setFlags(268435456);
Plugin.mContext.startActivity(startHomescreen);
}
}
}).timeout(1000).start(Plugin.mContext);
}
public static void stop() {
Plugin.mAppChecker.stop();
}
public static void requestUsageStatsPermission() {
if (needsUsageStatsPermission() && !hasUsageStatsPermission()) {
Plugin.mContext.startActivity(new Intent("android.settings.USAGE_ACCESS_SETTINGS"));
}
}
#TargetApi(19)
public static boolean hasUsageStatsPermission() {
final AppOpsManager appOps = (AppOpsManager)Plugin.mContext.getSystemService("appops");
final int mode = appOps.checkOpNoThrow("android:get_usage_stats", Process.myUid(), Plugin.mContext.getPackageName());
final boolean granted = mode == 0;
return granted;
}
public static boolean needsUsageStatsPermission() {
return Build.VERSION.SDK_INT >= 21;
}
public static void openSettings() {
final Intent intent = new Intent("android.settings.SETTINGS");
intent.addFlags(268435456);
Plugin.mContext.startActivity(intent);
}
}
This code is decompiled from a jar plugin from unity project
Is there anything I'm missing?
Your problem must be caused by some missing line in the manifest.
Android evolve really quickly and some application originally made for older version might not work anymore due to changing in the permission system.
That must apply to the Android Manifest as well. By luck you got it working on an older device, but it seems that handling newer ones is problematic.
Have you tried to recompile a way smaller version of the code and test it on multiple version ?
Just by looking at some exemple launcher (but made without the Unity Engine), can help you understand if you have miss something.
Here is a link to an Android Launcher I found (the first one) on GitHub: KISS/app/src/main/AndroidManifest.xml.
Try adding the line that you are missing from your, especially the intent-filter that help Android know what your apps should be aware of when showing it in menus, like the Launcher selector.
I am not an expert, but I know that working with Android can be a pain.
I was trying to check on implementation of few methods inside firebaseInstanceId class but I was routed to generated stub file instead.
public class FirebaseInstanceId {
private static java.util.Map<java.lang.String,com.google.firebase.iid.FirebaseInstanceId> zzbhH;
private static com.google.firebase.iid.zze zzclh;
private final com.google.firebase.FirebaseApp zzcli;
private final com.google.firebase.iid.zzd zzclj;
private final java.lang.String zzclk;
public static com.google.firebase.iid.FirebaseInstanceId getInstance() { /* compiled code */ }
#android.support.annotation.Keep
public static synchronized com.google.firebase.iid.FirebaseInstanceId getInstance(#android.support.annotation.NonNull com.google.firebase.FirebaseApp firebaseApp) { /* compiled code */ }
private FirebaseInstanceId(com.google.firebase.FirebaseApp firebaseApp, com.google.firebase.iid.zzd zzd) { /* compiled code */ }
java.lang.String zzabM() { /* compiled code */ }
public java.lang.String getId() { /* compiled code */ }
public long getCreationTime() { /* compiled code */ }
You need to enable Java Bytecode Decompiler from Android studio.
To enable decompiler follow below step
Press shift 2 times. the popup will appear then search for Java Bytecode Decompiler. just like below image.
Bingo now you can check stub code!!
If you have not downloaded source code for SDK tools then you can download it from SDK manager in Android studio.
I have an Android project based upon the fantastic code available at http://ikaruga2.wordpress.com/2011/08/10/video-live-wallpaper-part-4/. Essentially, this app is a live wallpaper that uses FFMpeg to read a video file frame by frame and play it out to screen using GLWallpaperService.
I downloaded the code and was able to get it running successfully on my phone. I made several changes and then tested again on several devices and all worked fine. This evening I tried to change the package name from "ffvideolivewallpaper.frankandrobot.com" to "com.nightscapecreations.orionkeysfree". I did a search and replace in the java, c, and xml files to replace them. I also modified the c file to replace "Java_ffvideolivewallpaper_frankandrobot_com_NativeCalls" with "Java_com_nightscapecreations_orionkeysfree_NativeCalls". However, when I run the app on my phone now I receive this error:
09-30 12:53:44.911: E/AndroidRuntime(24237): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:590)
09-30 12:53:44.911: E/AndroidRuntime(24237): at dalvik.system.NativeStart.main(Native Method)
09-30 12:53:44.911: E/AndroidRuntime(24237): Caused by: java.lang.UnsatisfiedLinkError: Cannot load library: link_image[1936]: 145 could not load needed library '/data/data/ffvideolivewallpaper.frankandrobot.com/lib/libavutil.so' for 'libavcore.so' (load_library[1091]: Library '/data/data/ffvideolivewallpaper.frankandrobot.com/lib/libavutil.so' not found)
09-30 12:53:44.911: E/AndroidRuntime(24237): at java.lang.Runtime.loadLibrary(Runtime.java:370)
09-30 12:53:44.911: E/AndroidRuntime(24237): at java.lang.System.loadLibrary(System.java:535)
09-30 12:53:44.911: E/AndroidRuntime(24237): at com.nightscapecreations.orionkeysfree.NativeCalls.<clinit>(NativeCalls.java:64)
09-30 12:53:44.911: E/AndroidRuntime(24237): ... 13 more
I'm assuming there's a reference to the old package name that I'm missing somewhere, but I can't find anything with Eclipse's file search. Eclipse is managing the NDK and compiling all the libraries and c code for me. So far I've tried:
Doing a clean build
Restarting Eclipse
Removing everything in the libs directory and building again
The native calls file that is erroring looks like this:
package com.nightscapecreations.orionkeysfree;
public class NativeCalls {
//ffmpeg
public static native void initVideo();
public static native void loadVideo(String fileName); //
public static native void prepareStorageFrame();
public static native void getFrame(); //
public static native void freeConversionStorage();
public static native void closeVideo();//
public static native void freeVideo();//
//opengl
public static native void initPreOpenGL(); //
public static native void initOpenGL(); //
public static native void drawFrame(); //
public static native void closeOpenGL(); //
public static native void closePostOpenGL();//
//wallpaper
public static native void updateVideoPosition();
public static native void setSpanVideo(boolean b);
//getters
public static native int getVideoHeight();
public static native int getVideoWidth();
//setters
public static native void setWallVideoDimensions(int w,int h);
public static native void setWallDimensions(int w,int h);
public static native void setScreenPadding(int w,int h);
public static native void setVideoMargins(int w,int h);
public static native void setDrawDimensions(int drawWidth,int drawHeight);
public static native void setOffsets(int x,int y);
public static native void setSteps(int xs,int ys);
public static native void setScreenDimensions(int w, int h);
public static native void setTextureDimensions(int tx,
int ty );
public static native void setOrientation(boolean b);
public static native void setPreviewMode(boolean b);
public static native void setTonality(int t);
public static native void toggleGetFrame(boolean b);
//fps
public static native void setLoopVideo(boolean b);
static {
System.loadLibrary("avcore");
System.loadLibrary("avformat");
System.loadLibrary("avcodec");
//System.loadLibrary("avdevice");
System.loadLibrary("avfilter");
System.loadLibrary("avutil");
System.loadLibrary("swscale");
System.loadLibrary("video");
}
}
How do I resolve this error? What else needs done when changing the package name? I'll need to do this many times in the future.
EDIT:
It looks like I was looking in the wrong place. The developer of the original version of the code pointed out that there is a package name passed in when compiling the ffmpeg libraries. He was nice enough to compile a new version for me with my package name and the wallpaper worked perfectly. We tried a compile without the package name, but when added to the app it just resulted in:
10-04 08:20:57.414: E/AndroidRuntime(19139): Caused by: java.lang.UnsatisfiedLinkError: Cannot load library: link_image[1936]: 145 could not load needed library 'libavutil.so' for 'libavcore.so' (load_library[1091]: Library 'libavutil.so' not found)
I'm guessing that I'll just need to compile a new version each time I make a new wallpaper. For those who are trying to do the same, I'd like to point out that the version of ffmpeg used in this project requires version 5 of the ndk; version 9 will not compile it correctly.
I've accepted an existing answer instead of adding my own as it does answer the original intent of my question, even if it didn't resolve this specific issue, and I think it could be helpful to other new developers.
If using Eclipse, the proper way to rename the package is to do the following: Right click on project -> Android Tools -> Rename Application Package.
The easiest change would be not to move the NativeCalls class to the new package. This may cause few import statements in Java files that use this class, but your C code can be kept unchanged. You can even use it without recompile.