TextRecognizer.isOperational() API always returns false - java

This question has been asked severally and only suggestions are made. Ill comprehend every suggestion hopefully.
the dependency is defined in the manifest
<meta-data
android:name="com.google.android.gms.version"
android:value="#integer/google_play_services_version"/>
<meta-data
android:name="com.google.android.gms.vision.DEPENDENCIES"
android:value="ocr" />
and added on the app level
compile 'com.google.android.gms:play-services-vision:9.8.0'
The test device has sufficient storage which is greater than 10% of the internal and also has a very good internet connection. Permissions are also clearly defined
We start the TextRecognizer to detect text and we get our null response:
TextRecognizer textRecognizer = new TextRecognizer.Builder(getContext()).build();
if (!textRecognizer.isOperational()) {
Log.w("Main Activity", "Dependencies are not yet available");
Toast.makeText(getContext(), "Cannot Detect", Toast.LENGTH_LONG).show();
if(((MainActivity) getActivity()).hasLowStorage()) {
Toast.makeText(getContext(), "Low Storage", Toast.LENGTH_LONG).show();
Log.w("Custom_Storage", "Low Storage");
}
}
Most suggestions are to use a lower dependency compile 'com.google.android.gms:play-services:7.8+' but it doesn't work for everyone. After publishing the app, some users cant use the app.
The suggestions are not solving the problem.
Similar questions:
TextRecognizer isOperational API always returns false and
detector.isOperational() always false on android

TextRecognizer API is required to download few dependency files. Usually it is done at the time of installation but sometimes it take longer time. App will automatically download those files. Wait some time to download those files. Until download is complete TextRecognizer.isOperational will return false. After the doanlowd is completed TextRecognizer.isOperational will return true.

Even I had the same problem. I just created a new project and copied and installed dll again. Now it is working.

Related

Android Q - Delete Media (Audio) File

I've been trying to get my app to be able to delete an audio file. However, after trying many possible solutions, I couldn't really find one that works.
Here is my solution so far:
public static void deleteFiles(List<Track> tracks, Context context,
final MutableLiveData<IntentSender> deletionIntentSenderLD){
final Uri AUDIO_URI = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
for(Track t : tracks){
try {
context.getContentResolver().delete(ContentUris
.withAppendedId(AUDIO_URI, t.getUriId()), null, null);
}catch (SecurityException securityException) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
if (securityException instanceof RecoverableSecurityException) {
deletionIntentSenderLD
.postValue(((RecoverableSecurityException) securityException)
.getUserAction().getActionIntent().getIntentSender());
} else
throw securityException;
} else
throw securityException;
}
}
}
When the try block fails a SecurityException is catch then the IntentSender is passed to the live data that is observed in a fragment:
audioViewModel.getDeletionIntentSenderLD().observe(getViewLifecycleOwner(),
intentSender -> {
try {
startIntentSenderForResult(intentSender, DELETE_PERMISSION_REQUEST,
null, 0 ,0, 0,
null);
} catch (IntentSender.SendIntentException e) {
e.printStackTrace();
}
});
I've tried implementing the onRequestPermissionResult() method but that doesn't do anything. I've also tried deleting the files using File file = new File(), however, due to the changes made to Android 10, I didn't expect it to work.
So after many Google searches, I've come to the conclusion that the best approach (to my knowledge) is to simply turn off scoped storage for Android Q (10).
Here, I'll provide two solutions. The first is the one where I turn it off and the second is the one where scope storage is still enable. However, a thing you should note is that the second solution is a little buggy, at times it actually does delete both the actual media file and updates the Media Store, but most times it simply deletes from the Media Store only. Obviously, this isn't a very good solution as on reboot your application would then load those files back in because the Media Store would scan for them.
Solution 1 - Turn off Scoped Storage
For this solution you can still target Android 11. All you have to do is go to the build.gradle file at the Module Level and set the compileSdkVersion and targetSdkVersion to 30.
After that, you go into the AndroidManifest.xml and have the uses-permission and application tag set up like this:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="29"
tools:ignore="ScopedStorage"/>
<application
android:requestLegacyExternalStorage="true"
...
After having done that, you could use the Content Resolver to delete the media file (and update the Media Store) and you do not have to worry about catching a security exception like its said in the Android docs. Your implementation for Android 11s delete operation should not be affected.
Solution-ish 2 - Turn on Scoped Storage
Firstly, in your manifest ensure that the WRITE_EXTERNAL_STORAGE permissions maxSdkVersion is set to 28. Also ensure that requestLegacyExternalStorage is set to false (don't think this is required). Then simply copy the code in my original post. You do not require a Live Data if you are doing the delete operation from your activity/fragment. But you should note that startIntentSenderForResult() requires an activity.
But as I mentioned before, I did experience some bugs with this. The most frustrating thing about this solution though is that it does not delete the actual file but instead deletes the entry from the Media Store. Maybe this has something to do with the fact that #blackapps mentioned, which is that you cannot bulk delete and I might have implemented it slightly wrong. Nevertheless, this is horrible for user experience if bulk deletion is impossible in Android 10.
The tutorials I followed for this are:
https://developer.android.com/training/data-storage/shared/media#remove-item
https://www.raywenderlich.com/9577211-scoped-storage-in-android-10-getting-started#toc-anchor-007
https://www.solutionanalysts.com/blog/scoped-storage-in-android-10/
Side Note - Delete on Android 11
To delete on Android 11 you just need to call createDeleteRequest() which should return a PendingIntent. From this PendingIntent you could get the IntentSender by using getIntentSender. Pass this intent sender to the activity/fragment then call startIntentSenderForResult() in your activity/fragment. This pops up a dialog to the user asking them if the application can delete a file. If the user gives permission the system goes ahead and deletes the file and updates the Media Store.
Side Side Note - Scoped Storage, Android 10 and Future
From everything I've seen, it seems to suggest that scoped storage is only enforced in Android 11 but I'm not entirely sure if the legacy option would still be available in Android 10 indefinitely. But I would have to do more research on this...

W/System: A resource failed to call release

When using the console of AndroidStudio on my app it shows:
W/System: A resource failed to call release.
Sometimes it is said multiple times. I know what it means but I've checked the almost 2k lines of code multiple times but I'm clueless what I'm missing to close/release.
Is there any way to expand on this information from the console? or how would you do to target what the resource is or when it fails to close? Any ideas are welcome. Thanks.
The answer from #guest works, but you can achieve the exact same thing without resorting to reflection using Strict Mode. Specifically, something like:
StrictMode.setVmPolicy(new VmPolicy.Builder()
.detectLeakedClosableObjects()
.penaltyLog()
.build());
In general, strict mode can do much more for you though (see link above to doc), and all you need to do for a default setup is:
StrictMode.enableDefaults(); # <-- This includes warning on leaked closeables
To enable strict mode "as soon as possible" you can add either of the above code options to the constructor of your application class, e.g.:
public class MyApp extends Application {
public MyApp() {
if(BuildConfig.DEBUG)
StrictMode.enableDefaults();
}
}
Note that in addition to just creating the class above, you need to tell Android that you have created a custom application class in the AndroidManifest.xml (so that an instance of it gets created when your application process starts, instead of Android creating the default Application class). You need to add/modify the android:name attribute of the <application> tag to point to the fully resolved package path of your custom application class (MyApp in this case):
<application
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:name="com.example.app.MyApp" <-- IMPORTANT PART: ADAPT FOR YOUR ACTUAL PROJECT
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
This message comes from dalvik.system.CloseGuard. When debugging, you can set it up to create stack traces as you create resources, so that you can track down what objects aren't being closed.
It's not part of the framework API, so I'm using reflection to turn that on:
try {
Class.forName("dalvik.system.CloseGuard")
.getMethod("setEnabled", boolean.class)
.invoke(null, true);
} catch (ReflectiveOperationException e) {
throw new RuntimeException(e);
}
more info: https://wh0.github.io/2020/08/12/closeguard.html
I don't think that you can get any more information out of Logcat.
The memory view of the Android Profiler is probably a good place to start. Looking at it while using your app should give you an idea of what actions cause memory to be allocated and not released.
You can also select sections from the timeline and drill down to specific allocations by
class.
Alternatively LeakCanary is a great library to detect memory leaks.
Fixed it by removing a function call that called itself through another function thereby making an infinite loop of calls to itself
Late answer, but it may be useful to someone else:
I faced the same error, but I forgot I had my VPN running in the background. Disconnecting the VPN did the trick for me.
This is to say it may be due to resources unrelated to your app or IDE you may want to check, like an antivirus, VPN, etc.

detector.isOperational() always false on android

I'm using the new google plays service: Barcode detector, for this porposue I'm following this tutorial : https://search-codelabs.appspot.com/codelabs/bar-codes
But when I run the application on my real device(Asus Nexus 7), the text view of the app always is showing me "Couldn't set up the detector" and i don't know how to make it work >< ...
Here some code for fast debugging:
public class DecoderBar extends Activity implements View.OnClickListener{
private TextView txt;
private ImageView img;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout_decoder);
Button b = (Button) findViewById(R.id.button);
txt = (TextView) findViewById(R.id.txtContent);
img = (ImageView) findViewById(R.id.imgview);
b.setOnClickListener(this);
}
// [...]
#Override
public void onClick(View v) {
Bitmap myBitmap = BitmapFactory.decodeResource(getApplicationContext().getResources(),R.drawable.popi);
img.setImageBitmap(myBitmap);
BarcodeDetector detector = new BarcodeDetector.Builder(getApplicationContext())
.setBarcodeFormats(Barcode.DATA_MATRIX | Barcode.QR_CODE)
.build();
if(!detector.isOperational()){
// Always show this message, so, never is operational!
txt.setText("Could not set up the detector!");
return;
}
Frame frame = new Frame.Builder().setBitmap(myBitmap).build();
SparseArray<Barcode> barcodes = detector.detect(frame);
Barcode thisCode = barcodes.valueAt(0);
txt.setText(thisCode.rawValue);
}
}
It looks like the first time barcode detector is used on each device, some download is done by Google Play Services. Here is the link:
https://developers.google.com/vision/multi-tracker-tutorial
And this is the excerpt:
The first time that an app using barcode and/or face APIs is installed
on a device, GMS will download a libraries to the device in order to
do barcode and face detection. Usually this is done by the installer
before the app is run for the first time.
I had this problem now. You can't update the Google Play Services. After I used the same as on the tutorial it works.
compile 'com.google.android.gms:play-services:7.8+'
Here is what was my case.
I was using BarcodeDetector for decoding QR codes from imported images. On 4 my testing devices it was working fine. On one was not reading anything from bitmap. I thought this might be incompatibility with android 5.0 but this was not the case. After hours of investigation I finally noticed that detector.isOperational(); returns false. The reason was:
The first time that an app using barcode and/or face APIs is installed on a device, GMS will download a libraries to the device in order to do barcode and face detection. Usually this is done by the installer before the app is run for the first time.
I had wi-fi off on that testing device. After turning it on and relaunching app, detector became operational and started decoding bitmaps.
To use the API, it's necessary to have internet connection, I had connection to my ADSL but not resolved DNS. Fixing that problem make my app works
Sometimes detector dependencies are downloaded when the app runs for the first time and not when the app installs. I too faced the same issue, the problem is either your network connection is weak or you don't have enough storage for download say 10% of the total space though it does not take that much space but downloads from Google Play Services does require good amount of storage and don't forget to clear cache(Simple check try to update any application from playstore). Refer this Github thread for more information.
Check your storage! make sure it is over 10%
That fixed my problem, and I answered it here too...
https://stackoverflow.com/a/43229272/6914806
you must not forget this:
add this to your AndroidManifest.xml
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<meta-data
android:name="com.google.android.gms.version"
android:value="#integer/google_play_services_version" />
<meta-data
android:name="com.google.android.gms.vision.DEPENDENCIES"
android:value="ocr"/>

Reliable way of detecting whether an Android app is running in 'BlueStacks'

I would like to ascertain at run-time inside an Android app whether it is running within the BlueStacks Android emulator. This is so I can modify the way the app runs when running inside BlueStacks.
BlueStacks does not support multi-touch so I want to implement an alternative to the standard pinch-to-zoom functionality my current app has.
E.g.
If (appIsRunningInBlueStacks){
mySurfaceView.enableMultiTouchAlternatives();
} else{
mySurfaceView.enableMultiTouchFeatures();
}
What is a reliable way of ascertaining the value of appIsRunningInBlueStacks?
EDIT Summary of answers to comments on question:
Ben, Taras, thanks for the suggestions. The Build.MODEL etc. values for BlueStacks are:
Model: "GT-I9100"
Manufacturer: "samsung"
Device: "GT-I9100"
Product: "GT-I9100"
This is the same model number as the Samsung Galaxy SII so it would not be ideal to use this for fear of treating all users with SIIs the same as those on BlueStacks.
CommonsWare, the app continues to run in BlueStacks even with the < uses-feature> for multitouch in the manifest. In fact (also answering iagreen's question)...
packageManager.hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN_MULTITOUCH_DISTINCT);
... returns true! This is to be expected I suppose as the emulator is convinced it is a Samsung Galaxy SII!
Therefore we are still without a way of reliably detecting whether an app is running on BlueStacks without also throwing all Samsung Galaxy SII users in the same bucket. Any other ideas?
All the above methods are not working on BlueStacks 5. The correct way to do is checking if the path of /mnt/windows/BstSharedFolder exists. It is working fine on both BlueStacks 4 and 5.
fun checkFilesExist(files: Array<String>): Boolean {
files.forEach {
val file = File(it)
if (file.exists()) {
return true
}
}
return false
}
fun isBlueStacks(): Boolean {
val BLUE_STACKS_FILES = arrayOf(
"/mnt/windows/BstSharedFolder"
)
return checkFilesExist(BLUE_STACKS_FILES)
}
You can check that the Bluestacks shared folder exist
/sdcard/windows/BstSharedFolder
Boolean onBlueStacks()
{
File sharedFolder = new File(Environment
.getExternalStorageDirectory().toString()
+ File.separatorChar
+ "windows"
+ File.separatorChar
+ "BstSharedFolder");
if (sharedFolder.exists())
{
return true;
}
return false;
}
After trying all the suggested solutions available online we found the Google's SafetyNet Attestation API is the only solution for detecting VMs like BlueStack(any version) and NoxPlayer.
Apps that care about content piracy (and other security issues) can filter their availability on the Google Play like Netflix filters devices on the PlayStore.
The new “device catalog” section of the console includes an option
called “SafetyNet exclusion,” which can be used to prevent “devices
that fail integrity tests or those that are uncertified by Google,”
from downloading a specific app: among these would be rooted devices
and those running custom ROMs.
But there is a catch user will still find the APK from cross-sharing or other distribution systems, so the client must implement SafetyNet Attestation API on the app level.
How does it work?
SafetyNet examines software and hardware information on the device
where your app is installed to create a profile of that device. The
service then attempts to find this same profile within a list of
device models that have passed Android compatibility testing. The API
also uses this software and hardware information to help you assess
the basic integrity of the device, as well as the APK information of
the calling app. This attestation helps you to determine whether or
not the particular device has been tampered with or otherwise
modified.
It's an (easy to implement) paid API from the Google which allows 10,000 free hits per day as of now :\
If anyone is interested in detecting VMs by them self, these are the good papers available suggesting heuristic approaches :
Evading Android Runtime Analysis via Sandbox Detection
Rage Against the Virtual Machine:
Hindering Dynamic Analysis of Android Malware
My version of BlueStacks is reporting my Build.Model as GT-N7100.
Using: android.opengl.GLES20.glGetString(android.opengl.GLES20.GL_RENDERER) I get Bluestacks.
It maybe too late but for the sake of others who have the same problem :
public boolean isRunningOnEmulator() {
return Build.FINGERPRINT.startsWith("generic")
|| Build.FINGERPRINT.startsWith("unknown")
|| Build.MODEL.contains("google_sdk")
|| Build.MODEL.contains("Emulator")
|| Build.MODEL.contains("Android SDK built for x86")
|| Build.MANUFACTURER.contains("Genymotion")
|| (Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic"))
|| "google_sdk".equals(Build.PRODUCT)
|| Build.PRODUCT.contains("vbox86p")
|| Build.DEVICE.contains("vbox86p")
|| Build.HARDWARE.contains("vbox86");
}
Based on Mr. Regis' answer, you can detect it when the shared folder is present. However in Bluestacks 4, using file.exists() will only return false. This is because the shared folder has no permissions (000 or ----------). But listing files in the directory will detect the folder.
String path = Environment.getExternalStorageDirectory().toString();
Log.d("FILES", "Path: " + path);
File directory = new File(path);
File[] files = directory.listFiles();
for (File file : files) {
if (file.getName().contains("windows")) {
Log.d("FILES", "windows file exists, it's a bluestacks emu");
}
}
This Will be unique.
There is no bluetooth device in Bluestack.
So try to get The Bluetooth Address string which is always 'null' on Bluestack or Any emulator.Make sure you are adding Bluetooth permission on your project manifest.
BluetoothAdapter m_BluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
String m_bluetoothAdd = m_BluetoothAdapter.getAddress();

Why do I get "Unable to start service Intent"?

I'm trying get some licensing code from AndroidPit.com working, but I get "Unable to start service Intent". Basically my code looks like this:
Intent licenseIntent = new Intent("de.androidpit.app.services.ILicenseService");
if (mContext.bindService(licenseIntent, this, Context.BIND_AUTO_CREATE))
{
// success
}
else
{
// failure (I get this all the time(
}
I tried passing ILicenseService class explicitly:
Intent licenseIntent = new Intent(mContext, de.androidpit.app.services.ILicenseService.class);
but I still get the same problem.
I managed to get Android Market LVL library working which uses identical code, so I don't really understand why it fails to find "de.androidpit.app.services.ILicenseService", but manages to find "com.android.vending.licensing.ILicensingService".
Most of the answers I found here say that you need to append stuff to your AndroidManifest.xml, but you don't anything for "com.android.vending.licensing.ILicensingService" to work, so I guess I shouldn't need anything "de.androidpit.app.services.ILicenseService" (they both derive from android.os.IInterface).
Thanks in advance.
Most of the answers I found here say that you need to append stuff to your AndroidManifest.xml
Those answers are correct.
but you don't anything for "com.android.vending.licensing.ILicensingService" to work
That is because com.android.vending.licensing.ILicensingService is a remote service, one that is not in your project, but rather in the firmware of the device.
so I guess I shouldn't need anything "de.androidpit.app.services.ILicenseService" (they both derive from android.os.IInterface).
That is flawed reasoning. By your argument, java.util.HashMap does not go in the manifest, and both java.util.HashMap and any implementation of Activity all derive from Object, so therefore you do not need to put your activities in the manifest. If you try this, you will quickly discover that your activities no longer work.
If it is a component (activity, service, content provider, or some implementations of BroadcastReceiver), and the implementation of the component is in your project (directly, via a JAR, via a library project, etc.), you must have an entry in the manifest for it.
Wherever you got the service from should provide you with instructions for adding the service to your manifest, and they should also supply you with instructions for creating the Intent used to bind to it. If they do not provide this documentation, perhaps you should reconsider your use of this product.
The solution in my case was to start a server part on my phone (AppCenter from AndroidPit.com in this case). No entries in AndroidManifest are necessary for the client application.

Categories

Resources