mirror of
https://github.com/PaddlePaddle/FastDeploy.git
synced 2025-10-10 02:50:19 +08:00
[Android] Update ui module structure. (#706)
* Remove redundant code for segmentation. * Classification Documentation and example improvement. * Ocr Documentation and example improvement. * 1.detection、face、seg module add "svPreview.enableCamera();". 2.java/android add fastdepolyUi module. * examples/vision/ to add OCRv3. * Modify UI directory name. * Refresh examples\vision,change OCR README.md * Update ui module * Update ui module Co-authored-by: DefTruth <31974251+DefTruth@users.noreply.github.com>
This commit is contained in:
1
java/android/ui/.gitignore
vendored
Normal file
1
java/android/ui/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/build
|
39
java/android/ui/build.gradle
Normal file
39
java/android/ui/build.gradle
Normal file
@@ -0,0 +1,39 @@
|
||||
plugins {
|
||||
id 'com.android.library'
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion 28
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 15
|
||||
targetSdkVersion 28
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
consumerProguardFiles "consumer-rules.pro"
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(include: ['*.aar'], dir: 'libs')
|
||||
implementation 'com.android.support:appcompat-v7:28.0.0'
|
||||
//noinspection GradleDependency
|
||||
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
|
||||
implementation 'com.android.support:design:28.0.0'
|
||||
implementation 'org.jetbrains:annotations:15.0'
|
||||
//noinspection GradleDependency
|
||||
testImplementation 'junit:junit:4.12'
|
||||
androidTestImplementation 'com.android.support.test:runner:1.0.2'
|
||||
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
|
||||
}
|
0
java/android/ui/consumer-rules.pro
Normal file
0
java/android/ui/consumer-rules.pro
Normal file
8
java/android/ui/local.properties
Normal file
8
java/android/ui/local.properties
Normal file
@@ -0,0 +1,8 @@
|
||||
## This file must *NOT* be checked into Version Control Systems,
|
||||
# as it contains information specific to your local configuration.
|
||||
#
|
||||
# Location of the SDK. This is only used by Gradle.
|
||||
# For customization when using a Version Control System, please read the
|
||||
# header note.
|
||||
#Fri Nov 25 17:48:04 CST 2022
|
||||
sdk.dir=D\:\\androidsdk
|
21
java/android/ui/proguard-rules.pro
vendored
Normal file
21
java/android/ui/proguard-rules.pro
vendored
Normal file
@@ -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
|
4
java/android/ui/src/main/AndroidManifest.xml
Normal file
4
java/android/ui/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.baidu.paddle.fastdeploy.ui">
|
||||
</manifest>
|
@@ -0,0 +1,313 @@
|
||||
package com.baidu.paddle.fastdeploy.ui;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.hardware.Camera;
|
||||
import android.net.Uri;
|
||||
import android.opengl.GLES20;
|
||||
import android.os.Environment;
|
||||
import android.provider.MediaStore;
|
||||
import android.util.Log;
|
||||
import android.view.Surface;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class Utils {
|
||||
private static final String TAG = Utils.class.getSimpleName();
|
||||
|
||||
public static void RecursiveCreateDirectories(String fileDir) {
|
||||
String[] fileDirs = fileDir.split("\\/");
|
||||
String topPath = "";
|
||||
for (int i = 0; i < fileDirs.length; i++) {
|
||||
topPath += "/" + fileDirs[i];
|
||||
File file = new File(topPath);
|
||||
if (file.exists()) {
|
||||
continue;
|
||||
} else {
|
||||
file.mkdir();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void copyFileFromAssets(Context appCtx, String srcPath, String dstPath) {
|
||||
if (srcPath.isEmpty() || dstPath.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
String dstDir = dstPath.substring(0, dstPath.lastIndexOf('/'));
|
||||
if (dstDir.length() > 0) {
|
||||
RecursiveCreateDirectories(dstDir);
|
||||
}
|
||||
InputStream is = null;
|
||||
OutputStream os = null;
|
||||
try {
|
||||
is = new BufferedInputStream(appCtx.getAssets().open(srcPath));
|
||||
os = new BufferedOutputStream(new FileOutputStream(new File(dstPath)));
|
||||
byte[] buffer = new byte[1024];
|
||||
int length = 0;
|
||||
while ((length = is.read(buffer)) != -1) {
|
||||
os.write(buffer, 0, length);
|
||||
}
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
os.close();
|
||||
is.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void copyDirectoryFromAssets(Context appCtx, String srcDir, String dstDir) {
|
||||
if (srcDir.isEmpty() || dstDir.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
if (!new File(dstDir).exists()) {
|
||||
new File(dstDir).mkdirs();
|
||||
}
|
||||
for (String fileName : appCtx.getAssets().list(srcDir)) {
|
||||
String srcSubPath = srcDir + File.separator + fileName;
|
||||
String dstSubPath = dstDir + File.separator + fileName;
|
||||
if (new File(srcSubPath).isDirectory()) {
|
||||
copyDirectoryFromAssets(appCtx, srcSubPath, dstSubPath);
|
||||
} else {
|
||||
copyFileFromAssets(appCtx, srcSubPath, dstSubPath);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static float[] parseFloatsFromString(String string, String delimiter) {
|
||||
String[] pieces = string.trim().toLowerCase().split(delimiter);
|
||||
float[] floats = new float[pieces.length];
|
||||
for (int i = 0; i < pieces.length; i++) {
|
||||
floats[i] = Float.parseFloat(pieces[i].trim());
|
||||
}
|
||||
return floats;
|
||||
}
|
||||
|
||||
public static long[] parseLongsFromString(String string, String delimiter) {
|
||||
String[] pieces = string.trim().toLowerCase().split(delimiter);
|
||||
long[] longs = new long[pieces.length];
|
||||
for (int i = 0; i < pieces.length; i++) {
|
||||
longs[i] = Long.parseLong(pieces[i].trim());
|
||||
}
|
||||
return longs;
|
||||
}
|
||||
|
||||
public static String getSDCardDirectory() {
|
||||
return Environment.getExternalStorageDirectory().getAbsolutePath();
|
||||
}
|
||||
|
||||
public static String getDCIMDirectory() {
|
||||
return Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).getAbsolutePath();
|
||||
}
|
||||
|
||||
public static Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {
|
||||
final double ASPECT_TOLERANCE = 0.3;
|
||||
double targetRatio = (double) w / h;
|
||||
if (sizes == null) return null;
|
||||
|
||||
Camera.Size optimalSize = null;
|
||||
double minDiff = Double.MAX_VALUE;
|
||||
|
||||
int targetHeight = h;
|
||||
|
||||
// Try to find an size match aspect ratio and size
|
||||
for (Camera.Size size : sizes) {
|
||||
double ratio = (double) size.width / size.height;
|
||||
if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
|
||||
if (Math.abs(size.height - targetHeight) < minDiff) {
|
||||
optimalSize = size;
|
||||
minDiff = Math.abs(size.height - targetHeight);
|
||||
}
|
||||
}
|
||||
|
||||
// Cannot find the one match the aspect ratio, ignore the requirement
|
||||
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;
|
||||
}
|
||||
|
||||
public static int getScreenWidth() {
|
||||
return Resources.getSystem().getDisplayMetrics().widthPixels;
|
||||
}
|
||||
|
||||
public static int getScreenHeight() {
|
||||
return Resources.getSystem().getDisplayMetrics().heightPixels;
|
||||
}
|
||||
|
||||
public static int getCameraDisplayOrientation(Context context, int cameraId) {
|
||||
Camera.CameraInfo info = new Camera.CameraInfo();
|
||||
Camera.getCameraInfo(cameraId, info);
|
||||
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
|
||||
int rotation = wm.getDefaultDisplay().getRotation();
|
||||
int degrees = 0;
|
||||
switch (rotation) {
|
||||
case Surface.ROTATION_0:
|
||||
degrees = 0;
|
||||
break;
|
||||
case Surface.ROTATION_90:
|
||||
degrees = 90;
|
||||
break;
|
||||
case Surface.ROTATION_180:
|
||||
degrees = 180;
|
||||
break;
|
||||
case Surface.ROTATION_270:
|
||||
degrees = 270;
|
||||
break;
|
||||
}
|
||||
int result;
|
||||
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
|
||||
result = (info.orientation + degrees) % 360;
|
||||
result = (360 - result) % 360; // compensate the mirror
|
||||
} else {
|
||||
// back-facing
|
||||
result = (info.orientation - degrees + 360) % 360;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static int createShaderProgram(String vss, String fss) {
|
||||
int vshader = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER);
|
||||
GLES20.glShaderSource(vshader, vss);
|
||||
GLES20.glCompileShader(vshader);
|
||||
int[] status = new int[1];
|
||||
GLES20.glGetShaderiv(vshader, GLES20.GL_COMPILE_STATUS, status, 0);
|
||||
if (status[0] == 0) {
|
||||
Log.e(TAG, GLES20.glGetShaderInfoLog(vshader));
|
||||
GLES20.glDeleteShader(vshader);
|
||||
vshader = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fshader = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER);
|
||||
GLES20.glShaderSource(fshader, fss);
|
||||
GLES20.glCompileShader(fshader);
|
||||
GLES20.glGetShaderiv(fshader, GLES20.GL_COMPILE_STATUS, status, 0);
|
||||
if (status[0] == 0) {
|
||||
Log.e(TAG, GLES20.glGetShaderInfoLog(fshader));
|
||||
GLES20.glDeleteShader(vshader);
|
||||
GLES20.glDeleteShader(fshader);
|
||||
fshader = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int program = GLES20.glCreateProgram();
|
||||
GLES20.glAttachShader(program, vshader);
|
||||
GLES20.glAttachShader(program, fshader);
|
||||
GLES20.glLinkProgram(program);
|
||||
GLES20.glDeleteShader(vshader);
|
||||
GLES20.glDeleteShader(fshader);
|
||||
GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, status, 0);
|
||||
if (status[0] == 0) {
|
||||
Log.e(TAG, GLES20.glGetProgramInfoLog(program));
|
||||
program = 0;
|
||||
return 0;
|
||||
}
|
||||
GLES20.glValidateProgram(program);
|
||||
GLES20.glGetProgramiv(program, GLES20.GL_VALIDATE_STATUS, status, 0);
|
||||
if (status[0] == 0) {
|
||||
Log.e(TAG, GLES20.glGetProgramInfoLog(program));
|
||||
GLES20.glDeleteProgram(program);
|
||||
program = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return program;
|
||||
}
|
||||
|
||||
public static boolean isSupportedNPU() {
|
||||
String hardware = android.os.Build.HARDWARE;
|
||||
return hardware.equalsIgnoreCase("kirin810") || hardware.equalsIgnoreCase("kirin990");
|
||||
}
|
||||
|
||||
public static Bitmap decodeBitmap(String path, int displayWidth, int displayHeight) {
|
||||
BitmapFactory.Options op = new BitmapFactory.Options();
|
||||
op.inJustDecodeBounds = true;// Only the width and height information of Bitmap is read, not the pixels.
|
||||
Bitmap bmp = BitmapFactory.decodeFile(path, op); // Get size information.
|
||||
int wRatio = (int) Math.ceil(op.outWidth / (float) displayWidth);// Get Scale Size.
|
||||
int hRatio = (int) Math.ceil(op.outHeight / (float) displayHeight);
|
||||
// If the specified size is exceeded, reduce the corresponding scale.
|
||||
if (wRatio > 1 && hRatio > 1) {
|
||||
if (wRatio > hRatio) {
|
||||
// If it is too wide, we will reduce the width to the required size. Note that the height will become smaller.
|
||||
op.inSampleSize = wRatio;
|
||||
} else {
|
||||
op.inSampleSize = hRatio;
|
||||
}
|
||||
}
|
||||
op.inJustDecodeBounds = false;
|
||||
bmp = BitmapFactory.decodeFile(path, op);
|
||||
// Create a Bitmap with a given width and height from the original Bitmap.
|
||||
return Bitmap.createScaledBitmap(bmp, displayWidth, displayHeight, true);
|
||||
}
|
||||
|
||||
public static String getRealPathFromURI(Context context, Uri contentURI) {
|
||||
String result;
|
||||
Cursor cursor = null;
|
||||
try {
|
||||
cursor = context.getContentResolver().query(contentURI, null, null, null, null);
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (cursor == null) {
|
||||
result = contentURI.getPath();
|
||||
} else {
|
||||
cursor.moveToFirst();
|
||||
int idx = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
|
||||
result = cursor.getString(idx);
|
||||
cursor.close();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static List<String> readTxt(String txtPath) {
|
||||
File file = new File(txtPath);
|
||||
if (file.isFile() && file.exists()) {
|
||||
try {
|
||||
FileInputStream fileInputStream = new FileInputStream(file);
|
||||
InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream);
|
||||
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
|
||||
String text;
|
||||
List<String> labels = new ArrayList<>();
|
||||
while ((text = bufferedReader.readLine()) != null) {
|
||||
labels.add(text);
|
||||
}
|
||||
return labels;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@@ -0,0 +1,33 @@
|
||||
package com.baidu.paddle.fastdeploy.ui.layout;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.RelativeLayout;
|
||||
|
||||
|
||||
public class ActionBarLayout extends RelativeLayout {
|
||||
private int layoutHeight = 150;
|
||||
|
||||
public ActionBarLayout(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public ActionBarLayout(Context context, @Nullable AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public ActionBarLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
int width = MeasureSpec.getSize(widthMeasureSpec);
|
||||
setMeasuredDimension(width, layoutHeight);
|
||||
setBackgroundColor(Color.BLACK);
|
||||
setAlpha(0.9f);
|
||||
}
|
||||
}
|
@@ -0,0 +1,111 @@
|
||||
package com.baidu.paddle.fastdeploy.ui.view;
|
||||
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceActivity;
|
||||
import android.support.annotation.LayoutRes;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v7.app.ActionBar;
|
||||
import android.support.v7.app.AppCompatDelegate;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
/**
|
||||
* A {@link PreferenceActivity} which implements and proxies the necessary calls
|
||||
* to be used with AppCompat.
|
||||
* <p>
|
||||
* This technique can be used with an {@link android.app.Activity} class, not just
|
||||
* {@link PreferenceActivity}.
|
||||
*/
|
||||
public abstract class AppCompatPreferenceActivity extends PreferenceActivity {
|
||||
private AppCompatDelegate mDelegate;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
getDelegate().installViewFactory();
|
||||
getDelegate().onCreate(savedInstanceState);
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostCreate(Bundle savedInstanceState) {
|
||||
super.onPostCreate(savedInstanceState);
|
||||
getDelegate().onPostCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
public ActionBar getSupportActionBar() {
|
||||
return getDelegate().getSupportActionBar();
|
||||
}
|
||||
|
||||
public void setSupportActionBar(@Nullable Toolbar toolbar) {
|
||||
getDelegate().setSupportActionBar(toolbar);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuInflater getMenuInflater() {
|
||||
return getDelegate().getMenuInflater();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentView(@LayoutRes int layoutResID) {
|
||||
getDelegate().setContentView(layoutResID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentView(View view) {
|
||||
getDelegate().setContentView(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentView(View view, ViewGroup.LayoutParams params) {
|
||||
getDelegate().setContentView(view, params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addContentView(View view, ViewGroup.LayoutParams params) {
|
||||
getDelegate().addContentView(view, params);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostResume() {
|
||||
super.onPostResume();
|
||||
getDelegate().onPostResume();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onTitleChanged(CharSequence title, int color) {
|
||||
super.onTitleChanged(title, color);
|
||||
getDelegate().setTitle(title);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
getDelegate().onConfigurationChanged(newConfig);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
super.onStop();
|
||||
getDelegate().onStop();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
getDelegate().onDestroy();
|
||||
}
|
||||
|
||||
public void invalidateOptionsMenu() {
|
||||
getDelegate().invalidateOptionsMenu();
|
||||
}
|
||||
|
||||
private AppCompatDelegate getDelegate() {
|
||||
if (mDelegate == null) {
|
||||
mDelegate = AppCompatDelegate.create(this, null);
|
||||
}
|
||||
return mDelegate;
|
||||
}
|
||||
}
|
@@ -0,0 +1,353 @@
|
||||
package com.baidu.paddle.fastdeploy.ui.view;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.SurfaceTexture;
|
||||
import android.hardware.Camera;
|
||||
import android.hardware.Camera.CameraInfo;
|
||||
import android.hardware.Camera.Size;
|
||||
import android.opengl.GLES11Ext;
|
||||
import android.opengl.GLES20;
|
||||
import android.opengl.GLSurfaceView;
|
||||
import android.opengl.GLSurfaceView.Renderer;
|
||||
import android.opengl.GLUtils;
|
||||
import android.opengl.Matrix;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
|
||||
import com.baidu.paddle.fastdeploy.ui.Utils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.FloatBuffer;
|
||||
import java.util.List;
|
||||
|
||||
import javax.microedition.khronos.egl.EGLConfig;
|
||||
import javax.microedition.khronos.opengles.GL10;
|
||||
|
||||
public class CameraSurfaceView extends GLSurfaceView implements Renderer,
|
||||
SurfaceTexture.OnFrameAvailableListener {
|
||||
private static final String TAG = CameraSurfaceView.class.getSimpleName();
|
||||
|
||||
public static int EXPECTED_PREVIEW_WIDTH = 1280; // 1920
|
||||
public static int EXPECTED_PREVIEW_HEIGHT = 720; // 960
|
||||
|
||||
protected int numberOfCameras;
|
||||
protected int selectedCameraId;
|
||||
protected boolean disableCamera = false;
|
||||
protected Camera camera;
|
||||
|
||||
protected Context context;
|
||||
protected SurfaceTexture surfaceTexture;
|
||||
protected int surfaceWidth = 0;
|
||||
protected int surfaceHeight = 0;
|
||||
protected int textureWidth = 0;
|
||||
protected int textureHeight = 0;
|
||||
|
||||
protected Bitmap ARGB8888ImageBitmap;
|
||||
protected boolean bitmapReleaseMode = true;
|
||||
|
||||
// In order to manipulate the camera preview data and render the modified one
|
||||
// to the screen, three textures are created and the data flow is shown as following:
|
||||
// previewdata->camTextureId->fboTexureId->drawTexureId->framebuffer
|
||||
protected int[] fbo = {0};
|
||||
protected int[] camTextureId = {0};
|
||||
protected int[] fboTexureId = {0};
|
||||
protected int[] drawTexureId = {0};
|
||||
|
||||
private final String vss = ""
|
||||
+ "attribute vec2 vPosition;\n"
|
||||
+ "attribute vec2 vTexCoord;\n" + "varying vec2 texCoord;\n"
|
||||
+ "void main() {\n" + " texCoord = vTexCoord;\n"
|
||||
+ " gl_Position = vec4 (vPosition.x, vPosition.y, 0.0, 1.0);\n"
|
||||
+ "}";
|
||||
|
||||
private final String fssCam2FBO = ""
|
||||
+ "#extension GL_OES_EGL_image_external : require\n"
|
||||
+ "precision mediump float;\n"
|
||||
+ "uniform samplerExternalOES sTexture;\n"
|
||||
+ "varying vec2 texCoord;\n"
|
||||
+ "void main() {\n"
|
||||
+ " gl_FragColor = texture2D(sTexture,texCoord);\n" + "}";
|
||||
|
||||
private final String fssTex2Screen = ""
|
||||
+ "precision mediump float;\n"
|
||||
+ "uniform sampler2D sTexture;\n"
|
||||
+ "varying vec2 texCoord;\n"
|
||||
+ "void main() {\n"
|
||||
+ " gl_FragColor = texture2D(sTexture,texCoord);\n" + "}";
|
||||
|
||||
private final float[] vertexCoords = {
|
||||
-1, -1,
|
||||
-1, 1,
|
||||
1, -1,
|
||||
1, 1};
|
||||
private float[] textureCoords = {
|
||||
0, 1,
|
||||
0, 0,
|
||||
1, 1,
|
||||
1, 0};
|
||||
|
||||
private FloatBuffer vertexCoordsBuffer;
|
||||
private FloatBuffer textureCoordsBuffer;
|
||||
|
||||
private int progCam2FBO = -1;
|
||||
private int progTex2Screen = -1;
|
||||
private int vcCam2FBO;
|
||||
private int tcCam2FBO;
|
||||
private int vcTex2Screen;
|
||||
private int tcTex2Screen;
|
||||
|
||||
public void setBitmapReleaseMode(boolean mode) {
|
||||
synchronized (this) {
|
||||
bitmapReleaseMode = mode;
|
||||
}
|
||||
}
|
||||
|
||||
public Bitmap getBitmap() {
|
||||
return ARGB8888ImageBitmap; // may null or recycled.
|
||||
}
|
||||
|
||||
public interface OnTextureChangedListener {
|
||||
boolean onTextureChanged(Bitmap ARGB8888ImageBitmap);
|
||||
}
|
||||
|
||||
private OnTextureChangedListener onTextureChangedListener = null;
|
||||
|
||||
public void setOnTextureChangedListener(OnTextureChangedListener listener) {
|
||||
onTextureChangedListener = listener;
|
||||
}
|
||||
|
||||
public CameraSurfaceView(Context ctx, AttributeSet attrs) {
|
||||
super(ctx, attrs);
|
||||
context = ctx;
|
||||
setEGLContextClientVersion(2);
|
||||
setRenderer(this);
|
||||
setRenderMode(RENDERMODE_WHEN_DIRTY);
|
||||
|
||||
// Find the total number of available cameras and the ID of the default camera
|
||||
numberOfCameras = Camera.getNumberOfCameras();
|
||||
CameraInfo cameraInfo = new CameraInfo();
|
||||
for (int i = 0; i < numberOfCameras; i++) {
|
||||
Camera.getCameraInfo(i, cameraInfo);
|
||||
if (cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK) {
|
||||
selectedCameraId = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
|
||||
// Create OES texture for storing camera preview data(YUV format)
|
||||
GLES20.glGenTextures(1, camTextureId, 0);
|
||||
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, camTextureId[0]);
|
||||
GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
|
||||
GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
|
||||
GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
|
||||
GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
|
||||
surfaceTexture = new SurfaceTexture(camTextureId[0]);
|
||||
surfaceTexture.setOnFrameAvailableListener(this);
|
||||
|
||||
// Prepare vertex and texture coordinates
|
||||
int bytes = vertexCoords.length * Float.SIZE / Byte.SIZE;
|
||||
vertexCoordsBuffer = ByteBuffer.allocateDirect(bytes).order(ByteOrder.nativeOrder()).asFloatBuffer();
|
||||
textureCoordsBuffer = ByteBuffer.allocateDirect(bytes).order(ByteOrder.nativeOrder()).asFloatBuffer();
|
||||
vertexCoordsBuffer.put(vertexCoords).position(0);
|
||||
textureCoordsBuffer.put(textureCoords).position(0);
|
||||
|
||||
// Create vertex and fragment shaders
|
||||
// camTextureId->fboTexureId
|
||||
progCam2FBO = Utils.createShaderProgram(vss, fssCam2FBO);
|
||||
vcCam2FBO = GLES20.glGetAttribLocation(progCam2FBO, "vPosition");
|
||||
tcCam2FBO = GLES20.glGetAttribLocation(progCam2FBO, "vTexCoord");
|
||||
GLES20.glEnableVertexAttribArray(vcCam2FBO);
|
||||
GLES20.glEnableVertexAttribArray(tcCam2FBO);
|
||||
// fboTexureId/drawTexureId -> screen
|
||||
progTex2Screen = Utils.createShaderProgram(vss, fssTex2Screen);
|
||||
vcTex2Screen = GLES20.glGetAttribLocation(progTex2Screen, "vPosition");
|
||||
tcTex2Screen = GLES20.glGetAttribLocation(progTex2Screen, "vTexCoord");
|
||||
GLES20.glEnableVertexAttribArray(vcTex2Screen);
|
||||
GLES20.glEnableVertexAttribArray(tcTex2Screen);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSurfaceChanged(GL10 gl, int width, int height) {
|
||||
surfaceWidth = width;
|
||||
surfaceHeight = height;
|
||||
openCamera();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDrawFrame(GL10 gl) {
|
||||
if (surfaceTexture == null) return;
|
||||
|
||||
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
|
||||
surfaceTexture.updateTexImage();
|
||||
float[] matrix = new float[16];
|
||||
surfaceTexture.getTransformMatrix(matrix);
|
||||
|
||||
// camTextureId->fboTexureId
|
||||
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fbo[0]);
|
||||
GLES20.glViewport(0, 0, textureWidth, textureHeight);
|
||||
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
|
||||
GLES20.glUseProgram(progCam2FBO);
|
||||
GLES20.glVertexAttribPointer(vcCam2FBO, 2, GLES20.GL_FLOAT, false, 4 * 2, vertexCoordsBuffer);
|
||||
textureCoordsBuffer.clear();
|
||||
textureCoordsBuffer.put(transformTextureCoordinates(textureCoords, matrix));
|
||||
textureCoordsBuffer.position(0);
|
||||
GLES20.glVertexAttribPointer(tcCam2FBO, 2, GLES20.GL_FLOAT, false, 4 * 2, textureCoordsBuffer);
|
||||
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
|
||||
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, camTextureId[0]);
|
||||
GLES20.glUniform1i(GLES20.glGetUniformLocation(progCam2FBO, "sTexture"), 0);
|
||||
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
|
||||
GLES20.glFlush();
|
||||
|
||||
// Check if the draw texture is set
|
||||
int targetTexureId = fboTexureId[0];
|
||||
if (onTextureChangedListener != null) {
|
||||
// Read pixels of FBO to a bitmap
|
||||
ByteBuffer pixelBuffer = ByteBuffer.allocate(textureWidth * textureHeight * 4);
|
||||
GLES20.glReadPixels(0, 0, textureWidth, textureHeight, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, pixelBuffer);
|
||||
|
||||
ARGB8888ImageBitmap = Bitmap.createBitmap(textureWidth, textureHeight, Bitmap.Config.ARGB_8888);
|
||||
ARGB8888ImageBitmap.copyPixelsFromBuffer(pixelBuffer);
|
||||
|
||||
boolean modified = onTextureChangedListener.onTextureChanged(ARGB8888ImageBitmap);
|
||||
|
||||
if (modified) {
|
||||
targetTexureId = drawTexureId[0];
|
||||
// Update a bitmap to the GL texture if modified
|
||||
GLES20.glActiveTexture(targetTexureId);
|
||||
// GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, targetTexureId);
|
||||
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, targetTexureId);
|
||||
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, ARGB8888ImageBitmap, 0);
|
||||
}
|
||||
if (bitmapReleaseMode) {
|
||||
ARGB8888ImageBitmap.recycle();
|
||||
}
|
||||
}
|
||||
|
||||
// fboTexureId/drawTexureId->Screen
|
||||
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
|
||||
GLES20.glViewport(0, 0, surfaceWidth, surfaceHeight);
|
||||
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
|
||||
GLES20.glUseProgram(progTex2Screen);
|
||||
GLES20.glVertexAttribPointer(vcTex2Screen, 2, GLES20.GL_FLOAT, false, 4 * 2, vertexCoordsBuffer);
|
||||
textureCoordsBuffer.clear();
|
||||
textureCoordsBuffer.put(textureCoords);
|
||||
textureCoordsBuffer.position(0);
|
||||
GLES20.glVertexAttribPointer(tcTex2Screen, 2, GLES20.GL_FLOAT, false, 4 * 2, textureCoordsBuffer);
|
||||
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
|
||||
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, targetTexureId);
|
||||
GLES20.glUniform1i(GLES20.glGetUniformLocation(progTex2Screen, "sTexture"), 0);
|
||||
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
|
||||
GLES20.glFlush();
|
||||
}
|
||||
|
||||
private float[] transformTextureCoordinates(float[] coords, float[] matrix) {
|
||||
float[] result = new float[coords.length];
|
||||
float[] vt = new float[4];
|
||||
for (int i = 0; i < coords.length; i += 2) {
|
||||
float[] v = {coords[i], coords[i + 1], 0, 1};
|
||||
Matrix.multiplyMV(vt, 0, matrix, 0, v, 0);
|
||||
result[i] = vt[0];
|
||||
result[i + 1] = vt[1];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
releaseCamera();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFrameAvailable(SurfaceTexture surfaceTexture) {
|
||||
requestRender();
|
||||
}
|
||||
|
||||
public void disableCamera() {
|
||||
disableCamera = true;
|
||||
}
|
||||
|
||||
public void enableCamera() {
|
||||
disableCamera = false;
|
||||
}
|
||||
|
||||
public void switchCamera() {
|
||||
releaseCamera();
|
||||
selectedCameraId = (selectedCameraId + 1) % numberOfCameras;
|
||||
openCamera();
|
||||
}
|
||||
|
||||
public void openCamera() {
|
||||
if (disableCamera) return;
|
||||
camera = Camera.open(selectedCameraId);
|
||||
List<Size> supportedPreviewSizes = camera.getParameters().getSupportedPreviewSizes();
|
||||
Size previewSize = Utils.getOptimalPreviewSize(supportedPreviewSizes, EXPECTED_PREVIEW_WIDTH,
|
||||
EXPECTED_PREVIEW_HEIGHT);
|
||||
Camera.Parameters parameters = camera.getParameters();
|
||||
parameters.setPreviewSize(previewSize.width, previewSize.height);
|
||||
if (parameters.getSupportedFocusModes().contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO)) {
|
||||
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
|
||||
}
|
||||
camera.setParameters(parameters);
|
||||
int degree = Utils.getCameraDisplayOrientation(context, selectedCameraId);
|
||||
camera.setDisplayOrientation(degree);
|
||||
boolean rotate = degree == 90 || degree == 270;
|
||||
textureWidth = rotate ? previewSize.height : previewSize.width;
|
||||
textureHeight = rotate ? previewSize.width : previewSize.height;
|
||||
|
||||
// Destroy FBO and draw textures
|
||||
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
|
||||
GLES20.glDeleteFramebuffers(1, fbo, 0);
|
||||
GLES20.glDeleteTextures(1, drawTexureId, 0);
|
||||
GLES20.glDeleteTextures(1, fboTexureId, 0);
|
||||
// Normal texture for storing modified camera preview data(RGBA format)
|
||||
GLES20.glGenTextures(1, drawTexureId, 0);
|
||||
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, drawTexureId[0]);
|
||||
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, textureWidth, textureHeight, 0,
|
||||
GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null);
|
||||
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
|
||||
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
|
||||
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
|
||||
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
|
||||
// FBO texture for storing camera preview data(RGBA format)
|
||||
GLES20.glGenTextures(1, fboTexureId, 0);
|
||||
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, fboTexureId[0]);
|
||||
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, textureWidth, textureHeight, 0,
|
||||
GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null);
|
||||
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
|
||||
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
|
||||
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
|
||||
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
|
||||
// Generate FBO and bind to FBO texture
|
||||
GLES20.glGenFramebuffers(1, fbo, 0);
|
||||
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fbo[0]);
|
||||
GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D,
|
||||
fboTexureId[0], 0);
|
||||
try {
|
||||
camera.setPreviewTexture(surfaceTexture);
|
||||
} catch (IOException exception) {
|
||||
Log.e(TAG, "IOException caused by setPreviewDisplay()", exception);
|
||||
}
|
||||
camera.startPreview();
|
||||
}
|
||||
|
||||
public void releaseCamera() {
|
||||
if (camera != null) {
|
||||
camera.setPreviewCallback(null);
|
||||
camera.stopPreview();
|
||||
camera.release();
|
||||
camera = null;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,43 @@
|
||||
package com.baidu.paddle.fastdeploy.ui.view;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Handler;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.ListView;
|
||||
|
||||
public class ResultListView extends ListView {
|
||||
public ResultListView(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public ResultListView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public ResultListView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
}
|
||||
|
||||
private Handler handler;
|
||||
|
||||
public void setHandler(Handler mHandler) {
|
||||
handler = mHandler;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
handler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
removeAllViewsInLayout();
|
||||
invalidate();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
|
||||
MeasureSpec.AT_MOST);
|
||||
super.onMeasure(widthMeasureSpec, expandSpec);
|
||||
}
|
||||
}
|
@@ -0,0 +1,48 @@
|
||||
package com.baidu.paddle.fastdeploy.ui.view.adapter;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.baidu.paddle.fastdeploy.ui.R;
|
||||
import com.baidu.paddle.fastdeploy.ui.view.model.BaseResultModel;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.List;
|
||||
|
||||
public class BaseResultAdapter extends ArrayAdapter<BaseResultModel> {
|
||||
private int resourceId;
|
||||
|
||||
public BaseResultAdapter(@NonNull Context context, int resource) {
|
||||
super(context, resource);
|
||||
}
|
||||
|
||||
public BaseResultAdapter(@NonNull Context context, int resource, @NonNull List<BaseResultModel> objects) {
|
||||
super(context, resource, objects);
|
||||
resourceId = resource;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
|
||||
BaseResultModel model = getItem(position);
|
||||
View view = LayoutInflater.from(getContext()).inflate(resourceId, null);
|
||||
TextView indexText = (TextView) view.findViewById(R.id.index);
|
||||
TextView nameText = (TextView) view.findViewById(R.id.name);
|
||||
TextView confidenceText = (TextView) view.findViewById(R.id.confidence);
|
||||
indexText.setText(String.valueOf(model.getIndex()));
|
||||
nameText.setText(String.valueOf(model.getName()));
|
||||
confidenceText.setText(formatFloatString(model.getConfidence()));
|
||||
return view;
|
||||
}
|
||||
|
||||
public static String formatFloatString(float number) {
|
||||
DecimalFormat df = new DecimalFormat("0.00");
|
||||
return df.format(number);
|
||||
}
|
||||
}
|
@@ -0,0 +1,41 @@
|
||||
package com.baidu.paddle.fastdeploy.ui.view.model;
|
||||
|
||||
public class BaseResultModel {
|
||||
private int index;
|
||||
private String name;
|
||||
private float confidence;
|
||||
|
||||
public BaseResultModel() {
|
||||
|
||||
}
|
||||
|
||||
public BaseResultModel(int index, String name, float confidence) {
|
||||
this.index = index;
|
||||
this.name = name;
|
||||
this.confidence = confidence;
|
||||
}
|
||||
|
||||
public float getConfidence() {
|
||||
return confidence;
|
||||
}
|
||||
|
||||
public void setConfidence(float confidence) {
|
||||
this.confidence = confidence;
|
||||
}
|
||||
|
||||
public int getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
public void setIndex(int index) {
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item>
|
||||
<shape android:shape="rectangle">
|
||||
<solid android:color="#FFFFFF" />
|
||||
|
||||
<stroke
|
||||
android:width="1px"
|
||||
android:color="#E5E5E5" />
|
||||
</shape>
|
||||
</item>
|
||||
</layer-list>
|
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/result_page_border_section_bk">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/index"
|
||||
style="@style/list_result_view_item_style"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_weight="0.2" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/name"
|
||||
style="@style/list_result_view_item_style"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_weight="0.6"
|
||||
android:maxWidth="300px" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/confidence"
|
||||
style="@style/list_result_view_item_style"
|
||||
android:layout_weight="0.2"
|
||||
android:layout_width="wrap_content" />
|
||||
</LinearLayout>
|
22
java/android/ui/src/main/res/values/colors.xml
Normal file
22
java/android/ui/src/main/res/values/colors.xml
Normal file
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="colorPrimary">#008577</color>
|
||||
<color name="colorPrimaryDark">#00574B</color>
|
||||
<color name="colorAccent">#D81B60</color>
|
||||
<color name="colorWindow">#FF000000</color>
|
||||
<color name="colorTopBar">#00000000</color>
|
||||
<color name="colorBottomBar">#00000000</color>
|
||||
<color name="colorText">#FFFFFFFF</color>
|
||||
|
||||
<color name="bk_black">#000000</color>
|
||||
<color name="bk_blue">#3B85F5</color>
|
||||
<color name="textColorHighlight">#F5A623</color>
|
||||
<color name="textColor">#FFFFFF</color>
|
||||
|
||||
<color name="bk_result_image_padding">#EEEEEE</color>
|
||||
|
||||
<color name="table_result_item_text_color">#3B85F5</color>
|
||||
<color name="table_result_tableheader_text_color">#333333</color>
|
||||
<color name="result_section_border_color">#E5E5E5</color>
|
||||
<color name="result_popview_tablebody_bk">#3b85f5</color>
|
||||
</resources>
|
70
java/android/ui/src/main/res/values/styles.xml
Normal file
70
java/android/ui/src/main/res/values/styles.xml
Normal file
@@ -0,0 +1,70 @@
|
||||
<resources>
|
||||
|
||||
<!-- Base application theme. -->
|
||||
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
|
||||
<!-- Customize your theme here. -->
|
||||
<item name="colorPrimary">@color/colorPrimary</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
||||
<item name="colorAccent">@color/colorAccent</item>
|
||||
<item name="actionOverflowMenuStyle">@style/OverflowMenuStyle</item>
|
||||
</style>
|
||||
|
||||
<style name="OverflowMenuStyle" parent="Widget.AppCompat.Light.PopupMenu.Overflow">
|
||||
<item name="overlapAnchor">false</item>
|
||||
</style>
|
||||
|
||||
<style name="AppTheme.NoActionBar">
|
||||
<item name="windowActionBar">false</item>
|
||||
<item name="windowNoTitle">true</item>
|
||||
</style>
|
||||
|
||||
<style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar"/>
|
||||
|
||||
<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light"/>
|
||||
|
||||
<style name="list_result_view_item_style">
|
||||
<item name="android:textColor">@color/table_result_item_text_color</item>
|
||||
<item name="android:layout_height">wrap_content</item>
|
||||
<item name="android:layout_weight">1</item>
|
||||
<item name="android:gravity">left</item>
|
||||
<item name="android:padding">30px</item>
|
||||
</style>
|
||||
|
||||
<style name="list_result_popview_item_style">
|
||||
<item name="android:textColor">@color/textColor</item>
|
||||
<item name="android:layout_height">wrap_content</item>
|
||||
<item name="android:gravity">left</item>
|
||||
<item name="android:padding">15px</item>
|
||||
<item name="android:background">@color/result_popview_tablebody_bk</item>
|
||||
<item name="android:layout_width">wrap_content</item>
|
||||
<item name="android:alpha">0.5</item>
|
||||
</style>
|
||||
|
||||
<style name="list_result_view_tablehead_style">
|
||||
<item name="android:textColor">@color/table_result_item_text_color</item>
|
||||
<item name="android:layout_height">wrap_content</item>
|
||||
<item name="android:layout_weight">1</item>
|
||||
<item name="android:gravity">left</item>
|
||||
<item name="android:padding">15px</item>
|
||||
</style>
|
||||
|
||||
<style name="list_result_popview_tablehead_style">
|
||||
<item name="android:textColor">@color/textColor</item>
|
||||
<item name="android:layout_height">wrap_content</item>
|
||||
<item name="android:layout_weight">1</item>
|
||||
<item name="android:gravity">left</item>
|
||||
<item name="android:padding">20px</item>
|
||||
</style>
|
||||
|
||||
<style name="action_btn">
|
||||
<item name="android:textColor">@color/textColor</item>
|
||||
<item name="android:background">@color/bk_black</item>
|
||||
</style>
|
||||
|
||||
<style name="action_btn_selected">
|
||||
<item name="android:textColor">@color/textColorHighlight</item>
|
||||
<item name="android:background">@color/bk_black</item>
|
||||
</style>
|
||||
|
||||
|
||||
</resources>
|
Reference in New Issue
Block a user