diff --git a/mace/examples/android/.gitignore b/mace/examples/android/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..39fb081a42a86ccf8f9cf99dbccc8bdf7c828bce
--- /dev/null
+++ b/mace/examples/android/.gitignore
@@ -0,0 +1,9 @@
+*.iml
+.gradle
+/local.properties
+/.idea/workspace.xml
+/.idea/libraries
+.DS_Store
+/build
+/captures
+.externalNativeBuild
diff --git a/mace/examples/android/README_zh.md b/mace/examples/android/README_zh.md
new file mode 100644
index 0000000000000000000000000000000000000000..eedbc7aa3108604cae69c3074c7293ad7ec16380
--- /dev/null
+++ b/mace/examples/android/README_zh.md
@@ -0,0 +1,15 @@
+# mace demo使用方法
+
+* 使用前需要生成静态库和头文件,具体参考[文档](docs)
+ * 把mace/public目录下的mace.h和mace_runtime.h拷贝到macelibrary/src/main/cpp/include下面
+ * 把生成的mace/codegen/engine/mace_engine_factory.h拷贝到macelibrary/src/main/cpp/include下面
+ * 静态库的路径是在mace/build/demo_app_models/lib/下
+* 使用android studio 导入项目,然后运行install run
+* 还可以使用gradle命令(需要安装gradle)生成apk 具体命令例如:./gradlew assemble(或者Release|Debug)
+
+## 交流与反馈
+* 欢迎通过Github Issues提交问题报告与建议
+* QQ群: 756046893
+
+## License
+[Apache License 2.0](LICENSE).
diff --git a/mace/examples/android/app/.gitignore b/mace/examples/android/app/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..796b96d1c402326528b4ba3c12ee9d92d0e212e9
--- /dev/null
+++ b/mace/examples/android/app/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/mace/examples/android/app/build.gradle b/mace/examples/android/app/build.gradle
new file mode 100644
index 0000000000000000000000000000000000000000..b9101ae015408ba68c81700254a728c98f1f5ced
--- /dev/null
+++ b/mace/examples/android/app/build.gradle
@@ -0,0 +1,76 @@
+apply plugin: 'com.android.application'
+
+android {
+ compileSdkVersion 26
+ defaultConfig {
+ applicationId "com.xiaomi.mace.demo"
+ minSdkVersion 23
+ targetSdkVersion 26
+ versionCode 1
+ versionName "1.0"
+ }
+
+ signingConfigs {
+ release {
+ storeFile file("mace_demo.jks")
+ keyAlias "keyAlias"
+ keyPassword "maceAndroid"
+ storePassword "maceAndroid"
+ }
+ debug {
+ storeFile file("mace_demo.jks")
+ keyAlias "keyAlias"
+ keyPassword "maceAndroid"
+ storePassword "maceAndroid"
+ }
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ signingConfig signingConfigs.release
+ }
+ }
+
+ flavorDimensions "mace"
+ productFlavors {
+ app {
+ dimension "mace"
+ }
+ }
+
+ sourceSets {
+ main {
+ jniLibs.srcDirs = ["libs"]
+ jni.srcDirs = ['src/main/jni', 'src/main/jni/']
+ }
+ }
+
+ applicationVariants.all { variant ->
+ if (variant.buildType.name != "release") {
+ return
+ }
+ def outputFolder = file("build/output/apk")
+
+ variant.outputs.all {output ->
+ def name = output.outputFile.name
+ def newName = "Mace_" + new Date().format("yyyyMMdd_HHmm") + "_" + defaultConfig.versionName + "_" + variant.flavorName + ".apk"
+ copy {
+ from output.outputFile.parent
+ into outputFolder
+ include name
+ rename(name, newName)
+ }
+ }
+ }
+
+}
+
+dependencies {
+ implementation fileTree(include: ['*.jar'], dir: 'libs')
+ implementation 'com.android.support:appcompat-v7:26.1.0'
+ implementation 'com.android.support.constraint:constraint-layout:1.1.0'
+ implementation project(':macelibrary')
+ implementation 'org.greenrobot:eventbus:3.1.1'
+}
diff --git a/mace/examples/android/app/mace_demo.jks b/mace/examples/android/app/mace_demo.jks
new file mode 100644
index 0000000000000000000000000000000000000000..a661209e040fad686ff74b38790db38de588eaf5
Binary files /dev/null and b/mace/examples/android/app/mace_demo.jks differ
diff --git a/mace/examples/android/app/src/main/AndroidManifest.xml b/mace/examples/android/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000000000000000000000000000000000000..e289b8122a26fc6e3b5bada3530d62ca653af647
--- /dev/null
+++ b/mace/examples/android/app/src/main/AndroidManifest.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mace/examples/android/app/src/main/assets/BUILD b/mace/examples/android/app/src/main/assets/BUILD
new file mode 100644
index 0000000000000000000000000000000000000000..c827de7be1807679c423ff5e9251ed1f9b9cce9d
--- /dev/null
+++ b/mace/examples/android/app/src/main/assets/BUILD
@@ -0,0 +1,15 @@
+package(default_visibility = ["//visibility:public"])
+
+licenses(["notice"]) # Apache 2.0
+
+# It is necessary to use this filegroup rather than globbing the files in this
+# folder directly the examples/android:tensorflow_demo target due to the fact
+# that assets_dir is necessarily set to "" there (to allow using other
+# arbitrary targets as assets).
+filegroup(
+ name = "asset_files",
+ srcs = glob(
+ ["**/*"],
+ exclude = ["BUILD"],
+ ),
+)
diff --git a/mace/examples/android/app/src/main/assets/cacheLabel.txt b/mace/examples/android/app/src/main/assets/cacheLabel.txt
new file mode 100644
index 0000000000000000000000000000000000000000..b52daf9a9db2a494e3e48e408f01b18e490bec24
--- /dev/null
+++ b/mace/examples/android/app/src/main/assets/cacheLabel.txt
@@ -0,0 +1,1001 @@
+background
+tench
+goldfish
+great white shark
+tiger shark
+hammerhead
+electric ray
+stingray
+cock
+hen
+ostrich
+brambling
+goldfinch
+house finch
+junco
+indigo bunting
+robin
+bulbul
+jay
+magpie
+chickadee
+water ouzel
+kite
+bald eagle
+vulture
+great grey owl
+European fire salamander
+common newt
+eft
+spotted salamander
+axolotl
+bullfrog
+tree frog
+tailed frog
+loggerhead
+leatherback turtle
+mud turtle
+terrapin
+box turtle
+banded gecko
+common iguana
+American chameleon
+whiptail
+agama
+frilled lizard
+alligator lizard
+Gila monster
+green lizard
+African chameleon
+Komodo dragon
+African crocodile
+American alligator
+triceratops
+thunder snake
+ringneck snake
+hognose snake
+green snake
+king snake
+garter snake
+water snake
+vine snake
+night snake
+boa constrictor
+rock python
+Indian cobra
+green mamba
+sea snake
+horned viper
+diamondback
+sidewinder
+trilobite
+harvestman
+scorpion
+black and gold garden spider
+barn spider
+garden spider
+black widow
+tarantula
+wolf spider
+tick
+centipede
+black grouse
+ptarmigan
+ruffed grouse
+prairie chicken
+peacock
+quail
+partridge
+African grey
+macaw
+sulphur-crested cockatoo
+lorikeet
+coucal
+bee eater
+hornbill
+hummingbird
+jacamar
+toucan
+drake
+red-breasted merganser
+goose
+black swan
+tusker
+echidna
+platypus
+wallaby
+koala
+wombat
+jellyfish
+sea anemone
+brain coral
+flatworm
+nematode
+conch
+snail
+slug
+sea slug
+chiton
+chambered nautilus
+Dungeness crab
+rock crab
+fiddler crab
+king crab
+American lobster
+spiny lobster
+crayfish
+hermit crab
+isopod
+white stork
+black stork
+spoonbill
+flamingo
+little blue heron
+American egret
+bittern
+crane
+limpkin
+European gallinule
+American coot
+bustard
+ruddy turnstone
+red-backed sandpiper
+redshank
+dowitcher
+oystercatcher
+pelican
+king penguin
+albatross
+grey whale
+killer whale
+dugong
+sea lion
+Chihuahua
+Japanese spaniel
+Maltese dog
+Pekinese
+Shih-Tzu
+Blenheim spaniel
+papillon
+toy terrier
+Rhodesian ridgeback
+Afghan hound
+basset
+beagle
+bloodhound
+bluetick
+black-and-tan coonhound
+Walker hound
+English foxhound
+redbone
+borzoi
+Irish wolfhound
+Italian greyhound
+whippet
+Ibizan hound
+Norwegian elkhound
+otterhound
+Saluki
+Scottish deerhound
+Weimaraner
+Staffordshire bullterrier
+American Staffordshire terrier
+Bedlington terrier
+Border terrier
+Kerry blue terrier
+Irish terrier
+Norfolk terrier
+Norwich terrier
+Yorkshire terrier
+wire-haired fox terrier
+Lakeland terrier
+Sealyham terrier
+Airedale
+cairn
+Australian terrier
+Dandie Dinmont
+Boston bull
+miniature schnauzer
+giant schnauzer
+standard schnauzer
+Scotch terrier
+Tibetan terrier
+silky terrier
+soft-coated wheaten terrier
+West Highland white terrier
+Lhasa
+flat-coated retriever
+curly-coated retriever
+golden retriever
+Labrador retriever
+Chesapeake Bay retriever
+German short-haired pointer
+vizsla
+English setter
+Irish setter
+Gordon setter
+Brittany spaniel
+clumber
+English springer
+Welsh springer spaniel
+cocker spaniel
+Sussex spaniel
+Irish water spaniel
+kuvasz
+schipperke
+groenendael
+malinois
+briard
+kelpie
+komondor
+Old English sheepdog
+Shetland sheepdog
+collie
+Border collie
+Bouvier des Flandres
+Rottweiler
+German shepherd
+Doberman
+miniature pinscher
+Greater Swiss Mountain dog
+Bernese mountain dog
+Appenzeller
+EntleBucher
+boxer
+bull mastiff
+Tibetan mastiff
+French bulldog
+Great Dane
+Saint Bernard
+Eskimo dog
+malamute
+Siberian husky
+dalmatian
+affenpinscher
+basenji
+pug
+Leonberg
+Newfoundland
+Great Pyrenees
+Samoyed
+Pomeranian
+chow
+keeshond
+Brabancon griffon
+Pembroke
+Cardigan
+toy poodle
+miniature poodle
+standard poodle
+Mexican hairless
+timber wolf
+white wolf
+red wolf
+coyote
+dingo
+dhole
+African hunting dog
+hyena
+red fox
+kit fox
+Arctic fox
+grey fox
+tabby
+tiger cat
+Persian cat
+Siamese cat
+Egyptian cat
+cougar
+lynx
+leopard
+snow leopard
+jaguar
+lion
+tiger
+cheetah
+brown bear
+American black bear
+ice bear
+sloth bear
+mongoose
+meerkat
+tiger beetle
+ladybug
+ground beetle
+long-horned beetle
+leaf beetle
+dung beetle
+rhinoceros beetle
+weevil
+fly
+bee
+ant
+grasshopper
+cricket
+walking stick
+cockroach
+mantis
+cicada
+leafhopper
+lacewing
+dragonfly
+damselfly
+admiral
+ringlet
+monarch
+cabbage butterfly
+sulphur butterfly
+lycaenid
+starfish
+sea urchin
+sea cucumber
+wood rabbit
+hare
+Angora
+hamster
+porcupine
+fox squirrel
+marmot
+beaver
+guinea pig
+sorrel
+zebra
+hog
+wild boar
+warthog
+hippopotamus
+ox
+water buffalo
+bison
+ram
+bighorn
+ibex
+hartebeest
+impala
+gazelle
+Arabian camel
+llama
+weasel
+mink
+polecat
+black-footed ferret
+otter
+skunk
+badger
+armadillo
+three-toed sloth
+orangutan
+gorilla
+chimpanzee
+gibbon
+siamang
+guenon
+patas
+baboon
+macaque
+langur
+colobus
+proboscis monkey
+marmoset
+capuchin
+howler monkey
+titi
+spider monkey
+squirrel monkey
+Madagascar cat
+indri
+Indian elephant
+African elephant
+lesser panda
+giant panda
+barracouta
+eel
+coho
+rock beauty
+anemone fish
+sturgeon
+gar
+lionfish
+puffer
+abacus
+abaya
+academic gown
+accordion
+acoustic guitar
+aircraft carrier
+airliner
+airship
+altar
+ambulance
+amphibian
+analog clock
+apiary
+apron
+ashcan
+assault rifle
+backpack
+bakery
+balance beam
+balloon
+ballpoint
+Band Aid
+banjo
+bannister
+barbell
+barber chair
+barbershop
+barn
+barometer
+barrel
+barrow
+baseball
+basketball
+bassinet
+bassoon
+bathing cap
+bath towel
+bathtub
+beach wagon
+beacon
+beaker
+bearskin
+beer bottle
+beer glass
+bell cote
+bib
+bicycle-built-for-two
+bikini
+binder
+binoculars
+birdhouse
+boathouse
+bobsled
+bolo tie
+bonnet
+bookcase
+bookshop
+bottlecap
+bow
+bow tie
+brass
+brassiere
+breakwater
+breastplate
+broom
+bucket
+buckle
+bulletproof vest
+bullet train
+butcher shop
+cab
+caldron
+candle
+cannon
+canoe
+can opener
+cardigan
+car mirror
+carousel
+carpenter's kit
+carton
+car wheel
+cash machine
+cassette
+cassette player
+castle
+catamaran
+CD player
+cello
+cellular telephone
+chain
+chainlink fence
+chain mail
+chain saw
+chest
+chiffonier
+chime
+china cabinet
+Christmas stocking
+church
+cinema
+cleaver
+cliff dwelling
+cloak
+clog
+cocktail shaker
+coffee mug
+coffeepot
+coil
+combination lock
+computer keyboard
+confectionery
+container ship
+convertible
+corkscrew
+cornet
+cowboy boot
+cowboy hat
+cradle
+crane
+crash helmet
+crate
+crib
+Crock Pot
+croquet ball
+crutch
+cuirass
+dam
+desk
+desktop computer
+dial telephone
+diaper
+digital clock
+digital watch
+dining table
+dishrag
+dishwasher
+disk brake
+dock
+dogsled
+dome
+doormat
+drilling platform
+drum
+drumstick
+dumbbell
+Dutch oven
+electric fan
+electric guitar
+electric locomotive
+entertainment center
+envelope
+espresso maker
+face powder
+feather boa
+file
+fireboat
+fire engine
+fire screen
+flagpole
+flute
+folding chair
+football helmet
+forklift
+fountain
+fountain pen
+four-poster
+freight car
+French horn
+frying pan
+fur coat
+garbage truck
+gasmask
+gas pump
+goblet
+go-kart
+golf ball
+golfcart
+gondola
+gong
+gown
+grand piano
+greenhouse
+grille
+grocery store
+guillotine
+hair slide
+hair spray
+half track
+hammer
+hamper
+hand blower
+hand-held computer
+handkerchief
+hard disc
+harmonica
+harp
+harvester
+hatchet
+holster
+home theater
+honeycomb
+hook
+hoopskirt
+horizontal bar
+horse cart
+hourglass
+iPod
+iron
+jack-o'-lantern
+jean
+jeep
+jersey
+jigsaw puzzle
+jinrikisha
+joystick
+kimono
+knee pad
+knot
+lab coat
+ladle
+lampshade
+laptop
+lawn mower
+lens cap
+letter opener
+library
+lifeboat
+lighter
+limousine
+liner
+lipstick
+Loafer
+lotion
+loudspeaker
+loupe
+lumbermill
+magnetic compass
+mailbag
+mailbox
+maillot
+maillot
+manhole cover
+maraca
+marimba
+mask
+matchstick
+maypole
+maze
+measuring cup
+medicine chest
+megalith
+microphone
+microwave
+military uniform
+milk can
+minibus
+miniskirt
+minivan
+missile
+mitten
+mixing bowl
+mobile home
+Model T
+modem
+monastery
+monitor
+moped
+mortar
+mortarboard
+mosque
+mosquito net
+motor scooter
+mountain bike
+mountain tent
+mouse
+mousetrap
+moving van
+muzzle
+nail
+neck brace
+necklace
+nipple
+notebook
+obelisk
+oboe
+ocarina
+odometer
+oil filter
+organ
+oscilloscope
+overskirt
+oxcart
+oxygen mask
+packet
+paddle
+paddlewheel
+padlock
+paintbrush
+pajama
+palace
+panpipe
+paper towel
+parachute
+parallel bars
+park bench
+parking meter
+passenger car
+patio
+pay-phone
+pedestal
+pencil box
+pencil sharpener
+perfume
+Petri dish
+photocopier
+pick
+pickelhaube
+picket fence
+pickup
+pier
+piggy bank
+pill bottle
+pillow
+ping-pong ball
+pinwheel
+pirate
+pitcher
+plane
+planetarium
+plastic bag
+plate rack
+plow
+plunger
+Polaroid camera
+pole
+police van
+poncho
+pool table
+pop bottle
+pot
+potter's wheel
+power drill
+prayer rug
+printer
+prison
+projectile
+projector
+puck
+punching bag
+purse
+quill
+quilt
+racer
+racket
+radiator
+radio
+radio telescope
+rain barrel
+recreational vehicle
+reel
+reflex camera
+refrigerator
+remote control
+restaurant
+revolver
+rifle
+rocking chair
+rotisserie
+rubber eraser
+rugby ball
+rule
+running shoe
+safe
+safety pin
+saltshaker
+sandal
+sarong
+sax
+scabbard
+scale
+school bus
+schooner
+scoreboard
+screen
+screw
+screwdriver
+seat belt
+sewing machine
+shield
+shoe shop
+shoji
+shopping basket
+shopping cart
+shovel
+shower cap
+shower curtain
+ski
+ski mask
+sleeping bag
+slide rule
+sliding door
+slot
+snorkel
+snowmobile
+snowplow
+soap dispenser
+soccer ball
+sock
+solar dish
+sombrero
+soup bowl
+space bar
+space heater
+space shuttle
+spatula
+speedboat
+spider web
+spindle
+sports car
+spotlight
+stage
+steam locomotive
+steel arch bridge
+steel drum
+stethoscope
+stole
+stone wall
+stopwatch
+stove
+strainer
+streetcar
+stretcher
+studio couch
+stupa
+submarine
+suit
+sundial
+sunglass
+sunglasses
+sunscreen
+suspension bridge
+swab
+sweatshirt
+swimming trunks
+swing
+switch
+syringe
+table lamp
+tank
+tape player
+teapot
+teddy
+television
+tennis ball
+thatch
+theater curtain
+thimble
+thresher
+throne
+tile roof
+toaster
+tobacco shop
+toilet seat
+torch
+totem pole
+tow truck
+toyshop
+tractor
+trailer truck
+tray
+trench coat
+tricycle
+trimaran
+tripod
+triumphal arch
+trolleybus
+trombone
+tub
+turnstile
+typewriter keyboard
+umbrella
+unicycle
+upright
+vacuum
+vase
+vault
+velvet
+vending machine
+vestment
+viaduct
+violin
+volleyball
+waffle iron
+wall clock
+wallet
+wardrobe
+warplane
+washbasin
+washer
+water bottle
+water jug
+water tower
+whiskey jug
+whistle
+wig
+window screen
+window shade
+Windsor tie
+wine bottle
+wing
+wok
+wooden spoon
+wool
+worm fence
+wreck
+yawl
+yurt
+web site
+comic book
+crossword puzzle
+street sign
+traffic light
+book jacket
+menu
+plate
+guacamole
+consomme
+hot pot
+trifle
+ice cream
+ice lolly
+French loaf
+bagel
+pretzel
+cheeseburger
+hotdog
+mashed potato
+head cabbage
+broccoli
+cauliflower
+zucchini
+spaghetti squash
+acorn squash
+butternut squash
+cucumber
+artichoke
+bell pepper
+cardoon
+mushroom
+Granny Smith
+strawberry
+orange
+lemon
+fig
+pineapple
+banana
+jackfruit
+custard apple
+pomegranate
+hay
+carbonara
+chocolate sauce
+dough
+meat loaf
+pizza
+potpie
+burrito
+red wine
+espresso
+cup
+eggnog
+alp
+bubble
+cliff
+coral reef
+geyser
+lakeside
+promontory
+sandbar
+seashore
+valley
+volcano
+ballplayer
+groom
+scuba diver
+rapeseed
+daisy
+yellow lady's slipper
+corn
+acorn
+hip
+buckeye
+coral fungus
+agaric
+gyromitra
+stinkhorn
+earthstar
+hen-of-the-woods
+bolete
+ear
+toilet tissue
\ No newline at end of file
diff --git a/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/AppModel.java b/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/AppModel.java
new file mode 100644
index 0000000000000000000000000000000000000000..c43f6266eeffcb66b4d5725023282c481f2cbf82
--- /dev/null
+++ b/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/AppModel.java
@@ -0,0 +1,75 @@
+// Copyright 2018 Xiaomi, Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.xiaomi.mace.demo;
+
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.util.Log;
+
+import com.xiaomi.mace.JniMaceUtils;
+import com.xiaomi.mace.demo.camera.MessageEvent;
+import com.xiaomi.mace.demo.result.InitData;
+import com.xiaomi.mace.demo.result.LabelCache;
+import com.xiaomi.mace.demo.result.ResultData;
+
+import org.greenrobot.eventbus.EventBus;
+
+public class AppModel {
+
+ private Handler mJniThread;
+ public static AppModel instance = new AppModel();
+ private AppModel() {
+ HandlerThread thread = new HandlerThread("jniThread");
+ thread.start();
+ mJniThread = new Handler(thread.getLooper());
+ }
+
+ public void maceMobilenetSetAttrs(final InitData initData) {
+ mJniThread.post(new Runnable() {
+ @Override
+ public void run() {
+ int result = JniMaceUtils.maceMobilenetSetAttrs(
+ initData.getOmpNumThreads(), initData.getCpuAffinityPolicy(),
+ initData.getGpuPerfHint(), initData.getGpuPriorityHint(),
+ initData.getKernelPath());
+ Log.i("APPModel", "maceMobilenetSetAttrs result = " + result);
+ }
+ });
+ }
+
+ public void maceMobilenetCreateEngine(final InitData initData) {
+ mJniThread.post(new Runnable() {
+ @Override
+ public void run() {
+ JniMaceUtils.maceMobilenetCreateEngine(initData.getModel(), initData.getDevice());
+ }
+ });
+ }
+
+ public void maceMobilenetClassify(final float[] input) {
+ mJniThread.post(new Runnable() {
+ @Override
+ public void run() {
+ long start = System.currentTimeMillis();
+ float[] result = JniMaceUtils.maceMobilenetClassify(input);
+
+ final ResultData resultData = LabelCache.instance().getResultFirst(result);
+ resultData.costTime = System.currentTimeMillis() - start;
+ EventBus.getDefault().post(new MessageEvent.MaceResultEvent(resultData));
+ }
+ });
+ }
+
+}
diff --git a/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/CameraActivity.java b/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/CameraActivity.java
new file mode 100644
index 0000000000000000000000000000000000000000..ae38719062cbe10facd9f6f5a98ad8a1461d08a7
--- /dev/null
+++ b/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/CameraActivity.java
@@ -0,0 +1,180 @@
+// Copyright 2018 Xiaomi, Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.xiaomi.mace.demo;
+
+import android.app.Activity;
+import android.content.pm.PackageManager;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+
+import com.xiaomi.mace.demo.camera.CameraEngage;
+import com.xiaomi.mace.demo.camera.CameraTextureView;
+import com.xiaomi.mace.demo.camera.ContextMenuDialog;
+
+import com.xiaomi.mace.demo.camera.MessageEvent;
+import com.xiaomi.mace.demo.result.InitData;
+
+import org.greenrobot.eventbus.EventBus;
+import org.greenrobot.eventbus.Subscribe;
+import org.greenrobot.eventbus.ThreadMode;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class CameraActivity extends Activity implements View.OnClickListener {
+
+ CameraEngage mCameraEngage;
+ ImageView mPictureResult;
+ Button mSelectMode;
+ Button mSelectPhoneType;
+ CameraTextureView mCameraTextureView;
+ private TextView mResultView;
+ private InitData initData = new InitData();
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
+ setContentView(R.layout.activity_camera);
+ mPictureResult = findViewById(R.id.iv_picture);
+ mResultView = findViewById(R.id.tv_show_result);
+ mCameraTextureView = findViewById(R.id.camera_texture);
+ mCameraEngage = CameraFactory.genCameEngage(mCameraTextureView);
+
+ mSelectMode = findViewById(R.id.tv_select_mode);
+ mSelectMode.setOnClickListener(this);
+
+ mSelectPhoneType = findViewById(R.id.tv_select_phone_type);
+ mSelectPhoneType.setOnClickListener(this);
+ initJni();
+ initView();
+
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ EventBus.getDefault().register(this);
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ EventBus.getDefault().unregister(this);
+ }
+
+ private void initView() {
+ mSelectMode.setText(initData.getModel());
+ mSelectPhoneType.setText(initData.getDevice());
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ mCameraEngage.onResume();
+ }
+
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ mCameraEngage.onPause();
+ }
+
+ @Subscribe(threadMode = ThreadMode.MAIN)
+ public void onPicture(MessageEvent.PicEvent picEvent) {
+ if (picEvent != null && picEvent.getBitmap() != null) {
+ mPictureResult.setImageBitmap(picEvent.getBitmap());
+ }
+ }
+
+ @Subscribe(threadMode = ThreadMode.MAIN)
+ public void onSetCameraViewSize(MessageEvent.OutputSizeEvent event) {
+ if (mCameraTextureView != null) {
+ mCameraTextureView.setRatio(event.width, event.height);
+ }
+ }
+
+
+ @Subscribe(threadMode = ThreadMode.MAIN)
+ public void onResultData(MessageEvent.MaceResultEvent resultData) {
+ if (resultData != null && resultData.getData() != null) {
+ String result = resultData.getData().name + "\n"
+ + resultData.getData().probability + "\ncost time(ms): "
+ + resultData.getData().costTime;
+ mResultView.setText(result);
+ }
+ }
+
+ @Override
+ public void onClick(View v) {
+ switch (v.getId()) {
+ case R.id.tv_select_mode:
+ showSelectMode();
+ break;
+ case R.id.tv_select_phone_type:
+ showPhoneType();
+ break;
+ }
+ }
+
+ private void initJni() {
+ AppModel.instance.maceMobilenetSetAttrs(initData);
+ AppModel.instance.maceMobilenetCreateEngine(initData);
+ }
+
+ @Override
+ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
+ super.onRequestPermissionsResult(requestCode, permissions, grantResults);
+ if (requestCode == Constant.CAMERA_PERMISSION_REQ) {
+ for (int result : grantResults) {
+ if (result != PackageManager.PERMISSION_GRANTED) {
+ mCameraEngage.onResume();
+ break;
+ }
+ }
+ }
+ }
+
+ private void showPhoneType() {
+ List menus = Arrays.asList(InitData.DEVICES);
+ ContextMenuDialog.show(this, menus, new ContextMenuDialog.OnClickItemListener() {
+ @Override
+ public void onCLickItem(String content) {
+ mSelectPhoneType.setText(content);
+ initData.setDevice(content);
+ AppModel.instance.maceMobilenetCreateEngine(initData);
+ }
+ });
+ }
+
+ private void showSelectMode() {
+ List menus = Arrays.asList(InitData.MODELS);
+ ContextMenuDialog.show(this, menus, new ContextMenuDialog.OnClickItemListener() {
+ @Override
+ public void onCLickItem(String content) {
+ mSelectMode.setText(content);
+ initData.setModel(content);
+ AppModel.instance.maceMobilenetCreateEngine(initData);
+ }
+ });
+ }
+}
diff --git a/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/CameraFactory.java b/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/CameraFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..a3fd21e3e27ecefdee11508532cebe055f094bd1
--- /dev/null
+++ b/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/CameraFactory.java
@@ -0,0 +1,35 @@
+// Copyright 2018 Xiaomi, Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.xiaomi.mace.demo;
+
+import android.os.Build;
+
+import com.xiaomi.mace.demo.camera.CameraApiLessM;
+import com.xiaomi.mace.demo.camera.CameraEngage;
+import com.xiaomi.mace.demo.camera.CameraTextureView;
+
+public class CameraFactory {
+
+ public static CameraEngage genCameEngage(CameraTextureView textureView) {
+ CameraEngage cameraEngage;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+// cameraEngage = new CameraApiMoreM(textureView);
+ cameraEngage = new CameraApiLessM(textureView);
+ } else {
+ cameraEngage = new CameraApiLessM(textureView);
+ }
+ return cameraEngage;
+ }
+}
diff --git a/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/Constant.java b/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/Constant.java
new file mode 100644
index 0000000000000000000000000000000000000000..a1f673a6e63366f183efaff81ec8dba52982ca7e
--- /dev/null
+++ b/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/Constant.java
@@ -0,0 +1,20 @@
+// Copyright 2018 Xiaomi, Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.xiaomi.mace.demo;
+
+public class Constant {
+
+ public static final int CAMERA_PERMISSION_REQ = 1;
+}
diff --git a/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/MaceApp.java b/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/MaceApp.java
new file mode 100644
index 0000000000000000000000000000000000000000..f525f63496fe5fac3608d77aa723f55cb0b1abb9
--- /dev/null
+++ b/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/MaceApp.java
@@ -0,0 +1,51 @@
+// Copyright 2018 Xiaomi, Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.xiaomi.mace.demo;
+
+import android.app.Application;
+import android.os.Handler;
+import android.os.HandlerThread;
+
+import com.xiaomi.mace.demo.result.LabelCache;
+
+public class MaceApp extends Application {
+
+ public static MaceApp app;
+ public Handler mBackground;
+ public Handler mMainHandler;
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ app = this;
+
+ mMainHandler = new Handler(getMainLooper());
+
+ HandlerThread thread = new HandlerThread("mace_app");
+ thread.start();
+ mBackground = new Handler(thread.getLooper());
+ mBackground.post(new Runnable() {
+ @Override
+ public void run() {
+ LabelCache.instance();
+ }
+ });
+ }
+
+ public Handler mainHandler() {
+ return mMainHandler;
+ }
+
+}
diff --git a/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/camera/CameraApiLessM.java b/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/camera/CameraApiLessM.java
new file mode 100644
index 0000000000000000000000000000000000000000..9b334c5ad0ada3ab48e77d9deb492acdfc360d1b
--- /dev/null
+++ b/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/camera/CameraApiLessM.java
@@ -0,0 +1,149 @@
+// Copyright 2018 Xiaomi, Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.xiaomi.mace.demo.camera;
+
+import android.graphics.ImageFormat;
+import android.hardware.Camera;
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.util.List;
+
+public class CameraApiLessM extends CameraEngage implements Camera.AutoFocusCallback {
+
+ private Camera mCamera;
+
+ public CameraApiLessM(CameraTextureView textureView) {
+ super(textureView);
+ }
+
+ @Override
+ public void openCamera(int width, int height) {
+ if (!checkCameraPermission()) {
+ return;
+ }
+ super.openCamera(width, height);
+ closeCamera();
+ String cameraId = getCameraId();
+ if (TextUtils.isEmpty(cameraId)) {
+ return;
+ }
+
+ mCamera = Camera.open(Integer.parseInt(cameraId));
+ setOutputConfig(width, height);
+ startPreview();
+ }
+
+ @Override
+ public void autoFocus() {
+ doAutoFocus();
+ }
+
+ @Override
+ public void closeCamera() {
+ if (mCamera != null) {
+ mCamera.stopPreview();
+ mCamera.setPreviewCallback(null);
+ mCamera.release();
+ mCamera = null;
+ }
+ }
+
+ @Override
+ public String getCameraId() {
+ Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
+ int cameraFacing = facingFrontPreview() ? Camera.CameraInfo.CAMERA_FACING_FRONT : Camera.CameraInfo.CAMERA_FACING_BACK;
+ for (int i = 0; i < Camera.getNumberOfCameras(); i++) {
+ Camera.getCameraInfo(i, cameraInfo);
+ if (cameraInfo.facing == cameraFacing) {
+ return String.valueOf(i);
+ }
+ }
+ return "";
+ }
+
+ @Override
+ public void startPreview() {
+ try {
+ doAutoFocus();
+ mCamera.setPreviewTexture(mSurfaceTexture);
+ mCamera.startPreview();
+ mCamera.setDisplayOrientation(90);
+ } catch (Exception e) {
+ Log.e(getClass().getName(), "startPreview error = " + e);
+ }
+ }
+
+ @Override
+ public void onAutoFocus(boolean success, Camera camera) {
+ if (success) {
+ mCamera.cancelAutoFocus();
+ }
+ }
+
+ private void doAutoFocus() {
+ try {
+ mCamera.autoFocus(this);
+ } catch (Throwable e) {
+ Log.e(this.getClass().getName(), "auto focus error = " + e);
+ }
+ }
+
+ private void setOutputConfig(int width, int height) {
+ Camera.Parameters parameters = mCamera.getParameters();
+ parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
+ parameters.setPreviewFormat(ImageFormat.JPEG);
+ parameters.setPictureFormat(ImageFormat.JPEG);
+ Camera.Size size = getOptimalSize(parameters.getSupportedPreviewSizes(), width, height);
+ mPreviewWidth = size.width;
+ mPreviewHeight = size.height;
+ parameters.setPreviewSize(size.width, size.height);
+ parameters.setPictureSize(size.width, size.height);
+ mCamera.setParameters(parameters);
+ mTextureView.setRatio(size.height, size.width);
+ }
+
+ private Camera.Size getOptimalSize(List sizes, int w, int h) {
+ final double ASPECT_TOLERANCE = 0.1;
+ double targetRatio = (double) h / w;
+ Camera.Size optimalSize = null;
+ double minDiff = Double.MAX_VALUE;
+
+ int targetHeight = h;
+
+ for (Camera.Size size : sizes) {
+ double ratio = (double) size.height / size.width;
+ if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) {
+ continue;
+ }
+ if (Math.abs(size.height - targetHeight) < minDiff) {
+ optimalSize = size;
+ minDiff = Math.abs(size.height - targetHeight);
+ }
+ }
+
+ if (optimalSize == null) {
+ minDiff = Double.MAX_VALUE;
+ for (Camera.Size size : sizes) {
+ if (Math.abs(size.height - targetHeight) < minDiff) {
+ optimalSize = size;
+ minDiff = Math.abs(size.height - targetHeight);
+ }
+ }
+ }
+
+ return optimalSize;
+ }
+}
diff --git a/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/camera/CameraApiMoreM.java b/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/camera/CameraApiMoreM.java
new file mode 100644
index 0000000000000000000000000000000000000000..8be09dd3f720560d1e44960dcdd2db149e4c1dd9
--- /dev/null
+++ b/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/camera/CameraApiMoreM.java
@@ -0,0 +1,270 @@
+// Copyright 2018 Xiaomi, Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.xiaomi.mace.demo.camera;
+
+import android.content.Context;
+import android.graphics.ImageFormat;
+import android.graphics.SurfaceTexture;
+import android.hardware.camera2.CameraCaptureSession;
+import android.hardware.camera2.CameraCaptureSession.CaptureCallback;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.CameraManager;
+import android.hardware.camera2.CaptureFailure;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.TotalCaptureResult;
+import android.hardware.camera2.params.StreamConfigurationMap;
+import android.media.ImageReader;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.support.annotation.NonNull;
+import android.util.Log;
+import android.util.Size;
+import android.view.Surface;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+public class CameraApiMoreM extends CameraEngage {
+
+ private CameraManager mCameraManager;
+ private ImageReader mImageReader;
+ private CameraCaptureSession mCameraCaptureSession;
+ private CaptureRequest.Builder mPreviewBuilder;
+ private Handler mCameraHandler;
+ private CameraDevice mCameraDevice;
+ private Size mPreviewSize;
+
+
+ private CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
+ @Override
+ public void onOpened(@NonNull CameraDevice camera) {
+ mCameraDevice = camera;
+ createPreviewSession();
+ }
+
+ @Override
+ public void onDisconnected(@NonNull CameraDevice camera) {
+ camera.close();
+ mCameraDevice = null;
+ }
+
+ @Override
+ public void onError(@NonNull CameraDevice camera, int error) {
+ camera.close();
+ mCameraDevice = null;
+ }
+ };
+
+ private CameraCaptureSession.CaptureCallback mCaptureCallback = new CaptureCallback() {
+ @Override
+ public void onCaptureProgressed(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull CaptureResult partialResult) {
+ super.onCaptureProgressed(session, request, partialResult);
+ }
+
+ @Override
+ public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) {
+ super.onCaptureCompleted(session, request, result);
+ }
+
+ @Override
+ public void onCaptureFailed(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull CaptureFailure failure) {
+ super.onCaptureFailed(session, request, failure);
+ }
+ };
+
+ private CameraCaptureSession.StateCallback mSessionStateCallback = new CameraCaptureSession.StateCallback() {
+ @Override
+ public void onConfigured(@NonNull CameraCaptureSession session) {
+ if (mCameraDevice == null) {
+ Log.e("bjh", "device must be not null");
+ return;
+ }
+ mCameraCaptureSession = session;
+ startPreview();
+ }
+
+ @Override
+ public void onConfigureFailed(@NonNull CameraCaptureSession session) {
+
+ }
+ };
+
+ private void createPreviewSession() {
+ try {
+ mSurfaceTexture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
+
+ Surface surface = new Surface(mSurfaceTexture);
+
+ mPreviewBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
+ mPreviewBuilder.addTarget(surface);
+
+ mCameraDevice.createCaptureSession(Arrays.asList(surface), mSessionStateCallback, null);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ }
+
+ public CameraApiMoreM(CameraTextureView textureView) {
+ super(textureView);
+ mCameraManager = (CameraManager) textureView.getContext().getSystemService(Context.CAMERA_SERVICE);
+ if (mCameraManager == null) {
+ throw new RuntimeException("camera manager must be not null");
+ }
+
+ HandlerThread handlerThread = new HandlerThread("camerabg");
+ handlerThread.start();
+ mCameraHandler = new Handler(handlerThread.getLooper());
+ }
+
+ @Override
+ public void openCamera(int width, int height) {
+ super.openCamera(width, height);
+ try {
+ if (!checkCameraPermission()) {
+ return;
+ }
+ setOutputConfig(width, height);
+ createImageReader();
+ mCameraManager.openCamera(getCameraId(), mStateCallback, mCameraHandler);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void setOutputConfig(int width, int height) {
+ try {
+ for (String cameraId : mCameraManager.getCameraIdList()) {
+ CameraCharacteristics characteristics = mCameraManager.getCameraCharacteristics(cameraId);
+
+ Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING);
+ if (facing != null && facing == CameraCharacteristics.LENS_FACING_FRONT) {
+ continue;
+ }
+
+ StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
+ if (map == null) {
+ continue;
+ }
+
+ Size largest = Collections.max(Arrays.asList(map.getOutputSizes(ImageFormat.JPEG)), new CompareSizesByArea());
+
+ mPreviewSize = chooseOptimalSize(map.getOutputSizes(SurfaceTexture.class), width, height, mPreviewWidth, mPreviewHeight, largest);
+ mPreviewWidth = mPreviewSize.getWidth();
+ mPreviewHeight = mPreviewSize.getHeight();
+ mTextureView.setRatio(mPreviewSize.getHeight(), mPreviewSize.getWidth());
+ break;
+ }
+ } catch (Exception e) {
+ Log.e("bjh", "error " + e);
+ }
+ }
+
+ private static Size chooseOptimalSize(Size[] choices, int textureViewWidth, int textureViewHeight, int maxWidth, int maxHeight, Size aspectRatio) {
+
+ // Collect the supported resolutions that are at least as big as the preview Surface
+ List bigEnough = new ArrayList<>();
+ // Collect the supported resolutions that are smaller than the preview Surface
+ List notBigEnough = new ArrayList<>();
+ int w = aspectRatio.getWidth();
+ int h = aspectRatio.getHeight();
+ for (Size option : choices) {
+ if (option.getWidth() <= maxWidth && option.getHeight() <= maxHeight && option.getHeight() == option.getWidth() * h / w) {
+ if (option.getWidth() >= textureViewWidth && option.getHeight() >= textureViewHeight) {
+ bigEnough.add(option);
+ } else {
+ notBigEnough.add(option);
+ }
+ }
+ }
+
+ // Pick the smallest of those big enough. If there is no one big enough, pick the
+ // largest of those not big enough.
+ if (bigEnough.size() > 0) {
+ return Collections.min(bigEnough, new CompareSizesByArea());
+ } else if (notBigEnough.size() > 0) {
+ return Collections.max(notBigEnough, new CompareSizesByArea());
+ } else {
+ return choices[0];
+ }
+ }
+
+ @Override
+ public void autoFocus() {
+ startPreview();
+ }
+
+ private void createImageReader() {
+ mImageReader = ImageReader.newInstance(mPreviewSize.getWidth(), mPreviewSize.getHeight(), ImageFormat.JPEG, 2);
+ }
+
+ @Override
+ public void closeCamera() {
+ if (mImageReader != null) {
+ mImageReader.close();
+ }
+ if (mCameraDevice != null) {
+ mCameraDevice.close();
+ }
+ if (mCameraCaptureSession != null) {
+ mCameraCaptureSession.close();
+ }
+ }
+ private static class CompareSizesByArea implements Comparator {
+
+ @Override
+ public int compare(Size lhs, Size rhs) {
+ return Long.signum((long) lhs.getWidth() * lhs.getHeight() - (long) rhs.getWidth() * rhs.getHeight());
+ }
+ }
+
+
+ @Override
+ public String getCameraId() {
+ try {
+ String[] idList = mCameraManager.getCameraIdList();
+ int currentFacing = facingFrontPreview() ? CameraCharacteristics.LENS_FACING_FRONT : CameraCharacteristics.LENS_FACING_BACK;
+ for (String id : idList) {
+ CameraCharacteristics characteristics = mCameraManager.getCameraCharacteristics(id);
+ int facing = characteristics.get(CameraCharacteristics.LENS_FACING);
+ if (facing != currentFacing) {
+ continue;
+ }
+ return id;
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return "";
+ }
+
+ @Override
+ public void startPreview() {
+ if (mCameraCaptureSession != null) {
+ try {
+ mPreviewBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
+ mCameraCaptureSession.setRepeatingRequest(mPreviewBuilder.build(), mCaptureCallback, mCameraHandler);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+}
diff --git a/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/camera/CameraEngage.java b/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/camera/CameraEngage.java
new file mode 100644
index 0000000000000000000000000000000000000000..af8b1b85c2110326fafa4153664ec8b43901fc6f
--- /dev/null
+++ b/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/camera/CameraEngage.java
@@ -0,0 +1,223 @@
+// Copyright 2018 Xiaomi, Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.xiaomi.mace.demo.camera;
+
+import android.Manifest;
+import android.app.Activity;
+import android.content.pm.PackageManager;
+import android.graphics.Bitmap;
+import android.graphics.SurfaceTexture;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.support.v4.content.ContextCompat;
+import android.util.Log;
+import android.view.TextureView.SurfaceTextureListener;
+import android.view.View;
+
+import com.xiaomi.mace.demo.AppModel;
+import com.xiaomi.mace.demo.MaceApp;
+
+import java.nio.FloatBuffer;
+
+import static com.xiaomi.mace.demo.Constant.CAMERA_PERMISSION_REQ;
+
+public abstract class CameraEngage implements SurfaceTextureListener {
+
+ /**
+ * preview height and width
+ */
+ int mPreviewHeight;
+ int mPreviewWidth;
+
+ /**
+ * show camera view
+ */
+ CameraTextureView mTextureView;
+ SurfaceTexture mSurfaceTexture;
+
+ /**
+ * switch camera use
+ */
+ private boolean mFacingFront = false;
+ /**
+ * camera background thread
+ */
+ private HandlerThread mBackgroundHandlerThread;
+ private Handler mBackgroundHandler;
+
+ /**
+ * mace need data size width and height
+ */
+ private static final int FINAL_SIZE = 224;
+ /**
+ * storage rgb value
+ */
+ private int[] colorValues;
+
+ /**
+ * mace float[] input
+ */
+ private FloatBuffer floatBuffer;
+
+ private final Object lock = new Object();
+
+ private boolean isCapturePic = false;
+
+ private Runnable mHandleCapturePicRunnable = new Runnable() {
+ @Override
+ public void run() {
+ synchronized (lock) {
+ if (isCapturePic) {
+ handleCapturePic();
+ }
+ }
+ mBackgroundHandler.postDelayed(mHandleCapturePicRunnable, 200);
+ }
+ };
+
+ private void handleCapturePic() {
+ if (mTextureView != null) {
+ Bitmap bitmap = mTextureView.getBitmap(FINAL_SIZE, FINAL_SIZE);
+ if (bitmap != null) {
+ bitmap.getPixels(colorValues, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight());
+ handleColorRgbs();
+// EventBus.getDefault().post(new MessageEvent.PicEvent(bitmap));
+ bitmap.recycle();
+ }
+ }
+ }
+
+
+ public CameraEngage(CameraTextureView mTextureView) {
+ this.mTextureView = mTextureView;
+
+ colorValues = new int[FINAL_SIZE * FINAL_SIZE];
+ float[] floatValues = new float[FINAL_SIZE * FINAL_SIZE * 3];
+ floatBuffer = FloatBuffer.wrap(floatValues, 0, FINAL_SIZE * FINAL_SIZE * 3);
+
+ mPreviewHeight = MaceApp.app.getResources().getDisplayMetrics().heightPixels;
+ mPreviewWidth = MaceApp.app.getResources().getDisplayMetrics().widthPixels;
+
+ mTextureView.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ autoFocus();
+ }
+ });
+ }
+
+ public void openCamera(int width, int height) {
+ startCapturePic();
+ }
+
+ public abstract void autoFocus();
+
+ public abstract void closeCamera();
+
+ public abstract String getCameraId();
+
+ public abstract void startPreview();
+
+ boolean facingFrontPreview() {
+ return mFacingFront;
+ }
+
+ public void setFacingFront(boolean facingFront) {
+ this.mFacingFront = facingFront;
+ onResume();
+ }
+
+
+ private void handleColorRgbs() {
+ floatBuffer.rewind();
+ for (int i = 0; i < colorValues.length; i++) {
+ int value = colorValues[i];
+ floatBuffer.put((((value >> 16) & 0xFF) - 128f)/ 128f);
+ floatBuffer.put((((value >> 8) & 0xFF) - 128f) / 128f);
+ floatBuffer.put(((value & 0xFF) - 128f) / 128f);
+ }
+ AppModel.instance.maceMobilenetClassify(floatBuffer.array());
+
+ }
+
+
+ public void onResume() {
+ if (mTextureView.isAvailable()) {
+ openCamera(mTextureView.getWidth(), mTextureView.getHeight());
+ } else {
+ mTextureView.setSurfaceTextureListener(this);
+ }
+ }
+
+ private void startCapturePic() {
+ mBackgroundHandlerThread = new HandlerThread("captureBackground");
+ mBackgroundHandlerThread.start();
+ mBackgroundHandler = new Handler(mBackgroundHandlerThread.getLooper());
+ synchronized (lock) {
+ isCapturePic = true;
+ }
+
+ mBackgroundHandler.post(mHandleCapturePicRunnable);
+ }
+
+ private void stopBackgroundThread() {
+ try {
+ mBackgroundHandlerThread.quitSafely();
+ mBackgroundHandlerThread.join();
+ mBackgroundHandler = null;
+ mBackgroundHandlerThread = null;
+ synchronized (lock) {
+ isCapturePic = false;
+ }
+ } catch (Exception e) {
+ Log.e(this.getClass().getName(), "stopBackgroundThread" + e);
+ }
+ }
+
+ public void onPause() {
+ closeCamera();
+ stopBackgroundThread();
+ }
+
+ @Override
+ public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
+ mSurfaceTexture = surface;
+ openCamera(width, height);
+ }
+
+ @Override
+ public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
+ }
+
+ @Override
+ public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
+ return false;
+ }
+
+ @Override
+ public void onSurfaceTextureUpdated(SurfaceTexture surface) {
+
+ }
+
+ boolean checkCameraPermission() {
+ if (ContextCompat.checkSelfPermission(mTextureView.getContext(), Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED ||
+ ContextCompat.checkSelfPermission(mTextureView.getContext(), Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
+ ((Activity) mTextureView.getContext()).requestPermissions(new String[]{Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE}, CAMERA_PERMISSION_REQ);
+ return false;
+ }
+ return true;
+ }
+
+}
diff --git a/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/camera/CameraTextureView.java b/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/camera/CameraTextureView.java
new file mode 100644
index 0000000000000000000000000000000000000000..ac9d710249b87fba88abca17e42df82eb29be041
--- /dev/null
+++ b/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/camera/CameraTextureView.java
@@ -0,0 +1,55 @@
+// Copyright 2018 Xiaomi, Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.xiaomi.mace.demo.camera;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.TextureView;
+
+public class CameraTextureView extends TextureView {
+
+ private int ratioWidth;
+ private int ratioHeight;
+
+ public CameraTextureView(Context context) {
+ super(context);
+ }
+
+ public CameraTextureView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public CameraTextureView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ public void setRatio(int width, int height) {
+ this.ratioWidth = width;
+ this.ratioHeight = height;
+ requestLayout();
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ int width = MeasureSpec.getSize(widthMeasureSpec);
+ int height = MeasureSpec.getSize(heightMeasureSpec);
+ if (ratioWidth <= 0 || ratioHeight <= 0) {
+ setMeasuredDimension(width, height);
+ } else {
+ setMeasuredDimension(width, width * ratioHeight / ratioWidth);
+ }
+ }
+}
diff --git a/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/camera/ContextMenuDialog.java b/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/camera/ContextMenuDialog.java
new file mode 100644
index 0000000000000000000000000000000000000000..6c9a14f55b2d4d85b827b82ce3a4b4f5ceca8a79
--- /dev/null
+++ b/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/camera/ContextMenuDialog.java
@@ -0,0 +1,69 @@
+// Copyright 2018 Xiaomi, Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.xiaomi.mace.demo.camera;
+
+import android.app.Activity;
+import android.app.DialogFragment;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.ListView;
+
+import com.xiaomi.mace.demo.R;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+public class ContextMenuDialog extends DialogFragment {
+
+ private List items = new ArrayList<>();
+ private OnClickItemListener listener;
+
+ public static void show(Activity activity, List items, OnClickItemListener listener) {
+ ContextMenuDialog dialog = new ContextMenuDialog();
+ dialog.items = items;
+ dialog.listener = listener;
+ dialog.show(activity.getFragmentManager(), "");
+ }
+
+ @Nullable
+ @Override
+ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
+ super.onCreateView(inflater, container, savedInstanceState);
+ View root = inflater.inflate(R.layout.layout_dialog, null);
+ final ListView listView = root.findViewById(R.id.list_menu);
+ ItemAdapter itemAdapter = new ItemAdapter();
+ listView.setAdapter(itemAdapter);
+ itemAdapter.setItems(items);
+ listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+ @Override
+ public void onItemClick(AdapterView> parent, View view, int position, long id) {
+ if (listener != null) {
+ listener.onCLickItem(items.get(position));
+ }
+ dismissAllowingStateLoss();
+ }
+ });
+ return root;
+ }
+
+ public static interface OnClickItemListener {
+ void onCLickItem(String content);
+ }
+}
diff --git a/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/camera/ItemAdapter.java b/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/camera/ItemAdapter.java
new file mode 100644
index 0000000000000000000000000000000000000000..d4341970b0e0dee2bfeec335fd5f4ec5d574fc6c
--- /dev/null
+++ b/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/camera/ItemAdapter.java
@@ -0,0 +1,72 @@
+// Copyright 2018 Xiaomi, Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.xiaomi.mace.demo.camera;
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.TextView;
+
+import com.xiaomi.mace.demo.R;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+public class ItemAdapter extends BaseAdapter {
+
+ private List items = new ArrayList<>();
+
+ public void setItems(List items) {
+ this.items = items;
+ notifyDataSetChanged();
+ }
+
+ @Override
+ public int getCount() {
+ return items.size();
+ }
+
+ @Override
+ public Object getItem(int position) {
+ return items.get(position);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ Holder holder;
+ if (convertView != null && convertView.getTag() instanceof Holder) {
+ holder = (Holder) convertView.getTag();
+ } else {
+ convertView = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_item, null);
+ holder = new Holder();
+ holder.itemView = convertView.findViewById(R.id.tv_item);
+ convertView.setTag(holder);
+ }
+
+ holder.itemView.setText(items.get(position));
+ return convertView;
+ }
+
+ class Holder {
+ TextView itemView;
+ }
+}
diff --git a/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/camera/MessageEvent.java b/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/camera/MessageEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..2c408c09537b2a8568fabf36487f192bd6318ac0
--- /dev/null
+++ b/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/camera/MessageEvent.java
@@ -0,0 +1,57 @@
+// Copyright 2018 Xiaomi, Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.xiaomi.mace.demo.camera;
+
+import android.graphics.Bitmap;
+
+import com.xiaomi.mace.demo.result.ResultData;
+
+
+public class MessageEvent {
+
+ public static class MaceResultEvent {
+ ResultData data;
+
+ public MaceResultEvent(ResultData data) {
+ this.data = data;
+ }
+
+ public ResultData getData() {
+ return data;
+ }
+ }
+
+ public static class PicEvent {
+ Bitmap bitmap;
+
+ public PicEvent(Bitmap bitmap) {
+ this.bitmap = bitmap;
+ }
+
+ public Bitmap getBitmap() {
+ return bitmap;
+ }
+ }
+
+ public static class OutputSizeEvent {
+ public int width;
+ public int height;
+
+ public OutputSizeEvent(int width, int height) {
+ this.width = width;
+ this.height = height;
+ }
+ }
+}
diff --git a/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/camera/MobilenetResultCallback.java b/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/camera/MobilenetResultCallback.java
new file mode 100644
index 0000000000000000000000000000000000000000..b039d2e0fa9ad626b7d235180c4e867c5ba63f51
--- /dev/null
+++ b/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/camera/MobilenetResultCallback.java
@@ -0,0 +1,19 @@
+// Copyright 2018 Xiaomi, Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.xiaomi.mace.demo.camera;
+
+public interface MobilenetResultCallback {
+ void onMaceResult(float[] result, long costTime);
+}
diff --git a/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/result/InitData.java b/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/result/InitData.java
new file mode 100644
index 0000000000000000000000000000000000000000..5159f44f12caf220fe40b31ba9e9eb46203ebe43
--- /dev/null
+++ b/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/result/InitData.java
@@ -0,0 +1,100 @@
+// Copyright 2018 Xiaomi, Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.xiaomi.mace.demo.result;
+
+import android.os.Environment;
+
+import java.io.File;
+
+public class InitData {
+
+ public static final String[] DEVICES = new String[]{"CPU", "GPU"};
+ public static final String[] MODELS = new String[]{"mobilenet_v1", "mobilenet_v2"};
+
+ private String model;
+ private String device = "";
+ private int ompNumThreads;
+ private int cpuAffinityPolicy;
+ private int gpuPerfHint;
+ private int gpuPriorityHint;
+ private String kernelPath = "";
+
+ public InitData() {
+ model = MODELS[0];
+ ompNumThreads = 2;
+ cpuAffinityPolicy = 1;
+ gpuPerfHint = 3;
+ gpuPriorityHint = 3;
+ device = DEVICES[0];
+ kernelPath = Environment.getDownloadCacheDirectory().getAbsolutePath() + File.separator + "mace";
+
+ }
+
+ public String getModel() {
+ return model;
+ }
+
+ public void setModel(String model) {
+ this.model = model;
+ }
+
+ public String getDevice() {
+ return device;
+ }
+
+ public void setDevice(String device) {
+ this.device = device;
+ }
+
+ public int getOmpNumThreads() {
+ return ompNumThreads;
+ }
+
+ public void setOmpNumThreads(int ompNumThreads) {
+ this.ompNumThreads = ompNumThreads;
+ }
+
+ public int getCpuAffinityPolicy() {
+ return cpuAffinityPolicy;
+ }
+
+ public void setCpuAffinityPolicy(int cpuAffinityPolicy) {
+ this.cpuAffinityPolicy = cpuAffinityPolicy;
+ }
+
+ public int getGpuPerfHint() {
+ return gpuPerfHint;
+ }
+
+ public void setGpuPerfHint(int gpuPerfHint) {
+ this.gpuPerfHint = gpuPerfHint;
+ }
+
+ public int getGpuPriorityHint() {
+ return gpuPriorityHint;
+ }
+
+ public void setGpuPriorityHint(int gpuPriorityHint) {
+ this.gpuPriorityHint = gpuPriorityHint;
+ }
+
+ public String getKernelPath() {
+ return kernelPath;
+ }
+
+ public void setKernelPath(String kernelPath) {
+ this.kernelPath = kernelPath;
+ }
+}
diff --git a/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/result/LabelCache.java b/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/result/LabelCache.java
new file mode 100644
index 0000000000000000000000000000000000000000..e525cea33822cbfbddf9b8c9cbe7ba7e894828bf
--- /dev/null
+++ b/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/result/LabelCache.java
@@ -0,0 +1,90 @@
+// Copyright 2018 Xiaomi, Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.xiaomi.mace.demo.result;
+
+import android.content.res.AssetManager;
+import android.util.Log;
+
+import com.xiaomi.mace.demo.MaceApp;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class LabelCache {
+
+ private static LabelCache labelCache;
+ private LabelCache() {
+ readCacheLabelFromLocalFile();
+ }
+ private List floatList = new ArrayList<>();
+ private List resultLabel = new ArrayList<>();
+ private ResultData mResultData;
+
+ public static LabelCache instance() {
+ if (labelCache == null) {
+ synchronized (LabelCache.class) {
+ if (labelCache == null) {
+ labelCache = new LabelCache();
+ }
+ }
+ }
+ return labelCache;
+ }
+
+
+ private void readCacheLabelFromLocalFile() {
+ try {
+ AssetManager assetManager = MaceApp.app.getApplicationContext().getAssets();
+ BufferedReader reader = new BufferedReader(new InputStreamReader(assetManager.open("cacheLabel.txt")));
+ String readLine = null;
+ while ((readLine = reader.readLine()) != null) {
+ Log.d("labelCache", "readLine = " + readLine);
+ resultLabel.add(readLine);
+ }
+ reader.close();
+ } catch (Exception e) {
+ Log.e("labelCache", "error " + e);
+ }
+ }
+
+ public ResultData getResultFirst(float[] floats) {
+ floatList.clear();
+ for (float f : floats) {
+ floatList.add(f);
+ }
+ float maxResult = Collections.max(floatList);
+
+ int indexResult = floatList.indexOf(maxResult);
+ if (indexResult < resultLabel.size()) {
+ String result = resultLabel.get(indexResult);
+ if (result != null) {
+ if (mResultData == null) {
+ mResultData = new ResultData(result, maxResult);
+ } else {
+ mResultData.updateData(result, maxResult);
+ }
+ return mResultData;
+ }
+ }
+ return null;
+
+
+ }
+
+
+}
diff --git a/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/result/ResultData.java b/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/result/ResultData.java
new file mode 100644
index 0000000000000000000000000000000000000000..3474465362b1a1333f7419ddbcacc04b287fb0ba
--- /dev/null
+++ b/mace/examples/android/app/src/main/java/com/xiaomi/mace/demo/result/ResultData.java
@@ -0,0 +1,35 @@
+// Copyright 2018 Xiaomi, Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.xiaomi.mace.demo.result;
+
+public class ResultData {
+ public String name;
+ public float probability;
+ public long costTime; //毫秒
+
+ public ResultData(String name, float probability) {
+ this.name = name;
+ this.probability = probability;
+ }
+
+ public ResultData(String name) {
+ this.name = name;
+ }
+
+ public void updateData(String name, float probability) {
+ this.name = name;
+ this.probability = probability;
+ }
+}
diff --git a/mace/examples/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/mace/examples/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
new file mode 100644
index 0000000000000000000000000000000000000000..c7bd21dbd86990cde81fea8abd3bf904b4546749
--- /dev/null
+++ b/mace/examples/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/mace/examples/android/app/src/main/res/drawable/ic_launcher_background.xml b/mace/examples/android/app/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 0000000000000000000000000000000000000000..d5fccc538c179838bfdce779c26eebb4fa0b5ce9
--- /dev/null
+++ b/mace/examples/android/app/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,170 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/mace/examples/android/app/src/main/res/layout/activity_camera.xml b/mace/examples/android/app/src/main/res/layout/activity_camera.xml
new file mode 100644
index 0000000000000000000000000000000000000000..14f5731061dcee1ecfd10823b6a8795ceeceb6c3
--- /dev/null
+++ b/mace/examples/android/app/src/main/res/layout/activity_camera.xml
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/mace/examples/android/app/src/main/res/layout/layout_dialog.xml b/mace/examples/android/app/src/main/res/layout/layout_dialog.xml
new file mode 100644
index 0000000000000000000000000000000000000000..6fac0d7bd03c26021c70d31425d157038352988f
--- /dev/null
+++ b/mace/examples/android/app/src/main/res/layout/layout_dialog.xml
@@ -0,0 +1,10 @@
+
+
+
+
\ No newline at end of file
diff --git a/mace/examples/android/app/src/main/res/layout/layout_item.xml b/mace/examples/android/app/src/main/res/layout/layout_item.xml
new file mode 100644
index 0000000000000000000000000000000000000000..54f8bfd8270ab3de3576baa20ba99dd9603b97aa
--- /dev/null
+++ b/mace/examples/android/app/src/main/res/layout/layout_item.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
diff --git a/mace/examples/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/mace/examples/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 0000000000000000000000000000000000000000..eca70cfe52eac1ba66ba280a68ca7be8fcf88a16
--- /dev/null
+++ b/mace/examples/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/mace/examples/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/mace/examples/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 0000000000000000000000000000000000000000..eca70cfe52eac1ba66ba280a68ca7be8fcf88a16
--- /dev/null
+++ b/mace/examples/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/mace/examples/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/mace/examples/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000000000000000000000000000000000000..a2f5908281d070150700378b64a84c7db1f97aa1
Binary files /dev/null and b/mace/examples/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/mace/examples/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/mace/examples/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 0000000000000000000000000000000000000000..1b523998081149a985cef0cdf89045b9ed29964a
Binary files /dev/null and b/mace/examples/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ
diff --git a/mace/examples/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/mace/examples/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000000000000000000000000000000000000..ff10afd6e182edb2b1a63c8f984e9070d9f950ba
Binary files /dev/null and b/mace/examples/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/mace/examples/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/mace/examples/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 0000000000000000000000000000000000000000..115a4c768a20c9e13185c17043f4c4d12dd4632a
Binary files /dev/null and b/mace/examples/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ
diff --git a/mace/examples/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/mace/examples/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000000000000000000000000000000000000..dcd3cd8083358269d6ed7894726283bb9bcbbfea
Binary files /dev/null and b/mace/examples/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/mace/examples/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/mace/examples/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 0000000000000000000000000000000000000000..459ca609d3ae0d3943ab44cdc27feef9256dc6d7
Binary files /dev/null and b/mace/examples/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ
diff --git a/mace/examples/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/mace/examples/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000000000000000000000000000000000000..8ca12fe024be86e868d14e91120a6902f8e88ac6
Binary files /dev/null and b/mace/examples/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/mace/examples/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/mace/examples/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000000000000000000000000000000000000..8e19b410a1b15ff180f3dacac19395fe3046cdec
Binary files /dev/null and b/mace/examples/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ
diff --git a/mace/examples/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/mace/examples/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000000000000000000000000000000000000..b824ebdd48db917eea2e67a82260a100371f8a24
Binary files /dev/null and b/mace/examples/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/mace/examples/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/mace/examples/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000000000000000000000000000000000000..4c19a13c239cb67b8a2134ddd5f325db1d2d5bee
Binary files /dev/null and b/mace/examples/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ
diff --git a/mace/examples/android/app/src/main/res/values/colors.xml b/mace/examples/android/app/src/main/res/values/colors.xml
new file mode 100644
index 0000000000000000000000000000000000000000..3ab3e9cbce07f7cdc941fc8ba424c05e83ed80f0
--- /dev/null
+++ b/mace/examples/android/app/src/main/res/values/colors.xml
@@ -0,0 +1,6 @@
+
+
+ #3F51B5
+ #303F9F
+ #FF4081
+
diff --git a/mace/examples/android/app/src/main/res/values/strings.xml b/mace/examples/android/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..4ce6d4753e8bda547b3f74c766bb9b105bb078f2
--- /dev/null
+++ b/mace/examples/android/app/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
+
+ 识物
+
diff --git a/mace/examples/android/app/src/main/res/values/styles.xml b/mace/examples/android/app/src/main/res/values/styles.xml
new file mode 100644
index 0000000000000000000000000000000000000000..0eb88fe3350eaa944c0c6fe7e949e1cab494e8e8
--- /dev/null
+++ b/mace/examples/android/app/src/main/res/values/styles.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
diff --git a/mace/examples/android/build.gradle b/mace/examples/android/build.gradle
new file mode 100644
index 0000000000000000000000000000000000000000..e6b32bc7884bb98a5024981d37fec787514b56c8
--- /dev/null
+++ b/mace/examples/android/build.gradle
@@ -0,0 +1,27 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+
+buildscript {
+
+ repositories {
+ google()
+ jcenter()
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:3.0.1'
+
+
+ // NOTE: Do not place your application dependencies here; they belong
+ // in the individual module build.gradle files
+ }
+}
+
+allprojects {
+ repositories {
+ google()
+ jcenter()
+ }
+}
+
+task clean(type: Delete) {
+ delete rootProject.buildDir
+}
diff --git a/mace/examples/android/gradle.properties b/mace/examples/android/gradle.properties
new file mode 100644
index 0000000000000000000000000000000000000000..7f50262cf4bb36bdcf86143333fa957e53a6d8bb
--- /dev/null
+++ b/mace/examples/android/gradle.properties
@@ -0,0 +1,18 @@
+# Project-wide Gradle settings.
+
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx1536m
+#android.useDeprecatedNdk=true
+
+# When configured, Gradle will run in incubating parallel model.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
diff --git a/mace/examples/android/gradle/wrapper/gradle-wrapper.jar b/mace/examples/android/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000000000000000000000000000000000000..13372aef5e24af05341d49695ee84e5f9b594659
Binary files /dev/null and b/mace/examples/android/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/mace/examples/android/gradle/wrapper/gradle-wrapper.properties b/mace/examples/android/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000000000000000000000000000000000000..810d36ffaadac7c0ed9b1df9de730b53998ee86c
--- /dev/null
+++ b/mace/examples/android/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Wed May 02 11:53:35 CST 2018
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
diff --git a/mace/examples/android/gradlew b/mace/examples/android/gradlew
new file mode 100755
index 0000000000000000000000000000000000000000..9d82f78915133e1c35a6ea51252590fb38efac2f
--- /dev/null
+++ b/mace/examples/android/gradlew
@@ -0,0 +1,160 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+ echo "$*"
+}
+
+die ( ) {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+esac
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+ JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/mace/examples/android/gradlew.bat b/mace/examples/android/gradlew.bat
new file mode 100644
index 0000000000000000000000000000000000000000..aec99730b4e8fcd90b57a0e8e01544fea7c31a89
--- /dev/null
+++ b/mace/examples/android/gradlew.bat
@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/mace/examples/android/macelibrary/.gitignore b/mace/examples/android/macelibrary/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..796b96d1c402326528b4ba3c12ee9d92d0e212e9
--- /dev/null
+++ b/mace/examples/android/macelibrary/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/mace/examples/android/macelibrary/CMakeLists.txt b/mace/examples/android/macelibrary/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..c34451975b2a5867769603f211a6d5df53e84767
--- /dev/null
+++ b/mace/examples/android/macelibrary/CMakeLists.txt
@@ -0,0 +1,60 @@
+# For more information about using CMake with Android Studio, read the
+# documentation: https://d.android.com/studio/projects/add-native-code.html
+
+# Sets the minimum version of CMake required to build the native library.
+
+cmake_minimum_required(VERSION 3.4.1)
+
+# Creates and names a library, sets it as either STATIC
+# or SHARED, and provides the relative paths to its source code.
+# You can define multiple libraries, and CMake builds them for you.
+# Gradle automatically packages shared libraries with your APK.
+
+#set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/../app/libs/${ANDROID_ABI})
+
+include_directories(${CMAKE_SOURCE_DIR}/)
+file(GLOB static_file ${CMAKE_SOURCE_DIR}/../../../build/demo_app_models/lib/arm64-v8a/*.a)
+
+MESSAGE(STATUS "FILE URL = ${CMAKE_SOURCE_DIR}")
+MESSAGE(STATUS "FILE URL = ${static_file}")
+
+foreach(fileStr ${static_file})
+ set(tmpstr ${fileStr})
+ MESSAGE(STATUS "FILE URL = ${tmpstr}")
+endforeach()
+
+add_library (mace_mobile_lib STATIC IMPORTED)
+set_target_properties(mace_mobile_lib PROPERTIES IMPORTED_LOCATION ${tmpstr})
+
+add_library( # Sets the name of the library.
+ mace_mobile_jni
+
+ # Sets the library as a shared library.
+ SHARED
+
+ # Provides a relative path to your source file(s).
+ src/main/cpp/image_classify.cc )
+
+# Searches for a specified prebuilt library and stores the path as a
+# variable. Because CMake includes system libraries in the search path by
+# default, you only need to specify the name of the public NDK library
+# you want to add. CMake verifies that the library exists before
+# completing its build.
+
+find_library( # Sets the name of the path variable.
+ log-lib
+
+ # Specifies the name of the NDK library that
+ # you want CMake to locate.
+ log )
+
+# Specifies libraries CMake should link to your target library. You
+# can link multiple libraries, such as libraries you define in this
+# build script, prebuilt third-party libraries, or system libraries.
+
+target_link_libraries( # Specifies the target library.
+ mace_mobile_jni
+ mace_mobile_lib
+ # Links the target library to the log library
+ # included in the NDK.
+ ${log-lib} )
\ No newline at end of file
diff --git a/mace/examples/android/macelibrary/build.gradle b/mace/examples/android/macelibrary/build.gradle
new file mode 100644
index 0000000000000000000000000000000000000000..1ee095f45af487c85b25c378700095ed7182d173
--- /dev/null
+++ b/mace/examples/android/macelibrary/build.gradle
@@ -0,0 +1,56 @@
+
+apply plugin: 'com.android.library'
+
+android {
+ compileSdkVersion 26
+
+ compileOptions {
+
+ }
+
+ defaultConfig {
+ minSdkVersion 23
+ targetSdkVersion 26
+ versionCode 1
+ versionName "1.0"
+
+ externalNativeBuild {
+ cmake {
+ cppFlags "-std=c++14 -fopenmp"
+ abiFilters "arm64-v8a"
+ }
+ }
+ }
+
+ externalNativeBuild {
+ cmake {
+ path "CMakeLists.txt"
+ }
+ }
+
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ }
+ }
+
+ sourceSets {
+ main {
+ jniLibs.srcDirs = ["src/main/jniLibs"]
+ jni.srcDirs = ['src/cpp']
+ }
+ }
+
+ task ndkClean(type: Delete) {
+ delete fileTree('.externalNativeBuild') {
+ exclude defaultConfig.ndk.abiFilters.collect { '**/' + it }
+ }
+ }
+ tasks.findByPath(':clean').dependsOn ndkClean
+}
+
+dependencies {
+ implementation fileTree(dir: 'libs', include: ['*.jar'])
+}
diff --git a/mace/examples/android/macelibrary/proguard-rules.pro b/mace/examples/android/macelibrary/proguard-rules.pro
new file mode 100644
index 0000000000000000000000000000000000000000..f1b424510da51fd82143bc74a0a801ae5a1e2fcd
--- /dev/null
+++ b/mace/examples/android/macelibrary/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/mace/examples/android/macelibrary/src/main/AndroidManifest.xml b/mace/examples/android/macelibrary/src/main/AndroidManifest.xml
new file mode 100644
index 0000000000000000000000000000000000000000..ec6016141909c2365cef56cc8e6735cf7c90e10d
--- /dev/null
+++ b/mace/examples/android/macelibrary/src/main/AndroidManifest.xml
@@ -0,0 +1,2 @@
+
diff --git a/mace/examples/android/macelibrary/src/main/cpp/image_classify.cc b/mace/examples/android/macelibrary/src/main/cpp/image_classify.cc
new file mode 100755
index 0000000000000000000000000000000000000000..1f4af4fb3df96f33fb80edd23e2b9179b81b8df0
--- /dev/null
+++ b/mace/examples/android/macelibrary/src/main/cpp/image_classify.cc
@@ -0,0 +1,220 @@
+// Copyright 2018 Xiaomi, Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/main/cpp/image_classify.h"
+
+#include
+#include
+
+#include
+#include
+#include