Search code examples
androidgoogle-play-servicesface-detection

Why isn't the new Play-Services FaceDetector available on some devices?


Background

Google has released a few months ago a new API to detect faces on bitmaps:

It's supposed to be faster and better than the built-in FaceDetector class, and it has no restrictions/limitations compared to it (like the need that the input bitmap will be with config 565 , bitmap width that's even, and have a max faces to detect).

The code is pretty simple, too:

manifest:

<meta-data
     android:name="com.google.android.gms.vision.DEPENDENCIES"
     android:value="face" />

java:

FaceDetector faceDetector = new
       FaceDetector.Builder(getApplicationContext()).setTrackingEnabled(false)
.build();
if(!faceDetector.isOperational()){
   //show error
  return;
  }
Frame frame = new Frame.Builder().setBitmap(myBitmap).build();
SparseArray<Face> faces = faceDetector.detect(frame);

The problem

It seems that the API isn't available on some devices, returning "false" when calling "isOperational()".

  • On Nexus 4 (Android 4.4.4) and Nexus 5 (Android 6.0.1) it doesn't work at all
  • On Nexus 5x (Android 6.0.1) and Galaxy S4 (Android 5.0) it works fine
  • On LG G2 (Android 4.2.2) it worked only from the second run of the sample.

What I've found

I've found some clues:

  1. On Github (here), other people also found this issue.

  2. The sample says (in "photo-demo", inside "PhotoViewerActivity.java" file) the library might not be available, yet that if it's not, it will be downloaded :

    if (!safeDetector.isOperational()) {
        // Note: The first time that an app using face API is installed on a device, GMS will
        // download a native library to the device in order to do detection.  Usually this
        // completes before the app is run for the first time.  But if that download has not yet
        // completed, then the above call will not detect any faces.
        //
        // isOperational() can be used to check if the required native library is currently
        // available.  The detector will automatically become operational once the library
        // download completes on device.
        Log.w(TAG, "Face detector dependencies are not yet available.");
    
        // Check for low storage.  If there is low storage, the native library will not be
        // downloaded, so detection will not become operational.
        IntentFilter lowstorageFilter = new IntentFilter(Intent.ACTION_DEVICE_STORAGE_LOW);
        boolean hasLowStorage = registerReceiver(null, lowstorageFilter) != null;
    
        if (hasLowStorage) {
            Toast.makeText(this, R.string.low_storage_error, Toast.LENGTH_LONG).show();
            Log.w(TAG, getString(R.string.low_storage_error));
        }
    }
    

I tried to reset the play-services app (so that maybe the library will be forced to be re-downloaded), but it didn't seem to work (tried on Nexus 5).

The question

  1. Is there a way to force the library to be downloaded, and then start using the API? Is there a listener to this operation?

  2. Would using "isOperational" trigger this download?

  3. How come it's not available on some Nexus devices? Am I missing here something that I should have known about using this library?

  4. Is it really without limitations/restrictions on the input, as I've found? I've noticed someone reported about memory issues (here). Would using try-catch (of OutOfMemoryError) help handling OOM ?


Solution

  • About why it doesn't work on some devices, Google answered it:

    There is a known issue with the new version of GMSCore (v9) that was just released today. From the release notes:

    • A service required by Mobile Vision is now disabled due to a serious bug in that service. This will prevent users who have not already used face or barcode detection from using those features. We do not recommend adding new Mobile Vision features to your app until this issue is fixed.
    • For apps that already use Mobile Vision features, check FaceDetector.isOperational() or BarcodeDetector.isOperational() to confirm detector readiness before using the face or barcode detector.