System designTroubleshooting

Depth camera not detected on Android: check USB host permissions

Why a USB depth camera works in one Android app but shows 'connect a camera' in another, and how USB host mode, per-app permissions and target SDK cause it.

LumaSpec Vision9 min read Share on LinkedIn

On this page 10 sections
  1. 01First, find out which layer failed
  2. 02Test the USB layer before blaming the app
  3. 03Cause 1: The app never obtained USB device permission
  4. 04Cause 2: targetSdkVersion behavior changes
  5. 05Cause 3: The USB device filter does not match
  6. 06Cable, adapter and power factors
  7. 07Why the same app can fail on one phone and work on another
  8. 08Verification checklist
  9. 09Prevention
  10. 10Questions

A USB stereo or Time-of-Flight depth camera that streams happily in one Android app but shows a "connect a camera" message in another is not broken. Android gates USB device access per application, and it changes that gate's rules with every API level an app targets. This guide walks through the causes in order of likelihood, the test that isolates each one, and the fixes, so you can go from a silent app to a streaming depth image.

The same failure appears across the 3D sensors we ship, whether it is a ToF unit like the MV-DT01WMU or a structured-light stereo camera such as the MV-DLS300P-04. The camera side is rarely the culprit on Android; the app and its build settings are.

3D sensorsHikrobot MV-DT01WMU ToF sensing cameraMV-DT01WMU
Type
Depth / ToF camera
Price on requestView and quote

First, find out which layer failed

Android USB camera detection has three layers, and each has its own failure mode:

  1. USB enumeration — the phone's kernel sees the device on the bus. If this fails, nothing works.
  2. App permission — Android grants a specific app the right to open the device. If this fails, only that app is blind.
  3. Device discovery — the app scans for devices matching a filter, by vendor ID, product ID, or device class. If the filter mismatches, the app ignores a device it is allowed to open.

The classic symptom from the field — a recording demo streams depth fine while a camera app on the same phone says nothing is connected — points squarely at layers 2 and 3. Two apps built from the same library but with different targetSdkVersion values behave differently because Android applies behavior changes based on what an app targets, not what the phone runs.

Test the USB layer before blaming the app

Before touching code, confirm the phone sees the camera:

  1. Open Settings > Connected devices on the phone (the exact menu name varies by vendor).
  2. Plug the camera in through its OTG adapter. A depth camera entry should appear within a second or two.
  3. Install any USB device info app and check the camera's vendor ID and product ID appear.
  4. Gently move the cable at both connectors while watching the list. A flickering entry means a mechanical or power problem, not a software one.

If the camera never appears, skip to the cable and power section below. If it appears reliably, the phone's USB host mode is working and the problem is in the app.

Cause 1: The app never obtained USB device permission

Android requires the user to grant each app permission to a USB device, per connection. When an app calls UsbManager.requestPermission(), the system shows a dialog; until the user accepts, hasPermission() returns false and opening the device fails. An app that skips the request, or that starts before the user answers, sees no camera.

Test: run the failing app and watch for the permission dialog the instant you plug the camera in. No dialog means the app never asked — either a code path bug or a missing intent filter for the USB attached event.

Fix: in the app, request permission explicitly before enumerating, and handle the result in a BroadcastReceiver for ACTION_USB_PERMISSION_GRANTED. The grant survives only until the device is unplugged, so an app that expects a one-time permanent grant will go blind on every reconnect.

Cause 2: targetSdkVersion behavior changes

This is the most common cause when two apps from the same library behave differently on one phone. Android opts an app into API-level behavior changes according to the targetSdkVersion in its build.gradle, not the Android release installed. A wrapper library written for an older API can break when compiled with a modern target: file-descriptor access to USB endpoints, default UsbManager behavior, and background execution limits have all tightened over the years.

Test: compare the targetSdkVersion of the working app and the failing app. A recording demo and a camera app built months apart from the same SDK often target different levels.

Fix: lower the failing app's targetSdkVersion to a level the library was written against. API 27 is the level most older USB camera wrappers were validated on, and it is the value that resolves this exact one-app-works-one-does-not report. Rebuild, reinstall, and re-run.

behavior applied = f(targetSdkVersion of the app, not Android version of the phone)

That line is worth pinning on the wall: two phones on the same Android release can show opposite results because the apps, not the phones, opt into the behavior.

Cause 3: The USB device filter does not match

Apps that auto-detect cameras usually filter by vendor ID and product ID in an XML resource file. If the filter lists one camera model's IDs and you connect a different model, the app ignores a device it has permission to open.

Test: compare the IDs from your USB device info app against every entry in the app's device_filter.xml. Also check the filter is attached to the USB-attached intent filter in the manifest.

Fix: add the camera's actual vendor and product IDs to the filter, or broaden the filter to the device class during debugging. If you are evaluating several depth sensors from the 3D camera finder, a filter that matches by vendor ID across that vendor's product range saves repeated manifest edits.

Cable, adapter and power factors

When no app on the phone can see the camera, the physical layer comes first:

  • OTG adapter wiring. Charge-only or partially wired adapters pass power but no data. Test with a short, known-good OTG cable.
  • Bus power budget. Depth cameras with projectors draw well over a standard USB 2.0 port's 500 mA at peaks. A phone port that negotiates less, or a long thin cable, causes brownouts that look like intermittent detection.
  • Connector fatigue. Micro-USB and worn USB-C ports drop data lines under vibration. The routing and strain-relief checks in robot camera cable failures: routing and fatigue checks apply to handheld set-ups too.

For permanent installations, use a shielded drag-chain rated data cable; our cables range includes high-flex USB3 camera cables. If your camera accepts external power, use it during debugging to take the phone's power budget out of the equation.

Cameras3D sensors

Laser profilers and stereo 3D cameras

170 models · from $699.00

Why the same app can fail on one phone and work on another

Vendor-specific builds of Android add their own USB permission and power-management policies, so two phones on the same nominal Android release can behave differently with the same app. When a camera works on one handset and not another:

  1. Confirm both phones enumerate the camera in Settings.
  2. Confirm both run the failing app at the same targetSdkVersion.
  3. Check the failing phone's USB settings for a "charge only" default mode when devices are attached.
  4. Test with the same OTG adapter on both phones to rule out the accessory.

For USB problems on the host side that are not Android-specific — depth cameras dropping at boot, connection limits on hubs — the diagnosis in multiple USB depth cameras: startup troubleshooting and multiple USB cameras: diagnose connection limits transfers directly, since the underlying enumeration path is the same. Frame drops that appear only after detection is fixed are covered in reducing frame drops on UVC camera Android USB connections.

Verification checklist

Work through this in order; stop at the first failure and fix it before moving on:

  • Camera appears in Settings > Connected devices on the failing phone.
  • The USB device info app shows the expected vendor and product IDs.
  • The failing app shows the system USB permission dialog on connect, and the user accepts it.
  • The failing app's targetSdkVersion matches the working app's (or the library's documented level).
  • The app's device_filter.xml contains the camera's IDs and is referenced by the manifest.
  • A short known-good OTG cable is in use, with no hub in line.
  • The camera's power mode, if configurable, is set to bus power appropriate to the port.

Prevention

Pin the targetSdkVersion your USB library was validated on in every demo and production app, and document it. Always request USB permission in code rather than relying on the dialog from a manifest intent filter, and re-request after every reconnect. Keep a USB device info app on every test handset so a thirty-second layer check settles any "is it the phone or the app" argument. And keep one known-good OTG cable in the kit — it eliminates half of all field reports before they are written up.

If you are selecting the depth camera itself rather than debugging one, the depth image field of view article explains why coverage differs between models, and our 3D sensor finder filters by type, from laser profilers to ToF cameras. For anything the checklist does not resolve, contact our support team through the contact page with the failing app's targetSdkVersion and the IDs your USB info app reports.

Questions

Why does one app see my depth camera and another does not, on the same phone?

The working app already holds USB device permission or uses an access method that triggers the system permission dialog. The failing app either never requests permission for the USB device, requests it with a wrong USB device filter, or is built against a target SDK version whose behavior changes break its enumeration path. The camera itself is fine. Compare the two apps' targetSdkVersion values and their USB device filter XML files; the difference is almost always there.

What does targetSdkVersion have to do with USB camera detection?

Android changes default behavior per API level, and apps are opted in based on the version they target, not the version on the phone. A wrapper library compiled with a modern target can hit restricted file-descriptor access, tightened UsbManager behavior, or scoped-storage-adjacent changes that break device access. Lowering targetSdkVersion to a version the library was written for (27 is a common choice for older wrappers) restores the old behavior. It is a build setting in build.gradle, not a change to the camera.

Do I need to grant USB permission every time the camera is plugged in?

Yes, by default Android grants USB device permission per app per connection, and revokes it when the device is unplugged. The system shows a dialog when the app calls requestPermission(). Ticking the dialog's use-by-default box, where the vendor's build supports it, can make the grant survive reconnects for that app. If an app expects a persistent grant that never happened, it silently finds no device. Watch for the dialog the first time, and check whether the failing app is waiting on a permission result that never arrives.

How do I check whether the phone sees the camera at the USB level?

Use a USB device info app from the Play Store, or check Settings > Connected devices. If the depth camera appears in the USB device list with its vendor and product ID, enumeration and the cable are fine and the problem is in the app layer. If it appears and disappears when you wiggle the connector, or never appears at all, treat it as a cable, adapter, or power problem before touching the app.

Can the cable cause detection problems even when charging works?

Yes. Many phones need an OTG adapter, and a charge-only or partially wired adapter can pass power but not the data pairs. Long or unpowered cables also drop the voltage a depth camera needs, so it powers up partially and fails enumeration. Test with a short, known-good OTG cable, and if the camera has an external power option, use it to rule out phone-side power limits.