public class CustomUtil {

  private static final String TAG = CustomUtil.class.getSimpleName();

  private static CustomUtil sInstance = null;
  private Context mContext;
  RenderScript mRenderScript;
  ScriptIntrinsicYuvToRGB mIntrinsicYuvToRGB;

  private CustomUtil(Context context) {
    mContext = context;
    mRenderScript = RenderScript.create(context);
    mIntrinsicYuvToRGB = ScriptIntrinsicYuvToRGB.create(mRenderScript, Element.U8_4(mRenderScript));
  }

  public static CustomUtil getInstance(Context context) {
    if (sInstance == null) {
      sInstance = new CustomUtil(context);
    }
    return sInstance;
  }

  public static String getString(Context context, int resId) {
    return context.getString(resId);
  }

  public static boolean isLandScape(Context context) {
    Configuration mConfiguration = context.getResources().getConfiguration(); //获取设置的配置信息
    int ori = mConfiguration.orientation; //获取屏幕方向

    if (ori == mConfiguration.ORIENTATION_LANDSCAPE) {
      //横屏
      return true;
    } else if (ori == mConfiguration.ORIENTATION_PORTRAIT) {
      //竖屏
      return false;
    }
    return false;
  }

  /**
   * 工具方法 base64编码
   *
   * @param bitmap
   * @return
   */
  public static String bitmapToBase64(Bitmap bitmap) {
    ByteArrayOutputStream bStream = new ByteArrayOutputStream();
    bitmap.compress(Bitmap.CompressFormat.JPEG, 80, bStream);
    return Base64.encodeToString(bStream.toByteArray(), 0);
  }

  /**
   * 采集照片
   *
   * @param data
   * @return
   */
  public Bitmap collectBitmap(byte[] data, Camera camera) {
    Bitmap collectBitmap = null;
    Camera.Parameters parameters = camera.getParameters();
    int imageFormat = parameters.getPreviewFormat();
    if (imageFormat == ImageFormat.NV21) {
      int w = parameters.getPreviewSize().width;
      int h = parameters.getPreviewSize().height;
      Rect rect = new Rect(0, 0, w, h);
      YuvImage img = new YuvImage(data, ImageFormat.NV21, w, h, null);
      ByteArrayOutputStream os = new ByteArrayOutputStream(
          data.length);
      if (!img.compressToJpeg(new Rect(0, 0, w, h), 100, os)) {
        return null;
      }
      File dirFile = new File(
          Environment.getExternalStorageDirectory() + "/DCIM/");
      if (!dirFile.exists()) {
        dirFile.mkdir();
      }
      byte[] tmp = os.toByteArray();
      Bitmap bmp = BitmapFactory.decodeByteArray(tmp, 0, tmp.length);
      Bitmap bitmap1 = getPicOrientation(bmp, 90, 0);
      collectBitmap = bitmap1;
    }
    return collectBitmap;
  }

  /**
   * 采集照片
   *
   * @param data
   * @return
   */
  public Bitmap collectBitmap(byte[] data, int width, int height, int orientation, int cameraId) {
    Logs.i(TAG, "orientation:" + orientation);
//        orientation = 0;

    Bitmap collectBitmap = null;
    Rect rect = new Rect(0, 0, width, height);
    YuvImage img = new YuvImage(data, ImageFormat.NV21, width, height, null);
    ByteArrayOutputStream os = new ByteArrayOutputStream(
        data.length);
    if (!img.compressToJpeg(new Rect(0, 0, width, height), 100, os)) {
      return null;
    }
    byte[] tmp = os.toByteArray();
    Bitmap bmp = BitmapFactory.decodeByteArray(tmp, 0, tmp.length);
    Bitmap bitmap1 = getPicOrientation(bmp, orientation, cameraId);
    collectBitmap = bitmap1;
    return collectBitmap;
  }

  public Bitmap rsYuvToRgb(byte[] data, int width, int height, int orientation, int cameraId) {
    Type.Builder yuvType = new Type.Builder(mRenderScript, Element.U8(mRenderScript)).setX(data.length);
    Allocation in = Allocation.createTyped(mRenderScript, yuvType.create(), Allocation.USAGE_SCRIPT);

    Type.Builder rgbaType = new Type.Builder(mRenderScript, Element.RGBA_8888(mRenderScript)).setX(width).setY(height);
    Allocation out = Allocation.createTyped(mRenderScript, rgbaType.create(), Allocation.USAGE_SCRIPT);

    in.copyFrom(data);

    mIntrinsicYuvToRGB.setInput(in);
    mIntrinsicYuvToRGB.forEach(out);

    Bitmap temp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
    out.copyTo(temp);

    Bitmap outBitmap = getPicOrientation(temp, orientation, cameraId);
    return outBitmap;
  }

  public void writeBitmapToDisk(Bitmap bitmap, String filePath) {
    FileUtils.makeDirs(filePath);
    FileOutputStream out = null;
    try {
      out = new FileOutputStream(filePath);
      bitmap.compress(Bitmap.CompressFormat.JPEG, 80, out);
      out.flush();
    } catch (IOException e) {
      e.printStackTrace();
    } finally {
      try {
        out.close();
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
  }

  private Bitmap getPicOrientation(Bitmap bmp, int orientation, int cameraId) {
    Camera.CameraInfo info =
        new Camera.CameraInfo();
    Camera.getCameraInfo(cameraId, info);

    Log.i(TAG, "orientation:" + info.orientation);
    Matrix matrix = new Matrix();
    if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
      switch (orientation) {
        case 90:
          matrix.preRotate(-90f);
          break;
        case 0:
          break;
        case 270:
          matrix.preRotate(270f);
          break;
        case 180:
          matrix.preRotate(180f);
          break;
      }
    } else {
      switch (orientation) {
        case 90:
          matrix.preRotate(90f);
          break;
        case 0:
          break;
        case 270:
          matrix.preRotate(270f);
          break;
        case 180:
          matrix.preRotate(180f);
          break;
      }
    }

    // 旋转图片

    bmp = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(),
        matrix, true);
    return bmp;
  }
} public final class Logs {
  private static final String TAG_CONTENT_PRINT = "%s:%s.%s:%d";
  private static boolean sIsLogEnabled = true;// 是否打开LOG
  private static String sApplicationTag = "Logs";// LOG默认TAG

  private static StackTraceElement getCurrentStackTraceElement() {
    return Thread.currentThread().getStackTrace()[4];

  }

  // 打印LOG
  public static void trace() {
    if (sIsLogEnabled) {
      Log.d(sApplicationTag, getContent(getCurrentStackTraceElement()));
    }
  }

  // 获取LOG
  private static String getContent(StackTraceElement trace) {
    return String.format(TAG_CONTENT_PRINT, sApplicationTag,
        trace.getClassName(), trace.getMethodName(),
        trace.getLineNumber());
  }

  // 获取LOG
  private static String getContents(StackTraceElement trace) {
    return String.format("%s:%s:%d", sApplicationTag,
        trace.getMethodName(), trace.getLineNumber());
  }

  // 打印默认TAG的LOG
  public static void traceStack() {
    if (sIsLogEnabled) {
      traceStack(sApplicationTag, Log.ERROR);
    }
  }

  // 打印Log当前调用栈信息
  public static void traceStack(String tag, int priority) {

    if (sIsLogEnabled) {
      StackTraceElement[] stackTrace = Thread.currentThread()
          .getStackTrace();
      Log.println(priority, tag, stackTrace[4].toString());
      StringBuilder str = new StringBuilder();
      String prevClass = null;
      for (int i = 5; i < stackTrace.length; i++) {
        String className = stackTrace[i].getFileName();
        int idx = className.indexOf(".java");
        if (idx >= 0) {
          className = className.substring(0, idx);
        }
        if (prevClass == null || !prevClass.equals(className)) {

          str.append(className.substring(0, idx));

        }
        prevClass = className;
        str.append(".").append(stackTrace[i].getMethodName())
            .append(":").append(stackTrace[i].getLineNumber())
            .append("->");
      }
      Log.println(priority, tag, str.toString());
    }
  }

  public static void v(String msg) {
    if (sIsLogEnabled) {
      // String methodname=getCurrentStackTraceElement().getMethodName()
      // Log.d(sApplicationTag,
      // getContents(getCurrentStackTraceElement()).substring(getContent(getCurrentStackTraceElement()).getStringUnicodeLength()-12,getContent(getCurrentStackTraceElement()).getStringUnicodeLength())+">"+msg);
      Log.v(sApplicationTag, getContents(getCurrentStackTraceElement())
          + ">" + msg);
    }
  }

  // 指定TAG和指定内容的方法
  public static void d(String tag, String msg) {
    if (sIsLogEnabled) {
      Log.d(tag, getContent(getCurrentStackTraceElement()) + ">" + msg);
    }
  }

  // 默认TAG和制定内容的方法
  public static void ds(String msg) {
    if (sIsLogEnabled) {
      Log.d(sApplicationTag, getContent(getCurrentStackTraceElement())
          + ">" + msg);
    }
  }

  public static void d(String msg) {
    if (sIsLogEnabled) {
      // String methodname=getCurrentStackTraceElement().getMethodName()
      // Log.d(sApplicationTag,
      // getContents(getCurrentStackTraceElement()).substring(getContent(getCurrentStackTraceElement()).getStringUnicodeLength()-12,getContent(getCurrentStackTraceElement()).getStringUnicodeLength())+">"+msg);
      Log.d(sApplicationTag, getContents(getCurrentStackTraceElement())
          + ">" + msg);
    }
  }

  // 下面的定义和上面方法相同，可以定义不同等级的Debugger
  public static void i(String tag, String msg) {
    if (sIsLogEnabled) {
      Log.i(tag, getContent(getCurrentStackTraceElement()) + ">" + msg);
    }
  }

  public static void d(String message, Object... args) {
    if (sIsLogEnabled) {
      d(String.format(message, args));
    }
  }

  public static void w(String tag, String msg) {
    if (sIsLogEnabled) {
      Log.w(tag, getContent(getCurrentStackTraceElement()) + ">" + msg);
    }
  }

  public static void e(String tag, String msg) {
    if (sIsLogEnabled) {
      Log.e(tag, getContent(getCurrentStackTraceElement()) + ">" + msg);
    }
  }

  // 默认TAG和制定内容的方法
  public static void i(String msg) {
    if (sIsLogEnabled) {
      Log.i(sApplicationTag, getContent(getCurrentStackTraceElement())
          + ">" + msg);
    }
  }

  // 默认TAG和制定内容的方法
  public static void w(String msg) {
    if (sIsLogEnabled) {
      Log.w(sApplicationTag, getContent(getCurrentStackTraceElement())
          + ">" + msg);
    }
  }

  // 默认TAG和制定内容的方法
  public static void e(String msg) {
    if (sIsLogEnabled) {
      Log.e(sApplicationTag, getContent(getCurrentStackTraceElement())
          + "\n>" + msg);
      // Log.e(sApplicationTag,
      // Thread.currentThread().getStackTrace()[2].getClassName());
      // Log.e(sApplicationTag,
      // Thread.currentThread().getStackTrace()[2].getMethodName());

    }
  }

  public static void e(Exception exception) {
    if (sIsLogEnabled) {
      Log.e(sApplicationTag, getContent(getCurrentStackTraceElement())
          + "\n>" + exception.getMessage());
      // Log.e(sApplicationTag,
      // Thread.currentThread().getStackTrace()[2].getClassName());
      // Log.e(sApplicationTag,
      // Thread.currentThread().getStackTrace()[2].getMethodName());
      exception.printStackTrace();
    }
  }

  public static void e(Exception exception, String string) {
    if (sIsLogEnabled) {
      Log.e(sApplicationTag,
          getContent(getCurrentStackTraceElement()) + "\n>"
              + exception.getMessage() + "\n>"
              + exception.getStackTrace() + "   " + string);
      // Log.e(sApplicationTag,
      // Thread.currentThread().getStackTrace()[2].getClassName());
      // Log.e(sApplicationTag,
      // Thread.currentThread().getStackTrace()[2].getMethodName());
      exception.printStackTrace();
    }
  }

  public static void e(String string, Exception exception) {
    if (sIsLogEnabled) {
      Log.e(sApplicationTag,
          getContent(getCurrentStackTraceElement()) + "\n>"
              + exception.getMessage() + "\n>"
              + exception.getStackTrace() + "   " + string);
      // Log.e(sApplicationTag,
      // Thread.currentThread().getStackTrace()[2].getClassName());
      // Log.e(sApplicationTag,
      // Thread.currentThread().getStackTrace()[2].getMethodName());
      exception.printStackTrace();
    }
  }

  public static void e(String tag, String message, Exception exception) {
    if (sIsLogEnabled) {
      Log.e(tag,
          getContent(getCurrentStackTraceElement()) + "\n>"
              + exception.getMessage() + "\n>"
              + exception.getStackTrace() + "   " + message);
      // Log.e(sApplicationTag,
      // Thread.currentThread().getStackTrace()[2].getClassName());
      // Log.e(sApplicationTag,
      // Thread.currentThread().getStackTrace()[2].getMethodName());
      exception.printStackTrace();
    }
  }

  public static boolean issIsLogEnabled() {
    return sIsLogEnabled;
  }

  public static void setsIsLogEnabled(boolean sIsLogEnabled) {
    Logs.sIsLogEnabled = sIsLogEnabled;
  }

  public static String getsApplicationTag() {
    return sApplicationTag;
  }

  public static void setsApplicationTag(String sApplicationTag) {
    Logs.sApplicationTag = sApplicationTag;
  }

  public static String getTagContentPrint() {
    return TAG_CONTENT_PRINT;
  }
} public class MeasureUtil {

  private static final String TAG = "MeasureUtil";

  public static int[] getScreenSize(Context activity) {
    // 获取屏幕密度（方法2）
    DisplayMetrics dm = new DisplayMetrics();
    Log.d(TAG, "activity" + activity);
    dm = activity.getResources().getDisplayMetrics();
    float density = dm.density; // 屏幕密度（像素比例：0.75/1.0/1.5/2.0）
    int densityDPI = dm.densityDpi; // 屏幕密度（每寸像素：120/160/240/320）
    float xdpi = dm.xdpi;
    float ydpi = dm.ydpi;
    int screenWidth = dm.widthPixels; // 屏幕宽（像素，如：480px）
    int screenHeight = dm.heightPixels; // 屏幕高（像素，如：800px）
    int[] screens = {screenWidth, screenHeight};
    return screens;
  }

} public class SnackBarUtils {

  public static void show(View view, int resId) {
    if (view == null)
      return;
    Snackbar.make(view, resId, Snackbar.LENGTH_SHORT).show();
  }

  public static void show(View view, String text) {
    if (view == null)
      return;
    Snackbar.make(view, text, Snackbar.LENGTH_SHORT).show();
  }

  public static void show(View view, String text, int colorId) {
    if (view == null)
      return;
    Snackbar snackbar = getSnackBar(view, text, colorId);
    snackbar.setActionTextColor(colorId);
    snackbar.show();
  }

  public static void show(View view, int resId, int colorId) {
    if (view == null)
      return;
    Snackbar snackbar = getSnackBar(view, resId, colorId);
    snackbar.setActionTextColor(colorId);
    snackbar.show();
  }

  public static void showError(View view, int resId) {
    if (view == null)
      return;
    getSnackBar(view, resId, Color.parseColor("#ff443e")).show();
  }

  public static void showError(View view, String text) {
    if (view == null)
      return;
    getSnackBar(view, text, Color.parseColor("#ff443e")).show();
  }

  public static Snackbar getSnackBar(View view, int resId) {
    Snackbar snackbar = Snackbar.make(view, resId, Snackbar.LENGTH_SHORT);
    snackbar.setCallback(new Snackbar.Callback() {
      @Override
      public void onDismissed(Snackbar snackbar, int event) {
        super.onDismissed(snackbar, event);
      }
    });
    return Snackbar.make(view, resId, Snackbar.LENGTH_SHORT);
  }

  public static Snackbar getSnackBar(View view, String text) {
    return Snackbar.make(view, text, Snackbar.LENGTH_SHORT);
  }

  public static Snackbar getSnackBar(View view, int resId, int colorId) {
    Snackbar snackbar = Snackbar.make(view, resId, Snackbar.LENGTH_SHORT);
    setSnackbarBackground(snackbar, colorId);
    return snackbar;
  }

  public static Snackbar getSnackBar(View view, String text, int colorId) {
    Snackbar snackbar = Snackbar.make(view, text, Snackbar.LENGTH_SHORT);
    setSnackbarBackground(snackbar, colorId);
    return snackbar;
  }

  public static void setSnackbarBackground(Snackbar snackbar, int background) {
    View view = snackbar.getView();
    view.setBackgroundColor(background);
  }

  public static void setSnackbarMessageTextColor(Snackbar snackbar, int color) {
    View view = snackbar.getView();
    ((TextView) view.findViewById(R.id.snackbar_text)).setTextColor(color);
  }

} public class StringUtils {

  private StringUtils() {
    throw new AssertionError();
  }

  /**
   * is null or its length is 0 or it is made by space
   * <p>
   * <pre>
   * isBlank(null) = true;
   * isBlank(&quot;&quot;) = true;
   * isBlank(&quot;  &quot;) = true;
   * isBlank(&quot;a&quot;) = false;
   * isBlank(&quot;a &quot;) = false;
   * isBlank(&quot; a&quot;) = false;
   * isBlank(&quot;a b&quot;) = false;
   * </pre>
   *
   * @param str
   * @return if string is null or its size is 0 or it is made by space, return
   * true, else return false.
   */
  public static boolean isBlank(String str) {
    return (str == null || str.trim().length() == 0);
  }

  /**
   * is null or its length is 0
   * <p>
   * <pre>
   * isEmpty(null) = true;
   * isEmpty(&quot;&quot;) = true;
   * isEmpty(&quot;  &quot;) = false;
   * </pre>
   *
   * @param str
   * @return if string is null or its size is 0, return true, else return
   * false.
   */
  public static boolean isEmpty(CharSequence str) {
    return (str == null || str.length() == 0);
  }

  /**
   * compare two string
   *
   * @param actual
   * @param expected
   * @return
   * @see ObjectUtils#isEquals(Object, Object)
   */
  public static boolean isEquals(String actual, String expected) {
    return ObjectUtils.isEquals(actual, expected);
  }

  /**
   * get length of CharSequence
   * <p>
   * <pre>
   * length(null) = 0;
   * length(\"\") = 0;
   * length(\"abc\") = 3;
   * </pre>
   *
   * @param str
   * @return if str is null or empty, return 0, else return
   * {@link CharSequence#length()}.
   */
  public static int length(CharSequence str) {
    return str == null ? 0 : str.length();
  }

  /**
   * null Object to empty string
   * <p>
   * <pre>
   * nullStrToEmpty(null) = &quot;&quot;;
   * nullStrToEmpty(&quot;&quot;) = &quot;&quot;;
   * nullStrToEmpty(&quot;aa&quot;) = &quot;aa&quot;;
   * </pre>
   *
   * @param str
   * @return
   */
  public static String nullStrToEmpty(Object str) {
    return (str == null ? "" : (str instanceof String ? (String) str : str
        .toString()));
  }

  /**
   * capitalize first letter
   * <p>
   * <pre>
   * capitalizeFirstLetter(null)     =   null;
   * capitalizeFirstLetter("")       =   "";
   * capitalizeFirstLetter("2ab")    =   "2ab"
   * capitalizeFirstLetter("a")      =   "A"
   * capitalizeFirstLetter("ab")     =   "Ab"
   * capitalizeFirstLetter("Abc")    =   "Abc"
   * </pre>
   *
   * @param str
   * @return
   */
  public static String capitalizeFirstLetter(String str) {
    if (isEmpty(str)) {
      return str;
    }

    char c = str.charAt(0);
    return (!Character.isLetter(c) || Character.isUpperCase(c)) ? str
        : new StringBuilder(str.length())
        .append(Character.toUpperCase(c))
        .append(str.substring(1)).toString();
  }

  /**
   * encoded in utf-8
   * <p>
   * <pre>
   * utf8Encode(null)        =   null
   * utf8Encode("")          =   "";
   * utf8Encode("aa")        =   "aa";
   * utf8Encode("啊啊啊啊")   = "%E5%95%8A%E5%95%8A%E5%95%8A%E5%95%8A";
   * </pre>
   *
   * @param str
   * @return
   * @throws UnsupportedEncodingException if an error occurs
   */
  public static String utf8Encode(String str) {
    if (!isEmpty(str) && str.getBytes().length != str.length()) {
      try {
        return URLEncoder.encode(str, "UTF-8");
      } catch (UnsupportedEncodingException e) {
        throw new RuntimeException(
            "UnsupportedEncodingException occurred. ", e);
      }
    }
    return str;
  }

  /**
   * encoded in utf-8, if exception, return defultReturn
   *
   * @param str
   * @param defultReturn
   * @return
   */
  public static String utf8Encode(String str, String defultReturn) {
    if (!isEmpty(str) && str.getBytes().length != str.length()) {
      try {
        return URLEncoder.encode(str, "UTF-8");
      } catch (UnsupportedEncodingException e) {
        return defultReturn;
      }
    }
    return str;
  }

  /**
   * get innerHtml from href
   * <p>
   * <pre>
   * getHrefInnerHtml(null)                                  = ""
   * getHrefInnerHtml("")                                    = ""
   * getHrefInnerHtml("mp3")                                 = "mp3";
   * getHrefInnerHtml("&lt;a innerHtml&lt;/a&gt;")                    = "&lt;a innerHtml&lt;/a&gt;";
   * getHrefInnerHtml("&lt;a&gt;innerHtml&lt;/a&gt;")                    = "innerHtml";
   * getHrefInnerHtml("&lt;a&lt;a&gt;innerHtml&lt;/a&gt;")                    = "innerHtml";
   * getHrefInnerHtml("&lt;a href="baidu.com"&gt;innerHtml&lt;/a&gt;")               = "innerHtml";
   * getHrefInnerHtml("&lt;a href="baidu.com" title="baidu"&gt;innerHtml&lt;/a&gt;") = "innerHtml";
   * getHrefInnerHtml("   &lt;a&gt;innerHtml&lt;/a&gt;  ")                           = "innerHtml";
   * getHrefInnerHtml("&lt;a&gt;innerHtml&lt;/a&gt;&lt;/a&gt;")                      = "innerHtml";
   * getHrefInnerHtml("jack&lt;a&gt;innerHtml&lt;/a&gt;&lt;/a&gt;")                  = "innerHtml";
   * getHrefInnerHtml("&lt;a&gt;innerHtml1&lt;/a&gt;&lt;a&gt;innerHtml2&lt;/a&gt;")        = "innerHtml2";
   * </pre>
   *
   * @param href
   * @return <ul>
   * <li>if href is null, return ""</li>
   * <li>if not match regx, return source</li>
   * <li>return the last string that match regx</li>
   * </ul>
   */
  public static String getHrefInnerHtml(String href) {
    if (isEmpty(href)) {
      return "";
    }

    String hrefReg = ".*<[\\s]*a[\\s]*.*>(.+?)<[\\s]*/a[\\s]*>.*";
    Pattern hrefPattern = Pattern
        .compile(hrefReg, Pattern.CASE_INSENSITIVE);
    Matcher hrefMatcher = hrefPattern.matcher(href);
    if (hrefMatcher.matches()) {
      return hrefMatcher.group(1);
    }
    return href;
  }

  /**
   * process special char in html
   * <p>
   * <pre>
   * htmlEscapeCharsToString(null) = null;
   * htmlEscapeCharsToString("") = "";
   * htmlEscapeCharsToString("mp3") = "mp3";
   * htmlEscapeCharsToString("mp3&lt;") = "mp3<";
   * htmlEscapeCharsToString("mp3&gt;") = "mp3\>";
   * htmlEscapeCharsToString("mp3&amp;mp4") = "mp3&mp4";
   * htmlEscapeCharsToString("mp3&quot;mp4") = "mp3\"mp4";
   * htmlEscapeCharsToString("mp3&lt;&gt;&amp;&quot;mp4") = "mp3\<\>&\"mp4";
   * </pre>
   *
   * @param source
   * @return
   */
  public static String htmlEscapeCharsToString(String source) {
    return StringUtils.isEmpty(source) ? source : source
        .replaceAll("&lt;", "<").replaceAll("&gt;", ">")
        .replaceAll("&amp;", "&").replaceAll("&quot;", "\"");
  }

  /**
   * transform half width char to full width char
   * <p>
   * <pre>
   * fullWidthToHalfWidth(null) = null;
   * fullWidthToHalfWidth("") = "";
   * fullWidthToHalfWidth(new String(new char[] {12288})) = " ";
   * fullWidthToHalfWidth("！＂＃＄％＆) = "!\"#$%&";
   * </pre>
   *
   * @param s
   * @return
   */
  public static String fullWidthToHalfWidth(String s) {
    if (isEmpty(s)) {
      return s;
    }

    char[] source = s.toCharArray();
    for (int i = 0; i < source.length; i++) {
      if (source[i] == 12288) {
        source[i] = ' ';
        // } else if (source[i] == 12290) {
        // source[i] = '.';
      } else if (source[i] >= 65281 && source[i] <= 65374) {
        source[i] = (char) (source[i] - 65248);
      } else {
        source[i] = source[i];
      }
    }
    return new String(source);
  }

  /**
   * transform full width char to half width char
   * <p>
   * <pre>
   * halfWidthToFullWidth(null) = null;
   * halfWidthToFullWidth("") = "";
   * halfWidthToFullWidth(" ") = new String(new char[] {12288});
   * halfWidthToFullWidth("!\"#$%&) = "！＂＃＄％＆";
   * </pre>
   *
   * @param s
   * @return
   */
  public static String halfWidthToFullWidth(String s) {
    if (isEmpty(s)) {
      return s;
    }

    char[] source = s.toCharArray();
    for (int i = 0; i < source.length; i++) {
      if (source[i] == ' ') {
        source[i] = (char) 12288;
        // } else if (source[i] == '.') {
        // source[i] = (char)12290;
      } else if (source[i] >= 33 && source[i] <= 126) {
        source[i] = (char) (source[i] + 65248);
      } else {
        source[i] = source[i];
      }
    }
    return new String(source);
  }

  public static boolean isZero(String s) {
    return isEquals("0", s);
  }

  public static int parseStringToInt(String s) {
    if (isBlank(s)) {
      return 0;
    }
    return Integer.parseInt(s);
  }

  @SuppressLint("SimpleDateFormat")
  @SuppressWarnings("deprecation")
  public static String dateToString(String s) {
    if (StringUtils.isBlank(s)) {
      return "";
    }
    s = s.substring(0, 10);
    Logs.d(s);
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
    Date date = null;
    Calendar calendar = Calendar.getInstance();
    try {
      date = sdf.parse(s);
      Logs.d("month:" + date.getMonth() + "");
      calendar.setTime(date);
    } catch (ParseException e) {
      e.printStackTrace();
      return "";
    }

    return calendar.get(Calendar.YEAR) + "年"
        + (calendar.get(Calendar.MONTH) + 1) + "月"
        + calendar.get(Calendar.DATE) + "日";
  }

  public static String dateSubString(String s) {
    if (StringUtils.isBlank(s)) {
      return "";
    }
    s = s.substring(0, 10);
    return s;
  }
} public class CameraSurfaceView extends SurfaceView implements SurfaceHolder.Callback, IConstants {

  private static final String TAG = CameraSurfaceView.class.getSimpleName();

  private boolean hasSurface; // 是否存在摄像头显示层
  private boolean isPortrait = true;
  private Context mContext;
  private SurfaceHolder mSurfaceHolder;
  private CameraManager mCameraManager;
  private BaseCameraHandler handler; // 这个是解码的回调句柄
  private int mCameraId = 1;
  private FaceCallback mFaceCallback;

  public CameraSurfaceView(Context context) {
    super(context);
    init(context);
  }

  public CameraSurfaceView(Context context, AttributeSet attrs) {
    super(context, attrs);
    init(context);
  }

  private void init(Context context) {
    this.mContext = context;
    mSurfaceHolder = getHolder();
    mSurfaceHolder.setFormat(PixelFormat.TRANSPARENT);//translucent半透明 transparent透明
    mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    mSurfaceHolder.addCallback(this);
    mCameraManager = CameraManager.newInstance(context, this);
    mCameraManager.setManualCameraId(mCameraId);
    initOrientation();
  }

  public int getCameraId() {
    return mCameraId;
  }

  public void setCameraId(int cameraId) {
    mCameraId = cameraId;
    mCameraManager.setManualCameraId(mCameraId);
  }

  private void initOrientation() {
  }

  public void setIsPortrait(boolean isPortrait) {
    this.isPortrait = isPortrait;
  }

  @Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    Log.i(TAG, "获取显示区域参数");
    int desiredWidth = 480;
    int desiredHeight = 640;
    /**
     * 每个MeasureSpec均包含两种数据，尺寸和设定类型，需要通过 MeasureSpec.getMode和getSize进行提取
     */
    int widthMode = MeasureSpec.getMode(widthMeasureSpec);
    int widthSize = MeasureSpec.getSize(widthMeasureSpec);
    int heightMode = MeasureSpec.getMode(heightMeasureSpec);
    int heightSize = MeasureSpec.getSize(heightMeasureSpec);

    // 参考值竖屏 800 1214
    // 参考值横屏 1280 734
    int width;
    int height;
    LayoutParams params;// 子布局的参数
    // 竖屏
    if (isPortrait) {
      // 测量宽度
      if (widthMode == MeasureSpec.EXACTLY) {
        // 精确值情况
        width = widthSize;
      } else if (widthMode == MeasureSpec.AT_MOST) {
        // 范围值情况，哪个小取哪个？
        width = Math.min(desiredWidth, widthSize);
      } else {
        // 没设定就是默认的了，呵呵
        width = desiredWidth;
      }

      // 高度设定同上
      if (heightMode == MeasureSpec.EXACTLY) {
        height = heightSize;
      } else if (heightMode == MeasureSpec.AT_MOST) {
        // height = Math.min(desiredHeight, heightSize);
        height = Math.min(desiredWidth, widthSize) * 4 / 3;
      } else {
        height = desiredHeight;
      }
      Log.i(TAG, "显示表明摄像头为竖屏");
      // 竖屏，宽度匹配，高度为宽度缩放
      //params = new LayoutParams((int) (width), (int) (height));

    } else {
      desiredWidth = 640;
      desiredHeight = 480;
      // 测量宽度
      if (widthMode == MeasureSpec.EXACTLY) {
        // 精确值情况
        width = widthSize;
      } else if (widthMode == MeasureSpec.AT_MOST) {
        // 范围值情况，哪个小取哪个？
        // width = Math.min(desiredWidth, widthSize);
        width = Math.min(desiredHeight, heightSize) * 4 / 3;
      } else {
        // 没设定就是默认的了，呵呵
        width = desiredWidth;
      }

      // 高度设定同上
      if (heightMode == MeasureSpec.EXACTLY) {
        height = heightSize;
      } else if (heightMode == MeasureSpec.AT_MOST) {
        height = Math.min(desiredHeight, heightSize);
      } else {
        height = desiredHeight;
      }
      // 横屏，高度匹配，宽度包裹
      //params = new LayoutParams((int) (width), (int) (height));
    }
    //viewfinderView.setLayoutParams(params);
    //surfaceView.setLayoutParams(params);
    setMeasuredDimension(width, height);
    Log.e(TAG, "CSV设定宽度:" + widthSize + "  设定高度:" + heightSize);// 让我们来输出他们
    Log.e(TAG, "CSV实际宽度:" + width + "  实际高度:" + height);// 让我们来输出他们
  }

  @Override
  public void surfaceCreated(SurfaceHolder holder) {
    if (!hasSurface && holder != null) {
      hasSurface = true;
      initCamera(holder);
    }
  }

  @Override
  public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
  }

  @Override
  public void surfaceDestroyed(SurfaceHolder holder) {
    mCameraManager.closeDriver();
    hasSurface = false;
  }

  public void onResume() {
    handler = null;// 清空handler
    if (hasSurface) {
      // 当activity暂停，但是并未停止的时候，surface仍然存在，所以 surfaceCreated()
      // 并不会调用，需要在此处初始化摄像头
      initCamera(mSurfaceHolder);
    } else {
      // 设置回调，等待 surfaceCreated() 初始化摄像头
      mSurfaceHolder.addCallback(this);
      mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }
  }

  public void onPause() {
    if (handler != null) {
      handler.quitSynchronously();
      handler = null;
    }
    mCameraManager.closeDriver();
    if (!hasSurface) {
      mSurfaceHolder.removeCallback(this);
    }
  }

  public SurfaceHolder getSurfaceHolder() {
    return mSurfaceHolder;
  }

  public CameraManager getCameraManager() {
    return mCameraManager;
  }

  /**
   * 获取消息句柄
   *
   * @return
   */
  public BaseCameraHandler getHandler() {
    return handler;
  }

  public void startCapture() {
    if (handler == null)
      return;
    handler.startCaptrue();
  }

  /**
   * 初始化摄像头，较为关键的内容
   *
   * @param surfaceHolder
   */
  private void initCamera(SurfaceHolder surfaceHolder) {
    if (surfaceHolder == null) {
      throw new IllegalStateException("SurfaceHolder is null");
    }
    if (mCameraManager.isOpen()) {
      Log.w(TAG, "Camera is opened！");
      return;
    }
    try {
      mCameraManager.openDriver(surfaceHolder);
      if (handler == null) {
        handler = new BaseCameraHandler(this);
        handler.startDecodeThread();
      }
    } catch (IOException ioe) {
      Log.w(TAG, ioe);
    } catch (RuntimeException e) {
      Log.w(TAG, "摄像头初始化失败", e);
    }
  }

  public FaceCallback getFaceCallback() {
    return mFaceCallback;
  }

  public void setFaceCallback(FaceCallback faceCallback) {
    mFaceCallback = faceCallback;
  }

  public interface FaceCallback {
    void onResullt(Bitmap[] bitmaps);
  }
} public class CheckAPI implements Constant {

  private static final String TAG = "CheckAPI";
  private static final Retrofit sRetrofit = new Retrofit.Builder()
      .baseUrl(API_SERVER)
      .addConverterFactory(GsonConverterFactory.create())
      .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
      .build();
  public static final EyekeyService sEyekeyManagerService = sRetrofit.create(EyekeyService.class);
  private static ArrayList<Call> sCalls = new ArrayList<>();

  /**
   * 检测给定图片(Image)中的所有人脸(Face)的位置和相应的面部属性
   *
   * @param base64 待检测图片数据信息,通过POST方法上传的二进制数据，原始图片大小需要小于3M
   * @param mode   (可选)检测模式 (默认) oneface
   *               。在oneface模式中，检测器仅找出图片中最大的一张脸。如果图中有多张人脸大小相同，随机返回一张人脸信息。
   * @param tip    (可选)指定一个不包含^@,&=*'"等非法字符且不超过255字节的字符串作为tip
   */
  public static Observable<FaceAttrs> checkingImageByBase64(String base64, String mode, String tip) {
    return sEyekeyManagerService.checkingImageData(APP_ID, APP_KEY, base64, mode, tip);
  }

  /**
   * 检测给定图片(Image)中的所有人脸(Face)的位置和相应的面部属性
   *
   * @param url  待检测图片url
   * @param mode (可选)检测模式 (默认) oneface
   *             。在oneface模式中，检测器仅找出图片中最大的一张脸。如果图中有多张人脸大小相同，随机返回一张人脸信息。
   * @param tip  (可选)指定一个不包含^@,&=*'"等非法字符且不超过255字节的字符串作为tip
   * @return
   */
  public static Observable<FaceAttrs> checkingImageByUrl(String url, String mode, String tip) {
    return sEyekeyManagerService.checkingImageUrl(APP_ID, APP_KEY, url, mode, tip);
  }

  /**
   * 检测给定人脸(Face)相应的面部轮廓，五官等关键点的位置，包括49点一种模式。
   *
   * @param face_id 待检测人脸的face_id
   * @param type    (可选)表示返回的关键点个数，目前支持49p, 默认为49p
   * @return
   */
  public static Observable<FaceMark> checkMark(String face_id, String type) {
    return sEyekeyManagerService.checkMark(APP_ID, APP_KEY, face_id, type);
  }

  /**
   * 计算两个Face的相似性以及五官可信度
   *
   * @param faceId1 第一个Face的face_id
   * @param faceId2 第二个Face的face_id
   * @return
   */
  public static Observable<MatchCompare> matchCompare(String faceId1, String faceId2) {
    return sEyekeyManagerService.matchCompare(APP_ID, APP_KEY, faceId1, faceId2);
  }

  /**
   * 由第三方应用服务端发起，向EYEKEY平台确认应用客户端获取的动态是否有效。
   * 若第三方应用调用认证match_verify接口由Server端发起并获得动态码，则可以不用调用此接口。
   * 若第三方应用的动态码有效则返回true，否则返回false。
   *
   * @param dynamicode 第三方应用获取的动态码
   * @param peopleName 对应的People
   * @return
   */
  public static Observable<MatchConfirm> matchConfirm(String dynamicode, String peopleName) {
    return sEyekeyManagerService.matchConfirm(APP_ID, APP_KEY, dynamicode, peopleName);
  }

  /**
   * 给定一个Face和一个People，返回是否是同一个人的判断以及可信度
   *
   * @param faceId     待验证的face_id
   * @param peopleName 对应的People
   * @return
   */
  public static Observable<MatchVerify> matchVerify(String faceId, String peopleName) {
    return sEyekeyManagerService.matchVerify(APP_ID, APP_KEY, faceId, peopleName).subscribeOn(Schedulers.io());
  }

  /**
   * 给定一个Face和一个Facegather，在Facegather内搜索最相似的Face
   *
   * @param faceId         待搜索的Face的face_id
   * @param faceGatherName 指定搜索范围为此Facegather
   * @param count          (可选)表示一共获取不超过count 个 搜索结果。默认count=3，选择相似度最高的三个face返回
   * @return
   */
  public static Observable<MatchSearch> matchSearch(String faceId, String faceGatherName, int count) {
    return sEyekeyManagerService.matchSearch(APP_ID, APP_KEY, faceId, faceGatherName, count);
  }

  /**
   * 对于一个待查询的Face列表（或者对于给定的Image中所有的Face），在一个Crowd中查询最相似的People
   *
   * @param crowdName 识别候选人组成的Crowd
   * @param faceId    开发者也可以指定一个face_id的列表来对这些crowd进行识别。
   *                  可以设置此参数face_id为一个逗号隔开的face_id列表
   * @return
   */
  public static Observable<MatchIdentify> matchIdentify(String crowdName, String faceId) {
    return sEyekeyManagerService.matchIdentify(APP_ID, APP_KEY, crowdName, faceId);
  }

  /**
   * 创建一个facegather
   *
   * @param faceGatherName (可选)facegather的Name信息，必须在App中全局唯一。Name不能包含^@,&=*
   *                       '"等非法字符，且长度不得超过255。Name也可以不指定，此时系统将产生一个随机的name。
   * @param faceId         (可选)一组用逗号分隔的face_id, 表示将这些Face加入到该facegather中
   * @param tip            (可选)facegather相关的tip，不需要全局唯一，不能包含^@,&=*'"等非法字符，长度不能超过255。
   * @return
   */
  public static Observable<FaceGatherCreate> faceGatherCreate(String faceGatherName, String faceId, String tip) {
    return sEyekeyManagerService.faceGatherCreate(APP_ID, APP_KEY, faceGatherName, faceId, tip);
  }

  /**
   * 删除facegather
   *
   * @param faceGatherName 用逗号隔开的待删除的facegatherid列表或者name列表
   * @return
   */
  public static Observable<FaceGatherDelete> facegatherDelete(String faceGatherName) {
    return sEyekeyManagerService.facegatherDelete(APP_ID, APP_KEY, faceGatherName);
  }

  /**
   * 将一组Face加入到一个facegather中
   *
   * @param faceGatherName 相应facegather的name或者id
   * @param faceId         一组用逗号分隔的face_id,表示将这些Face加入到相应facegather中
   * @return
   */
  public static Observable<FaceGatherAddFace> faceGatherAddFace(String faceGatherName, String faceId) {
    return sEyekeyManagerService.faceGatherAddFace(APP_ID, APP_KEY, faceGatherName, faceId);
  }

  /**
   * 删除facegather中的一个或多个Face
   *
   * @param faceGatherName 相应facegather的name或者id
   * @param faceId         一组用逗号分隔的face_id列表，表示将这些face从该facegather中删除。开发者也可以指定face_id=all
   *                       , 表示删除该facegather所有相关Face
   * @return
   */
  public static Observable<FaceGatherRemoveFace> faceGatherRemoveface(String faceGatherName, String faceId) {
    return sEyekeyManagerService.faceGatherRemoveFace(APP_ID, APP_KEY, faceGatherName, faceId);
  }

  /**
   * 设置facegather的name和tip
   *
   * @param faceGatherName 相应facegather的name或者id
   * @param name           (可选)新的name
   * @param tip            (可选)新的tip
   * @return
   */
  public static Observable<FaceGatherSet> faceGatherSet(String faceGatherName, String name, String tip) {
    return sEyekeyManagerService.faceGatherSet(APP_ID, APP_KEY, faceGatherName, name, tip);
  }

  /**
   * 获取一个facegather的信息, 包括name, id, tip, 相关的face等信息
   *
   * @param faceGatherName 相应facegather的id或name
   * @return
   */
  public static Observable<FaceGatherGet> faceGatherGet(String faceGatherName) {
    return sEyekeyManagerService.faceGatherGet(APP_ID, APP_KEY, faceGatherName);
  }

  /**
   * 创建一个People
   *
   * @param peopleName (可选)People的Name信息，必须在App中全局唯一。Name不能包含^@,&=*
   *                   '"等非法字符，且长度不得超过255。Name也可以不指定，此时系统将产生一个随机的name
   * @param faceId     (可选)一组用逗号分隔的face_id, 表示将这些Face加入到该People中
   * @param tip        (可选)People相关的tip，不需要全局唯一，不能包含^@,&=*'"等非法字符，长度不能超过255
   * @param crowdName  (可选)一组用逗号分割的crowd id列表或者crowd
   *                   name列表。如果该参数被指定，该People被create之后就会被加入到这些组中
   * @return
   */
  public static Observable<PeopleCreate> peopleCreate(String faceId, String peopleName, String tip, String crowdName) {
    return sEyekeyManagerService.peopleCreate(APP_ID, APP_KEY, faceId, peopleName, tip, crowdName);
  }

  /**
   * 删除一组People
   *
   * @param peopleName 用逗号隔开的待删除的People id列表或者name列表
   * @return
   */
  public static Observable<PeopleDelete> peopleDelete(String peopleName) {
    return sEyekeyManagerService.peopleDelete(APP_ID, APP_KEY, peopleName).subscribeOn(Schedulers.io());
  }

  /**
   * ·将一组Face加入到一个People中。注意，一个Face只能被加入到一个People中。 ·一个People最多允许包含10000个Face
   *
   * @param faceId     一组用逗号分隔的face_id,表示将这些Face加入到相应People中。
   * @param peopleName 相应People的name或者id
   * @return
   */
  public static Observable<PeopleAdd> peopleAdd(String faceId, String peopleName) {
    return sEyekeyManagerService.peopleAdd(APP_ID, APP_KEY, faceId, peopleName).subscribeOn(Schedulers.io());
  }

  /**
   * 删除People中的一个或多个Face
   *
   * @param peopleName 相应People的name或者id
   * @param faceId     可传入一组用逗号分隔的face_id列表，表示将这些face从指定的People中删除。开发者也可以指定face_id=
   *                   all, 表示删除People所有相关Face。
   * @return
   */
  public static Observable<PeopleRemove> peopleRemove(String peopleName, String faceId) {
    return sEyekeyManagerService.peopleRemove(APP_ID, APP_KEY, peopleName, faceId);
  }

  /**
   * 设置People的name和tip
   *
   * @param peopleName 相应People的name或者id
   * @param name       新的name(可选)
   * @param tip        新的tip(可选)
   * @return
   */
  public static Observable<PeopleSet> peopleSet(String peopleName, String name, String tip) {
    return sEyekeyManagerService.peopleSet(APP_ID, APP_KEY, peopleName, name, tip);
  }

  /**
   * 获取一个People的信息, 包括name, id, tip, 相关的face, 以及crowds等信息
   *
   * @param peopleName 相应People的name或者id
   * @return
   */
  public static Observable<PeopleGet> peopleGet(String peopleName) {
    return sEyekeyManagerService.peopleGet(APP_ID, APP_KEY, peopleName, "face");
  }

  /**
   * ·创建一个Crowd。一个Crowd最多允许包含1000个People。开发版最多允许创建5个crowd。
   *
   * @param crowdName  (可选)Crowd的Name信息，必须在App中全局唯一。Name不能包含^@,&=*
   *                   '"等非法字符，且长度不得超过255。Name也可以不指定，此时系统将产生一个随机的name
   * @param peopleName (可选)一组用逗号分隔的people_id或people_name,
   *                   表示将这些People加入到该Crowd中。注意，一个People可以被加入到多个Crowd中。
   * @param tip        (可选)Crowd的tip，不需要全局唯一，不能包含^@,&=*'"等非法字符，长度不能超过255
   * @return
   */
  public static Observable<CrowdCreate> crowdCreate(String crowdName, String peopleName, String tip) {
    return sEyekeyManagerService.crowdCreate(APP_ID, APP_KEY, crowdName, peopleName, tip);
  }

  /**
   * 删除一组Crowd。
   *
   * @param crowdName 一组用逗号分割的crowd_id或crowd_name，表示删除这些Crowd
   * @return
   */
  public static Observable<CrowdDelete> crowdDelete(String crowdName) {
    return sEyekeyManagerService.crowdDelete(APP_ID, APP_KEY, crowdName);
  }

  /**
   * 从Crowd中删除一个或一组People。
   *
   * @param crowdName  Crowd的id或name。
   * @param peopleName 一组用逗号分割的people_id列表或者people_name列表，表示将这些people从该Crowd中删除。
   *                   开发者也可以指定people_id=all, 表示删掉该Crowd中所有People。
   * @return
   */
  public static Observable<CrowdAddAndRemove> crowdRemove(String crowdName, String peopleName) {
    return sEyekeyManagerService.crowdRemove(APP_ID, APP_KEY, crowdName, peopleName);
  }

  /**
   * 将一组People加入到一个Crowd中。一个Crowd最多允许包含10000个People。
   *
   * @param crowdName  相应Crowd的id或name
   * @param peopleName 一组用逗号分隔的people_id或people_name，表示将这些People加入到相应Crowd中。
   * @return
   */
  public static Observable<CrowdAddAndRemove> crowdAdd(String crowdName, String peopleName) {
    return sEyekeyManagerService.crowdAdd(APP_ID, APP_KEY, crowdName, peopleName);
  }

  /**
   * 获取Crowd的信息，包括Crowd中的People列表，Crowd的tip等信息。
   *
   * @param crowdName 待查询Crowd的id或name。开发者也可以指定crowd_id=none，
   *                  此时将返回所有未加入任何Crowd的People。
   * @return
   */
  public static Observable<CrowdGet> crowdGet(String crowdName) {
    return sEyekeyManagerService.crowdGet(APP_ID, APP_KEY, crowdName);
  }

  /**
   * 获取该App相关的信息。
   *
   * @return
   */
  public static Observable<AppInfo> getAppInfo() {
    Observable<AppInfo> observable = sEyekeyManagerService.getAppinfo(APP_ID, APP_KEY);
    return sEyekeyManagerService.getAppinfo(APP_ID, APP_KEY);
  }

  public static void cancelAllCall() {
    for (Call call : sCalls) {
      if (call != null) {
        call.cancel();
      }
    }
    sCalls.clear();
  }

  public interface EyekeyService {

    @FormUrlEncoded
    @POST(Constant.Check + "/checking")
    Observable<FaceAttrs> checkingImageData(
        @Field("app_id") String appId,
        @Field("app_key") String appKey,
        @Field("img") String dataImage,
        @Field("mode") String mode,
        @Field("tip") String tip
    );

    @GET(Constant.Check + "/checking")
    Observable<FaceAttrs> checkingImageUrl(
        @Query("app_id") String appId,
        @Query("app_key") String appKey,
        @Query("url") String url,
        @Query("mode") String mode,
        @Query("tip") String tip
    );

    @GET(Constant.Check + "/check_mark")
    Observable<FaceMark> checkMark(
        @Query("app_id") String appId,
        @Query("app_key") String appKey,
        @Query("face_id") String faceId,
        @Query("type") String type
    );

    @GET(Constant.Match + "/match_compare")
    Observable<MatchCompare> matchCompare(
        @Query("app_id") String appId,
        @Query("app_key") String appKey,
        @Query("face_id1") String faceId1,
        @Query("face_id2") String faceId2
    );

    @GET(Constant.Match + "/match_confirm")
    Observable<MatchConfirm> matchConfirm(
        @Query("app_id") String appId,
        @Query("app_key") String appKey,
        @Query("dynamicode") String dynamicode,
        @Query("people_name") String peopleName

    );

    @GET(Constant.Match + "/match_verify")
    Observable<MatchVerify> matchVerify(
        @Query("app_id") String appId,
        @Query("app_key") String appKey,
        @Query("face_id") String faceId,
        @Query("people_name") String peopleName
    );

    @GET(Constant.Match + "/match_search")
    Observable<MatchSearch> matchSearch(
        @Query("app_id") String appId,
        @Query("app_key") String appKey,
        @Query("face_id") String faceId,
        @Query("facegather_name") String faceGatherName,
        @Query("count") int count
    );

    @GET(Constant.Match + "/match_identify")
    Observable<MatchIdentify> matchIdentify(
        @Query("app_id") String appId,
        @Query("app_key") String appKey,
        @Query("crowd_name") String crowdName,
        @Query("face_id") String faceId
    );

    @GET(Constant.FaceGather + "/facegather_create")
    Observable<FaceGatherCreate> faceGatherCreate(
        @Query("app_id") String appId,
        @Query("app_key") String appKey,
        @Query("facegather_name") String faceGatherName,
        @Query("face_id") String faceId,
        @Query("tip") String tip
    );

    @GET(Constant.FaceGather + "/facegather_delete")
    Observable<FaceGatherDelete> facegatherDelete(
        @Query("app_id") String appId,
        @Query("app_key") String appKey,
        @Query("facegather_name") String faceGatherName

    );

    @GET(Constant.FaceGather + "/facegather_addface")
    Observable<FaceGatherAddFace> faceGatherAddFace(
        @Query("app_id") String appId,
        @Query("app_key") String appKey,
        @Query("facegather_name") String faceGatherName,
        @Query("face_id") String faceId
    );

    @GET(Constant.FaceGather + "/facegather_removeface")
    Observable<FaceGatherRemoveFace> faceGatherRemoveFace(
        @Query("app_id") String appId,
        @Query("app_key") String appKey,
        @Query("facegather_name") String faceGatherName,
        @Query("face_id") String faceId
    );

    @GET(Constant.FaceGather + "/facegather_set")
    Observable<FaceGatherSet> faceGatherSet(
        @Query("app_id") String appId,
        @Query("app_key") String appKey,
        @Query("facegather_name") String faceGatherName,
        @Query("name") String name,
        @Query("tip") String tip
    );

    @GET(Constant.FaceGather + "/facegather_get")
    Observable<FaceGatherGet> faceGatherGet(
        @Query("app_id") String appId,
        @Query("app_key") String appKey,
        @Query("facegather_name") String faceGatherName
    );

    @GET(Constant.People + "/people_create")
    Observable<PeopleCreate> peopleCreate(
        @Query("app_id") String appId,
        @Query("app_key") String appKey,
        @Query("face_id") String faceId,
        @Query("people_name") String peopleName,
        @Query("tip") String tip,
        @Query("crowd_name") String crowdName
    );


    @GET(Constant.People + "/people_delete")
    Observable<PeopleDelete> peopleDelete(
        @Query("app_id") String appId,
        @Query("app_key") String appKey,
        @Query("people_name") String peopleName
    );

    @GET(Constant.People + "/people_add")
    Observable<PeopleAdd> peopleAdd(
        @Query("app_id") String appId,
        @Query("app_key") String appKey,
        @Query("face_id") String faceId,
        @Query("people_name") String peopleName
    );

    @GET(Constant.People + "/people_remove")
    Observable<PeopleRemove> peopleRemove(
        @Query("app_id") String appId,
        @Query("app_key") String appKey,
        @Query("people_name") String peopleName,
        @Query("face_id") String faceId
    );

    @GET(Constant.People + "/people_set")
    Observable<PeopleSet> peopleSet(
        @Query("app_id") String appId,
        @Query("app_key") String appKey,
        @Query("people_name") String peopleName,
        @Query("name") String name,
        @Query("tip") String tip
    );

    @GET(Constant.People + "/people_get")
    Observable<PeopleGet> peopleGet(
        @Query("app_id") String appId,
        @Query("app_key") String appKey,
        @Query("people_name") String peopleName,
        @Query("type") String type
    );

    @GET(Constant.Crowd + "/crowd_create")
    Observable<CrowdCreate> crowdCreate(
        @Query("app_id") String appId,
        @Query("app_key") String appKey,
        @Query("crowd_name") String crowdName,
        @Query("people_name") String peopleName,
        @Query("tip") String tip
    );

    @GET(Constant.Crowd + "/crowd_delete")
    Observable<CrowdDelete> crowdDelete(
        @Query("app_id") String appId,
        @Query("app_key") String appKey,
        @Query("crowd_name") String crowdName
    );

    @GET(Constant.Crowd + "/crowd_remove")
    Observable<CrowdAddAndRemove> crowdRemove(
        @Query("app_id") String appId,
        @Query("app_key") String appKey,
        @Query("crowd_name") String crowdName,
        @Query("people_name") String peopleName
    );

    @GET(Constant.Crowd + "/crowd_add")
    Observable<CrowdAddAndRemove> crowdAdd(
        @Query("app_id") String appId,
        @Query("app_key") String appKey,
        @Query("crowd_name") String crowdName,
        @Query("people_name") String peopleName
    );

    @GET(Constant.Crowd + "/crowd_get")
    Observable<CrowdGet> crowdGet(
        @Query("app_id") String appId,
        @Query("app_key") String appKey,
        @Query("crowd_name") String crowdName
    );

    @GET(Constant.Info + "/get_appinfo")
    Observable<AppInfo> getAppinfo(
        @Query("app_id") String appId,
        @Query("app_key") String appKey
    );
  }
} public interface Constant {
  /**
   * 访问云平台服务接口的地址
   */
  String API_SERVER = "http://api.eyekey.com/";
  String Check = API_SERVER + "/face/Check";
  String Match = API_SERVER + "/face/Match";
  String FaceGather = API_SERVER + "/face/FaceGather";
  String People = API_SERVER + "/People";
  String Crowd = API_SERVER + "/Crowd";
  String Info = API_SERVER + "/Info";
  /**
   * 用户不存在
   */
  String RES_CODE_1025 = "1025";

  String RES_CODE_0000 = "0000";

} public class Face {

  private Attribute attribute;

  private String face_id;

  private Position position;

  private String tag;

  public Attribute getAttribute() {
    return this.attribute;
  }

  public void setAttribute(Attribute attribute) {
    this.attribute = attribute;
  }

  public String getFace_id() {
    return this.face_id;
  }

  public void setFace_id(String face_id) {
    this.face_id = face_id;
  }

  public Position getPosition() {
    return this.position;
  }

  public void setPosition(Position position) {
    this.position = position;
  }

  public String getTag() {
    return this.tag;
  }

  public void setTag(String tag) {
    this.tag = tag;
  }

  @Override
  public String toString() {
    return "Face [attribute=" + attribute + ", face_id=" + face_id
        + ", position=" + position + ", tag=" + tag + "]";
  }
} public class FaceAttrs {
  private List<Face> face;

  private int img_height;

  private String img_id;

  private int img_width;

  private String res_code;

  public List<Face> getFace() {
    return this.face;
  }

  public void setFace(List<Face> face) {
    this.face = face;
  }

  public int getImg_height() {
    return this.img_height;
  }

  public void setImg_height(int img_height) {
    this.img_height = img_height;
  }

  public String getImg_id() {
    return this.img_id;
  }

  public void setImg_id(String img_id) {
    this.img_id = img_id;
  }

  public int getImg_width() {
    return this.img_width;
  }

  public void setImg_width(int img_width) {
    this.img_width = img_width;
  }

  public String getRes_code() {
    return this.res_code;
  }

  public void setRes_code(String res_code) {
    this.res_code = res_code;
  }

  @Override
  public String toString() {
    return "FaceAttrs [face=" + face + ", img_height=" + img_height
        + ", img_id=" + img_id + ", img_width=" + img_width
        + ", res_code=" + res_code + "]";
  }
} public class PeopleAdd {
  private int face_added;

  private int fingerprint_added;

  private int iris_added;

  private String message;

  private String res_code;

  private boolean success;

  public int getFace_added() {
    return this.face_added;
  }

  public void setFace_added(int face_added) {
    this.face_added = face_added;
  }

  public int getFingerprint_added() {
    return this.fingerprint_added;
  }

  public void setFingerprint_added(int fingerprint_added) {
    this.fingerprint_added = fingerprint_added;
  }

  public int getIris_added() {
    return this.iris_added;
  }

  public void setIris_added(int iris_added) {
    this.iris_added = iris_added;
  }

  public String getMessage() {
    return this.message;
  }

  public void setMessage(String message) {
    this.message = message;
  }

  public String getRes_code() {
    return this.res_code;
  }

  public void setRes_code(String res_code) {
    this.res_code = res_code;
  }

  public boolean getSuccess() {
    return this.success;
  }

  public void setSuccess(boolean success) {
    this.success = success;
  }

  @Override
  public String toString() {
    return "PeopleAdd{" +
        "face_added=" + face_added +
        ", fingerprint_added=" + fingerprint_added +
        ", iris_added=" + iris_added +
        ", message='" + message + '\'' +
        ", res_code='" + res_code + '\'' +
        ", success=" + success +
        '}';
  }
} public class PeopleCreate {

  private int added_crowd;

  private int added_face;

  private int added_fingerprint;

  private int added_iris;

  private String people_id;

  private String people_name;

  private String res_code;

  private String message;

  public int getAdded_crowd() {
    return this.added_crowd;
  }

  public void setAdded_crowd(int added_crowd) {
    this.added_crowd = added_crowd;
  }

  public int getAdded_face() {
    return this.added_face;
  }

  public void setAdded_face(int added_face) {
    this.added_face = added_face;
  }

  public int getAdded_fingerprint() {
    return this.added_fingerprint;
  }

  public void setAdded_fingerprint(int added_fingerprint) {
    this.added_fingerprint = added_fingerprint;
  }

  public int getAdded_iris() {
    return this.added_iris;
  }

  public void setAdded_iris(int added_iris) {
    this.added_iris = added_iris;
  }

  public String getPeople_id() {
    return this.people_id;
  }

  public void setPeople_id(String people_id) {
    this.people_id = people_id;
  }

  public String getPeople_name() {
    return this.people_name;
  }

  public void setPeople_name(String people_name) {
    this.people_name = people_name;
  }

  public String getRes_code() {
    return this.res_code;
  }

  public void setRes_code(String res_code) {
    this.res_code = res_code;
  }

  public String getMessage() {
    return message;
  }

  public void setMessage(String message) {
    this.message = message;
  }

  @Override
  public String toString() {
    return "PeopleCreate{" +
        "added_crowd=" + added_crowd +
        ", added_face=" + added_face +
        ", added_fingerprint=" + added_fingerprint +
        ", added_iris=" + added_iris +
        ", people_id='" + people_id + '\'' +
        ", people_name='" + people_name + '\'' +
        ", res_code='" + res_code + '\'' +
        ", message='" + message + '\'' +
        '}';
  }
}
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.app.ProgressDialog;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.media.AudioManager;
import android.media.SoundPool;
import android.os.Handler;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.View;
import android.view.animation.OvershootInterpolator;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import com.techshino.eyekeydemo.R;
import com.techshino.eyekeydemo.utils.CustomUtil;
import com.techshino.eyekeydemo.utils.Logs;
import com.techshino.eyekeydemo.utils.MeasureUtil;
import com.techshino.eyekeydemo.utils.SnackBarUtils;
import com.techshino.eyekeydemo.utils.StringUtils;
import com.techshino.eyekeydemo.view.CameraSurfaceView;
import com.techshino.eyekeysdk.api.CheckAPI;
import com.techshino.eyekeysdk.conn.Constant;
import com.techshino.eyekeysdk.entity.Face;
import com.techshino.eyekeysdk.entity.FaceAttrs;
import com.techshino.eyekeysdk.entity.PeopleAdd;
import com.techshino.eyekeysdk.entity.PeopleCreate;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import butterknife.BindView;
import butterknife.OnClick;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
package com.techshino.eyekeydemo.activity;





/**
 * <p>
 * Created by wangzhi on 2015/12/28.
 * 注册
 */
public class RegisterActivity extends BaseAppcompatActivity implements CameraSurfaceView.FaceCallback {

  public static final String ARG_CAMERA_ID = RegisterActivity.class.getSimpleName() + ".camera_id";
  public static final String ARG_NAME = RegisterActivity.class.getSimpleName() + ".name";
  public static final String ARG_IS_CREATED = RegisterActivity.class.getSimpleName() + ".created";
  private static final String TAG = RegisterActivity.class.getSimpleName();
  @BindView(R.id.cameraSurface)
  CameraSurfaceView mSurfaceView;
  @BindView(R.id.img1)
  ImageView mImg1;
  @BindView(R.id.img2)
  ImageView mImg2;
  @BindView(R.id.img3)
  ImageView mImg3;
  @BindView(R.id.toolbar)
  Toolbar mToolbar;
  @BindView(R.id.takeBtn)
  ImageView mTakeBtn;
  @BindView(R.id.bgFrame)
  ImageView mBgFrame;
  ProgressDialog mProgressDialog;
  private String mName;
  /**
   * 是否已经创建people
   */
  private boolean isCreated;
  /**
   * 是否有faceId
   */
  private boolean hasFaceId = false;
  private List<String> mBase64List = new ArrayList<String>();
  private SoundPool mSoundPool;
  private String mFaceAll = "";

  @Override
  public void initData() {
    Intent intent = getIntent();
    int cameraId = intent.getIntExtra(ARG_CAMERA_ID, 1);
    mName = intent.getStringExtra(ARG_NAME);
    isCreated = intent.getBooleanExtra(ARG_IS_CREATED, false);

    mProgressDialog = new ProgressDialog(this);
    mProgressDialog.setCancelable(false);

    mSurfaceView.setCameraId(cameraId);
    setSupportActionBar(mToolbar);
    getSupportActionBar().setDisplayHomeAsUpEnabled(true);
    getSupportActionBar().setTitle("");
    mToolbar.setBackgroundColor(Color.TRANSPARENT);
    mToolbar.setNavigationOnClickListener(v -> RegisterActivity.this.finish());
    mSoundPool = new SoundPool(1, AudioManager.STREAM_MUSIC, 5);
    try {
      mSoundPool.load(getAssets().openFd("prompt.wav"), 1);
    } catch (IOException e) {
      e.printStackTrace();
    }

    // 设置拍照回掉接口
    mSurfaceView.setFaceCallback(this);

    if (CustomUtil.isLandScape(this)) {
      setLandLayoutParams();
    } else {
      setPortraitLayoutParams();
    }
  }

  private void setLandLayoutParams() {
    mToolbar.setVisibility(View.GONE);

    int screenWidth = MeasureUtil.getScreenSize(this)[0];
    int screenHeight = MeasureUtil.getScreenSize(this)[1];
    Logs.i(TAG, "screenWidth:" + screenWidth);