Android - hasSystemFeature()、サポートされているFeature確認

AndroidはSystem Featureということを定義して、このデバイスがどのような機能をサポートしているAppが分かるようにします。

たとえば、Androidデバイスがカメラをサポートしていない可能性があります。 SmartPhoneはほとんどのカメラをサポートしますがWatchはサポートしていない可能性があるからです。 いくつかのカメラアプリがWatchにインストールされたとき、カメラ関連のコードを実行すると、Exceptionが発生し、アプリが死ぬことができます。 このような時System Featureを確認して、カメラをサポートすることを確認することができます。

サンプルコードは、kotlinで作成されました。

PackageManager.hasSystemFeature()

hasSystemFeature(String featureName)は引数として渡されたFeatureが定義されているかどうかの結果をbooleanとして返します。

public abstract boolean hasSystemFeature(@NonNull String featureName);

次のようにデバイスにカメラFeatureが定義されているかどうかを確認することができます。

if (packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
    Log.d("Test", "Camera is available in this device")
}

次のように trueを返した場合、このデバイスは、カメラFeatureが定義されていて、実際にカメラがデバイスにサポートされることを意味します。

11-15 11:13:04.280  5002  5002 D Test    : Camera is available in this device

FEATURE_WATCHはSmartPhoneに定義されておらず、Watch deviceのみ定義されています。したがって、このFeatureでこのデバイスがWatchのかSmartPhoneのか区別することができます。

if (packageManager.hasSystemFeature(PackageManager.FEATURE_WATCH)) {
    Log.d("Test", "It's a watch device")
}

Feature 種類

Androidで定義したFeatureは、Frameworkのコードである PackageManager.javaに定義されています。

定義された内容は、Android developer - PackageManagerで確認することができます。

上記サイトから、このように見えるコードで PackageManager.FEATURE_LOCATION_NETWORKのように使用することができます。

public static final String FEATURE_LOCATION_NETWORK
Constant Value: "android.hardware.location.network"

PackageManager.getSystemAvailableFeatures()

getSystemAvailableFeatures()は現在のデバイスに定義されたすべてのFeatureを FeatureInfo[]配列で返します。

public abstract FeatureInfo[] getSystemAvailableFeatures();

次のようにすべてのFeatureの名前とバージョン情報を出力することができます。

val featureInfoArray = packageManager.systemAvailableFeatures
for (feature: FeatureInfo in featureInfoArray) {
    Log.d("Test", "name: ${feature.name}, version: ${feature.version}")
}

結果は次のとおりです。内容を見れば、デバイスがTouchscreenをサポートしている地図Featureとして定義されています。

11-15 11:13:04.281  5002  5002 D Test    : name: android.software.adoptable_storage, version: 0
11-15 11:13:04.281  5002  5002 D Test    : name: android.hardware.sensor.accelerometer, version: 0
11-15 11:13:04.281  5002  5002 D Test    : name: android.hardware.faketouch, version: 0
11-15 11:13:04.281  5002  5002 D Test    : name: android.software.backup, version: 0
11-15 11:13:04.282  5002  5002 D Test    : name: android.hardware.touchscreen, version: 0
11-15 11:13:04.282  5002  5002 D Test    : name: android.hardware.touchscreen.multitouch, version: 0
....
11-15 11:13:04.283  5002  5002 D Test    : name: android.hardware.location, version: 0
11-15 11:13:04.283  5002  5002 D Test    : name: android.hardware.vulkan.level, version: 1
11-15 11:13:04.283  5002  5002 D Test    : name: android.software.secure_lock_screen, version: 0
11-15 11:13:04.283  5002  5002 D Test    : name: android.hardware.telephony, version: 0
11-15 11:13:04.283  5002  5002 D Test    : name: android.software.file_based_encryption, version: 0

このメソッドは、API 24以上で提供しています。

hasSystemFeature(String featureName, int version)

hasSystemFeature(featureName)と違って、version情報も引数として渡されます。 Featureを登録する際にversionも設定できます。 いくつかのバージョン以上のFeatureが登録されているかどうか確認するときに、このメソッドを使用することができます。

/**
 * Check whether the given feature name and version is one of the available
 * features as returned by {@link #getSystemAvailableFeatures()}. Since
 * features are defined to always be backwards compatible, this returns true
 * if the available feature version is greater than or equal to the
 * requested version.
 *
 * @return Returns true if the devices supports the feature, else false.
 */
public abstract boolean hasSystemFeature(@NonNull String featureName, int version);

例えば、上記の FEATURE_VULKAN_HARDWARE_LEVELはversionが1に設定されていることを確認しました。 もしversion 2をサポートしているデバイスがあり、バージョンごとに異なるAPIを呼び出す必要がある場合にこのメソッドを使用して区別することができます。

11-15 11:13:04.283  5002  5002 D Test    : name: android.hardware.vulkan.level, version: 1

次のようにバージョンに応じて、他の動作をするようにすることができます。

if (packageManager.hasSystemFeature(PackageManager.FEATURE_VULKAN_HARDWARE_LEVEL, 1)) {
    Log.d("Test", "FEATURE_VULKAN_HARDWARE_LEVEL >= 1")
}

if (packageManager.hasSystemFeature(PackageManager.FEATURE_VULKAN_HARDWARE_LEVEL, 2)) {
    Log.d("Test", "Has FEATURE_VULKAN_HARDWARE_LEVEL >= 2")
}

実行してみると、このデバイスは、version 1をサポートするため、以下のように出力されます。

11-15 11:34:32.375  5606  5606 D Test    : FEATURE_VULKAN_HARDWARE_LEVEL >= 1

このメソッドは、API 24以上で提供しています。

adbシェルでフィーチャーを確認する

adb shell pm has-feature [feature name]でどんなフィーチャーがデバイスに定義されているかどうかを確認することができます。 FeatureのStringを入力する必要があります。

$ adb shell pm has-feature android.hardware.vulkan.level
true

$ adb shell pm has-feature android.hardware.location
true

デバイスに定義されたすべてのFeatureを確認したい場合は、 adb shell pm list featuresコマンドを使用してください。

$ adb shell pm list features

feature:reqGlEsVersion=0x20000
feature:android.hardware.audio.output
feature:android.hardware.bluetooth
feature:android.hardware.bluetooth_le
feature:android.hardware.camera
feature:android.hardware.camera.any
feature:android.hardware.camera.ar
feature:android.hardware.camera.autofocus
feature:android.hardware.camera.capability.manual_post_processing
feature:android.hardware.camera.capability.manual_sensor
feature:android.hardware.camera.capability.raw
feature:android.hardware.camera.concurrent
feature:android.hardware.camera.flash
feature:android.hardware.camera.front
feature:android.hardware.camera.level.full
feature:android.hardware.faketouch
feature:android.hardware.fingerprint
feature:android.hardware.location
feature:android.hardware.vulkan.level=1
....

バージョンが0であれば、バージョン情報は省略され、0を超えると、以下のように feature_name=1のようにバージョンが表示されます。

feature:android.hardware.vulkan.level=1
codechachaCopyright ©2019 codechacha