Android demo: read MultiBox priors from a txt file in Java rather than reading from a proto file in C++ code, in order to reduce code/build complexity.

New model file archive with corresponding changes has been uploaded to https://storage.googleapis.com/download.tensorflow.org/models/mobile_multibox_v1a.zip

Resolves #6670
Change: 144872035
diff --git a/WORKSPACE b/WORKSPACE
index e093151..a0c936a 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -34,8 +34,8 @@
 new_http_archive(
   name = "mobile_multibox",
   build_file = "models.BUILD",
-  url = "https://storage.googleapis.com/download.tensorflow.org/models/mobile_multibox_v1.zip",
-  sha256 = "b4c178fd6236dcf0a20d25d07c45eebe85281263978c6a6f1dfc49d75befc45f"
+  url = "https://storage.googleapis.com/download.tensorflow.org/models/mobile_multibox_v1a.zip",
+  sha256 = "859edcddf84dddb974c36c36cfc1f74555148e9c9213dedacf1d6b613ad52b96"
 )
 
 new_http_archive(
diff --git a/tensorflow/examples/android/BUILD b/tensorflow/examples/android/BUILD
index 0c1cea5..c795ba6 100644
--- a/tensorflow/examples/android/BUILD
+++ b/tensorflow/examples/android/BUILD
@@ -39,7 +39,6 @@
         "notap",
     ],
     deps = [
-        ":demo_proto_lib_cc",
         "//tensorflow/contrib/android:android_tensorflow_inference_jni",
         "//tensorflow/core:android_tensorflow_lib",
         LINKER_SCRIPT,
@@ -118,20 +117,3 @@
 )
 
 exports_files(["AndroidManifest.xml"])
-
-load(
-    "//tensorflow/core:platform/default/build_config.bzl",
-    "tf_proto_library",
-)
-
-tf_proto_library(
-    name = "demo_proto_lib",
-    srcs = glob(
-        ["**/*.proto"],
-    ),
-    cc_api_version = 2,
-    visibility = ["//visibility:public"],
-)
-
-# -----------------------------------------------------------------------------
-# Google-internal targets go here (must be at the end).
diff --git a/tensorflow/examples/android/jni/box_coder_jni.cc b/tensorflow/examples/android/jni/box_coder_jni.cc
deleted file mode 100644
index be85414..0000000
--- a/tensorflow/examples/android/jni/box_coder_jni.cc
+++ /dev/null
@@ -1,92 +0,0 @@
-/* Copyright 2016 The TensorFlow Authors. 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.
-==============================================================================*/
-
-// This file loads the box coder mappings.
-
-#include <android/asset_manager.h>
-#include <android/asset_manager_jni.h>
-#include <android/bitmap.h>
-
-#include <jni.h>
-#include <pthread.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <map>
-#include <queue>
-#include <sstream>
-#include <string>
-
-#include "tensorflow/contrib/android/jni/jni_utils.h"
-#include "tensorflow/core/platform/env.h"
-#include "tensorflow/core/platform/types.h"
-
-#include "tensorflow/examples/android/proto/box_coder.pb.h"
-
-#define TENSORFLOW_METHOD(METHOD_NAME) \
-  Java_org_tensorflow_demo_TensorFlowMultiBoxDetector_##METHOD_NAME  // NOLINT
-
-#ifdef __cplusplus
-extern "C" {
-#endif  // __cplusplus
-
-JNIEXPORT void JNICALL TENSORFLOW_METHOD(loadCoderOptions)(
-    JNIEnv* env, jobject thiz, jobject java_asset_manager, jstring location,
-    jfloatArray priors);
-
-#ifdef __cplusplus
-}  // extern "C"
-#endif  // __cplusplus
-
-JNIEXPORT void JNICALL TENSORFLOW_METHOD(loadCoderOptions)(
-    JNIEnv* env, jobject thiz, jobject java_asset_manager, jstring location,
-    jfloatArray priors) {
-  AAssetManager* const asset_manager =
-      AAssetManager_fromJava(env, java_asset_manager);
-  LOG(INFO) << "Acquired AssetManager.";
-
-  const std::string location_str = GetString(env, location);
-
-  org_tensorflow_demo::MultiBoxCoderOptions multi_options;
-
-  LOG(INFO) << "Reading file to proto: " << location_str;
-  ReadFileToProtoOrDie(asset_manager, location_str.c_str(), &multi_options);
-
-  LOG(INFO) << "Read file. " << multi_options.box_coder_size() << " entries.";
-
-  jboolean iCopied = JNI_FALSE;
-  jfloat* values = env->GetFloatArrayElements(priors, &iCopied);
-
-  const int array_length = env->GetArrayLength(priors);
-  LOG(INFO) << "Array length: " << array_length
-            << " (/8 = " << (array_length / 8) << ")";
-  CHECK_EQ(array_length % 8, 0);
-
-  const int num_items =
-      std::min(array_length / 8, multi_options.box_coder_size());
-
-  for (int i = 0; i < num_items; ++i) {
-    const org_tensorflow_demo::BoxCoderOptions& options =
-        multi_options.box_coder(i);
-
-    for (int j = 0; j < 4; ++j) {
-      const org_tensorflow_demo::BoxCoderPrior& prior = options.priors(j);
-      values[i * 8 + j * 2] = prior.mean();
-      values[i * 8 + j * 2 + 1] = prior.stddev();
-    }
-  }
-  env->ReleaseFloatArrayElements(priors, values, 0);
-
-  LOG(INFO) << "Read " << num_items << " options";
-}
diff --git a/tensorflow/examples/android/proto/box_coder.proto b/tensorflow/examples/android/proto/box_coder.proto
deleted file mode 100644
index 8576294..0000000
--- a/tensorflow/examples/android/proto/box_coder.proto
+++ /dev/null
@@ -1,42 +0,0 @@
-syntax = "proto2";
-
-package org_tensorflow_demo;
-
-// Prior for a single feature (like minimum x coordinate, width, area, etc.)
-message BoxCoderPrior {
-  optional float mean = 1 [default = 0.0];
-  optional float stddev = 2 [default = 1.0];
-};
-
-// Box encoding/decoding configuration for a single box.
-message BoxCoderOptions {
-  // Number of priors must match the number of values used to encoded
-  // values which is derived from the use_... flags below.
-  repeated BoxCoderPrior priors = 1;
-
-  // Minimum/maximum X/Y of the four corners are used as features.
-  // Order: MinX, MinY, MaxX, MaxY.
-  // Number of values: 4.
-  optional bool use_corners = 2 [default = true];
-
-  // Width and height of the box in this order.
-  // Number of values: 2.
-  optional bool use_width_height = 3 [default = false];
-
-  // Coordinates of the center of the box.
-  // Order: X, Y.
-  // Number of values: 2.
-  optional bool use_center = 4 [default = false];
-
-  // Area of the box.
-  // Number of values: 1.
-  optional bool use_area = 5 [default = false];
-};
-
-// Options for MultiBoxCoder which is a encoder/decoder for a fixed number of
-// boxes.
-// A list of BoxCoderOptions that allows for storing multiple box coder options
-// in a single file.
-message MultiBoxCoderOptions {
-  repeated BoxCoderOptions box_coder = 1;
-};
diff --git a/tensorflow/examples/android/src/org/tensorflow/demo/DetectorActivity.java b/tensorflow/examples/android/src/org/tensorflow/demo/DetectorActivity.java
index 9ab5a71..d06f2d3 100644
--- a/tensorflow/examples/android/src/org/tensorflow/demo/DetectorActivity.java
+++ b/tensorflow/examples/android/src/org/tensorflow/demo/DetectorActivity.java
@@ -60,7 +60,7 @@
   private static final String MB_OUTPUT_NAMES = "output_locations/Reshape,output_scores/Reshape";
   private static final String MB_MODEL_FILE = "file:///android_asset/multibox_model.pb";
   private static final String MB_LOCATION_FILE =
-      "file:///android_asset/multibox_location_priors.pb";
+      "file:///android_asset/multibox_location_priors.txt";
 
   // Configuration values for tiny-yolo-voc. Note that the graph is not included with TensorFlow and
   // must be manually placed in the assets/ directory by the user.
diff --git a/tensorflow/examples/android/src/org/tensorflow/demo/TensorFlowMultiBoxDetector.java b/tensorflow/examples/android/src/org/tensorflow/demo/TensorFlowMultiBoxDetector.java
index e438956..34a4361 100644
--- a/tensorflow/examples/android/src/org/tensorflow/demo/TensorFlowMultiBoxDetector.java
+++ b/tensorflow/examples/android/src/org/tensorflow/demo/TensorFlowMultiBoxDetector.java
@@ -19,10 +19,16 @@
 import android.graphics.Bitmap;
 import android.graphics.RectF;
 import android.os.Trace;
+import java.io.BufferedReader;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
 import java.util.ArrayList;
 import java.util.Comparator;
 import java.util.List;
 import java.util.PriorityQueue;
+import java.util.StringTokenizer;
 import org.tensorflow.contrib.android.TensorFlowInferenceInterface;
 import org.tensorflow.demo.env.Logger;
 
@@ -80,7 +86,7 @@
       final float imageStd,
       final String inputName,
       final String outputName) {
-    TensorFlowMultiBoxDetector d = new TensorFlowMultiBoxDetector();
+    final TensorFlowMultiBoxDetector d = new TensorFlowMultiBoxDetector();
     d.inputName = inputName;
     d.inputSize = inputSize;
     d.imageMean = imageMean;
@@ -89,7 +95,11 @@
 
     d.boxPriors = new float[numLocations * 8];
 
-    d.loadCoderOptions(assetManager, locationFilename, d.boxPriors);
+    try {
+      d.loadCoderOptions(assetManager, locationFilename, d.boxPriors);
+    } catch (final IOException e) {
+      throw new RuntimeException("Error initializing box priors from " + locationFilename);
+    }
 
     // Pre-allocate buffers.
     d.outputNames = outputName.split(",");
@@ -110,9 +120,42 @@
 
   private TensorFlowMultiBoxDetector() {}
 
-  // Load BoxCoderOptions from native code.
-  private native void loadCoderOptions(
-      AssetManager assetManager, String locationFilename, float[] boxPriors);
+  private void loadCoderOptions(
+      final AssetManager assetManager, final String locationFilename, final float[] boxPriors)
+      throws IOException {
+    // Try to be intelligent about opening from assets or sdcard depending on prefix.
+    final String assetPrefix = "file:///android_asset/";
+    InputStream is;
+    if (locationFilename.startsWith(assetPrefix)) {
+      is = assetManager.open(locationFilename.split(assetPrefix)[1]);
+    } else {
+      is = new FileInputStream(locationFilename);
+    }
+
+    // Read values. Number of values per line doesn't matter, as long as they are separated
+    // by commas and/or whitespace, and there are exactly numLocations * 8 values total.
+    // Values are in the order mean, std for each consecutive corner of each box, for a total of 8
+    // per location.
+    final BufferedReader reader = new BufferedReader(new InputStreamReader(is));
+    int priorIndex = 0;
+    String line;
+    while ((line = reader.readLine()) != null) {
+      final StringTokenizer st = new StringTokenizer(line, ", ");
+      while (st.hasMoreTokens()) {
+        final String token = st.nextToken();
+        try {
+          final float number = Float.parseFloat(token);
+          boxPriors[priorIndex++] = number;
+        } catch (final NumberFormatException e) {
+          // Silently ignore.
+        }
+      }
+    }
+    if (priorIndex != boxPriors.length) {
+      throw new RuntimeException(
+          "BoxPrior length mismatch: " + priorIndex + " vs " + boxPriors.length);
+    }
+  }
 
   private float[] decodeLocationsEncoding(final float[] locationEncoding) {
     final float[] locations = new float[locationEncoding.length];
@@ -216,7 +259,7 @@
   }
 
   @Override
-  public void enableStatLogging(boolean debug) {
+  public void enableStatLogging(final boolean debug) {
     inferenceInterface.enableStatLogging(debug);
   }