[
  {
    "path": ".gitignore",
    "content": "*.iml\n.gradle\n/local.properties\n/.idea/workspace.xml\n/.idea/libraries\n.DS_Store\n/build\n/captures\n.externalNativeBuild\n"
  },
  {
    "path": ".idea/codeStyles/Project.xml",
    "content": "<component name=\"ProjectCodeStyleConfiguration\">\n  <code_scheme name=\"Project\" version=\"173\">\n    <codeStyleSettings language=\"XML\">\n      <indentOptions>\n        <option name=\"CONTINUATION_INDENT_SIZE\" value=\"4\" />\n      </indentOptions>\n      <arrangement>\n        <rules>\n          <section>\n            <rule>\n              <match>\n                <AND>\n                  <NAME>xmlns:android</NAME>\n                  <XML_ATTRIBUTE />\n                  <XML_NAMESPACE>^$</XML_NAMESPACE>\n                </AND>\n              </match>\n            </rule>\n          </section>\n          <section>\n            <rule>\n              <match>\n                <AND>\n                  <NAME>xmlns:.*</NAME>\n                  <XML_ATTRIBUTE />\n                  <XML_NAMESPACE>^$</XML_NAMESPACE>\n                </AND>\n              </match>\n              <order>BY_NAME</order>\n            </rule>\n          </section>\n          <section>\n            <rule>\n              <match>\n                <AND>\n                  <NAME>.*:id</NAME>\n                  <XML_ATTRIBUTE />\n                  <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>\n                </AND>\n              </match>\n            </rule>\n          </section>\n          <section>\n            <rule>\n              <match>\n                <AND>\n                  <NAME>.*:name</NAME>\n                  <XML_ATTRIBUTE />\n                  <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>\n                </AND>\n              </match>\n            </rule>\n          </section>\n          <section>\n            <rule>\n              <match>\n                <AND>\n                  <NAME>name</NAME>\n                  <XML_ATTRIBUTE />\n                  <XML_NAMESPACE>^$</XML_NAMESPACE>\n                </AND>\n              </match>\n            </rule>\n          </section>\n          <section>\n            <rule>\n              <match>\n                <AND>\n                  <NAME>style</NAME>\n                  <XML_ATTRIBUTE />\n                  <XML_NAMESPACE>^$</XML_NAMESPACE>\n                </AND>\n              </match>\n            </rule>\n          </section>\n          <section>\n            <rule>\n              <match>\n                <AND>\n                  <NAME>.*</NAME>\n                  <XML_ATTRIBUTE />\n                  <XML_NAMESPACE>^$</XML_NAMESPACE>\n                </AND>\n              </match>\n              <order>BY_NAME</order>\n            </rule>\n          </section>\n          <section>\n            <rule>\n              <match>\n                <AND>\n                  <NAME>.*</NAME>\n                  <XML_ATTRIBUTE />\n                  <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>\n                </AND>\n              </match>\n              <order>ANDROID_ATTRIBUTE_ORDER</order>\n            </rule>\n          </section>\n          <section>\n            <rule>\n              <match>\n                <AND>\n                  <NAME>.*</NAME>\n                  <XML_ATTRIBUTE />\n                  <XML_NAMESPACE>.*</XML_NAMESPACE>\n                </AND>\n              </match>\n              <order>BY_NAME</order>\n            </rule>\n          </section>\n        </rules>\n      </arrangement>\n    </codeStyleSettings>\n  </code_scheme>\n</component>"
  },
  {
    "path": ".idea/gradle.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"GradleMigrationSettings\" migrationVersion=\"1\" />\n  <component name=\"GradleSettings\">\n    <option name=\"linkedExternalProjectsSettings\">\n      <GradleProjectSettings>\n        <option name=\"testRunner\" value=\"PLATFORM\" />\n        <option name=\"distributionType\" value=\"DEFAULT_WRAPPED\" />\n        <option name=\"externalProjectPath\" value=\"$PROJECT_DIR$\" />\n        <option name=\"modules\">\n          <set>\n            <option value=\"$PROJECT_DIR$\" />\n            <option value=\"$PROJECT_DIR$/app\" />\n          </set>\n        </option>\n        <option name=\"resolveModulePerSourceSet\" value=\"false\" />\n      </GradleProjectSettings>\n    </option>\n  </component>\n</project>"
  },
  {
    "path": ".idea/inspectionProfiles/Project_Default.xml",
    "content": "<component name=\"InspectionProjectProfileManager\">\n  <profile version=\"1.0\">\n    <option name=\"myName\" value=\"Project Default\" />\n    <inspection_tool class=\"JavaDoc\" enabled=\"true\" level=\"WARNING\" enabled_by_default=\"true\">\n      <option name=\"TOP_LEVEL_CLASS_OPTIONS\">\n        <value>\n          <option name=\"ACCESS_JAVADOC_REQUIRED_FOR\" value=\"none\" />\n          <option name=\"REQUIRED_TAGS\" value=\"\" />\n        </value>\n      </option>\n      <option name=\"INNER_CLASS_OPTIONS\">\n        <value>\n          <option name=\"ACCESS_JAVADOC_REQUIRED_FOR\" value=\"none\" />\n          <option name=\"REQUIRED_TAGS\" value=\"\" />\n        </value>\n      </option>\n      <option name=\"METHOD_OPTIONS\">\n        <value>\n          <option name=\"ACCESS_JAVADOC_REQUIRED_FOR\" value=\"none\" />\n          <option name=\"REQUIRED_TAGS\" value=\"@return@param@throws or @exception\" />\n        </value>\n      </option>\n      <option name=\"FIELD_OPTIONS\">\n        <value>\n          <option name=\"ACCESS_JAVADOC_REQUIRED_FOR\" value=\"none\" />\n          <option name=\"REQUIRED_TAGS\" value=\"\" />\n        </value>\n      </option>\n      <option name=\"IGNORE_DEPRECATED\" value=\"false\" />\n      <option name=\"IGNORE_JAVADOC_PERIOD\" value=\"true\" />\n      <option name=\"IGNORE_DUPLICATED_THROWS\" value=\"false\" />\n      <option name=\"IGNORE_POINT_TO_ITSELF\" value=\"false\" />\n      <option name=\"myAdditionalJavadocTags\" value=\"date,fileName:,date:,author:,QQ:745612618,packageName:\" />\n    </inspection_tool>\n  </profile>\n</component>"
  },
  {
    "path": ".idea/jarRepositories.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"RemoteRepositoriesConfiguration\">\n    <remote-repository>\n      <option name=\"id\" value=\"central\" />\n      <option name=\"name\" value=\"Maven Central repository\" />\n      <option name=\"url\" value=\"https://repo1.maven.org/maven2\" />\n    </remote-repository>\n    <remote-repository>\n      <option name=\"id\" value=\"jboss.community\" />\n      <option name=\"name\" value=\"JBoss Community repository\" />\n      <option name=\"url\" value=\"https://repository.jboss.org/nexus/content/repositories/public/\" />\n    </remote-repository>\n    <remote-repository>\n      <option name=\"id\" value=\"maven2\" />\n      <option name=\"name\" value=\"maven2\" />\n      <option name=\"url\" value=\"https://maven.google.com\" />\n    </remote-repository>\n    <remote-repository>\n      <option name=\"id\" value=\"BintrayJCenter\" />\n      <option name=\"name\" value=\"BintrayJCenter\" />\n      <option name=\"url\" value=\"https://jcenter.bintray.com/\" />\n    </remote-repository>\n    <remote-repository>\n      <option name=\"id\" value=\"maven\" />\n      <option name=\"name\" value=\"maven\" />\n      <option name=\"url\" value=\"https://jitpack.io\" />\n    </remote-repository>\n    <remote-repository>\n      <option name=\"id\" value=\"Google\" />\n      <option name=\"name\" value=\"Google\" />\n      <option name=\"url\" value=\"https://dl.google.com/dl/android/maven2/\" />\n    </remote-repository>\n    <remote-repository>\n      <option name=\"id\" value=\"$USER_HOME$/Library/Android/sdk/extras/google/m2repository\" />\n      <option name=\"name\" value=\"$USER_HOME$/Library/Android/sdk/extras/google/m2repository\" />\n      <option name=\"url\" value=\"file:$USER_HOME$/Library/Android/sdk/extras/google/m2repository/\" />\n    </remote-repository>\n    <remote-repository>\n      <option name=\"id\" value=\"$USER_HOME$/Library/Android/sdk/extras/m2repository\" />\n      <option name=\"name\" value=\"$USER_HOME$/Library/Android/sdk/extras/m2repository\" />\n      <option name=\"url\" value=\"file:$USER_HOME$/Library/Android/sdk/extras/m2repository/\" />\n    </remote-repository>\n    <remote-repository>\n      <option name=\"id\" value=\"$USER_HOME$/Library/Android/sdk/extras/android/m2repository\" />\n      <option name=\"name\" value=\"$USER_HOME$/Library/Android/sdk/extras/android/m2repository\" />\n      <option name=\"url\" value=\"file:$USER_HOME$/Library/Android/sdk/extras/android/m2repository/\" />\n    </remote-repository>\n  </component>\n</project>"
  },
  {
    "path": ".idea/misc.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"ASMPluginConfiguration\">\n    <asm skipDebug=\"false\" skipFrames=\"false\" skipCode=\"false\" expandFrames=\"false\" />\n    <groovy codeStyle=\"LEGACY\" />\n  </component>\n  <component name=\"NullableNotNullManager\">\n    <option name=\"myDefaultNullable\" value=\"android.support.annotation.Nullable\" />\n    <option name=\"myDefaultNotNull\" value=\"android.support.annotation.NonNull\" />\n    <option name=\"myNullables\">\n      <value>\n        <list size=\"12\">\n          <item index=\"0\" class=\"java.lang.String\" itemvalue=\"org.jetbrains.annotations.Nullable\" />\n          <item index=\"1\" class=\"java.lang.String\" itemvalue=\"javax.annotation.Nullable\" />\n          <item index=\"2\" class=\"java.lang.String\" itemvalue=\"edu.umd.cs.findbugs.annotations.Nullable\" />\n          <item index=\"3\" class=\"java.lang.String\" itemvalue=\"android.support.annotation.Nullable\" />\n          <item index=\"4\" class=\"java.lang.String\" itemvalue=\"javax.annotation.CheckForNull\" />\n          <item index=\"5\" class=\"java.lang.String\" itemvalue=\"androidx.annotation.Nullable\" />\n          <item index=\"6\" class=\"java.lang.String\" itemvalue=\"androidx.annotation.RecentlyNullable\" />\n          <item index=\"7\" class=\"java.lang.String\" itemvalue=\"org.checkerframework.checker.nullness.qual.Nullable\" />\n          <item index=\"8\" class=\"java.lang.String\" itemvalue=\"org.checkerframework.checker.nullness.compatqual.NullableDecl\" />\n          <item index=\"9\" class=\"java.lang.String\" itemvalue=\"org.checkerframework.checker.nullness.compatqual.NullableType\" />\n          <item index=\"10\" class=\"java.lang.String\" itemvalue=\"android.annotation.Nullable\" />\n          <item index=\"11\" class=\"java.lang.String\" itemvalue=\"com.android.annotations.Nullable\" />\n        </list>\n      </value>\n    </option>\n    <option name=\"myNotNulls\">\n      <value>\n        <list size=\"11\">\n          <item index=\"0\" class=\"java.lang.String\" itemvalue=\"org.jetbrains.annotations.NotNull\" />\n          <item index=\"1\" class=\"java.lang.String\" itemvalue=\"javax.annotation.Nonnull\" />\n          <item index=\"2\" class=\"java.lang.String\" itemvalue=\"edu.umd.cs.findbugs.annotations.NonNull\" />\n          <item index=\"3\" class=\"java.lang.String\" itemvalue=\"android.support.annotation.NonNull\" />\n          <item index=\"4\" class=\"java.lang.String\" itemvalue=\"androidx.annotation.NonNull\" />\n          <item index=\"5\" class=\"java.lang.String\" itemvalue=\"androidx.annotation.RecentlyNonNull\" />\n          <item index=\"6\" class=\"java.lang.String\" itemvalue=\"org.checkerframework.checker.nullness.qual.NonNull\" />\n          <item index=\"7\" class=\"java.lang.String\" itemvalue=\"org.checkerframework.checker.nullness.compatqual.NonNullDecl\" />\n          <item index=\"8\" class=\"java.lang.String\" itemvalue=\"org.checkerframework.checker.nullness.compatqual.NonNullType\" />\n          <item index=\"9\" class=\"java.lang.String\" itemvalue=\"android.annotation.NonNull\" />\n          <item index=\"10\" class=\"java.lang.String\" itemvalue=\"com.android.annotations.NonNull\" />\n        </list>\n      </value>\n    </option>\n  </component>\n  <component name=\"ProjectRootManager\" version=\"2\" languageLevel=\"JDK_1_7\" project-jdk-name=\"1.8\" project-jdk-type=\"JavaSDK\">\n    <output url=\"file://$PROJECT_DIR$/build/classes\" />\n  </component>\n  <component name=\"ProjectType\">\n    <option name=\"id\" value=\"Android\" />\n  </component>\n  <component name=\"masterDetails\">\n    <states>\n      <state key=\"ProjectJDKs.UI\">\n        <settings>\n          <last-edited>1.8</last-edited>\n          <splitter-proportions>\n            <option name=\"proportions\">\n              <list>\n                <option value=\"0.2\" />\n              </list>\n            </option>\n          </splitter-proportions>\n        </settings>\n      </state>\n    </states>\n  </component>\n</project>"
  },
  {
    "path": ".idea/modules.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"ProjectModuleManager\">\n    <modules>\n      <module fileurl=\"file://$PROJECT_DIR$/CameraMaster.iml\" filepath=\"$PROJECT_DIR$/CameraMaster.iml\" />\n      <module fileurl=\"file://$PROJECT_DIR$/.idea/modules/app/CameraMaster-app.iml\" filepath=\"$PROJECT_DIR$/.idea/modules/app/CameraMaster-app.iml\" group=\"CameraMaster/app\" />\n      <module fileurl=\"file://$PROJECT_DIR$/.idea/modules/camerax/CameraMaster-camerax.iml\" filepath=\"$PROJECT_DIR$/.idea/modules/camerax/CameraMaster-camerax.iml\" group=\"CameraMaster/camerax\" />\n      <module fileurl=\"file://$PROJECT_DIR$/.idea/modules/Downloads-githubwork-CameraMaster.iml\" filepath=\"$PROJECT_DIR$/.idea/modules/Downloads-githubwork-CameraMaster.iml\" group=\"CameraMaster\" />\n      <module fileurl=\"file://$PROJECT_DIR$/.idea/modules/app/Downloads-githubwork-CameraMaster-app.iml\" filepath=\"$PROJECT_DIR$/.idea/modules/app/Downloads-githubwork-CameraMaster-app.iml\" group=\"CameraMaster/app\" />\n      <module fileurl=\"file://$PROJECT_DIR$/app/app.iml\" filepath=\"$PROJECT_DIR$/app/app.iml\" />\n      <module fileurl=\"file://$PROJECT_DIR$/.idea/modules/app/camerax/camerax.iml\" filepath=\"$PROJECT_DIR$/.idea/modules/app/camerax/camerax.iml\" group=\"CameraMaster/app/camerax\" />\n      <module fileurl=\"file://$PROJECT_DIR$/.idea/modules/githubwork-CameraMaster.iml\" filepath=\"$PROJECT_DIR$/.idea/modules/githubwork-CameraMaster.iml\" group=\"CameraMaster\" />\n      <module fileurl=\"file://$PROJECT_DIR$/.idea/modules/app/githubwork-CameraMaster-app.iml\" filepath=\"$PROJECT_DIR$/.idea/modules/app/githubwork-CameraMaster-app.iml\" group=\"CameraMaster/app\" />\n      <module fileurl=\"file://$PROJECT_DIR$/.idea/modules/yangmingchuan-Downloads-githubwork-CameraMaster.iml\" filepath=\"$PROJECT_DIR$/.idea/modules/yangmingchuan-Downloads-githubwork-CameraMaster.iml\" group=\"CameraMaster\" />\n    </modules>\n  </component>\n</project>"
  },
  {
    "path": ".idea/runConfigurations.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"RunConfigurationProducerService\">\n    <option name=\"ignoredProducers\">\n      <set>\n        <option value=\"org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer\" />\n        <option value=\"org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer\" />\n        <option value=\"org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer\" />\n      </set>\n    </option>\n  </component>\n</project>"
  },
  {
    "path": ".idea/vcs.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"VcsDirectoryMappings\">\n    <mapping directory=\"$PROJECT_DIR$\" vcs=\"Git\" />\n  </component>\n</project>"
  },
  {
    "path": "README.md",
    "content": "# SunCamera\n\n一个 学习自定义的 Camera1 、Camera2 、Camera X 和 OpenglES 的Demo\n\n# 版本迭代\n \n -  1.3 完善部分bug （暂时停止维护，抽空整理成底层SDK，相对架构来一次深度的学习）\n -  1.2 添加 拍照录像及硬件设备信息调节界面\n -  1.1 添加 Camera 2 相机使用界面\n -  1.0 添加 Camera 1 相机使用界面\n\n# 感谢\n\nhttps://github.com/chensowf/Camera   录像代码部分参考和学习。感谢开源\n\n\n# 效果图\n\n1. 目前 拍照 摄像界面 效果界面主要 在 CameraVideoActivity 界面中。\n\n![image](https://github.com/yangmingchuan/CameraMaster/blob/5d92dda84ff32038e7abe94a7a15c40eea7f1a66/app/src/main/res/drawable-v24/64F105A2D530CDE27A0F21CBC6C0B877.gif)\n\n2.camera+surfaceview 博客地址：https://www.jianshu.com/p/af39024896ce\n\n![image](https://upload-images.jianshu.io/upload_images/6188347-cd61d9a329522b0a?imageMogr2/auto-orient/)\n\n\n3. camera2 + TextureView   博客地址 ： https://www.jianshu.com/p/c99fd9dfd77f\n\n4. camera2 + glSurfaceview  + opengles  博客地址 ： https://www.jianshu.com/p/e4ece3f21ec8\n\n![image](https://img-blog.csdnimg.cn/2019040210145280.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzI3OTQ4NjU5,size_16,color_FFFFFF,t_70)\n\n"
  },
  {
    "path": "app/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "app/build.gradle",
    "content": "apply plugin: 'com.android.application'\n\nandroid {\n    compileSdkVersion 27\n    defaultConfig {\n        applicationId \"camera.cn.cameramaster\"\n        minSdkVersion 17\n        targetSdkVersion 27\n        versionCode 103\n        versionName \"1.0.3\"\n        testInstrumentationRunner \"android.support.test.runner.AndroidJUnitRunner\"\n    }\n    buildTypes {\n        debug {\n            debuggable true\n            zipAlignEnabled false\n            minifyEnabled false\n            shrinkResources false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n\n        release {\n            debuggable false\n            zipAlignEnabled true\n            minifyEnabled true\n            shrinkResources true\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n    buildToolsVersion '27.0.3'\n}\n\ndependencies {\n    implementation fileTree(include: ['*.jar'], dir: 'libs')\n    implementation 'com.android.support:appcompat-v7:27.1.1'\n    implementation 'com.android.support.constraint:constraint-layout:1.1.3'\n    testImplementation 'junit:junit:4.12'\n    implementation 'com.android.support:cardview-v7:27.1.1'\n    implementation 'com.android.support:recyclerview-v7:27.1.1'\n    androidTestImplementation 'com.android.support.test:runner:1.0.2'\n    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'\n    // butterknife\n    implementation 'com.jakewharton:butterknife:8.8.1'\n    annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'\n    // permission\n    implementation 'com.yanzhenjie:permission:2.0.0-rc4'\n    implementation 'com.android.support:exifinterface:27.1.1'\n    // api\n    implementation 'com.yanzhenjie.andserver:api:2.0.4'\n    annotationProcessor 'com.yanzhenjie.andserver:processor:2.0.4'\n    // load json\n    implementation 'com.alibaba:fastjson:1.2.48'\n    implementation 'com.yanzhenjie:loading:1.0.0'\n    // event bus\n    implementation 'org.greenrobot:eventbus:3.1.1'\n\n    api \"io.reactivex.rxjava2:rxjava:2.1.0\"\n    api \"io.reactivex.rxjava2:rxandroid:2.1.0\"\n}\n"
  },
  {
    "path": "app/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile\n"
  },
  {
    "path": "app/src/androidTest/java/camera/cn/cameramaster/ExampleInstrumentedTest.java",
    "content": "package camera.cn.cameramaster;\n\nimport android.content.Context;\nimport android.support.test.InstrumentationRegistry;\nimport android.support.test.runner.AndroidJUnit4;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\n\nimport static org.junit.Assert.*;\n\n/**\n * Instrumented test, which will execute on an Android device.\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\n */\n@RunWith(AndroidJUnit4.class)\npublic class ExampleInstrumentedTest {\n    @Test\n    public void useAppContext() throws Exception {\n        // Context of the app under test.\n        Context appContext = InstrumentationRegistry.getTargetContext();\n\n        assertEquals(\"camera.cn.cameramaster\", appContext.getPackageName());\n    }\n}\n"
  },
  {
    "path": "app/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    package=\"camera.cn.cameramaster\">\n\n    <uses-permission android:name=\"android.permission.CAMERA\" />\n    <uses-permission android:name=\"android.permission.INTERNET\" />\n    <uses-permission android:name=\"android.permission.READ_EXTERNAL_STORAGE\" />\n    <uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\" />\n    <uses-permission android:name=\"android.permission.RECORD_AUDIO\" />\n    <uses-permission android:name=\"android.permission.FLASHLIGHT\" />\n\n    <uses-permission android:name=\"android.permission.MODIFY_PHONE_STATE\"\n        tools:ignore=\"ProtectedPermissions\" />\n\n    <uses-feature android:name=\"android.hardware.camera\" />\n    <uses-feature android:name=\"android.hardware.camera.autofocus\" />\n\n    <application\n        android:name=\".base.App\"\n        android:allowBackup=\"true\"\n        android:hardwareAccelerated=\"true\"\n        android:icon=\"@drawable/ic_launcher_camera\"\n        android:label=\"@string/app_name\"\n        android:largeHeap=\"true\"\n        android:roundIcon=\"@drawable/ic_launcher_camera\"\n        android:supportsRtl=\"true\"\n        android:theme=\"@style/AppTheme\">\n\n        <!-- 首页 -->\n        <activity android:name=\".ui.MainActivity\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\" />\n\n                <category android:name=\"android.intent.category.LAUNCHER\" />\n                <!-- 设置为开机显示应用 -->\n                <!-- <category android:name=\"android.intent.category.HOME\" /> -->\n                <category android:name=\"android.intent.category.DEFAULT\" />\n                <category android:name=\"android.intent.category.MONKEY\" />\n            </intent-filter>\n        </activity>\n\n        <!-- 5.0- 拍照界面 -->\n        <activity android:name=\".ui.CameraActivity\" />\n\n        <!-- 显示图像界面 -->\n        <activity android:name=\".ui.ShowPicActivity\" />\n\n        <!-- 开机广播接受者 -->\n        <receiver android:name=\".OpenReceiver\">\n            <intent-filter>\n\n                <!-- 注册开机广播地址 -->\n                <action android:name=\"android.intent.action.BOOT_COMPLETED\" />\n            </intent-filter>\n        </receiver>\n\n        <activity android:name=\".ui.Camera2Activity\" />\n        <activity android:name=\".ui.GoogleCameraActivity\"></activity>\n        <activity android:name=\".ui.CameraSurfaceViewActivity\"></activity>\n\n        <service\n            android:name=\".server.CoreService\"\n            android:exported=\"false\" />\n\n        <activity android:name=\".ui.CameraVideoActivity\"></activity>\n\n        <provider\n            android:name=\"android.support.v4.content.FileProvider\"\n            android:authorities=\"${applicationId}.fileprovider\"\n            android:exported=\"false\"\n            android:grantUriPermissions=\"true\">\n            <meta-data\n                android:name=\"android.support.FILE_PROVIDER_PATHS\"\n                android:resource=\"@xml/file_paths\" />\n        </provider>\n    </application>\n\n</manifest>"
  },
  {
    "path": "app/src/main/assets/web/css/login.css",
    "content": ".sec_body { color:#404040;background:#EBEBEB;text-shadow:#ddd 0 1px 0px;font-family:Helvetica;line-height:1.5;font-size:small; }\n.center_father {color:#404040;text-align: center;}\n.center_son { margin-right: auto; margin-left: auto; }"
  },
  {
    "path": "app/src/main/assets/web/index.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n    <meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\"/>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <meta name=\"format-detection\" content=\"telephone=no\"/>\n    <title>AndServer Sample</title>\n    <style>\n        .center_horizontal{margin:0 auto;text-align:center;}\n    </style>\n</head>\n<body>\n<div class=\"center_horizontal\"><img src=\"./image/logo.png\" width=\"100%\"></div>\n<div>\n    <a href=\"/login.html\">Login</a><br/><br/>\n    More, please see the sample code.\n</div>\n</body>\n</html>"
  },
  {
    "path": "app/src/main/assets/web/login.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n    <meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\"/>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=no\">\n    <meta name=\"format-detection\" content=\"telephone=no\"/>\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"css/login.css\">\n\n    <title>Sign In</title>\n\n</head>\n<body class=\"sec_body\">\n<div class=\"center_father\">\n    <h1 class=\"center\" style=\"margin:0 0;font-size:x-large;padding:0;\">Sign In</h1>\n</div>\n<form id=\"form1\" method=\"post\" action=\"/user/login\">\n    <table align=\"center\" cellpadding=\"0\" cellspacing=\"0\">\n        <tr>\n            <td width=\"100\" align=\"right\">Account:&nbsp;&nbsp;</td>\n            <td width=\"276\"><input name=\"account\" type=\"text\" id=\"account\" value=\"123\"/></td>\n        </tr>\n        <tr>\n            <td width=\"100\">&nbsp;&nbsp;</td>\n            <td width=\"276\">&nbsp;&nbsp;</td>\n        </tr>\n        <tr>\n            <td align=\"right\">Password:&nbsp;&nbsp;</td>\n            <td><input name=\"password\" type=\"password\" id=\"password\" value=\"123\"/></td>\n        </tr>\n        <tr>\n            <td width=\"100\">&nbsp;&nbsp;</td>\n            <td width=\"276\">&nbsp;&nbsp;</td>\n        </tr>\n        <tr>\n            <td colspan=\"2\" align=\"center\">\n                <input type=\"submit\" name=\"Submit\" value=\"Sign In\"/>\n            </td>\n        </tr>\n    </table>\n    <p>Account:&nbsp;123, Password:&nbsp;123</p>\n</form>\n</body>\n</html>\n"
  },
  {
    "path": "app/src/main/java/camera/cn/cameramaster/OpenReceiver.java",
    "content": "package camera.cn.cameramaster;\n\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.util.Log;\n\nimport camera.cn.cameramaster.ui.MainActivity;\n\n/**\n * 开机\n * @packageName: cn.tongue.tonguecamera\n * @fileName: OpenReceiver\n * @date: 2019/1/28  13:09\n * @author: ymc\n * @QQ:745612618\n */\n\npublic class OpenReceiver  extends BroadcastReceiver {\n    @Override\n    public void onReceive(Context context, Intent intent) {\n\n        Log.i(\"broadCastReceiver\",\"onReceiver...\");\n\n        Intent mBootIntent = new Intent(context, MainActivity.class);\n        // 必须设置FLAG_ACTIVITY_NEW_TASK\n        mBootIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n        context.startActivity(mBootIntent);\n\n    }\n\n}"
  },
  {
    "path": "app/src/main/java/camera/cn/cameramaster/adapter/EffectAdapter.java",
    "content": "package camera.cn.cameramaster.adapter;\n\nimport android.content.Context;\nimport android.support.annotation.NonNull;\nimport android.support.v7.widget.RecyclerView;\nimport android.util.Log;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.TextView;\n\nimport butterknife.BindView;\nimport butterknife.ButterKnife;\nimport camera.cn.cameramaster.R;\n\n/**\n * effect 适配器\n *\n * @packageName: cn.tongue.tonguecamera.adapter\n * @fileName: EffectAdapter\n * @date: 2019/4/17  14:33\n * @author: ymc\n * @QQ:745612618\n */\n\npublic class EffectAdapter extends RecyclerView.Adapter<EffectAdapter.EffectViewHolder> {\n    private LayoutInflater mLayoutInflater;\n    private String[] effectArr;\n\n    public EffectAdapter(Context mContext,String[] arr) {\n        this.effectArr = arr;\n        mLayoutInflater = LayoutInflater.from(mContext);\n    }\n\n    @NonNull\n    @Override\n    public EffectViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {\n        return new EffectViewHolder(mLayoutInflater.inflate(R.layout.item_rv_text, parent, false));\n    }\n\n    @Override\n    public void onBindViewHolder(@NonNull EffectViewHolder holder, int position) {\n        holder.mTextView.setText(effectArr[position]);\n    }\n\n    @Override\n    public int getItemCount() {\n        return effectArr.length;\n    }\n\n    public class EffectViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {\n        @BindView(R.id.text_view)\n        TextView mTextView;\n\n        EffectViewHolder(View view) {\n            super(view);\n            ButterKnife.bind(this, view);\n            view.setOnClickListener(this);\n        }\n\n        @Override\n        public void onClick(View v) {\n            if (effectOnItemClickListener != null) {\n                effectOnItemClickListener.itemOnClick(getPosition());\n            }\n        }\n    }\n\n    private EffectOnItemClickListener effectOnItemClickListener;\n\n    public interface EffectOnItemClickListener {\n\n        void itemOnClick(int position);\n\n    }\n\n    public void setEffectOnItemClickListener(EffectOnItemClickListener effectOnItemClickListener) {\n        this.effectOnItemClickListener = effectOnItemClickListener;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/camera/cn/cameramaster/adapter/MenuAdapter.java",
    "content": "package camera.cn.cameramaster.adapter;\n\nimport android.content.Context;\nimport android.graphics.Color;\nimport android.support.annotation.NonNull;\nimport android.support.v7.widget.RecyclerView;\nimport android.util.TypedValue;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.TextView;\n\nimport java.util.List;\n\nimport camera.cn.cameramaster.R;\nimport camera.cn.cameramaster.view.AutoLocateHorizontalView;\n\n/**\n * 选项适配器\n *\n * @author ymc\n * @date 2019年5月8日 10:38:54\n */\n\npublic class MenuAdapter extends RecyclerView.Adapter<MenuAdapter.ItemViewHolder>\n        implements AutoLocateHorizontalView.IAutoLocateHorizontalView {\n    private Context context;\n    private View view;\n    private List<String> ages;\n    private AutoLocateHorizontalView recyclerView;\n\n    public MenuAdapter(Context context, List<String> ages, AutoLocateHorizontalView recyclerView){\n        this.context = context;\n        this.ages = ages;\n        this.recyclerView = recyclerView;\n    }\n\n    @NonNull\n    @Override\n    public ItemViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {\n        view = LayoutInflater.from(context).inflate(R.layout.item_age,parent,false);\n        return new ItemViewHolder(view);\n    }\n\n    @Override\n    public void onBindViewHolder(@NonNull ItemViewHolder holder, int position) {\n        holder.tvAge.setText(ages.get(position));\n    }\n\n    @Override\n    public int getItemCount() {\n        return  ages.size();\n    }\n\n    @Override\n    public View getItemView() {\n        return view;\n    }\n\n    @Override\n    public void onViewSelected(boolean isSelected, int pos, RecyclerView.ViewHolder holder, int itemWidth) {\n        if(isSelected) {\n            ((ItemViewHolder) holder).tvAge.setTextSize(TypedValue.COMPLEX_UNIT_SP,16);\n            ((ItemViewHolder) holder).tvAge.setTextColor(Color.WHITE);\n            ((ItemViewHolder) holder).tvAge.setAlpha(1.0f);\n        }else{\n            ((ItemViewHolder) holder).tvAge.setTextSize(TypedValue.COMPLEX_UNIT_SP,14);\n            ((ItemViewHolder) holder).tvAge.setTextColor(Color.rgb(0xfe,0xfe,0xfe));\n            ((ItemViewHolder) holder).tvAge.setAlpha(0.5f);\n        }\n    }\n\n    class ItemViewHolder extends RecyclerView.ViewHolder{\n        TextView tvAge;\n        ItemViewHolder(View itemView) {\n            super(itemView);\n            tvAge = itemView.findViewById(R.id.tv_age);\n            tvAge.setTag(this);\n            tvAge.setOnClickListener(new View.OnClickListener() {\n                @Override\n                public void onClick(View v) {\n                    ItemViewHolder itemViewHolder = (ItemViewHolder)v.getTag();\n                    int position = recyclerView.getChildAdapterPosition(itemViewHolder.itemView);\n                    position--;\n                    recyclerView.moveToPosition(position);\n                }\n            });\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/camera/cn/cameramaster/adapter/SenseAdapter.java",
    "content": "package camera.cn.cameramaster.adapter;\n\nimport android.content.Context;\nimport android.support.annotation.NonNull;\nimport android.support.v7.widget.RecyclerView;\nimport android.util.Log;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.TextView;\n\nimport butterknife.BindView;\nimport butterknife.ButterKnife;\nimport camera.cn.cameramaster.R;\n\n/**\n * effect 适配器\n *\n * @packageName: cn.tongue.tonguecamera.adapter\n * @fileName: EffectAdapter\n * @date: 2019/4/17  14:33\n * @author: ymc\n * @QQ:745612618\n */\n\npublic class SenseAdapter extends RecyclerView.Adapter<SenseAdapter.EffectViewHolder> {\n    private LayoutInflater mLayoutInflater;\n    private String[] senseArr;\n\n    public SenseAdapter(Context mContext,String[] arr) {\n        this.senseArr = arr;\n        mLayoutInflater = LayoutInflater.from(mContext);\n    }\n\n    @NonNull\n    @Override\n    public EffectViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {\n        return new EffectViewHolder(mLayoutInflater.inflate(R.layout.item_rv_text, parent, false));\n    }\n\n    @Override\n    public void onBindViewHolder(@NonNull EffectViewHolder holder, int position) {\n        holder.mTextView.setText(senseArr[position]);\n    }\n\n    @Override\n    public int getItemCount() {\n        return senseArr.length;\n    }\n\n    public class EffectViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {\n        @BindView(R.id.text_view)\n        TextView mTextView;\n\n        EffectViewHolder(View view) {\n            super(view);\n            ButterKnife.bind(this, view);\n            view.setOnClickListener(this);\n        }\n\n        @Override\n        public void onClick(View v) {\n            if (senseOnItemClickListener != null) {\n                senseOnItemClickListener.itemOnClick(getPosition());\n            }\n        }\n    }\n\n    private SenseOnItemClickListener senseOnItemClickListener;\n\n    public interface SenseOnItemClickListener {\n\n        void itemOnClick(int position);\n\n    }\n\n    public void setSenseOnItemClickListener(SenseOnItemClickListener senseOnItemClickListener) {\n        this.senseOnItemClickListener = senseOnItemClickListener;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/camera/cn/cameramaster/base/App.java",
    "content": "/*\n * Copyright 2018 Yan Zhenjie.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage camera.cn.cameramaster.base;\n\nimport android.app.Application;\nimport android.content.Context;\nimport android.os.Environment;\nimport android.support.annotation.NonNull;\n\nimport com.yanzhenjie.andserver.util.IOUtils;\n\nimport java.io.File;\n\nimport camera.cn.cameramaster.server.util.FileUtils;\n\n\n/**\n * application\n *\n * Created by YanZhenjie on 2018/6/9.\n * @author ymc\n */\n\npublic class App extends Application {\n\n    private static App mInstance;\n\n    private File mRootDir;\n\n    @Override\n    public void onCreate() {\n        super.onCreate();\n\n        if (mInstance == null) {\n            mInstance = this;\n            initRootPath(this);\n        }\n    }\n\n    @NonNull\n    public static App getInstance() {\n        return mInstance;\n    }\n\n    @NonNull\n    public File getRootDir() {\n        return mRootDir;\n    }\n\n    private void initRootPath(Context context) {\n        if (mRootDir != null) {\n            return;\n        }\n\n        if (FileUtils.storageAvailable()) {\n            mRootDir = Environment.getExternalStorageDirectory();\n        } else {\n            mRootDir = context.getFilesDir();\n        }\n        mRootDir = new File(mRootDir, \"AndServer\");\n        IOUtils.createFolder(mRootDir);\n    }\n}"
  },
  {
    "path": "app/src/main/java/camera/cn/cameramaster/base/BaseActivity.java",
    "content": "package camera.cn.cameramaster.base;\n\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.support.annotation.Nullable;\nimport android.support.v4.view.ViewCompat;\nimport android.support.v7.app.AppCompatActivity;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.view.Window;\nimport android.view.WindowManager;\n\nimport butterknife.ButterKnife;\nimport butterknife.Unbinder;\nimport camera.cn.cameramaster.R;\n\n/**\n *  基础Activity\n *\n * @packageName: cn.ymc.vip.suntimejava.base\n * @fileName: BaseActivity\n * @date: 2019/1/8  17:35\n * @author: ymc\n * @QQ:745612618\n */\n\npublic abstract class BaseActivity extends AppCompatActivity {\n\n    protected BaseActivity activity;\n    private Unbinder bun;\n\n    @Override\n    protected void onCreate(@Nullable Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        //去除标题栏\n        supportRequestWindowFeature(Window.FEATURE_NO_TITLE);\n        //去除状态栏\n        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,\n                WindowManager.LayoutParams.FLAG_FULLSCREEN);\n        setContentView(getLayoutId());\n//        getSupportActionBar().hide();\n        bun = ButterKnife.bind(this);\n        activity = this;\n        initStatusColor();\n        initView();\n        initData();\n    }\n\n    /**\n     * 设置透明状态栏,这样才能让 ContentView 向上  6.0小米手机设置 tootlbar 会被挤上去\n     * window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);\n     */\n    private void initStatusColor() {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){\n            Window window = activity.getWindow();\n            window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);\n            //设置状态栏颜色\n            window.setStatusBarColor(getColor(R.color.theme));\n\n            ViewGroup mContentView = activity.findViewById(Window.ID_ANDROID_CONTENT);\n            View mChildView = mContentView.getChildAt(0);\n            if (mChildView != null) {\n                //注意不是设置 ContentView 的 FitsSystemWindows, 而是设置 ContentView 的第一个子 View . 使其不为系统 View 预留空间.\n                ViewCompat.setFitsSystemWindows(mChildView, false);\n            }\n        }\n    }\n\n    protected abstract int getLayoutId();\n    protected abstract void initView();\n    protected abstract void initData();\n\n    @Override\n    protected void onDestroy() {\n        bun.unbind();\n        super.onDestroy();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/camera/cn/cameramaster/bean/Lab.java",
    "content": "package camera.cn.cameramaster.bean;\n\n/**\n * lab 实体类\n *\n * @packageName: cn.tongue.tonguecamera.bean\n * @fileName: Lab\n * @date: 2019/4/3  13:37\n * @author: ymc\n * @QQ:745612618\n */\n\npublic class Lab {\n\n    public double L;\n    public double a;\n    public double b;\n\n    public double getL() {\n        return L;\n    }\n\n    public void setL(double l) {\n        L = l;\n    }\n\n    public double getA() {\n        return a;\n    }\n\n    public void setA(double a) {\n        this.a = a;\n    }\n\n    public double getB() {\n        return b;\n    }\n\n    public void setB(double b) {\n        this.b = b;\n    }\n\n    @Override\n    public String toString() {\n        return \"Lab l:\" + L + \" Lab a:\" + a + \" Lab b:\" + b;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/camera/cn/cameramaster/filter/AFilter.java",
    "content": "/*\n *\n * AFilter.java\n * \n * Created by Wuwang on 2016/11/19\n * Copyright © 2016年 深圳哎吖科技. All rights reserved.\n */\npackage camera.cn.cameramaster.filter;\n\nimport android.content.res.Resources;\nimport android.opengl.GLES20;\nimport android.util.Log;\nimport android.util.SparseArray;\n\nimport java.io.InputStream;\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\nimport java.nio.FloatBuffer;\nimport java.nio.ShortBuffer;\nimport java.util.Arrays;\n\nimport camera.cn.cameramaster.util.MatrixUtils;\n\n\n/**\n * Description:\n */\npublic abstract class AFilter {\n\n    private static final String TAG=\"Filter\";\n\n    public static final int KEY_OUT=0x101;\n    public static final int KEY_IN=0x102;\n    public static final int KEY_INDEX=0x201;\n\n    public static boolean DEBUG=true;\n    /**\n     * 单位矩阵\n     */\n    public static final float[] OM= MatrixUtils.getOriginalMatrix();\n    /**\n     * 程序句柄\n     */\n    protected int mProgram;\n    /**\n     * 顶点坐标句柄\n     */\n    protected int mHPosition;\n    /**\n     * 纹理坐标句柄\n     */\n    protected int mHCoord;\n    /**\n     * 总变换矩阵句柄\n     */\n    protected int mHMatrix;\n    /**\n     * 默认纹理贴图句柄\n     */\n    protected int mHTexture;\n\n    protected Resources mRes;\n\n\n    /**\n     * 顶点坐标Buffer\n     */\n    protected FloatBuffer mVerBuffer;\n\n    /**\n     * 纹理坐标Buffer\n     */\n    protected FloatBuffer mTexBuffer;\n\n    /**\n     * 索引坐标Buffer\n     */\n    protected ShortBuffer mindexBuffer;\n\n    protected int mFlag=0;\n\n    private float[] matrix= Arrays.copyOf(OM,16);\n\n    private int textureType=0;      //默认使用Texture2D0\n    private int textureId=0;\n    //顶点坐标\n    private float pos[] = {\n        -1.0f,  1.0f,\n        -1.0f, -1.0f,\n        1.0f, 1.0f,\n        1.0f,  -1.0f,\n    };\n\n    //纹理坐标\n    private float[] coord={\n        0.0f, 0.0f,\n        0.0f,  1.0f,\n        1.0f,  0.0f,\n        1.0f, 1.0f,\n    };\n\n    private SparseArray<boolean[]> mBools;\n    private SparseArray<int[]> mInts;\n    private SparseArray<float[]> mFloats;\n\n    public AFilter(Resources mRes){\n        this.mRes=mRes;\n        initBuffer();\n    }\n\n    public final void create(){\n        onCreate();\n    }\n\n    public final void setSize(int width,int height){\n        onSizeChanged(width,height);\n    }\n\n    public void draw(){\n        onClear();\n        onUseProgram();\n        onSetExpandData();\n        onBindTexture();\n        onDraw();\n    }\n\n    public void setMatrix(float[] matrix){\n        this.matrix=matrix;\n    }\n\n    public float[] getMatrix(){\n        return matrix;\n    }\n\n    public final void setTextureType(int type){\n        this.textureType=type;\n    }\n\n    public final int getTextureType(){\n        return textureType;\n    }\n\n    public final int getTextureId(){\n        return textureId;\n    }\n\n    public final void setTextureId(int textureId){\n        this.textureId=textureId;\n    }\n\n    public void setFlag(int flag){\n        this.mFlag=flag;\n    }\n\n    public int getFlag(){\n        return mFlag;\n    }\n\n    public void setFloat(int type,float ... params){\n        if(mFloats==null){\n            mFloats=new SparseArray<>();\n        }\n        mFloats.put(type,params);\n    }\n    public void setInt(int type,int ... params){\n        if(mInts==null){\n            mInts=new SparseArray<>();\n        }\n        mInts.put(type,params);\n    }\n    public void setBool(int type,boolean ... params){\n        if(mBools==null){\n            mBools=new SparseArray<>();\n        }\n        mBools.put(type,params);\n    }\n\n    public boolean getBool(int type,int index) {\n        if (mBools == null){\n            return false;\n        }\n        boolean[] b = mBools.get(type);\n        return !(b == null || b.length <= index) && b[index];\n    }\n\n    public int getInt(int type,int index){\n        if (mInts == null){\n            return 0;\n        }\n        int[] b = mInts.get(type);\n        if(b == null || b.length <= index){\n            return 0;\n        }\n        return b[index];\n    }\n\n    public float getFloat(int type,int index){\n        if (mFloats == null) {\n            return 0;\n        }\n        float[] b = mFloats.get(type);\n        if(b == null || b.length <= index){\n            return 0;\n        }\n        return b[index];\n    }\n\n    public int getOutputTexture(){\n        return -1;\n    }\n\n    /**\n     * 实现此方法，完成程序的创建，可直接调用createProgram来实现\n     */\n    protected abstract void onCreate();\n    protected abstract void onSizeChanged(int width,int height);\n\n    protected final void createProgram(String vertex, String fragment){\n        mProgram= uCreateGlProgram(vertex,fragment);\n        mHPosition= GLES20.glGetAttribLocation(mProgram, \"vPosition\");\n        mHCoord= GLES20.glGetAttribLocation(mProgram,\"vCoord\");\n        mHMatrix= GLES20.glGetUniformLocation(mProgram,\"vMatrix\");\n        mHTexture= GLES20.glGetUniformLocation(mProgram,\"vTexture\");\n    }\n\n    protected final void createProgramByAssetsFile(String vertex, String fragment){\n        createProgram(uRes(mRes,vertex),uRes(mRes,fragment));\n    }\n\n    /**\n     * Buffer初始化\n     */\n    protected void initBuffer(){\n        ByteBuffer a= ByteBuffer.allocateDirect(32);\n        a.order(ByteOrder.nativeOrder());\n        mVerBuffer=a.asFloatBuffer();\n        mVerBuffer.put(pos);\n        mVerBuffer.position(0);\n        ByteBuffer b= ByteBuffer.allocateDirect(32);\n        b.order(ByteOrder.nativeOrder());\n        mTexBuffer=b.asFloatBuffer();\n        mTexBuffer.put(coord);\n        mTexBuffer.position(0);\n    }\n\n    protected void onUseProgram(){\n        GLES20.glUseProgram(mProgram);\n    }\n\n    /**\n     * 启用顶点坐标和纹理坐标进行绘制\n     */\n    protected void onDraw(){\n        GLES20.glEnableVertexAttribArray(mHPosition);\n        GLES20.glVertexAttribPointer(mHPosition,2, GLES20.GL_FLOAT, false, 0,mVerBuffer);\n        GLES20.glEnableVertexAttribArray(mHCoord);\n        GLES20.glVertexAttribPointer(mHCoord, 2, GLES20.GL_FLOAT, false, 0, mTexBuffer);\n        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP,0,4);\n        GLES20.glDisableVertexAttribArray(mHPosition);\n        GLES20.glDisableVertexAttribArray(mHCoord);\n    }\n\n    /**\n     * 清除画布\n     */\n    protected void onClear(){\n        GLES20.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);\n        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);\n    }\n\n    /**\n     * 设置其他扩展数据\n     */\n    protected void onSetExpandData(){\n        GLES20.glUniformMatrix4fv(mHMatrix,1,false,matrix,0);\n    }\n\n    /**\n     * 绑定默认纹理\n     */\n    protected void onBindTexture(){\n        GLES20.glActiveTexture(GLES20.GL_TEXTURE0+textureType);\n        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,getTextureId());\n        GLES20.glUniform1i(mHTexture,textureType);\n    }\n\n    public static void glError(int code,Object index){\n        if(DEBUG&&code!=0){\n            Log.e(TAG,\"glError:\"+code+\"---\"+index);\n        }\n    }\n\n    //通过路径加载Assets中的文本内容\n    public static String uRes(Resources mRes, String path){\n        StringBuilder result=new StringBuilder();\n        try{\n            InputStream is=mRes.getAssets().open(path);\n            int ch;\n            byte[] buffer=new byte[1024];\n            while (-1!=(ch=is.read(buffer))){\n                result.append(new String(buffer,0,ch));\n            }\n        }catch (Exception e){\n            return null;\n        }\n        return result.toString().replaceAll(\"\\\\r\\\\n\",\"\\n\");\n    }\n\n    //创建GL程序\n    public static int uCreateGlProgram(String vertexSource, String fragmentSource){\n        int vertex=uLoadShader(GLES20.GL_VERTEX_SHADER,vertexSource);\n        if(vertex==0){\n            return 0;\n        }\n        int fragment=uLoadShader(GLES20.GL_FRAGMENT_SHADER,fragmentSource);\n        if(fragment==0){\n            return 0;\n        }\n        int program= GLES20.glCreateProgram();\n        if(program!=0){\n            GLES20.glAttachShader(program,vertex);\n            GLES20.glAttachShader(program,fragment);\n            GLES20.glLinkProgram(program);\n            int[] linkStatus=new int[1];\n            GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS,linkStatus,0);\n            if(linkStatus[0]!= GLES20.GL_TRUE){\n                glError(1,\"Could not link program:\"+ GLES20.glGetProgramInfoLog(program));\n                GLES20.glDeleteProgram(program);\n                program=0;\n            }\n        }\n        return program;\n    }\n\n    //加载shader\n    public static int uLoadShader(int shaderType,String source){\n        int shader= GLES20.glCreateShader(shaderType);\n        if(0!=shader){\n            GLES20.glShaderSource(shader,source);\n            GLES20.glCompileShader(shader);\n            int[] compiled=new int[1];\n            GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS,compiled,0);\n            if(compiled[0]==0){\n                glError(1,\"Could not compile shader:\"+shaderType);\n                glError(1,\"GLES20 Error:\"+ GLES20.glGetShaderInfoLog(shader));\n                GLES20.glDeleteShader(shader);\n                shader=0;\n            }\n        }\n        return shader;\n    }\n\n\n}\n"
  },
  {
    "path": "app/src/main/java/camera/cn/cameramaster/filter/TextureFilter.java",
    "content": "package camera.cn.cameramaster.filter;\n\nimport android.content.res.Resources;\nimport android.graphics.SurfaceTexture;\n\nimport java.nio.ByteBuffer;\n\n/**\n * @packageName: cn.tongue.tonguecamera.filter\n * @fileName: TextureFilter\n * @date: 2019/3/15  14:40\n * @author: ymc\n * @QQ:745612618\n */\n\npublic class TextureFilter extends  AFilter{\n    private int width=0;\n    private int height=0;\n\n    private int[] fFrame = new int[1];\n    private int[] fTexture = new int[1];\n    private int[] mCameraTexture=new int[1];\n\n    private SurfaceTexture mSurfaceTexture;\n    private float[] mCoordOM=new float[16];\n    /**\n     * 获取Track数据\n     */\n    private ByteBuffer tBuffer;\n\n\n    public TextureFilter(Resources mRes) {\n        super(mRes);\n    }\n\n    @Override\n    protected void onCreate() {\n\n    }\n\n    @Override\n    protected void onSizeChanged(int width, int height) {\n\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/camera/cn/cameramaster/server/AnyEventType.java",
    "content": "package camera.cn.cameramaster.server;\n\n/**\n * event bus 消息类\n *\n * @packageName: cn.tongue.tonguecamera.eventbus\n * @fileName: AnyEventType\n * @date: 2019/4/24  18:36\n * @author: ymc\n * @QQ:745612618\n */\n\npublic class AnyEventType {\n\n    public AnyEventType(){}\n\n}\n"
  },
  {
    "path": "app/src/main/java/camera/cn/cameramaster/server/CoreService.java",
    "content": "/*\n * Copyright © 2018 Yan Zhenjie.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage camera.cn.cameramaster.server;\n\nimport android.app.Service;\nimport android.content.Intent;\nimport android.os.IBinder;\nimport android.support.annotation.Nullable;\nimport android.util.Log;\n\nimport com.yanzhenjie.andserver.AndServer;\nimport com.yanzhenjie.andserver.Server;\n\nimport java.util.concurrent.TimeUnit;\n\nimport camera.cn.cameramaster.server.util.NetUtils;\n\n\n/**\n * server\n *\n * Created by Yan Zhenjie on 2018/6/9.\n * @author ymc\n */\npublic class CoreService extends Service {\n    private static final String TAG = \"CoreService\";\n    private Server mServer;\n\n    @Override\n    public void onCreate() {\n        mServer = AndServer.serverBuilder()\n            .inetAddress(NetUtils.getLocalIPAddress())\n            .port(8081)\n            .timeout(10, TimeUnit.SECONDS)\n            .listener(new Server.ServerListener() {\n                @Override\n                public void onStarted() {\n                    String hostAddress = mServer.getInetAddress().getHostAddress();\n                    ServerManager.onServerStart(CoreService.this, hostAddress);\n                    Log.e(TAG, \"onStarted: \");\n                }\n\n                @Override\n                public void onStopped() {\n                    ServerManager.onServerStop(CoreService.this);\n                    Log.e(TAG, \"onStopped: \");\n                }\n\n                @Override\n                public void onException(Exception e) {\n                    ServerManager.onServerError(CoreService.this, e.getMessage());\n                    Log.e(TAG, \"onException: \");\n                }\n            })\n            .build();\n    }\n\n    @Override\n    public int onStartCommand(Intent intent, int flags, int startId) {\n        startServer();\n        return START_STICKY;\n    }\n\n    @Override\n    public void onDestroy() {\n        stopServer();\n        super.onDestroy();\n    }\n\n    /**\n     * Start server.\n     */\n    private void startServer() {\n        if (mServer.isRunning()) {\n            String hostAddress = mServer.getInetAddress().getHostAddress();\n            ServerManager.onServerStart(CoreService.this, hostAddress);\n        } else {\n            mServer.startup();\n        }\n    }\n\n    /**\n     * Stop server.\n     */\n    private void stopServer() {\n        mServer.shutdown();\n    }\n\n    @Nullable\n    @Override\n    public IBinder onBind(Intent intent) {\n        return null;\n    }\n}"
  },
  {
    "path": "app/src/main/java/camera/cn/cameramaster/server/ServerManager.java",
    "content": "/*\n * Copyright © 2018 Yan Zhenjie.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage camera.cn.cameramaster.server;\n\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.os.Build;\nimport android.support.annotation.RequiresApi;\n\nimport camera.cn.cameramaster.ui.GoogleCameraActivity;\n\n\n/**\n *\n * Created by Yan Zhenjie on 2018/6/9.\n * @author ymc\n */\n\npublic class ServerManager extends BroadcastReceiver {\n\n    private static final String ACTION = \"com.yanzhenjie.andserver.receiver\";\n\n    private static final String CMD_KEY = \"CMD_KEY\";\n    private static final String MESSAGE_KEY = \"MESSAGE_KEY\";\n\n    private static final int CMD_VALUE_START = 1;\n    private static final int CMD_VALUE_ERROR = 2;\n    private static final int CMD_VALUE_STOP = 4;\n\n    /**\n     * Notify serverStart.\n     *\n     * @param context context.\n     */\n    public static void onServerStart(Context context, String hostAddress) {\n        sendBroadcast(context, CMD_VALUE_START, hostAddress);\n    }\n\n    /**\n     * Notify serverStop.\n     *\n     * @param context context.\n     */\n    public static void onServerError(Context context, String error) {\n        sendBroadcast(context, CMD_VALUE_ERROR, error);\n    }\n\n    /**\n     * Notify serverStop.\n     *\n     * @param context context.\n     */\n    public static void onServerStop(Context context) {\n        sendBroadcast(context, CMD_VALUE_STOP);\n    }\n\n    private static void sendBroadcast(Context context, int cmd) {\n        sendBroadcast(context, cmd, null);\n    }\n\n    private static void sendBroadcast(Context context, int cmd, String message) {\n        Intent broadcast = new Intent(ACTION);\n        broadcast.putExtra(CMD_KEY, cmd);\n        broadcast.putExtra(MESSAGE_KEY, message);\n        context.sendBroadcast(broadcast);\n    }\n\n    private GoogleCameraActivity mActivity;\n    private Intent mService;\n\n    public ServerManager(GoogleCameraActivity activity) {\n        this.mActivity = activity;\n        mService = new Intent(activity, CoreService.class);\n    }\n\n    /**\n     * Register broadcast.\n     */\n    public void register() {\n        IntentFilter filter = new IntentFilter(ACTION);\n        mActivity.registerReceiver(this, filter);\n    }\n\n    /**\n     * UnRegister broadcast.\n     */\n    public void unRegister() {\n        mActivity.unregisterReceiver(this);\n    }\n\n    public void startServer() {\n        mActivity.startService(mService);\n    }\n\n    public void stopServer() {\n        mActivity.stopService(mService);\n    }\n\n    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)\n    @Override\n    public void onReceive(Context context, Intent intent) {\n        String action = intent.getAction();\n        if (ACTION.equals(action)) {\n            int cmd = intent.getIntExtra(CMD_KEY, 0);\n            switch (cmd) {\n                case CMD_VALUE_START: {\n                    String ip = intent.getStringExtra(MESSAGE_KEY);\n                    mActivity.onServerStart(ip);\n                    break;\n                }\n                case CMD_VALUE_ERROR: {\n                    String error = intent.getStringExtra(MESSAGE_KEY);\n                    mActivity.onServerError(error);\n                    break;\n                }\n                case CMD_VALUE_STOP: {\n                    mActivity.onServerStop();\n                    break;\n                }\n                default:\n                    break;\n            }\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/camera/cn/cameramaster/server/TestController.java",
    "content": "package camera.cn.cameramaster.server;\n\nimport android.os.Build;\nimport android.support.annotation.RequiresApi;\nimport android.util.Log;\n\nimport com.alibaba.fastjson.JSON;\nimport com.yanzhenjie.andserver.annotation.Addition;\nimport com.yanzhenjie.andserver.annotation.CookieValue;\nimport com.yanzhenjie.andserver.annotation.FormPart;\nimport com.yanzhenjie.andserver.annotation.GetMapping;\nimport com.yanzhenjie.andserver.annotation.PathVariable;\nimport com.yanzhenjie.andserver.annotation.PostMapping;\nimport com.yanzhenjie.andserver.annotation.RequestBody;\nimport com.yanzhenjie.andserver.annotation.RequestMapping;\nimport com.yanzhenjie.andserver.annotation.RequestParam;\nimport com.yanzhenjie.andserver.annotation.ResponseBody;\nimport com.yanzhenjie.andserver.annotation.RestController;\nimport com.yanzhenjie.andserver.http.HttpRequest;\nimport com.yanzhenjie.andserver.http.HttpResponse;\nimport com.yanzhenjie.andserver.http.cookie.Cookie;\nimport com.yanzhenjie.andserver.http.multipart.MultipartFile;\nimport com.yanzhenjie.andserver.http.session.Session;\nimport com.yanzhenjie.andserver.util.MediaType;\n\nimport org.greenrobot.eventbus.EventBus;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.List;\n\nimport camera.cn.cameramaster.server.model.UserInfo;\nimport camera.cn.cameramaster.server.util.FileUtils;\n\n\n/**\n * 测试控制器\n *\n * @packageName: ymc.cn.servertest\n * @fileName: TestController\n * @date: 2019/4/23  16:15\n * @author: ymc\n * @QQ:745612618\n */\n\n@RestController\n@RequestMapping(path = \"/test\")\n@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)\npublic class TestController {\n\n    private static final String TAG = \"TestController\";\n\n    private static final String LOGIN_ATTRIBUTE = \"USER.LOGIN.SIGN\";\n\n    @ResponseBody\n    @GetMapping(\"/take\")\n    public void takeCamera() {\n        EventBus.getDefault().post(new AnyEventType());\n    }\n\n    @GetMapping(path = \"/get/{userId}\", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)\n    String info(@PathVariable(name = \"userId\") String userId) {\n        return userId;\n    }\n\n    @PostMapping(path = \"/login\", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)\n    String login(HttpRequest request, HttpResponse response, @RequestParam(name = \"account\",required = false\n    ) String account, @RequestParam(name = \"password\",required = false) String password) {\n        Session session = request.getValidSession();\n        session.setAttribute(LOGIN_ATTRIBUTE, true);\n\n        Cookie cookie = new Cookie(\"account\", account + \"=\" + password);\n        response.addCookie(cookie);\n        return \"login successful\";\n    }\n\n    @Addition(stringType = \"login\", booleanType = true)\n    @GetMapping(path = \"/userInfo\", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)\n    UserInfo userInfo(@CookieValue(\"account\") String account) {\n        Log.e(TAG, \"Account: \" + account);\n        UserInfo userInfo = new UserInfo();\n        userInfo.setmUserId(\"123\");\n        userInfo.setmUserName(\"AndServer\");\n        return userInfo;\n    }\n\n    @PostMapping(path = \"/upload\", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)\n    String upload(@RequestParam(name = \"header\") MultipartFile file) throws IOException {\n        File localFile = FileUtils.createRandomFile(file);\n        file.transferTo(localFile);\n        return localFile.getAbsolutePath();\n    }\n\n    @GetMapping(path = \"/consume\", consumes = {\"application/json\", \"!application/xml\"})\n    String consume() {\n        return \"Consume is successful\";\n    }\n\n    @GetMapping(path = \"/produce\", produces = {\"application/json; charset=utf-8\"})\n    String produce() {\n        return \"Produce is successful\";\n    }\n\n    @GetMapping(path = \"/include\", params = {\"name=123\"})\n    String include(@RequestParam(name = \"name\") String name) {\n        return name;\n    }\n\n    @GetMapping(path = \"/exclude\", params = \"name!=123\")\n    String exclude() {\n        return \"Exclude is successful.\";\n    }\n\n    @GetMapping(path = {\"/mustKey\", \"/getName\"}, params = \"name\")\n    String getMustKey(@RequestParam(name = \"name\") String name) {\n        return name;\n    }\n\n    @PostMapping(path = {\"/mustKey\", \"/postName\"}, params = \"name\")\n    String postMustKey(@RequestParam(name = \"name\") String name) {\n        return name;\n    }\n\n    @GetMapping(path = \"/noName\", params = \"!name\")\n    String noName() {\n        return \"NoName is successful.\";\n    }\n\n    @PostMapping(path = \"/formPart\")\n    String forPart(@FormPart(name = \"user\") UserInfo userInfo) {\n        return JSON.toJSONString(userInfo);\n    }\n\n    @PostMapping(path = \"/jsonBody\")\n    String jsonBody(@RequestBody UserInfo userInfo) {\n        return JSON.toJSONString(userInfo);\n    }\n\n    @PostMapping(path = \"/listBody\")\n    String jsonBody(@RequestBody List<UserInfo> infoList) {\n        return JSON.toJSONString(infoList);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/camera/cn/cameramaster/server/component/LoggerInterceptor.java",
    "content": "/*\n * Copyright 2018 Yan Zhenjie.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage camera.cn.cameramaster.server.component;\n\nimport android.support.annotation.NonNull;\nimport android.util.Log;\n\nimport com.alibaba.fastjson.JSON;\nimport com.yanzhenjie.andserver.annotation.Interceptor;\nimport com.yanzhenjie.andserver.framework.HandlerInterceptor;\nimport com.yanzhenjie.andserver.framework.handler.RequestHandler;\nimport com.yanzhenjie.andserver.http.HttpMethod;\nimport com.yanzhenjie.andserver.http.HttpRequest;\nimport com.yanzhenjie.andserver.http.HttpResponse;\nimport com.yanzhenjie.andserver.util.MultiValueMap;\n\n/**\n * 拦截器\n *\n * @author ymc\n */\n\n@Interceptor\npublic class LoggerInterceptor implements HandlerInterceptor {\n\n    private static final String TAG = \"LoggerInterceptor\";\n\n    @Override\n    public boolean onIntercept(@NonNull HttpRequest request, @NonNull HttpResponse response,\n                               @NonNull RequestHandler handler) {\n        String path = request.getPath();\n        HttpMethod method = request.getMethod();\n        MultiValueMap<String, String> valueMap = request.getParameter();\n        Log.e(TAG, \"Path: \" + path);\n        Log.e(TAG, \"Method: \" + method.value());\n        Log.e(TAG, \"Param: \" + JSON.toJSONString(valueMap));\n        return false;\n    }\n}"
  },
  {
    "path": "app/src/main/java/camera/cn/cameramaster/server/model/UserInfo.java",
    "content": "package camera.cn.cameramaster.server.model;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\nimport com.alibaba.fastjson.annotation.JSONField;\n\n/**\n * 用户\n *\n * @packageName: ymc.cn.servertest.model\n * @fileName: UserInfo\n * @date: 2019/4/23  17:31\n * @author: ymc\n * @QQ:745612618\n */\n\npublic class UserInfo implements Parcelable {\n\n    @JSONField(name = \"userId\")\n    private String mUserId;\n    @JSONField(name = \"userName\")\n    private String mUserName;\n\n    public static final Creator<UserInfo> CREATOR = new Creator<UserInfo>() {\n        @Override\n        public UserInfo createFromParcel(Parcel in) {\n            return new UserInfo(in);\n        }\n\n        @Override\n        public UserInfo[] newArray(int size) {\n            return new UserInfo[size];\n        }\n    };\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @Override\n    public void writeToParcel(Parcel dest, int flags) {\n        dest.writeString(mUserId);\n        dest.writeString(mUserName);\n    }\n\n    public UserInfo() {\n    }\n\n    protected UserInfo(Parcel in) {\n        mUserId = in.readString();\n        mUserName = in.readString();\n    }\n\n    public String getmUserId() {\n        return mUserId;\n    }\n\n    public void setmUserId(String mUserId) {\n        this.mUserId = mUserId;\n    }\n\n    public String getmUserName() {\n        return mUserName;\n    }\n\n    public void setmUserName(String mUserName) {\n        this.mUserName = mUserName;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/camera/cn/cameramaster/server/util/FileUtils.java",
    "content": "/*\n * Copyright 2018 Yan Zhenjie.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage camera.cn.cameramaster.server.util;\n\nimport android.os.Environment;\nimport android.webkit.MimeTypeMap;\n\nimport com.yanzhenjie.andserver.http.multipart.MultipartFile;\nimport com.yanzhenjie.andserver.util.StringUtils;\n\nimport java.io.File;\nimport java.util.UUID;\n\nimport camera.cn.cameramaster.base.App;\n\n\n/**\n * Created by YanZhenjie on 2018/6/9.\n */\npublic class FileUtils {\n\n    /**\n     * Create a random file based on mimeType.\n     *\n     * @param file file.\n     *\n     * @return file object.\n     */\n    public static File createRandomFile(MultipartFile file) {\n        String extension = MimeTypeMap.getSingleton().getExtensionFromMimeType(file.getContentType().toString());\n        if (StringUtils.isEmpty(extension)) {\n            extension = MimeTypeMap.getFileExtensionFromUrl(file.getFilename());\n        }\n        String uuid = UUID.randomUUID().toString();\n        return new File(App.getInstance().getRootDir(), uuid + \".\" + extension);\n    }\n\n    /**\n     * SD is available.\n     *\n     * @return true, otherwise is false.\n     */\n    public static boolean storageAvailable() {\n        if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {\n            File sd = new File(Environment.getExternalStorageDirectory().getAbsolutePath());\n            return sd.canWrite();\n        } else {\n            return false;\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/camera/cn/cameramaster/server/util/NetUtils.java",
    "content": "/*\n * Copyright © 2018 Yan Zhenjie.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage camera.cn.cameramaster.server.util;\n\nimport java.net.InetAddress;\nimport java.net.NetworkInterface;\nimport java.net.SocketException;\nimport java.util.Enumeration;\nimport java.util.regex.Pattern;\n\n/**\n * Created by YanZhenjie on 2018/6/9.\n */\npublic class NetUtils {\n\n    /**\n     * Ipv4 address check.\n     */\n    private static final Pattern IPV4_PATTERN = Pattern.compile(\n        \"^(\" + \"([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\\\.){3}\" +\n            \"([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$\");\n\n    /**\n     * Check if valid IPV4 address.\n     *\n     * @param input the address string to check for validity.\n     *\n     * @return True if the input parameter is a valid IPv4 address.\n     */\n    public static boolean isIPv4Address(String input) {\n        return IPV4_PATTERN.matcher(input).matches();\n    }\n\n    /**\n     * Get local Ip address.\n     */\n    public static InetAddress getLocalIPAddress() {\n        Enumeration<NetworkInterface> enumeration = null;\n        try {\n            enumeration = NetworkInterface.getNetworkInterfaces();\n        } catch (SocketException e) {\n            e.printStackTrace();\n        }\n        if (enumeration != null) {\n            while (enumeration.hasMoreElements()) {\n                NetworkInterface nif = enumeration.nextElement();\n                Enumeration<InetAddress> inetAddresses = nif.getInetAddresses();\n                if (inetAddresses != null) {\n                    while (inetAddresses.hasMoreElements()) {\n                        InetAddress inetAddress = inetAddresses.nextElement();\n                        if (!inetAddress.isLoopbackAddress() && isIPv4Address(inetAddress.getHostAddress())) {\n                            return inetAddress;\n                        }\n                    }\n                }\n            }\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/camera/cn/cameramaster/ui/Camera2Activity.java",
    "content": "package camera.cn.cameramaster.ui;\n\nimport android.Manifest;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.PackageManager;\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapFactory;\nimport android.graphics.ImageFormat;\nimport android.graphics.SurfaceTexture;\nimport android.hardware.camera2.CameraAccessException;\nimport android.hardware.camera2.CameraCaptureSession;\nimport android.hardware.camera2.CameraCharacteristics;\nimport android.hardware.camera2.CameraDevice;\nimport android.hardware.camera2.CameraManager;\nimport android.hardware.camera2.CameraMetadata;\nimport android.hardware.camera2.CaptureFailure;\nimport android.hardware.camera2.CaptureRequest;\nimport android.hardware.camera2.TotalCaptureResult;\nimport android.hardware.camera2.params.StreamConfigurationMap;\nimport android.media.Image;\nimport android.media.ImageReader;\nimport android.os.Build;\nimport android.os.Environment;\nimport android.support.annotation.RequiresApi;\nimport android.support.v4.app.ActivityCompat;\nimport android.util.Size;\nimport android.util.SparseIntArray;\nimport android.view.Surface;\nimport android.view.TextureView;\nimport android.view.View;\nimport android.widget.ImageView;\nimport android.widget.Toast;\n\nimport java.nio.ByteBuffer;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.Comparator;\nimport java.util.List;\n\nimport butterknife.BindView;\nimport butterknife.OnClick;\nimport camera.cn.cameramaster.R;\nimport camera.cn.cameramaster.base.BaseActivity;\nimport camera.cn.cameramaster.util.AppConstant;\nimport camera.cn.cameramaster.util.BitmapUtils;\n\n/**\n * 基于 camera2 自定义拍照界面  (5.0以上)\n *\n * @author ymc\n * @date 2019年1月28日 13:56:02\n */\n\npublic class Camera2Activity extends BaseActivity {\n    @BindView(R.id.textureView)\n    TextureView textureView;\n    @BindView(R.id.iv_back2)\n    ImageView ivBack;\n    @BindView(R.id.camera_flash2)\n    ImageView ivFlash2;\n    @BindView(R.id.camera_switch2)\n    ImageView ivSwitch2;\n    @BindView(R.id.img_camera2)\n    ImageView ivCamera2;\n\n    private CameraDevice mCameraDevice;\n    /**\n     * 摄像头id（0代表后置摄像头，1代表前置摄像头）\n     */\n    private String mCameraId = \"0\";\n    private ImageReader imageReader;\n    public static int height;\n    public static int width;\n    private Size previewSize;\n    private CaptureRequest.Builder captureRequestBuilder;\n    private CaptureRequest mCaptureRequest;\n    private CameraCaptureSession mPreviewSession;\n    /**\n     * 判断是否有拍照权限的标识码\n     */\n    private final int RESULT_CODE_CAMERA = 1;\n    private CaptureRequest.Builder mCaptureRequestBuilder;\n\n    private static final SparseIntArray ORIENTATIONS = new SparseIntArray();\n\n    static {\n        ORIENTATIONS.append(Surface.ROTATION_0, 90);\n        ORIENTATIONS.append(Surface.ROTATION_90, 0);\n        ORIENTATIONS.append(Surface.ROTATION_180, 270);\n        ORIENTATIONS.append(Surface.ROTATION_270, 180);\n    }\n\n    @Override\n    protected int getLayoutId() {\n        return R.layout.activity_camera2;\n    }\n\n    @Override\n    protected void initView() {\n        textureView.setSurfaceTextureListener(surfaceTextureListener);\n    }\n\n    @Override\n    protected void initData() {\n\n    }\n\n    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)\n    @OnClick({R.id.iv_back2, R.id.img_camera2})\n    public void onClick(View view) {\n        switch (view.getId()) {\n            case R.id.iv_back2:\n                finish();\n                break;\n            case R.id.img_camera2:\n                takePicture();\n                break;\n            default:\n                break;\n        }\n    }\n\n    /**\n     * 启动拍照\n     */\n    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)\n    private void startCamera() {\n        if (textureView.isAvailable()) {\n            if (mCameraDevice == null) {\n                openCamera();\n            }\n        } else {\n            textureView.setSurfaceTextureListener(surfaceTextureListener);\n        }\n    }\n\n    /**\n     * 拍照\n     */\n    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)\n    private void takePicture() {\n        try {\n            if (mCameraDevice == null) {\n                return;\n            }\n            // 创建拍照请求\n            captureRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);\n            // 设置自动对焦模式\n            captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);\n            // 将imageReader的surface设为目标\n            captureRequestBuilder.addTarget(imageReader.getSurface());\n            // 获取设备方向\n            int rotation = getWindowManager().getDefaultDisplay().getRotation();\n            // 根据设备方向计算设置照片的方向\n            captureRequestBuilder.set(CaptureRequest.JPEG_ORIENTATION\n                    , ORIENTATIONS.get(rotation));\n            // 停止连续取景\n            mPreviewSession.stopRepeating();\n            //拍照\n            CaptureRequest captureRequest = captureRequestBuilder.build();\n            //设置拍照监听\n            mPreviewSession.capture(captureRequest, captureCallback, null);\n        } catch (CameraAccessException e) {\n            e.printStackTrace();\n        }\n    }\n\n    /**\n     * 监听拍照结果\n     */\n    private CameraCaptureSession.CaptureCallback captureCallback = new CameraCaptureSession.CaptureCallback() {\n        // 拍照成功\n        @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)\n        @Override\n        public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) {\n            // 重设自动对焦模式\n            captureRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_CANCEL);\n            // 设置自动曝光模式\n            captureRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);\n            try {\n                //重新进行预览\n                mPreviewSession.setRepeatingRequest(mCaptureRequest, null, null);\n            } catch (CameraAccessException e) {\n                e.printStackTrace();\n            }\n        }\n\n        @Override\n        public void onCaptureFailed(CameraCaptureSession session, CaptureRequest request, CaptureFailure failure) {\n            super.onCaptureFailed(session, request, failure);\n        }\n    };\n\n    /**\n     * TextureView的监听\n     */\n    private TextureView.SurfaceTextureListener surfaceTextureListener = new TextureView.SurfaceTextureListener() {\n\n        @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)\n        @Override\n        public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {\n            Camera2Activity.width = width;\n            Camera2Activity.height = height;\n            openCamera();\n        }\n\n        @Override\n        public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {\n        }\n\n        @Override\n        public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {\n            stopCamera();\n            return true;\n        }\n\n        @Override\n        public void onSurfaceTextureUpdated(SurfaceTexture surface) {\n        }\n    };\n\n\n    /**\n     * 打开摄像头\n     */\n    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)\n    private void openCamera() {\n        CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);\n        //设置摄像头特性\n        setCameraCharacteristics(manager);\n        try {\n            if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {\n                String[] perms = {\"android.permission.CAMERA\"};\n                ActivityCompat.requestPermissions(Camera2Activity.this, perms, RESULT_CODE_CAMERA);\n            } else {\n                manager.openCamera(mCameraId, stateCallback, null);\n            }\n\n        } catch (CameraAccessException e) {\n            e.printStackTrace();\n        }\n    }\n\n\n    /**\n     * 设置摄像头的参数\n     */\n    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)\n    private void setCameraCharacteristics(CameraManager manager) {\n        try {\n            // 获取指定摄像头的特性\n            CameraCharacteristics characteristics\n                    = manager.getCameraCharacteristics(mCameraId);\n            // 获取摄像头支持的配置属性\n            StreamConfigurationMap map = characteristics.get(\n                    CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);\n            // 获取摄像头支持的最大尺寸\n            Size largest = Collections.max(\n                    Arrays.asList(map.getOutputSizes(ImageFormat.JPEG)), new CompareSizesByArea());\n            // 创建一个ImageReader对象，用于获取摄像头的图像数据\n            imageReader = ImageReader.newInstance(largest.getWidth(), largest.getHeight(),\n                    ImageFormat.JPEG, 2);\n            //设置获取图片的监听\n            imageReader.setOnImageAvailableListener(imageAvailableListener, null);\n            // 获取最佳的预览尺寸\n            previewSize = chooseOptimalSize(map.getOutputSizes(\n                    SurfaceTexture.class), width, height, largest);\n        } catch (CameraAccessException e) {\n            e.printStackTrace();\n        } catch (NullPointerException e) {\n        }\n    }\n\n    /**\n     * 为Size定义一个比较器Comparator\n     */\n    static class CompareSizesByArea implements Comparator<Size> {\n        @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)\n        @Override\n        public int compare(Size lhs, Size rhs) {\n            return Long.signum((long) lhs.getWidth() * lhs.getHeight() -\n                    (long) rhs.getWidth() * rhs.getHeight());\n        }\n    }\n\n    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)\n    private static Size chooseOptimalSize(Size[] choices\n            , int width, int height, Size aspectRatio) {\n        // 收集摄像头支持的大过预览Surface的分辨率\n        List<Size> bigEnough = new ArrayList<>();\n        int w = aspectRatio.getWidth();\n        int h = aspectRatio.getHeight();\n        for (Size option : choices) {\n            if (option.getHeight() == option.getWidth() * h / w &&\n                    option.getWidth() >= width && option.getHeight() >= height) {\n                bigEnough.add(option);\n            }\n        }\n        if (bigEnough.size() > 0) {\n            return Collections.min(bigEnough, new CompareSizesByArea());\n        } else {\n            //没有合适的预览尺寸\n            return choices[0];\n        }\n    }\n\n    /**\n     * 摄像头状态的监听\n     */\n    private CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() {\n        // 摄像头被打开时触发该方法\n        @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)\n        @Override\n        public void onOpened(CameraDevice cameraDevice) {\n            mCameraDevice = cameraDevice;\n            // 开始预览\n            takePreview();\n        }\n\n        // 摄像头断开连接时触发该方法\n        @Override\n        public void onDisconnected(CameraDevice cameraDevice) {\n            stopCamera();\n        }\n\n        // 打开摄像头出现错误时触发该方法\n        @Override\n        public void onError(CameraDevice cameraDevice, int error) {\n            stopCamera();\n        }\n    };\n\n    /**\n     * 开始预览\n     */\n    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)\n    private void takePreview() {\n        SurfaceTexture mSurfaceTexture = textureView.getSurfaceTexture();\n        //设置TextureView的缓冲区大小\n        mSurfaceTexture.setDefaultBufferSize(previewSize.getWidth(), previewSize.getHeight());\n        //获取Surface显示预览数据\n        Surface mSurface = new Surface(mSurfaceTexture);\n        try {\n            //创建预览请求\n            mCaptureRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);\n            // 设置自动对焦模式\n            mCaptureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);\n            //设置Surface作为预览数据的显示界面\n            mCaptureRequestBuilder.addTarget(mSurface);\n            //创建相机捕获会话，第一个参数是捕获数据的输出Surface列表，第二个参数是CameraCaptureSession的状态回调接口，当它创建好后会回调onConfigured方法，第三个参数用来确定Callback在哪个线程执行，为null的话就在当前线程执行\n            mCameraDevice.createCaptureSession(Arrays.asList(mSurface, imageReader.getSurface()), new CameraCaptureSession.StateCallback() {\n                @Override\n                public void onConfigured(CameraCaptureSession session) {\n                    try {\n                        //开始预览\n                        mCaptureRequest = mCaptureRequestBuilder.build();\n                        mPreviewSession = session;\n                        //设置反复捕获数据的请求，这样预览界面就会一直有数据显示\n                        mPreviewSession.setRepeatingRequest(mCaptureRequest, null, null);\n                    } catch (CameraAccessException e) {\n                        e.printStackTrace();\n                    }\n                }\n\n                @Override\n                public void onConfigureFailed(CameraCaptureSession session) {\n                }\n            }, null);\n        } catch (CameraAccessException e) {\n            e.printStackTrace();\n        }\n    }\n\n    /**\n     * 释放\n     */\n    private void stopCamera() {\n        if (mCameraDevice != null) {\n            mCameraDevice.close();\n            mCameraDevice = null;\n        }\n    }\n\n    /**\n     * 监听拍照的图片\n     */\n    private ImageReader.OnImageAvailableListener imageAvailableListener = new ImageReader.OnImageAvailableListener() {\n        // 当照片数据可用时激发该方法\n        @Override\n        public void onImageAvailable(ImageReader reader) {\n            //先验证手机是否有sdcard\n            String status = Environment.getExternalStorageState();\n            if (!status.equals(Environment.MEDIA_MOUNTED)) {\n                Toast.makeText(getApplicationContext(), \"你的sd卡不可用。\", Toast.LENGTH_SHORT).show();\n                return;\n            }\n            Image image = reader.acquireNextImage();\n            ByteBuffer buffer = image.getPlanes()[0].getBuffer();\n            byte[] data = new byte[buffer.remaining()];\n            buffer.get(data);\n            String filePath = Environment.getExternalStorageDirectory().getPath() + \"/DCIM/Camera/\" +\n                    System.currentTimeMillis() + \".jpg\";\n            Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);\n            BitmapUtils.saveJPGE_After(getApplicationContext(), bitmap, filePath, 100);\n            if (!bitmap.isRecycled()) {\n                bitmap.recycle();\n            }\n            Intent intent = new Intent();\n            intent.putExtra(AppConstant.KEY.IMG_PATH, filePath);\n            intent.putExtra(AppConstant.KEY.PIC_WIDTH, width);\n            intent.putExtra(AppConstant.KEY.PIC_HEIGHT, height);\n            setResult(AppConstant.RESULT_CODE.RESULT_OK, intent);\n            finish();\n        }\n\n    };\n\n    @Override\n    protected void onPause() {\n        super.onPause();\n        if (mCameraDevice != null) {\n            stopCamera();\n        }\n    }\n\n    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)\n    @Override\n    protected void onResume() {\n        super.onResume();\n        startCamera();\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/camera/cn/cameramaster/ui/CameraActivity.java",
    "content": "package camera.cn.cameramaster.ui;\n\nimport android.content.Intent;\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapFactory;\nimport android.graphics.ImageFormat;\nimport android.graphics.Rect;\nimport android.graphics.YuvImage;\nimport android.hardware.Camera;\nimport android.os.Environment;\nimport android.util.DisplayMetrics;\nimport android.util.Log;\nimport android.view.SurfaceHolder;\nimport android.view.SurfaceView;\nimport android.view.View;\nimport android.widget.ImageView;\nimport android.widget.Toast;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.IOException;\n\nimport butterknife.BindView;\nimport butterknife.OnClick;\nimport camera.cn.cameramaster.R;\nimport camera.cn.cameramaster.base.BaseActivity;\nimport camera.cn.cameramaster.util.AppConstant;\nimport camera.cn.cameramaster.util.BitmapUtils;\nimport camera.cn.cameramaster.util.CameraUtil;\nimport camera.cn.cameramaster.view.ShowSurfaceView;\n\n/**\n * 拍照界面\n * 5.0 版本以前的拍照\n *\n * @author ymc\n */\n\npublic class CameraActivity extends BaseActivity implements SurfaceHolder.Callback {\n    private static final String TAG = \"CameraActivity\";\n    @BindView(R.id.surfaceView2)\n    ShowSurfaceView svShow;\n    @BindView(R.id.surfaceView)\n    SurfaceView svContent;\n    @BindView(R.id.img_camera)\n    ImageView ivCamera;\n    @BindView(R.id.camera_flash)\n    ImageView ivFlash;\n    @BindView(R.id.camera_switch)\n    ImageView ivSwitch;\n    @BindView(R.id.iv_back)\n    ImageView ivBack;\n\n    private Camera mCamera;\n    private SurfaceHolder mHolder;\n    private CameraUtil cameraInstance;\n    /**\n     * 屏幕宽高\n     */\n    private int screenWidth;\n    private int screenHeight;\n    /**\n     * 图片宽高\n     */\n    private int picWidth;\n\n    /**\n     * 是否有界面\n     */\n    private boolean isView = true;\n    /**\n     * 拍照id  1： 前摄像头  0：后摄像头\n     */\n    private int mCameraId = 0;\n    /**\n     * 闪光灯类型 0 ：关闭 1： 打开 2：自动\n     */\n    private int light_type = 0;\n\n    /**\n     * 图片高度\n     */\n    private int picHeight;\n\n    @Override\n    protected int getLayoutId() {\n        return R.layout.activity_camera;\n    }\n\n    @Override\n    protected void initView() {\n        mHolder = svContent.getHolder();\n        mHolder.addCallback(this);\n    }\n\n    @Override\n    protected void initData() {\n        cameraInstance = CameraUtil.getInstance();\n        DisplayMetrics dm = getResources().getDisplayMetrics();\n        screenWidth = dm.widthPixels;\n        screenHeight = dm.heightPixels;\n\n    }\n\n    @Override\n    protected void onResume() {\n        super.onResume();\n        if (mCamera == null) {\n            mCamera = getCamera(mCameraId);\n            if (mHolder != null) {\n                startPreview(mCamera, mHolder);\n            }\n        }\n    }\n\n    @OnClick({R.id.img_camera, R.id.camera_flash, R.id.camera_switch, R.id.iv_back})\n    public void OnClick(View view) {\n        switch (view.getId()) {\n            // 点击拍照\n            case R.id.img_camera:\n                switch (light_type) {\n                    case 0:\n                        //关闭\n                        cameraInstance.turnLightOff(mCamera);\n                        break;\n                    case 1:\n                        cameraInstance.turnLightOn(mCamera);\n                        break;\n                    case 2:\n                        //自动\n                        cameraInstance.turnLightAuto(mCamera);\n                        break;\n                    default:\n                        break;\n                }\n                takePhoto();\n                break;\n            // 切换闪光灯\n            case R.id.camera_flash:\n                if (mCameraId == 1) {\n                    Toast.makeText(this, \"请切换到后置摄像头\", Toast.LENGTH_LONG).show();\n                    return;\n                }\n                Camera.Parameters parameters = mCamera.getParameters();\n                switch (light_type) {\n                    case 0:\n                        //打开\n                        light_type = 1;\n                        ivFlash.setImageResource(R.mipmap.icon_camera_on);\n                        parameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);//开启\n                        mCamera.setParameters(parameters);\n                        break;\n                    case 1:\n                        //自动\n                        light_type = 2;\n                        parameters.setFlashMode(Camera.Parameters.FLASH_MODE_AUTO);\n                        mCamera.setParameters(parameters);\n                        ivFlash.setImageResource(R.mipmap.icon_camera_a);\n                        break;\n                    case 2:\n                        //关闭\n                        light_type = 0;\n                        //关闭\n                        parameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);\n                        mCamera.setParameters(parameters);\n                        ivFlash.setImageResource(R.mipmap.icon_camera_off);\n                        break;\n                    default:\n                        break;\n                }\n                break;\n            //切换前后摄像头\n            case R.id.camera_switch:\n                switchCamera();\n                break;\n            // 返回按钮\n            case R.id.iv_back:\n                finish();\n                break;\n            default:\n                break;\n        }\n    }\n\n    /**\n     * 切换前后摄像头\n     */\n    public void switchCamera() {\n        releaseCamera();\n        mCameraId = (mCameraId + 1) % Camera.getNumberOfCameras();\n        mCamera = getCamera(mCameraId);\n        if (mHolder != null) {\n            startPreview(mCamera, mHolder);\n        }\n    }\n\n    /**\n     * 拍照\n     */\n    private void takePhoto() {\n        mCamera.takePicture(null, null, new Camera.PictureCallback() {\n            @Override\n            public void onPictureTaken(byte[] data, Camera camera) {\n                isView = false;\n                //将data 转换为位图 或者你也可以直接保存为文件使用 FileOutputStream\n                //这里我相信大部分都有其他用处把 比如加个水印 后续再讲解\n                Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);\n                Bitmap saveBitmap = cameraInstance.setTakePicktrueOrientation(mCameraId, bitmap);\n                saveBitmap = Bitmap.createScaledBitmap(saveBitmap, screenWidth, screenHeight, true);\n                String imgpath = getExternalFilesDir(Environment.DIRECTORY_DCIM).getPath() +\n                        File.separator + System.currentTimeMillis() + \".jpeg\";\n                Log.e(TAG, \"imgpath: ---  \" + imgpath);\n                BitmapUtils.saveJPGE_After(getApplicationContext(), saveBitmap, imgpath, 100);\n                if (!bitmap.isRecycled()) {\n                    bitmap.recycle();\n                }\n                if (!saveBitmap.isRecycled()) {\n                    saveBitmap.recycle();\n                }\n                Intent intent = new Intent();\n                intent.putExtra(AppConstant.KEY.IMG_PATH, imgpath);\n                intent.putExtra(AppConstant.KEY.PIC_WIDTH, picWidth);\n                intent.putExtra(AppConstant.KEY.PIC_HEIGHT, picHeight);\n                setResult(AppConstant.RESULT_CODE.RESULT_OK, intent);\n                finish();\n            }\n        });\n\n    }\n\n    @Override\n    public void surfaceCreated(SurfaceHolder holder) {\n        startPreview(mCamera, holder);\n    }\n\n    @Override\n    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {\n        mCamera.stopPreview();\n        startPreview(mCamera, holder);\n    }\n\n    @Override\n    public void surfaceDestroyed(SurfaceHolder holder) {\n        releaseCamera();\n    }\n\n    /**\n     * 释放相机资源\n     */\n    private void releaseCamera() {\n        if (mCamera != null) {\n            mCamera.setPreviewCallback(null);\n            mCamera.stopPreview();\n            mCamera.release();\n            mCamera = null;\n        }\n    }\n\n    /**\n     * 预览相机\n     */\n    private void startPreview(Camera camera, SurfaceHolder holder) {\n        try {\n            setupCamera(camera);\n            camera.setPreviewDisplay(holder);\n            mCamera.setPreviewCallback(new Camera.PreviewCallback() {\n                @Override\n                public void onPreviewFrame(byte[] data, Camera camera) {\n                    Camera.Size size = camera.getParameters().getPreviewSize();\n                    ByteArrayOutputStream stream = new ByteArrayOutputStream();\n                    try{\n                        // YUV转为RGB\n                        YuvImage image = new YuvImage(data, ImageFormat.NV21, size.width, size.height, null);\n                        image.compressToJpeg(new Rect(0, 0, size.width/2, size.height/2), 20, stream);\n                        Bitmap bmp = BitmapFactory.decodeByteArray(stream.toByteArray(), 0, stream.size());\n                        svShow.setBitmap(BitmapUtils.rotateMyBitmap(BitmapUtils.ImgaeToNegative(bmp)));\n                        stream.close();\n                    }catch(Exception ex){\n                        Log.e(\"Sys\",\"Error:\"+ex.getMessage());\n                    }\n                }\n            });\n            cameraInstance.setCameraDisplayOrientation(this, mCameraId, camera);\n            camera.startPreview();\n            isView = true;\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n    }\n\n    /**\n     * 设置surfaceView的尺寸 因为camera默认是横屏，所以取得支持尺寸也都是横屏的尺寸\n     * 我们在startPreview方法里面把它矫正了过来，但是这里我们设置设置surfaceView的尺寸的时候要注意 previewSize.height<previewSize.width\n     * previewSize.width才是surfaceView的高度\n     * 一般相机都是屏幕的宽度 这里设置为屏幕宽度 高度自适应 你也可以设置自己想要的大小\n     */\n    private void setupCamera(Camera camera) {\n        Camera.Parameters parameters = camera.getParameters();\n        if (parameters.getSupportedFocusModes().contains(\n                Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {\n            parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);\n        }\n        //根据屏幕尺寸获取最佳 大小\n        Camera.Size previewSize = cameraInstance.getPicPreviewSize(parameters.getSupportedPreviewSizes(),\n                screenHeight, screenWidth);\n        parameters.setPreviewSize(previewSize.width, previewSize.height);\n\n        Camera.Size pictrueSize = cameraInstance.getPicPreviewSize(parameters.getSupportedPictureSizes(),\n                screenHeight,screenWidth);\n        parameters.setPictureSize(pictrueSize.width, pictrueSize.height);\n        camera.setParameters(parameters);\n//        picHeight = (screenWidth * pictrueSize.width) / pictrueSize.height;\n        picWidth = pictrueSize.width;\n        picHeight = pictrueSize.height;\n//        FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(screenWidth,\n//                (screenWidth * pictrueSize.width) / pictrueSize.height);\n//        svContent.setLayoutParams(params);\n    }\n\n    /**\n     * 获取Camera实例\n     *\n     * @return Camera\n     */\n    private Camera getCamera(int id) {\n        Camera camera = null;\n        try {\n            camera = Camera.open(id);\n        } catch (Exception e) {\n            Log.e(TAG, \"getCamera: \" + e);\n        }\n        return camera;\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/camera/cn/cameramaster/ui/CameraSurfaceViewActivity.java",
    "content": "package camera.cn.cameramaster.ui;\n\nimport android.os.Build;\nimport android.support.annotation.RequiresApi;\nimport android.support.constraint.ConstraintLayout;\nimport android.util.DisplayMetrics;\nimport android.util.Log;\nimport android.util.Size;\nimport android.view.View;\nimport android.widget.FrameLayout;\nimport android.widget.LinearLayout;\n\nimport butterknife.BindView;\nimport butterknife.OnClick;\nimport camera.cn.cameramaster.R;\nimport camera.cn.cameramaster.base.BaseActivity;\nimport camera.cn.cameramaster.util.CameraV2;\nimport camera.cn.cameramaster.view.CameraV2GLSurfaceView;\n\n/**\n * 基于 camera2 surfaceview 过滤界面\n * 参考url ： [https://blog.csdn.net/lb377463323/article/details/78054892]\n *\n * @author ymc\n * @date 2019年2月12日 14:32:37\n */\n\npublic class CameraSurfaceViewActivity extends BaseActivity {\n    private static final String TAG = \"CameraSVActivity\";\n    @BindView(R.id.frame_layout)\n    FrameLayout frameLayout;\n    private CameraV2 mCamera;\n    private CameraV2GLSurfaceView mCameraV2GLSurfaceView;\n\n    @Override\n    protected int getLayoutId() {\n        return R.layout.activity_camera_sv;\n    }\n\n    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)\n    @Override\n    protected void initView() {\n        mCameraV2GLSurfaceView = new CameraV2GLSurfaceView(this);\n        DisplayMetrics dm = new DisplayMetrics();\n        getWindowManager().getDefaultDisplay().getMetrics(dm);\n        mCamera = new CameraV2(this);\n        Size size = mCamera.setUpCameraOutputs(dm.widthPixels, dm.heightPixels);\n        if (!mCamera.openCamera()) {\n            Log.e(TAG, \"mCamera openCamera err\");\n            return;\n        }\n        mCameraV2GLSurfaceView.init(mCamera, false,\n                CameraSurfaceViewActivity.this);\n        // 将 surfaceview 添加到布局中\n        ConstraintLayout.LayoutParams lp = new ConstraintLayout.LayoutParams(\n                LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);\n        lp.width = size.getHeight();\n        lp.height = size.getWidth();\n        mCameraV2GLSurfaceView.setLayoutParams(lp);\n        frameLayout.addView(mCameraV2GLSurfaceView);\n    }\n\n    @Override\n    protected void initData() {\n\n    }\n\n    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)\n    @OnClick({R.id.iv_back, R.id.img_camera})\n    public void onClick(View view) {\n        switch (view.getId()) {\n            case R.id.iv_back:\n                finish();\n                break;\n            case R.id.img_camera:\n                mCamera.lockFocus();\n                break;\n            default:\n                break;\n        }\n    }\n\n    // TODO: 2019/4/3 会退到当前界面如何重新启动相机\n    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)\n    @Override\n    protected void onResume() {\n        super.onResume();\n        mCamera.startBackgroundThread();\n        // 存在关联则打开相机，没有则绑定事件\n//        mCamera.openCamera();\n    }\n\n    @Override\n    protected void onPause() {\n        mCamera.closeCamera();\n        mCamera.stopBackgroundThread();\n        super.onPause();\n    }\n\n    @Override\n    protected void onDestroy() {\n        super.onDestroy();\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/camera/cn/cameramaster/ui/CameraVideoActivity.java",
    "content": "package camera.cn.cameramaster.ui;\n\nimport android.Manifest;\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.PackageManager;\nimport android.graphics.SurfaceTexture;\nimport android.hardware.Sensor;\nimport android.hardware.SensorEvent;\nimport android.hardware.SensorEventListener;\nimport android.hardware.SensorManager;\nimport android.hardware.camera2.CameraMetadata;\nimport android.hardware.camera2.CaptureRequest;\nimport android.hardware.camera2.params.RggbChannelVector;\nimport android.media.MediaRecorder;\nimport android.net.Uri;\nimport android.os.Build;\nimport android.os.Looper;\nimport android.support.annotation.RequiresApi;\nimport android.support.v4.content.ContextCompat;\nimport android.support.v7.widget.LinearLayoutManager;\nimport android.support.v7.widget.RecyclerView;\nimport android.util.Log;\nimport android.view.MotionEvent;\nimport android.view.Surface;\nimport android.view.TextureView;\nimport android.view.View;\nimport android.view.animation.AlphaAnimation;\nimport android.view.animation.Animation;\nimport android.view.animation.Transformation;\nimport android.view.animation.TranslateAnimation;\nimport android.widget.ImageButton;\nimport android.widget.ImageView;\nimport android.widget.LinearLayout;\nimport android.widget.RelativeLayout;\nimport android.widget.SeekBar;\nimport android.widget.Switch;\nimport android.widget.TextView;\n\nimport java.io.File;\nimport java.util.ArrayList;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.concurrent.TimeUnit;\n\nimport butterknife.BindView;\nimport butterknife.OnClick;\nimport camera.cn.cameramaster.R;\nimport camera.cn.cameramaster.adapter.EffectAdapter;\nimport camera.cn.cameramaster.adapter.MenuAdapter;\nimport camera.cn.cameramaster.adapter.SenseAdapter;\nimport camera.cn.cameramaster.base.BaseActivity;\nimport camera.cn.cameramaster.view.AwbSeekBarChangeListener;\nimport camera.cn.cameramaster.util.AppConstant;\nimport camera.cn.cameramaster.util.cameravideo.CameraHelper;\nimport camera.cn.cameramaster.util.cameravideo.ICamera2;\nimport camera.cn.cameramaster.util.cameravideo.IVideoControl;\nimport camera.cn.cameramaster.util.cameravideo.VideoPlayer;\nimport camera.cn.cameramaster.view.AutoFitTextureView;\nimport camera.cn.cameramaster.view.AutoLocateHorizontalView;\nimport camera.cn.cameramaster.view.AwbSeekBar;\nimport io.reactivex.Observable;\nimport io.reactivex.android.schedulers.AndroidSchedulers;\nimport io.reactivex.disposables.Disposable;\nimport io.reactivex.functions.Consumer;\nimport io.reactivex.functions.Function;\n\nimport static camera.cn.cameramaster.util.AppConstant.SHOW_AE;\nimport static camera.cn.cameramaster.util.AppConstant.SHOW_AWB;\nimport static camera.cn.cameramaster.util.AppConstant.SHOW_EFFECT;\nimport static camera.cn.cameramaster.util.AppConstant.SHOW_SENSE;\n\n/**\n * 拍照 视频\n *\n * @author ymc\n * @date 2019年5月7日 13:49:17\n */\n\n@RequiresApi(api = Build.VERSION_CODES.M)\npublic class CameraVideoActivity extends BaseActivity implements IVideoControl.PlaySeekTimeListener,\n        IVideoControl.PlayStateListener, ICamera2.TakePhotoListener,\n        SensorEventListener, ICamera2.CameraReady, AutoLocateHorizontalView.OnSelectedPositionChangedListener {\n\n    private static final String TAG = \"CameraVideoActivity\";\n\n    /**\n     * 当前的显示面板状态\n     */\n    public int TEXTURE_STATE = AppConstant.TEXTURE_PREVIEW_STATE;\n\n    @BindView(R.id.video_photo)\n    ImageView videoPhoto;\n    @BindView(R.id.video_texture)\n    AutoFitTextureView videoTexture;\n    @BindView(R.id.video_record_seek_bar)\n    SeekBar videoRecordSeekBar;\n    @BindView(R.id.video_time)\n    TextView videoTime;\n    @BindView(R.id.video_switch_flash)\n    ImageView videoSwitchFlash;\n    @BindView(R.id.video_switch_camera)\n    ImageView videoSwitchCamera;\n    @BindView(R.id.video_play)\n    ImageButton videoPlay;\n    @BindView(R.id.video_delete)\n    ImageButton videoDelete;\n    @BindView(R.id.video_menu)\n    AutoLocateHorizontalView videoMenu;\n    @BindView(R.id.video_record)\n    ImageButton videoRecord;\n    @BindView(R.id.video_save)\n    ImageButton videoSave;\n    @BindView(R.id.video_mine_play)\n    ImageButton videoMinePlay;\n    @BindView(R.id.video_seek_bar)\n    SeekBar videoSeekBar;\n    @BindView(R.id.video_seek_time)\n    TextView videoSeekTime;\n    @BindView(R.id.video_hint_text)\n    TextView videoHintText;\n    /**\n     * 焦点框\n     */\n    @BindView(R.id.video_fouces)\n    ImageView videoFouces;\n    /**\n     * zoom 缩小\n     */\n    @BindView(R.id.video_minus)\n    ImageView videoMinus;\n    /**\n     * scale zoom 条\n     */\n    @BindView(R.id.video_scale)\n    SeekBar videoScale;\n    /**\n     *  zoom 放大\n     */\n    @BindView(R.id.video_add)\n    ImageView videoAdd;\n    @BindView(R.id.video_scale_bar_layout)\n    RelativeLayout videoScaleBarLayout;\n    /**\n     * 底部切换布局\n     */\n    @BindView(R.id.layout_bottom)\n    RelativeLayout mLayoutBottom;\n\n    /**\n     * ae 修改布局\n     */\n    @BindView(R.id.layout_ae)\n    LinearLayout layoutAe;\n    /**\n     * 特效\n     */\n    @BindView(R.id.layout_effect)\n    LinearLayout llEffect;\n    @BindView(R.id.rv_effect_list)\n    RecyclerView evEffectList;\n    /**\n     * sense 布局\n     */\n    @BindView(R.id.layout_sense)\n    LinearLayout llSense;\n    @BindView(R.id.rv_sense_list)\n    RecyclerView evSenseList;\n    @BindView(R.id.sb_ae)\n    SeekBar sbAe;\n\n    /**\n     * awb 手动设置布局\n     */\n    @BindView(R.id.layout_setting)\n    LinearLayout llAWBSetting;\n    @BindView(R.id.awb_seek_bar)\n    SeekBar sbAWB;\n\n    @BindView(R.id.sb_awb)\n    AwbSeekBar sbAwb;\n\n    /**\n     * awb\n     */\n    @BindView(R.id.layout_awb)\n    LinearLayout layoutAwb;\n\n    @BindView(R.id.rl_camera)\n    RelativeLayout rlCamera;\n\n    @BindView(R.id.switch_ae)\n    Switch switchAe;\n\n    @BindView(R.id.txt_sb_txt)\n    TextView tvSbTxt;\n\n    /**\n     * 视频播放器\n     */\n    private VideoPlayer mVideoPlayer;\n    /**\n     * 相机模式\n     */\n    private int MODE;\n    /**\n     * 视频保存路径\n     */\n    private String mVideoPath;\n    /**\n     * 拍照工具类\n     */\n    private CameraHelper cameraHelper;\n    /**\n     * 菜单适配器\n     */\n    private MenuAdapter mMenuAdapter;\n    /**\n     * 当前拍照模式\n     */\n    private int NOW_MODE;\n    /**\n     * 触摸事件处理类\n     */\n    private CameraTouch mCameraTouch;\n    /**\n     * 放大缩小seekBar 是否可以隐藏\n     */\n    private boolean isCanHind;\n    /**\n     * 手动对焦 动画\n     */\n    private FoucesAnimation mFoucesAnimation;\n    /**\n     * 前 后 摄像头标识\n     */\n    private ICamera2.CameraType mNowCameraType = ICamera2.CameraType.BACK;\n    /**\n     * 单点标识\n     */\n    private boolean hasRecordClick = false;\n    /**\n     * 是否在 录制中\n     */\n    private boolean hasRecording = false;\n    /**\n     * 图片路径\n     */\n    private String mCameraPath;\n    /**\n     * 倒计时\n     */\n    private Disposable mDisposable;\n    /**\n     * 是否正在播放 标识\n     */\n    private boolean hasPlaying = false;\n    /**\n     * 是否有拍照权限\n     */\n    private boolean isNoPremissionPause;\n\n    /**\n     * 定义文字动画\n     */\n    private AlphaAnimation mAlphaInAnimation;\n    private AlphaAnimation mAlphaOutAnimation;\n    private SenseAdapter sAdapter;\n    private EffectAdapter effectAdapter;\n    private Runnable mImageFoucesRunnable = new Runnable() {\n        @Override\n        public void run() {\n            videoFouces.setVisibility(View.GONE);\n        }\n    };\n    /**\n     * 3s后隐藏的runnable\n     */\n    private Runnable SeekBarLayoutRunnalbe = new Runnable() {\n        @Override\n        public void run() {\n            videoScaleBarLayout.setVisibility(View.GONE);\n        }\n    };\n    /**\n     * 视频播放模式控件隐藏\n     */\n    private Runnable mHindViewRunnable = new Runnable() {\n        @Override\n        public void run() {\n            hindPlayView();\n        }\n    };\n    /**\n     * 底部 布局集合\n     */\n    private List<View> mLayoutList = new LinkedList<>();\n    /**\n     * visible与invisible之间切换的动画\n     */\n    private TranslateAnimation mShowAction;\n\n    /**\n     * 设置 rgb 色域\n     * @param whiteBalance 0- 100\n     * @return RggbChannelVector\n     */\n    public static RggbChannelVector colorTemperature(int whiteBalance) {\n        float temperature = whiteBalance/100;\n        float red;\n        float green;\n        float blue;\n\n        //Calculate red\n        if (temperature <= 66)\n            red = 255;\n        else {\n            red = temperature - 60;\n            red = (float) (329.698727446 * (Math.pow((double) red, -0.1332047592)));\n            if (red < 0)\n                red = 0;\n            if (red > 255)\n                red = 255;\n        }\n\n\n        //Calculate green\n        if (temperature <= 66) {\n            green = temperature;\n            green = (float) (99.4708025861 * Math.log(green) - 161.1195681661);\n            if (green < 0)\n                green = 0;\n            if (green > 255)\n                green = 255;\n        } else {\n            green = temperature - 60;\n            green = (float) (288.1221695283 * (Math.pow((double) green, -0.0755148492)));\n            if (green < 0)\n                green = 0;\n            if (green > 255)\n                green = 255;\n        }\n\n        //calculate blue\n        if (temperature >= 66)\n            blue = 255;\n        else if (temperature <= 19)\n            blue = 0;\n        else {\n            blue = temperature - 10;\n            blue = (float) (138.5177312231 * Math.log(blue) - 305.0447927307);\n            if (blue < 0)\n                blue = 0;\n            if (blue > 255)\n                blue = 255;\n        }\n\n        Log.e(TAG, \"red=\" + red + \", green=\" + green + \", blue=\" + blue + \", paroess:\"+whiteBalance);\n        return new RggbChannelVector((red/255) * 2, (green/255), (green/255), (blue/255) * 2);\n    }\n\n    @Override\n    protected int getLayoutId() {\n        return R.layout.activity_camera_video;\n    }\n\n    @Override\n    protected void initView() {\n        // 将底部布局 依次添加到 列表中\n        mLayoutList.clear();\n        mLayoutList.add(mLayoutBottom);\n        mLayoutList.add(layoutAe);\n        mLayoutList.add(layoutAwb);\n        mLayoutList.add(llEffect);\n        mLayoutList.add(llSense);\n        mLayoutList.add(llAWBSetting);\n        // 初始化 切换动画\n        mShowAction = new TranslateAnimation(Animation.RELATIVE_TO_SELF,\n                0.0f, Animation.RELATIVE_TO_SELF, 0.0f,\n                Animation.RELATIVE_TO_SELF, -1.0f,\n                Animation.RELATIVE_TO_SELF, 0.0f);\n        mShowAction.setDuration(100);\n\n        mVideoPlayer = new VideoPlayer();\n        //设置时间戳回调\n        mVideoPlayer.setPlaySeekTimeListener(this);\n        MODE = getIntent().getIntExtra(\"mode\", AppConstant.CAMERA_MODE);\n\n        if (MODE == AppConstant.CAMERA_MODE) {\n            //摄像头模式\n            initCameraMode();\n        } else if (MODE == AppConstant.VIDEO_MODE) {\n            //视频播放模式\n            mVideoPath = getIntent().getStringExtra(\"videoPath\");\n            initVideoMode();\n        }\n        mFoucesAnimation = new FoucesAnimation();\n        // 淡入动画\n        mAlphaInAnimation = new AlphaAnimation(0.0f, 1.0f);\n        mAlphaInAnimation.setDuration(500);\n        // 淡出动画\n        mAlphaOutAnimation = new AlphaAnimation(1.0f, 0.0f);\n        mAlphaOutAnimation.setDuration(500);\n\n        sbAwb.setmOnAwbSeekBarChangeListener(cameraHelper);\n\n        LinearLayoutManager ms = new LinearLayoutManager(this);\n        ms.setOrientation(LinearLayoutManager.HORIZONTAL);\n        LinearLayoutManager ms1 = new LinearLayoutManager(this);\n        ms1.setOrientation(LinearLayoutManager.HORIZONTAL);\n        evSenseList.setLayoutManager(ms);\n        evEffectList.setLayoutManager(ms1);\n        sAdapter = new SenseAdapter(this, AppConstant.senseArr);\n        effectAdapter = new EffectAdapter(this,AppConstant.effectArr);\n        evSenseList.setAdapter(sAdapter);\n        evEffectList.setAdapter(effectAdapter);\n        // rv 点击事件\n        initListener();\n    }\n\n    @Override\n    protected void initData() {\n        mCameraPath = cameraHelper.getPhotoFilePath();\n        mVideoPath = cameraHelper.getVideoFilePath();\n        sbAWB.setOnSeekBarChangeListener(new awbSettingSeekBarListener());\n        sbAe.setOnSeekBarChangeListener(new CameraSeekBarListener());\n    }\n\n    /**\n     * 初始化 录像\n     */\n    private void initVideoMode() {\n        hindMenu();\n        hindSwitchCamera();\n        hindVideoRecordSeekBar();\n        mVideoPlayer.setPlayStateListener(this);\n        videoRecord.setVisibility(View.GONE);\n        videoHintText.setVisibility(View.GONE);\n        videoTexture.setOnClickListener(new View.OnClickListener() {\n            @Override\n            public void onClick(View v) {     //单机屏幕显示出控件\n                if (videoMinePlay.getVisibility() == View.VISIBLE) {\n                    hindPlayView();\n                } else {\n                    showPlayView();\n                    videoTexture.postDelayed(mHindViewRunnable, 3000);\n                }\n            }\n        });\n\n        videoSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {\n            private int progress;\n            @Override\n            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {\n                if (fromUser) {\n                    this.progress = progress;\n                }\n            }\n\n            @Override\n            public void onStartTrackingTouch(SeekBar seekBar) {\n                //触摸进度条取消几秒后隐藏的事件\n                videoTexture.removeCallbacks(mHindViewRunnable);\n            }\n\n            @Override\n            public void onStopTrackingTouch(SeekBar seekBar) {\n                mVideoPlayer.seekTo(progress);\n                videoTexture.postDelayed(mHindViewRunnable, 3000);\n            }\n        });\n    }\n\n    /**\n     * 初始化 拍照\n     */\n    @RequiresApi(api = Build.VERSION_CODES.M)\n    @SuppressLint(\"ClickableViewAccessibility\")\n    private void initCameraMode() {\n        if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) !=\n                PackageManager.PERMISSION_GRANTED ||\n                ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) !=\n                        PackageManager.PERMISSION_GRANTED ||\n                ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)\n                        != PackageManager.PERMISSION_GRANTED) {\n            isNoPremissionPause = true;\n        }\n        initCamera(mNowCameraType);\n        cameraHelper = new CameraHelper(this);\n        cameraHelper.setTakePhotoListener(this);\n        cameraHelper.setCameraReady(this);\n        cameraHelper.setShowTextView(tvSbTxt);\n        mVideoPlayer.setLoopPlay(true);\n        List<String> menus = new ArrayList<>();\n        menus.add(\"拍照\");\n        menus.add(\"录像\");\n        menus.add(\"曝光\");\n        menus.add(\"白平衡\");\n        menus.add(\"效果\");\n        menus.add(\"感觉\");\n        menus.add(\"手动设置\");\n\n        mMenuAdapter = new MenuAdapter(this, menus, videoMenu);\n        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);\n        linearLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);\n        videoMenu.setLayoutManager(linearLayoutManager);\n        videoMenu.setAdapter(mMenuAdapter);\n        videoMenu.setOnSelectedPositionChangedListener(this);\n\n        mCameraTouch = new CameraTouch();\n\n        videoMenu.setOnTouchListener(new HorizontalViewTouchListener());\n        registerSensor();\n        initScaleSeekbar();\n    }\n\n    /**\n     * 初始化摄像头\n     *\n     * @param cameraType\n     */\n    private void initCamera(ICamera2.CameraType cameraType) {\n        if (cameraHelper == null) {\n            return;\n        }\n        if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)\n                != PackageManager.PERMISSION_GRANTED) {\n            return;\n        }\n        cameraHelper.setTextureView(videoTexture);\n        cameraHelper.openCamera(cameraType);\n    }\n\n    /**\n     * 初始化 scale seekBar\n     */\n    private void initScaleSeekbar() {\n        videoScale.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {\n\n            @Override\n            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {\n                if (fromUser) {\n                    float scale = (float) progress / (float) seekBar.getMax() * cameraHelper.getMaxZoom();\n                    cameraHelper.cameraZoom(scale);\n                    mCameraTouch.setScale(scale);\n                }\n            }\n\n            @Override\n            public void onStartTrackingTouch(SeekBar seekBar) {\n                removeSeekBarRunnable();\n            }\n\n            @Override\n            public void onStopTrackingTouch(SeekBar seekBar) {\n                seekBarDelayedHind();\n            }\n        });\n    }\n\n    /**\n     * 点击事件\n     *\n     * @param view view\n     */\n    @RequiresApi(api = Build.VERSION_CODES.M)\n    @OnClick({R.id.video_switch_camera, R.id.video_switch_flash})\n    public void cameraOnClickListener(View view) {\n        switch (view.getId()) {\n            // 切换摄像头状态\n            case R.id.video_switch_camera:\n                if (mNowCameraType == ICamera2.CameraType.FRONT) {\n                    cameraHelper.switchCamera(ICamera2.CameraType.BACK);\n                    mNowCameraType = ICamera2.CameraType.BACK;\n                } else {\n                    cameraHelper.switchCamera(ICamera2.CameraType.FRONT);\n                    mNowCameraType = ICamera2.CameraType.FRONT;\n                }\n                mCameraTouch.resetScale();\n                break;\n            case R.id.video_switch_flash:\n                Object o = videoSwitchFlash.getTag();\n                if (o == null || ((int) o) == 0) {\n                    videoSwitchFlash.setBackgroundResource(R.mipmap.flash_auto);\n                    videoSwitchFlash.setTag(1);\n                    cameraHelper.flashSwitchState(ICamera2.FlashState.AUTO);\n                } else if (((int) o) == 1) {\n                    videoSwitchFlash.setBackgroundResource(R.mipmap.flash_open);\n                    videoSwitchFlash.setTag(2);\n                    cameraHelper.flashSwitchState(ICamera2.FlashState.OPEN);\n                } else {\n                    videoSwitchFlash.setBackgroundResource(R.mipmap.flash_close);\n                    videoSwitchFlash.setTag(0);\n                    cameraHelper.flashSwitchState(ICamera2.FlashState.CLOSE);\n                }\n                break;\n            default:\n                break;\n        }\n    }\n\n    /**\n     * 传感器继承方法 重力发生改变\n     * 根据重力方向 动态旋转拍照图片角度(暂时关闭该方法)\n     *\n     * 使用以下方法\n     * int rotation = getWindowManager().getDefaultDisplay().getRotation();\n     * @param event event\n     */\n    @Override\n    public void onSensorChanged(SensorEvent event) {\n        if (event.sensor.getType() == Sensor.TYPE_ORIENTATION) {\n            float x = event.values[0];\n            float y = event.values[1];\n            float z = event.values[2];\n//            Log.e(TAG, \"onSensorChanged: x: \" + x +\"   y: \"+y +\"  z : \"+z);\n            if (z > 55.0f) {\n                //向左横屏\n            } else if (z < -55.0f) {\n                //向右横屏\n            } else if (y > 60.0f) {\n                //是倒竖屏\n            } else {\n                //正竖屏\n            }\n        }\n        if (event.sensor.getType() == Sensor.TYPE_LIGHT) {\n            float light = event.values[0];\n            cameraHelper.setLight(light);\n        }\n    }\n\n    /**\n     * 注册陀螺仪传感器\n     */\n    private void registerSensor() {\n        SensorManager mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);\n        Sensor mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);\n        Sensor mLightSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);\n        if (mSensor == null) {\n            return;\n        }\n        mSensorManager.registerListener(this, mSensor, Sensor.TYPE_ORIENTATION);\n        mSensorManager.registerListener(this, mLightSensor, Sensor.TYPE_LIGHT);\n    }\n\n    /**\n     * 当已注册传感器的精度发生变化时调用\n     *\n     * @param sensor   sensor\n     * @param accuracy 传感器的新精度\n     */\n    @Override\n    public void onAccuracyChanged(Sensor sensor, int accuracy) {\n\n    }\n\n    @Override\n    public void onSeekTime(int allTime, final int time) {\n        if (videoSeekBar ==null || videoSeekBar.getVisibility() != View.VISIBLE){\n            return;\n        }\n        if (videoSeekBar.getMax() != allTime){\n            videoSeekBar.setMax(allTime);\n        }\n        videoSeekBar.setProgress(time);\n        videoSeekTime.post(new Runnable() {\n            @Override\n            public void run() {\n                float t = (float) time / 1000.0f;\n                videoSeekTime.setText(cameraHelper.secToTime(Math.round(t)));\n            }\n        });\n    }\n\n    @Override\n    public void onStartListener(int width, int height) {\n        videoTexture.setVideoAspectRatio(width, height);\n        videoMinePlay.setImageResource(R.mipmap.ic_pause);\n        videoPlay.setImageResource(R.mipmap.ic_pause);\n    }\n\n    @Override\n    public void onCompletionListener() {\n        hasPlaying = false;\n        videoMinePlay.setImageResource(R.mipmap.ic_play);\n        videoPlay.setImageResource(R.mipmap.ic_play);\n        videoPlay.setVisibility(View.VISIBLE);\n    }\n\n    /**\n     * 拍照完成回调\n     *\n     * @param file          文件\n     * @param photoRotation 角度\n     * @param width         宽度\n     * @param height        高度\n     */\n    @Override\n    public void onTakePhotoFinish(final File file, int photoRotation, int width, int height) {\n        runOnUiThread(new Runnable() {\n            @Override\n            public void run() {\n                hindSwitchCamera();\n                hindMenu();\n                showRecordEndView();\n                videoSwitchFlash.setVisibility(View.GONE);\n                videoRecord.setVisibility(View.GONE);\n                videoHintText.setVisibility(View.GONE);\n                TEXTURE_STATE = AppConstant.TEXTURE_PHOTO_STATE;\n                videoTexture.setVisibility(View.GONE);\n                videoPhoto.setImageURI(cameraHelper.getUriFromFile(CameraVideoActivity.this, file));\n                videoPhoto.setVisibility(View.VISIBLE);\n            }\n        });\n    }\n\n    /**\n     * 相机准备完毕\n     */\n    @Override\n    public void onCameraReady() {\n        videoRecord.setClickable(true);\n    }\n\n    /**\n     * 横向菜单列表 修改点击事件\n     *\n     * @param pos\n     */\n    @Override\n    public void selectedPositionChanged(int pos) {\n        Log.e(TAG, \"selectedPositionChanged: \"+pos);\n        switch (pos){\n            case 0:{\n                showLayout(0, false);\n                NOW_MODE = AppConstant.VIDEO_TAKE_PHOTO;\n                cameraHelper.setCameraState(ICamera2.CameraMode.TAKE_PHOTO);\n                videoHintText.setText(\"点击拍照\");\n                break;\n            }\n            case 1:{\n                showLayout(0, false);\n                NOW_MODE = AppConstant.VIDEO_RECORD_MODE;\n                cameraHelper.setCameraState(ICamera2.CameraMode.RECORD_VIDEO);\n                videoHintText.setText(\"点击录像\");\n                break;\n            }\n            // 调整 曝光\n            case 2:{\n                showLayout(SHOW_AE, true);\n                break;\n            }\n            // 调整 白平衡\n            case 3:{\n                showLayout(SHOW_AWB, true);\n                break;\n            }\n            // 调整 效果\n            case 4:{\n                showLayout(3, true);\n                break;\n            }\n            // 调整 感觉\n            case 5:{\n                showLayout(4, true);\n                break;\n            }\n            // 调整 感觉\n            case 6:{\n                showLayout(5, true);\n                break;\n            }\n        }\n    }\n\n    /**\n     * 录像时长倒计时\n     */\n    @SuppressLint(\"SetTextI18n\")\n    private void recordCountDown() {\n        videoTime.setVisibility(View.VISIBLE);\n        videoRecordSeekBar.setVisibility(View.VISIBLE);\n        final int count = 10;\n        mDisposable = Observable.interval(1, 1, TimeUnit.SECONDS)\n                .take(count + 1)\n                .map(new Function<Long, Long>() {\n                    @Override\n                    public Long apply(Long aLong) {\n                        return count - aLong;\n                    }\n                }).observeOn(AndroidSchedulers.mainThread())\n                .subscribe(new Consumer<Long>() {\n                    @Override\n                    public void accept(Long aLong) {\n                        long time = 11 - aLong;\n                        if (time < 10) {\n                            videoTime.setText(\"0:0\" + String.valueOf(time));\n                        } else {\n                            videoTime.setText(\"0:\" + String.valueOf(time));\n                        }\n                        videoRecordSeekBar.setProgress((int) time);\n                        if (time == AppConstant.VIDEO_MAX_TIME) {\n                            videoTime.postDelayed(new Runnable() {\n                                @Override\n                                public void run() {\n                                    recordVideoOrTakePhoto();\n                                    hindVideoRecordSeekBar();\n                                }\n                            }, 300);\n                        }\n                    }\n                });\n    }\n\n    /**\n     * 拍照或者录像\n     */\n    @OnClick(R.id.video_record)\n    public void recordVideoOrTakePhoto() {\n        if (hasRecordClick) {\n            return;\n        }\n        hasRecordClick = true;\n        if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO)\n                != PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission\n                (this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {\n            Log.e(TAG, \"cameraOnClickListener: 动态权限获取失败...\");\n            return;\n        }\n        //拍照\n        if (NOW_MODE == AppConstant.VIDEO_TAKE_PHOTO && mCameraPath!=null) {\n            int rotation = getWindowManager().getDefaultDisplay().getRotation();\n            cameraHelper.setDeviceRotation(rotation);\n            cameraHelper.takePhone(mCameraPath, ICamera2.MediaType.JPEG);\n        }\n        //录制视频\n        if (NOW_MODE == AppConstant.VIDEO_RECORD_MODE) {\n            if (!hasRecording) {\n                // 暂停录像\n                if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO)\n                        != PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission\n                        (this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {\n                    return;\n                }\n\n                mVideoPath = cameraHelper.getVideoFilePath();\n                hasRecording = cameraHelper.startVideoRecord(mVideoPath, MediaRecorder.OutputFormat.MPEG_4);\n                if (hasRecording) {\n                    videoRecord.setImageResource(R.mipmap.ic_recording);\n                    hindSwitchCamera();\n                    recordCountDown();\n                    hindMenu();\n                    //      mVideoHintText.setVisibility(View.GONE);\n                    videoHintText.setText(\"点击停止\");\n                    videoSwitchFlash.setVisibility(View.GONE);\n                    TEXTURE_STATE = AppConstant.TEXTURE_RECORD_STATE;\n                }\n            } else {\n                // 开始录像\n                if (mDisposable != null && !mDisposable.isDisposed()){\n                    mDisposable.dispose();\n                }\n                mDisposable = null;\n                videoSeekTime.setVisibility(View.GONE);\n                hasRecording = false;\n                cameraHelper.stopVideoRecord();\n\n                videoRecord.setImageResource(R.drawable.ic_camera);\n                videoRecord.setVisibility(View.GONE);\n                videoHintText.setVisibility(View.GONE);\n                showRecordEndView();\n                hindVideoRecordSeekBar();\n                playVideo();\n            }\n        }\n        hasRecordClick = false;\n    }\n\n    /**\n     * 返回 取消拍照或者 录像\n     */\n    @OnClick(R.id.video_delete)\n    public void deleteVideoOrPicture() {\n        if (TEXTURE_STATE == AppConstant.TEXTURE_PLAY_STATE) {\n            mVideoPlayer.stop();\n            cameraHelper.startBackgroundThread();\n            cameraHelper.openCamera(mNowCameraType);\n            mCameraTouch.resetScale();  //重新打开摄像头重置一下放大倍数\n            File file = new File(mVideoPath);\n            if (file.exists()){\n                file.delete();\n            }\n            videoHintText.setText(\"点击录像\");\n        } else if (TEXTURE_STATE == AppConstant.TEXTURE_PHOTO_STATE) {\n            File file = new File(mCameraPath);\n            if (file.exists()){\n                file.delete();\n            }\n            cameraHelper.resumePreview();\n            videoTexture.setVisibility(View.VISIBLE);\n            videoPhoto.setVisibility(View.GONE);\n            videoHintText.setText(\"点击拍照\");\n        }\n        initData();\n        TEXTURE_STATE = AppConstant.TEXTURE_PREVIEW_STATE;\n        hindRecordEndView();\n        videoSwitchCamera.setVisibility(View.VISIBLE);\n        videoMenu.setVisibility(View.VISIBLE);\n        videoRecord.setVisibility(View.VISIBLE);\n        videoTime.setVisibility(View.GONE);\n        videoTime.setText(\"0:00\");\n        videoHintText.setVisibility(View.VISIBLE);\n        videoSwitchFlash.setVisibility(View.VISIBLE);\n    }\n\n    /**\n     * 发送视频或者图片\n     */\n    @OnClick(R.id.video_save)\n    public void saveVideoOrPhoto() {\n        final Intent data;\n        data = new Intent();\n        if (NOW_MODE == AppConstant.VIDEO_TAKE_PHOTO){\n            data.putExtra(\"path\", mCameraPath);\n            data.putExtra(\"mediaType\", \"image\");\n            saveMedia(new File(mCameraPath));\n        }\n        else if (NOW_MODE == AppConstant.VIDEO_RECORD_MODE) {\n            data.putExtra(\"path\", mVideoPath);\n            data.putExtra(\"mediaType\", \"video\");\n            saveMedia(new File(mVideoPath));\n        }\n        setResult(RESULT_OK, data);\n        finish();\n    }\n\n    /**\n     * 移除对焦 消失任务\n     */\n    private void removeImageFoucesRunnable() {\n        videoFouces.removeCallbacks(mImageFoucesRunnable);\n    }\n\n    /**\n     * 添加 延时消失任务\n     */\n    private void imageFoucesDelayedHind() {\n        videoFouces.postDelayed(mImageFoucesRunnable, 500);\n    }\n\n    /**\n     * seekBar 添加延时消失任务\n     */\n    private void seekBarDelayedHind() {\n        if (isCanHind) {\n            videoScaleBarLayout.postDelayed(SeekBarLayoutRunnalbe, 2000);\n        }\n        isCanHind = false;\n    }\n\n    /**\n     * 移除隐藏 seekBar消失的任务\n     */\n    private void removeSeekBarRunnable() {\n        isCanHind = true;\n        videoScale.removeCallbacks(SeekBarLayoutRunnalbe);\n    }\n\n    /**\n     * 显示播放视频 的 确认和删除按钮\n     */\n    private void showRecordEndView() {\n        videoSave.setVisibility(View.VISIBLE);\n        videoDelete.setVisibility(View.VISIBLE);\n    }\n\n    /**\n     * 隐藏视频录像的进度条\n     */\n    private void hindVideoRecordSeekBar() {\n        videoRecordSeekBar.setVisibility(View.GONE);\n        videoRecordSeekBar.setProgress(0);\n    }\n\n    /**\n     * 关闭摄像头\n     */\n    private void closeCamera() {\n        videoRecord.setClickable(false);\n        cameraHelper.closeCamera();\n        cameraHelper.stopBackgroundThread();\n    }\n\n    /**\n     * 播放视频\n     */\n    private void playVideo() {\n        closeCamera();\n        if (mVideoPath != null && mVideoPlayer != null) {\n            mVideoPlayer.setDataSourceAndPlay(mVideoPath);\n            hasPlaying = true;\n            //视频播放状态\n            TEXTURE_STATE = AppConstant.TEXTURE_PLAY_STATE;\n        }\n    }\n\n    /**\n     * 移动焦点图标\n     *\n     * @param x x坐标\n     * @param y y坐标\n     */\n    private void moveFouces(int x, int y) {\n        videoFouces.setVisibility(View.VISIBLE);\n        RelativeLayout.LayoutParams layoutParams\n                = (RelativeLayout.LayoutParams) videoFouces.getLayoutParams();\n        videoFouces.setLayoutParams(layoutParams);\n        mFoucesAnimation.setDuration(500);\n        mFoucesAnimation.setRepeatCount(0);\n        mFoucesAnimation.setOldMargin(x, y);\n        videoFouces.startAnimation(mFoucesAnimation);\n        cameraHelper.requestFocus(x, y);\n    }\n\n    @Override\n    protected void onResume() {\n        super.onResume();\n        if (cameraHelper != null) {\n            cameraHelper.startBackgroundThread();\n        }\n\n        if (videoTexture.isAvailable()) {\n            if (MODE == AppConstant.CAMERA_MODE) {\n                if (TEXTURE_STATE == AppConstant.TEXTURE_PREVIEW_STATE) {\n                    //预览状态\n                    initCamera(mNowCameraType);\n                } else if (TEXTURE_STATE == AppConstant.TEXTURE_PLAY_STATE) {\n                    //视频播放状态\n                    mVideoPlayer.play();\n                }\n                mVideoPlayer.setVideoPlayWindow(new Surface(videoTexture.getSurfaceTexture()));\n            }\n        } else {\n            videoTexture.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {\n                @Override\n                public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {\n                    if (MODE == AppConstant.CAMERA_MODE) {\n                        if (TEXTURE_STATE == AppConstant.TEXTURE_PREVIEW_STATE) {\n                            //预览状态\n                            initCamera(mNowCameraType);\n                        } else if (TEXTURE_STATE == AppConstant.TEXTURE_PLAY_STATE) {\n                            //视频播放状态\n                            mVideoPlayer.play();\n                        }\n                        mVideoPlayer.setVideoPlayWindow(new Surface(videoTexture.getSurfaceTexture()));\n                    } else if (MODE == AppConstant.VIDEO_MODE) {\n                        mVideoPlayer.setVideoPlayWindow(new Surface(videoTexture.getSurfaceTexture()));\n                        Log.e(\"videoPath\", \"path:\" + mVideoPath);\n                        mVideoPlayer.setDataSourceAndPlay(mVideoPath);\n                        hasPlaying = true;\n                        //视频播放状态\n                        TEXTURE_STATE = AppConstant.TEXTURE_PLAY_STATE;\n                    }\n                }\n\n                @Override\n                public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {\n                }\n\n                @Override\n                public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {\n                    return true;\n                }\n\n                @Override\n                public void onSurfaceTextureUpdated(SurfaceTexture surface) {\n\n                }\n            });\n        }\n    }\n\n    @Override\n    protected void onPause() {\n        super.onPause();\n        if (isNoPremissionPause) {\n            isNoPremissionPause = false;\n            return;\n        }\n        Log.e(\"camera\", \"mode:\" + MODE);\n        if (MODE == AppConstant.CAMERA_MODE) {\n            if (TEXTURE_STATE == AppConstant.TEXTURE_PREVIEW_STATE) {\n                cameraHelper.closeCamera();\n                cameraHelper.stopBackgroundThread();\n            } else if (TEXTURE_STATE == AppConstant.TEXTURE_PLAY_STATE) {\n                mVideoPlayer.pause();\n            }\n        }\n    }\n\n    /**\n     * 隐藏切换摄像头按钮\n     */\n    private void hindSwitchCamera() {\n        videoSwitchCamera.setVisibility(View.GONE);\n    }\n\n    /**\n     * 隐藏切换菜单\n     */\n    private void hindMenu() {\n        videoMenu.setVisibility(View.GONE);\n    }\n\n    /**\n     * 刷新相册\n     *\n     * @param mediaFile 文件\n     */\n    private void saveMedia(File mediaFile) {\n        Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);\n        Uri uri = Uri.fromFile(mediaFile);\n        intent.setData(uri);\n        sendBroadcast(intent);\n    }\n\n    /**\n     * 隐藏录像完成后底部两个按钮\n     */\n    private void hindRecordEndView() {\n        videoSave.setVisibility(View.GONE);\n        videoDelete.setVisibility(View.GONE);\n    }\n\n    /**\n     * 隐藏播放界面的控件出来\n     */\n    private void hindPlayView() {\n        videoSeekBar.setVisibility(View.GONE);\n        videoMinePlay.setVisibility(View.GONE);\n        videoPlay.setVisibility(View.GONE);\n        videoSeekTime.setVisibility(View.GONE);\n    }\n\n    /**\n     * 显示播放界面的控件出来\n     */\n    private void showPlayView() {\n        videoSeekBar.setVisibility(View.VISIBLE);\n        videoMinePlay.setVisibility(View.VISIBLE);\n        videoPlay.setVisibility(View.VISIBLE);\n        videoSeekTime.setVisibility(View.VISIBLE);\n    }\n\n    /**\n     * 显示和隐藏控件\n     *\n     * @param showWhat\n     * @param showOrNot\n     */\n    private void showLayout(int showWhat, boolean showOrNot) {\n        View v = mLayoutList.get(showWhat);\n        if (showOrNot) {\n            //全部隐藏但是AF/AE的显示出来\n            for (int i = 0; i < mLayoutBottom.getChildCount(); i++) {\n                if (mLayoutBottom.getChildAt(i).getVisibility() == View.VISIBLE) {\n                    mLayoutBottom.getChildAt(i).setVisibility(View.GONE);\n                }\n            }\n            v.startAnimation(mShowAction);\n            v.setVisibility(View.VISIBLE);\n        } else {\n            //全部隐藏但是capture的显示出来\n            for (int i = 0; i < mLayoutBottom.getChildCount(); i++) {\n                if (mLayoutBottom.getChildAt(i).getVisibility() == View.VISIBLE) {\n                    mLayoutBottom.getChildAt(i).setVisibility(View.GONE);\n                }\n            }\n            rlCamera.startAnimation(mShowAction);\n            rlCamera.setVisibility(View.VISIBLE);\n        }\n    }\n\n    /**\n     * rv点击事件 初始化\n     */\n    private void initListener() {\n        sAdapter.setSenseOnItemClickListener(new SenseAdapter.SenseOnItemClickListener() {\n            @Override\n            public void itemOnClick(int position) {\n                cameraHelper.setCameraBuilerMode(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_USE_SCENE_MODE);\n                switch (position) {\n                    case 0:\n                        cameraHelper.setCameraBuilerMode(CaptureRequest.CONTROL_SCENE_MODE, CameraMetadata.CONTROL_SCENE_MODE_DISABLED);\n                        break;\n                    case 1:\n                        cameraHelper.setCameraBuilerMode(CaptureRequest.CONTROL_SCENE_MODE, CameraMetadata.CONTROL_SCENE_MODE_FACE_PRIORITY);\n                        break;\n                    case 2:\n                        cameraHelper.setCameraBuilerMode(CaptureRequest.CONTROL_SCENE_MODE, CameraMetadata.CONTROL_SCENE_MODE_ACTION);\n                        break;\n                    case 3:\n                        cameraHelper.setCameraBuilerMode(CaptureRequest.CONTROL_SCENE_MODE, CameraMetadata.CONTROL_SCENE_MODE_PORTRAIT);\n                        break;\n                    case 4:\n                        cameraHelper.setCameraBuilerMode(CaptureRequest.CONTROL_SCENE_MODE, CameraMetadata.CONTROL_SCENE_MODE_LANDSCAPE);\n                        break;\n                    case 5:\n                        cameraHelper.setCameraBuilerMode(CaptureRequest.CONTROL_SCENE_MODE, CameraMetadata.CONTROL_SCENE_MODE_NIGHT);\n                        break;\n                    case 6:\n                        cameraHelper.setCameraBuilerMode(CaptureRequest.CONTROL_SCENE_MODE, CameraMetadata.CONTROL_SCENE_MODE_NIGHT_PORTRAIT);\n                        break;\n                    case 7:\n                        cameraHelper.setCameraBuilerMode(CaptureRequest.CONTROL_SCENE_MODE, CameraMetadata.CONTROL_SCENE_MODE_THEATRE);\n                        break;\n                    case 8:\n                        cameraHelper.setCameraBuilerMode(CaptureRequest.CONTROL_SCENE_MODE, CameraMetadata.CONTROL_SCENE_MODE_BEACH);\n                        break;\n                    case 9:\n                        cameraHelper.setCameraBuilerMode(CaptureRequest.CONTROL_SCENE_MODE, CameraMetadata.CONTROL_SCENE_MODE_SNOW);\n                        break;\n                    case 10:\n                        cameraHelper.setCameraBuilerMode(CaptureRequest.CONTROL_SCENE_MODE, CameraMetadata.CONTROL_SCENE_MODE_SUNSET);\n                        break;\n                    case 11:\n                        cameraHelper.setCameraBuilerMode(CaptureRequest.CONTROL_SCENE_MODE, CameraMetadata.CONTROL_SCENE_MODE_STEADYPHOTO);\n                        break;\n                    case 12:\n                        cameraHelper.setCameraBuilerMode(CaptureRequest.CONTROL_SCENE_MODE, CameraMetadata.CONTROL_SCENE_MODE_FIREWORKS);\n                        break;\n                    case 13:\n                        cameraHelper.setCameraBuilerMode(CaptureRequest.CONTROL_SCENE_MODE, CameraMetadata.CONTROL_SCENE_MODE_SPORTS);\n                        break;\n                    case 14:\n                        cameraHelper.setCameraBuilerMode(CaptureRequest.CONTROL_SCENE_MODE, CameraMetadata.CONTROL_SCENE_MODE_PARTY);\n                        break;\n                    case 15:\n                        cameraHelper.setCameraBuilerMode(CaptureRequest.CONTROL_SCENE_MODE, CameraMetadata.CONTROL_SCENE_MODE_CANDLELIGHT);\n                        break;\n                    case 16:\n                        cameraHelper.setCameraBuilerMode(CaptureRequest.CONTROL_SCENE_MODE, CameraMetadata.CONTROL_SCENE_MODE_BARCODE);\n                        break;\n                    default:\n                        break;\n                }\n            }\n        });\n\n        effectAdapter.setEffectOnItemClickListener(new EffectAdapter.EffectOnItemClickListener() {\n            @Override\n            public void itemOnClick(int position) {\n                switch (position) {\n                    case 0:\n                        cameraHelper.setCameraBuilerMode(CaptureRequest.CONTROL_EFFECT_MODE, CameraMetadata.CONTROL_EFFECT_MODE_AQUA);\n                        break;\n                    case 1:\n                        cameraHelper.setCameraBuilerMode(CaptureRequest.CONTROL_EFFECT_MODE, CameraMetadata.CONTROL_EFFECT_MODE_BLACKBOARD);\n                        break;\n                    case 2:\n                        cameraHelper.setCameraBuilerMode(CaptureRequest.CONTROL_EFFECT_MODE, CameraMetadata.CONTROL_EFFECT_MODE_MONO);\n                        break;\n                    case 3:\n                        cameraHelper.setCameraBuilerMode(CaptureRequest.CONTROL_EFFECT_MODE, CameraMetadata.CONTROL_EFFECT_MODE_NEGATIVE);\n                        break;\n                    case 4:\n                        cameraHelper.setCameraBuilerMode(CaptureRequest.CONTROL_EFFECT_MODE, CameraMetadata.CONTROL_EFFECT_MODE_POSTERIZE);\n                        break;\n                    case 5:\n                        cameraHelper.setCameraBuilerMode(CaptureRequest.CONTROL_EFFECT_MODE, CameraMetadata.CONTROL_EFFECT_MODE_SEPIA);\n                        break;\n                    case 6:\n                        cameraHelper.setCameraBuilerMode(CaptureRequest.CONTROL_EFFECT_MODE, CameraMetadata.CONTROL_EFFECT_MODE_SOLARIZE);\n                        break;\n                    case 7:\n                        cameraHelper.setCameraBuilerMode(CaptureRequest.CONTROL_EFFECT_MODE, CameraMetadata.CONTROL_EFFECT_MODE_WHITEBOARD);\n                        break;\n                    case 8:\n                        cameraHelper.setCameraBuilerMode(CaptureRequest.CONTROL_EFFECT_MODE, CameraMetadata.CONTROL_EFFECT_MODE_OFF);\n                        break;\n                    default:\n                        break;\n                }\n            }\n        });\n    }\n\n    /**\n     * 横向列表 touch事件 (拍照预览 缩放)\n     */\n    private class HorizontalViewTouchListener implements View.OnTouchListener {\n\n        private long mClickOn;\n        private float mLastX;\n        private float mLastY;\n\n        @Override\n        public boolean onTouch(View view, MotionEvent motionEvent) {\n            switch (motionEvent.getActionMasked()) {\n                case MotionEvent.ACTION_DOWN:\n                    if (motionEvent.getPointerCount() == 1) {\n                        mClickOn = System.currentTimeMillis();\n                        mLastX = motionEvent.getX();\n                        mLastY = motionEvent.getY();\n                    }\n                    break;\n                // 用户两指按下事件\n                case MotionEvent.ACTION_POINTER_DOWN:\n                    mCameraTouch.onScaleStart(motionEvent);\n                    return true;\n                case MotionEvent.ACTION_MOVE:\n                    if (motionEvent.getPointerCount() == 2) {\n                        mCameraTouch.onScale(motionEvent);\n                        return true;\n                    } else {\n                        float x = motionEvent.getX() - mLastX;\n                        float y = motionEvent.getY() - mLastY;\n                        if (Math.abs(x) >= 10 || Math.abs(y) >= 10) {\n                            mClickOn = 0;\n                        }\n                    }\n                    break;\n                case MotionEvent.ACTION_UP:\n                    if (motionEvent.getPointerCount() == 1) {\n                        if ((System.currentTimeMillis() - mClickOn) < 500) {\n                            moveFouces((int) motionEvent.getX(), (int) motionEvent.getY());\n                        }\n                    }\n                    break;\n                case MotionEvent.ACTION_POINTER_UP:\n                    mCameraTouch.onScaleEnd(motionEvent);\n                    return true;\n                default:\n                    break;\n            }\n            return false;\n        }\n    }\n\n    /**\n     * TextureView 触摸方法\n     */\n    private class CameraTouch {\n        private float mOldScale = 1.0f;\n        private float mScale;\n        private float mSpan = 0;\n        private float mOldSpan;\n        private float mFirstDistance = 0;\n\n        public void onScale(MotionEvent event) {\n            if (event.getPointerCount() == 2) {\n                if (mFirstDistance == 0) {\n                    mFirstDistance = distance(event);\n                }\n\n                float distance = distance(event);\n                float scale;\n                if (distance > mFirstDistance) {\n                    scale = (distance - mFirstDistance) / 80;\n                    scale = scale + mSpan;\n                    mOldSpan = scale;\n                    mScale = scale;\n                } else if (distance < mFirstDistance) {\n                    scale = distance / mFirstDistance;\n                    mOldSpan = scale;\n                    mScale = scale * mOldScale;\n                } else {\n                    return;\n                }\n\n                cameraHelper.cameraZoom(mScale);\n                videoScale.setProgress((int) ((mScale / cameraHelper.getMaxZoom()) * videoScale.getMax()));\n                if (mScale < 1.0f) {\n                    videoScale.setProgress(0);\n                }\n            }\n        }\n\n        /**\n         * scale 开始\n         *\n         * @param event\n         */\n        public void onScaleStart(MotionEvent event) {\n            mFirstDistance = 0;\n            setScaleMax((int) cameraHelper.getMaxZoom());\n            videoScaleBarLayout.setVisibility(View.VISIBLE);\n            removeSeekBarRunnable();\n        }\n\n        /**\n         * scale 结束\n         *\n         * @param event MotionEvent\n         */\n        private void onScaleEnd(MotionEvent event) {\n            if (mScale < 1.0f) {\n                mOldScale = 1.0f;\n            } else if (mScale > cameraHelper.getMaxZoom()) {\n                mOldScale = cameraHelper.getMaxZoom();\n            } else {\n                mOldScale = mScale;\n            }\n            mSpan = mOldSpan;\n\n            if (event != null) {\n                seekBarDelayedHind();\n            }\n        }\n\n        /**\n         * 重置 缩放\n         */\n        public void resetScale() {\n            mOldScale = 1.0f;\n            mSpan = 0f;\n            mFirstDistance = 0f;\n            videoScale.setProgress(0);\n        }\n\n        public void setScale(float scale) {\n            mScale = scale;\n            mOldSpan = scale;\n            onScaleEnd(null);\n        }\n\n        /**\n         * 计算两个手指间的距离\n         *\n         * @param event MotionEvent\n         * @return 距离\n         */\n        private float distance(MotionEvent event) {\n            float dx = event.getX(1) - event.getX(0);\n            float dy = event.getY(1) - event.getY(0);\n            // 使用勾股定理返回两点之间的距离\n            return (float) Math.sqrt(dx * dx + dy * dy);\n        }\n\n        private void setScaleMax(int max) {\n            videoScale.setMax(max * 100);\n        }\n    }\n\n    /**\n     * camera 点击对焦动画\n     */\n    private class FoucesAnimation extends Animation {\n\n        private int width = cameraHelper.dip2px(CameraVideoActivity.this, 150);\n        private int W = cameraHelper.dip2px(CameraVideoActivity.this, 65);\n\n        private int oldMarginLeft;\n        private int oldMarginTop;\n\n        @Override\n        protected void applyTransformation(float interpolatedTime, Transformation t) {\n\n            RelativeLayout.LayoutParams layoutParams =\n                    (RelativeLayout.LayoutParams) videoFouces.getLayoutParams();\n            int w = (int) (width * (1 - interpolatedTime));\n            if (w < W) {\n                w = W;\n            }\n            layoutParams.width = w;\n            layoutParams.height = w;\n            if (w == W) {\n                videoFouces.setLayoutParams(layoutParams);\n                return;\n            }\n            layoutParams.leftMargin = oldMarginLeft - (w / 2);\n            layoutParams.topMargin = oldMarginTop + (w / 8);\n            videoFouces.setLayoutParams(layoutParams);\n        }\n\n        public void setOldMargin(int oldMarginLeft, int oldMarginTop) {\n            this.oldMarginLeft = oldMarginLeft;\n            this.oldMarginTop = oldMarginTop;\n            removeImageFoucesRunnable();\n            imageFoucesDelayedHind();\n        }\n    }\n\n    /**\n     * 曝光 ae 滑动监听事件\n     */\n    private class CameraSeekBarListener implements SeekBar.OnSeekBarChangeListener {\n\n        @Override\n        public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {\n            switch (seekBar.getId()){\n                case R.id.sb_ae: {\n                    if (switchAe.isChecked()) {\n                        // 曝光增益\n                        if (cameraHelper.getRange1() == null) {\n                            break;\n                        }\n                        Log.e(TAG, \"曝光增益范围：\" + cameraHelper.getRange1().toString());\n                        int maxmax = cameraHelper.getRange1().getUpper();\n                        int minmin = cameraHelper.getRange1().getLower();\n                        int all = maxmax - minmin;\n                        int time = 100 / all;\n                        int ae = ((progress / time) - maxmax) > maxmax ? maxmax :\n                                ((progress / time) - maxmax) < minmin ? minmin : ((progress / time) - maxmax);\n                        cameraHelper.setAERegions(ae);\n                        tvSbTxt.setText(\"曝光增益：\" + ae);\n                    } else {\n                        // 曝光时间\n                        if (cameraHelper.getEtr() == null) {\n                            tvSbTxt.setText(\"获取曝光时间失败\");\n                            break;\n                        }\n                        Log.e(TAG, \"曝光时间范围：\" + cameraHelper.getEtr().toString());\n                        long max = cameraHelper.getEtr().getUpper();\n                        long min = cameraHelper.getEtr().getLower();\n                        long ae = ((progress * (max - min)) / 100 + min);\n                        cameraHelper.setAeTime(ae);\n                        tvSbTxt.setText(\"曝光时间：\" + ae);\n                    }\n                    break;\n                }\n            }\n        }\n\n        @Override\n        public void onStartTrackingTouch(SeekBar seekBar) {\n            tvSbTxt.setVisibility(View.VISIBLE);\n            tvSbTxt.startAnimation(mAlphaInAnimation);\n        }\n\n        @Override\n        public void onStopTrackingTouch(SeekBar seekBar) {\n            tvSbTxt.startAnimation(mAlphaOutAnimation);\n            tvSbTxt.setVisibility(View.INVISIBLE);\n        }\n    }\n\n    /**\n     * 手动白平衡 滑动监听事件\n     */\n    private class awbSettingSeekBarListener implements SeekBar.OnSeekBarChangeListener {\n\n        @Override\n        public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {\n\n            cameraHelper.setCameraBuilerMode(CaptureRequest.CONTROL_AWB_MODE, CaptureRequest.CONTROL_AWB_MODE_OFF);\n            cameraHelper.setCameraBuilerMode(CaptureRequest.COLOR_CORRECTION_MODE, CaptureRequest.COLOR_CORRECTION_MODE_TRANSFORM_MATRIX);\n            // 小米华为 没有的权限\n            cameraHelper.setCameraBuilerMode(CaptureRequest.COLOR_CORRECTION_GAINS, colorTemperature(progress+2000));\n\n        }\n\n        @Override\n        public void onStartTrackingTouch(SeekBar seekBar) {\n\n        }\n\n        @Override\n        public void onStopTrackingTouch(SeekBar seekBar) {\n\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/camera/cn/cameramaster/ui/GoogleCameraActivity.java",
    "content": "package camera.cn.cameramaster.ui;\n\nimport android.Manifest;\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.PackageManager;\nimport android.content.res.Configuration;\nimport android.graphics.ImageFormat;\nimport android.graphics.Matrix;\nimport android.graphics.Point;\nimport android.graphics.Rect;\nimport android.graphics.RectF;\nimport android.graphics.SurfaceTexture;\nimport android.hardware.camera2.CameraAccessException;\nimport android.hardware.camera2.CameraCaptureSession;\nimport android.hardware.camera2.CameraCharacteristics;\nimport android.hardware.camera2.CameraDevice;\nimport android.hardware.camera2.CameraManager;\nimport android.hardware.camera2.CameraMetadata;\nimport android.hardware.camera2.CaptureRequest;\nimport android.hardware.camera2.CaptureResult;\nimport android.hardware.camera2.TotalCaptureResult;\nimport android.hardware.camera2.params.StreamConfigurationMap;\nimport android.media.Image;\nimport android.media.ImageReader;\nimport android.media.MediaRecorder;\nimport android.net.Uri;\nimport android.os.Build;\nimport android.os.Handler;\nimport android.os.HandlerThread;\nimport android.provider.MediaStore;\nimport android.support.annotation.NonNull;\nimport android.support.annotation.RequiresApi;\nimport android.support.v4.content.ContextCompat;\nimport android.support.v7.widget.LinearLayoutManager;\nimport android.support.v7.widget.RecyclerView;\nimport android.text.TextUtils;\nimport android.util.Log;\nimport android.util.Range;\nimport android.util.Size;\nimport android.util.SparseIntArray;\nimport android.view.Surface;\nimport android.view.TextureView;\nimport android.view.View;\nimport android.view.animation.AlphaAnimation;\nimport android.view.animation.Animation;\nimport android.view.animation.ScaleAnimation;\nimport android.view.animation.TranslateAnimation;\nimport android.widget.CompoundButton;\nimport android.widget.ImageView;\nimport android.widget.LinearLayout;\nimport android.widget.RelativeLayout;\nimport android.widget.SeekBar;\nimport android.widget.Switch;\nimport android.widget.TextView;\nimport android.widget.Toast;\n\nimport com.yanzhenjie.loading.dialog.LoadingDialog;\n\nimport org.greenrobot.eventbus.EventBus;\nimport org.greenrobot.eventbus.Subscribe;\n\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.concurrent.Semaphore;\nimport java.util.concurrent.TimeUnit;\n\nimport butterknife.BindView;\nimport butterknife.OnCheckedChanged;\nimport butterknife.OnClick;\nimport camera.cn.cameramaster.R;\nimport camera.cn.cameramaster.adapter.EffectAdapter;\nimport camera.cn.cameramaster.adapter.SenseAdapter;\nimport camera.cn.cameramaster.base.BaseActivity;\nimport camera.cn.cameramaster.server.AnyEventType;\nimport camera.cn.cameramaster.view.AwbSeekBarChangeListener;\nimport camera.cn.cameramaster.server.ServerManager;\nimport camera.cn.cameramaster.util.AppConstant;\nimport camera.cn.cameramaster.util.CompareSizesByArea;\nimport camera.cn.cameramaster.util.Utils;\nimport camera.cn.cameramaster.view.AutoTextureView;\nimport camera.cn.cameramaster.view.ShowSurfaceView;\nimport camera.cn.cameramaster.view.AnimationTextView;\nimport camera.cn.cameramaster.view.AwbSeekBar;\n\nimport static android.provider.MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO;\nimport static camera.cn.cameramaster.util.AppConstant.SHOW_AE;\nimport static camera.cn.cameramaster.util.AppConstant.SHOW_AWB;\nimport static camera.cn.cameramaster.util.AppConstant.SHOW_EFFECT;\nimport static camera.cn.cameramaster.util.AppConstant.SHOW_ISO;\nimport static camera.cn.cameramaster.util.AppConstant.SHOW_SENSE;\nimport static camera.cn.cameramaster.util.AppConstant.SHOW_ZOOM;\n\n/**\n * google 拍照 demo\n *\n * @author ymc\n * @date 2019年1月28日 17:32:45\n * @url https://github.com/googlesamples/android-Camera2Basic\n */\n@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)\npublic class GoogleCameraActivity extends BaseActivity {\n    private static final String TAG = \"GoogleCameraActivity\";\n    /**\n     * 这里为了测试 相机将画布设置为 1像素，如果 想要看原版效果，\n     * 则隐藏 ShowSurfaceView ，将AutoFitTextureView设置充满\n     */\n    @BindView(R.id.textureView_g)\n    AutoTextureView mTextureView;\n    @BindView(R.id.surfaceView2)\n    ShowSurfaceView svShow;\n    /**\n     * 闪光灯\n     */\n    @BindView(R.id.iv_flash)\n    ImageView ivFlash;\n    /**\n     * 曝光\n     */\n    @BindView(R.id.iv_ae)\n    ImageView ivAW;\n    /**\n     * 白平衡\n     */\n    @BindView(R.id.iv_awb)\n    ImageView ivAWB;\n    /**\n     * 光感度\n     */\n    @BindView(R.id.iv_iso)\n    ImageView ivISO;\n    /**\n     * 放大倍数\n     */\n    @BindView(R.id.iv_zoom)\n    ImageView ivZoom;\n    /**\n     * 影响\n     */\n    @BindView(R.id.iv_effect)\n    ImageView ivEffect;\n    /**\n     * 感应\n     */\n    @BindView(R.id.iv_sense)\n    ImageView ivSense;\n    /**\n     * 底部切换布局\n     */\n    @BindView(R.id.layout_bottom)\n    RelativeLayout mLayoutBottom;\n    /**\n     * 拍照布局\n     */\n    @BindView(R.id.homecamera_bottom_relative2)\n    RelativeLayout mLayoutCapture;\n    @BindView(R.id.img_camera_g)\n    ImageView ivCamereVideo;\n    @BindView(R.id.switch_ae)\n    Switch switchAe;\n    @BindView(R.id.sb_ae)\n    SeekBar sbAe;\n    @BindView(R.id.layout_ae)\n    LinearLayout layoutAe;\n    @BindView(R.id.sb_zoom)\n    SeekBar sbZoom;\n    @BindView(R.id.layout_zoom)\n    LinearLayout layoutZoom;\n    @BindView(R.id.sb_awb)\n    AwbSeekBar sbAwb;\n    @BindView(R.id.layout_awb)\n    LinearLayout layoutAwb;\n    @BindView(R.id.switch_iso)\n    Switch switchIso;\n    @BindView(R.id.sb_iso)\n    SeekBar sbIso;\n    @BindView(R.id.layout_iso)\n    LinearLayout layoutIso;\n    @BindView(R.id.txt_window_txt)\n    AnimationTextView txtWindowTxt;\n    @BindView(R.id.txt_sb_txt)\n    TextView tvSbTxt;\n    @BindView(R.id.layout_effect)\n    LinearLayout llEffect;\n    @BindView(R.id.rv_effect_list)\n    RecyclerView evEffectList;\n    @BindView(R.id.layout_sense)\n    LinearLayout llSense;\n    @BindView(R.id.rv_sense_list)\n    RecyclerView evSenseList;\n\n    /**\n     * visible与invisible之间切换的动画\n     */\n    private TranslateAnimation mShowAction;\n\n    /**\n     * Conversion from screen rotation to JPEG orientation.\n     */\n    private static final SparseIntArray ORIENTATIONS = new SparseIntArray();\n    private static final int REQUEST_CAMERA_PERMISSION = 1;\n    /**\n     * 相机预览状态\n     */\n    private static final int STATE_PREVIEW = 0;\n    /**\n     * 等待相机锁定\n     */\n    private static final int STATE_WAITING_LOCK = 1;\n    /**\n     * 相机状态：等待曝光处于预捕获状态。\n     */\n    private static final int STATE_WAITING_PRECAPTURE = 2;\n    /**\n     * 相机状态：等待曝光状态不是预捕获。\n     */\n    private static final int STATE_WAITING_NON_PRECAPTURE = 3;\n    /**\n     * 相机状态：已拍摄照片。\n     */\n    private static final int STATE_PICTURE_TAKEN = 4;\n    /**\n     * Camera2 API保证的最大预览宽度\n     */\n    private static final int MAX_PREVIEW_WIDTH = 1920;\n    /**\n     * Camera2 API保证的最大预览高度\n     */\n    private static final int MAX_PREVIEW_HEIGHT = 1280;\n    /**\n     * 当前拍照id\n     */\n    private String mCameraId;\n    /**\n     * 相机预览\n     */\n    private CameraCaptureSession mCaptureSession;\n    private CameraDevice mCameraDevice;\n    /**\n     * 预览\n     */\n    private Size mPreviewSize;\n    /**\n     * 相机预览\n     */\n    private CaptureRequest.Builder mPreviewRequestBuilder;\n    private CaptureRequest mPreviewRequest;\n    /**\n     * 视频对象\n     */\n    private MediaRecorder mMediaRecorder;\n    /**\n     * 当前相机状态.\n     */\n    private int mState = STATE_PREVIEW;\n\n    /**\n     * 在关闭相机之前阻止应用程序退出\n     */\n    private Semaphore mCameraOpenCloseLock = new Semaphore(1);\n\n    /**\n     * 当前相机设备是否支持Flash\n     */\n    private boolean mFlashSupported;\n\n    /**\n     * 相机传感器的方向\n     */\n    private int mSensorOrientation;\n\n    private HandlerThread mBackgroundThread;\n\n    private Handler mBackgroundHandler;\n\n    private ImageReader mImageReader;\n\n    private File mFile;\n\n    private File mVideoPath;\n\n    /**\n     * true ： 正在录制  /  false ：反之\n     */\n    private boolean hasVideoOn = false;\n\n    /**\n     * 闪光灯类型 0 ：关闭   1： 打开   2：自动\n     */\n    private int flishType = 0;\n\n    /**\n     * 是否显示底部 布局的按钮\n     */\n    private boolean showAeFlag = false;\n    /**\n     * 底部 布局集合\n     */\n    private List<View> mLayoutList = new LinkedList<>();\n    /**\n     * 文字动画\n     */\n    private ScaleAnimation mScaleWindowAnimation;\n    /**\n     * 淡入动画\n     */\n    private AlphaAnimation mAlphaInAnimation;\n    /**\n     * 淡出动画\n     */\n    private AlphaAnimation mAlphaOutAnimation;\n\n    static {\n        ORIENTATIONS.append(Surface.ROTATION_0, 90);\n        ORIENTATIONS.append(Surface.ROTATION_90, 0);\n        ORIENTATIONS.append(Surface.ROTATION_180, 270);\n        ORIENTATIONS.append(Surface.ROTATION_270, 180);\n    }\n\n    /**\n     * 加载动画\n     */\n    private LoadingDialog mDialog;\n\n    /**\n     * url\n     */\n    private String mRootUrl;\n\n    /**\n     * 服务管理器\n     */\n    private ServerManager mServerManager;\n    /**\n     * 是否显示Awb的按钮\n     */\n    private boolean showAwbFlag = false;\n    /**\n     * 是否显示 iso 的按钮\n     */\n    private boolean showIsoFlag = false;\n    /**\n     * 是否显示 effect 的按钮\n     */\n    private boolean showEffectFlag = false;\n    /**\n     * 是否显示 iso 的按钮\n     */\n    private boolean showSenseFlag = false;\n    /**\n     * 相机配置\n     */\n    private CameraCharacteristics characteristics;\n    /**\n     * 相机 曝光 范围\n     */\n    private Range<Integer> range1;\n    /**\n     * 曝光时间\n     */\n    private Range<Long> etr;\n    /**\n     * 相机 iso 范围\n     */\n    private Range<Integer> isoRange;\n    /**\n     * zoom 是否显示标识\n     */\n    private boolean showZoomFlag = false;\n    /**\n     * 相机 管理类\n     */\n    private CameraManager manager;\n\n    private SenseAdapter sAdapter;\n    private EffectAdapter effectAdapter;\n    /**\n     * 图片保存名称\n     */\n    private String fileName;\n    /**\n     * 静态大小\n     */\n    private Size largest;\n    private Surface surface;\n    /**\n     * 是否正在录制中\n     */\n    private boolean isRecording = false;\n\n    @Override\n    protected int getLayoutId() {\n        return R.layout.activity_google_camera;\n    }\n\n    @SuppressLint(\"ClickableViewAccessibility\")\n    @Override\n    protected void initView() {\n        mShowAction = new TranslateAnimation(Animation.RELATIVE_TO_SELF,\n                0.0f, Animation.RELATIVE_TO_SELF, 0.0f,\n                Animation.RELATIVE_TO_SELF, -1.0f,\n                Animation.RELATIVE_TO_SELF, 0.0f);\n        mShowAction.setDuration(300);\n\n        mScaleWindowAnimation = new ScaleAnimation(2.0f, 1.0f, 2.0f,\n                1.0f, Animation.RELATIVE_TO_SELF, 0.5f,\n                Animation.RELATIVE_TO_SELF, 0.5f);\n        mScaleWindowAnimation.setDuration(300);\n\n        mAlphaInAnimation = new AlphaAnimation(0.0f, 1.0f);\n        mAlphaInAnimation.setDuration(500);\n        mAlphaOutAnimation = new AlphaAnimation(1.0f, 0.0f);\n        mAlphaOutAnimation.setDuration(500);\n        mMediaRecorder = new MediaRecorder();\n        txtWindowTxt.setmAnimation(mScaleWindowAnimation);\n        sbAe.setOnSeekBarChangeListener(new CameraSeekBarListener());\n        sbZoom.setOnSeekBarChangeListener(new CameraSeekBarListener());\n        sbIso.setOnSeekBarChangeListener(new CameraSeekBarListener());\n\n        LinearLayoutManager ms = new LinearLayoutManager(this);\n        ms.setOrientation(LinearLayoutManager.HORIZONTAL);\n        LinearLayoutManager ms1 = new LinearLayoutManager(this);\n        ms1.setOrientation(LinearLayoutManager.HORIZONTAL);\n        evSenseList.setLayoutManager(ms);\n        evEffectList.setLayoutManager(ms1);\n        sAdapter = new SenseAdapter(this, AppConstant.senseArr);\n        effectAdapter = new EffectAdapter(this,AppConstant.effectArr);\n        evSenseList.setAdapter(sAdapter);\n        evEffectList.setAdapter(effectAdapter);\n        //注册 eventbus\n        EventBus.getDefault().register(this);\n    }\n\n    @Subscribe\n    public void onEvent(AnyEventType event) {\n        lockFocus();\n    }\n\n    @Override\n    protected void initData() {\n\n        fileName = System.currentTimeMillis() + \".jpg\";\n        mFile = new File(getExternalFilesDir(null), fileName);\n        // 将底部布局 依次添加到 列表中\n        mLayoutList.clear();\n        mLayoutList.add(mLayoutBottom);\n        mLayoutList.add(layoutAe);\n        mLayoutList.add(layoutAwb);\n        mLayoutList.add(layoutIso);\n        mLayoutList.add(layoutZoom);\n        mLayoutList.add(llEffect);\n        mLayoutList.add(llSense);\n\n        // AndServer run in the service.\n        mServerManager = new ServerManager(this);\n        mServerManager.register();\n        mServerManager.startServer();\n    }\n\n\n    @RequiresApi(api = Build.VERSION_CODES.M)\n    @Override\n    public void onResume() {\n        super.onResume();\n        startBackgroundThread();\n        // 存在关联则打开相机，没有则绑定事件\n        if (mTextureView.isAvailable()) {\n            openCamera(mTextureView.getWidth(), mTextureView.getHeight());\n        } else {\n            mTextureView.setSurfaceTextureListener(mSurfaceTextureListener);\n        }\n    }\n\n\n    /**\n     * SurfaceTextureListener  监听事件\n     */\n    private final TextureView.SurfaceTextureListener mSurfaceTextureListener\n            = new TextureView.SurfaceTextureListener() {\n\n        @RequiresApi(api = Build.VERSION_CODES.M)\n        @Override\n        public void onSurfaceTextureAvailable(SurfaceTexture texture, int width, int height) {\n            openCamera(width, height);\n        }\n\n        @Override\n        public void onSurfaceTextureSizeChanged(SurfaceTexture texture, int width, int height) {\n            configureTransform(width, height);\n        }\n\n        @Override\n        public boolean onSurfaceTextureDestroyed(SurfaceTexture texture) {\n            return true;\n        }\n\n        @Override\n        public void onSurfaceTextureUpdated(SurfaceTexture texture) {\n        }\n    };\n\n    /**\n     * CameraDevice 改变状态时候 调用\n     */\n    private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {\n\n        @Override\n        public void onOpened(@NonNull CameraDevice cameraDevice) {\n            //打开相机时会调用此方法。 我们在这里开始相机预览。\n            mCameraOpenCloseLock.release();\n            mCameraDevice = cameraDevice;\n            createCameraPreviewSession();\n        }\n\n        @Override\n        public void onDisconnected(@NonNull CameraDevice cameraDevice) {\n            mCameraOpenCloseLock.release();\n            cameraDevice.close();\n            mCameraDevice = null;\n        }\n\n        @Override\n        public void onError(@NonNull CameraDevice cameraDevice, int error) {\n            mCameraOpenCloseLock.release();\n            cameraDevice.close();\n            mCameraDevice = null;\n            finish();\n        }\n\n    };\n\n    /**\n     * ImageReader 的回调对象。 静止图像已准备好保存。\n     */\n    private final ImageReader.OnImageAvailableListener mOnImageAvailableListener\n            = new ImageReader.OnImageAvailableListener() {\n        @Override\n        public void onImageAvailable(ImageReader reader) {\n            Image mImage = reader.acquireNextImage();\n            ByteBuffer buffer = mImage.getPlanes()[0].getBuffer();\n            byte[] bytes = new byte[buffer.remaining()];\n            buffer.get(bytes);\n            FileOutputStream output = null;\n            try {\n                output = new FileOutputStream(mFile);\n                output.write(bytes);\n            } catch (IOException e) {\n                e.printStackTrace();\n            } finally {\n                mImage.close();\n                if (null != output) {\n                    try {\n                        output.close();\n                    } catch (IOException e) {\n                        e.printStackTrace();\n                    }\n                }\n            }\n            // 其次把文件插入到系统图库\n            try {\n                MediaStore.Images.Media.insertImage(getContentResolver(),\n                        mFile.getAbsolutePath(), fileName, null);\n            } catch (FileNotFoundException e) {\n                e.printStackTrace();\n            }\n            // 最后通知图库更新\n            sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse(mFile.getPath())));\n            Toast.makeText(GoogleCameraActivity.this, \"保存成功\", Toast.LENGTH_SHORT).show();\n//            mBackgroundHandler.post(new ImageSaver(reader.acquireNextImage(), mFile));\n//            Image image = reader.acquireLatestImage();\n//            if (image != null) {\n//                int imageWidth = image.getWidth();\n//                int imageHeight = image.getHeight();\n//                byte[] data68 = Camera2Util.getBytesFromImageAsType(image, 2);\n//                int rgb[] = Camera2Util.decodeYUV420SP(data68, imageWidth, imageHeight);\n//                Bitmap bitmap2 = Bitmap.createBitmap(rgb, 0, imageWidth,\n//                        imageWidth, imageHeight, Bitmap.Config.ARGB_8888);\n//                Bitmap d65bitmap = BitmapUtils.rotateMyBitmap(BitmapUtils.ImgaeToNegative(bitmap2));\n//                svShow.setBitmap(d65bitmap);\n//                image.close();\n//            }\n//            setResult(AppConstant.RESULT_CODE.RESULT_OK);\n//            finish();\n        }\n    };\n\n    /**\n     * 处理与jpg文件捕捉的事件监听(预览)\n     */\n    private CameraCaptureSession.CaptureCallback mCaptureCallback\n            = new CameraCaptureSession.CaptureCallback() {\n\n        private void process(CaptureResult result) {\n            switch (mState) {\n                case STATE_PREVIEW: {\n                    // 预览正常\n                    break;\n                }\n                case STATE_WAITING_LOCK: {\n                    Integer afState = result.get(CaptureResult.CONTROL_AF_STATE);\n                    if (afState == null) {\n                        captureStillPicture();\n                    } else if (CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED == afState ||\n                            CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED == afState) {\n                        Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);\n                        if (aeState == null ||\n                                aeState == CaptureResult.CONTROL_AE_STATE_CONVERGED) {\n                            mState = STATE_PICTURE_TAKEN;\n                            captureStillPicture();\n                        } else {\n                            runPrecaptureSequence();\n                        }\n                    }\n                    break;\n                }\n                case STATE_WAITING_PRECAPTURE: {\n                    Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);\n                    if (aeState == null ||\n                            aeState == CaptureResult.CONTROL_AE_STATE_PRECAPTURE ||\n                            aeState == CaptureRequest.CONTROL_AE_STATE_FLASH_REQUIRED) {\n                        mState = STATE_WAITING_NON_PRECAPTURE;\n                    }\n                    break;\n                }\n                case STATE_WAITING_NON_PRECAPTURE: {\n                    Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);\n                    if (aeState == null || aeState != CaptureResult.CONTROL_AE_STATE_PRECAPTURE) {\n                        mState = STATE_PICTURE_TAKEN;\n                        captureStillPicture();\n                    }\n                    break;\n                }\n                default:\n                    break;\n            }\n        }\n\n        @Override\n        public void onCaptureProgressed(@NonNull CameraCaptureSession session,\n                                        @NonNull CaptureRequest request,\n                                        @NonNull CaptureResult partialResult) {\n            process(partialResult);\n        }\n\n        @Override\n        public void onCaptureCompleted(@NonNull CameraCaptureSession session,\n                                       @NonNull CaptureRequest request,\n                                       @NonNull TotalCaptureResult result) {\n            process(result);\n        }\n\n    };\n\n    /**\n     * 给定摄像机支持的尺寸 否则选择最小的一个尺寸\n     *\n     * @param choices           相机支持预期输出的尺寸列表\n     * @param textureViewWidth  纹理视图相对于传感器坐标的宽度\n     * @param textureViewHeight 纹理视图相对于传感器坐标的高度\n     * @param maxWidth          最大宽度\n     * @param maxHeight         最大高度\n     * @param aspectRatio       纵横比\n     * @return size\n     */\n    private static Size chooseOptimalSize(Size[] choices, int textureViewWidth,\n                                          int textureViewHeight, int maxWidth, int maxHeight, Size aspectRatio) {\n\n        // 收集至少与预览Surface一样大的支持的分辨率\n        List<Size> bigEnough = new ArrayList<>();\n        // 收集小于预览Surface的支持的分辨率\n        List<Size> notBigEnough = new ArrayList<>();\n        int w = aspectRatio.getWidth();\n        int h = aspectRatio.getHeight();\n        for (Size option : choices) {\n            if (option.getWidth() <= maxWidth && option.getHeight() <= maxHeight &&\n                    option.getHeight() == option.getWidth() * h / w) {\n                if (option.getWidth() >= textureViewWidth &&\n                        option.getHeight() >= textureViewHeight) {\n                    bigEnough.add(option);\n                } else {\n                    notBigEnough.add(option);\n                }\n            }\n        }\n        // 挑选适合的尺寸\n        if (bigEnough.size() > 0) {\n            return Collections.min(bigEnough, new CompareSizesByArea());\n        } else if (notBigEnough.size() > 0) {\n            return Collections.max(notBigEnough, new CompareSizesByArea());\n        } else {\n            Log.e(TAG, \"Couldn't find any suitable preview size\");\n            return choices[0];\n        }\n    }\n\n    @Override\n    public void onPause() {\n        closeCamera();\n        stopBackgroundThread();\n        super.onPause();\n    }\n\n    /**\n     * 设置与摄像头相关的成员变量。\n     *\n     * @param width  摄像机预览的可用大小宽度\n     * @param height 相机预览的可用尺寸高度\n     */\n    @SuppressWarnings(\"SuspiciousNameCombination\")\n    private void setUpCameraOutputs(int width, int height) {\n        CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);\n        try {\n            for (String cameraId : manager.getCameraIdList()) {\n                characteristics = manager.getCameraCharacteristics(cameraId);\n                // 仅适用后置摄像头\n                Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING);\n                if (facing != null && facing == CameraCharacteristics.LENS_FACING_FRONT) {\n                    continue;\n                }\n                //得到相机支持的流配置(包括支持的图片分辨率等),不支持就返回\n                StreamConfigurationMap map = characteristics.get(\n                        CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);\n                if (map == null) {\n                    continue;\n                }\n                List<CaptureRequest.Key<?>> ss = characteristics.getAvailableCaptureRequestKeys();\n                Log.e(TAG, ss.toString());\n                // 曝光增益 范围\n                range1 = characteristics.get(CameraCharacteristics.CONTROL_AE_COMPENSATION_RANGE);\n                //获取支持的iso范围\n                isoRange = characteristics.get(CameraCharacteristics.SENSOR_INFO_SENSITIVITY_RANGE);\n                // 曝光时长\n                int[] avails = characteristics.get(CameraCharacteristics.CONTROL_AE_AVAILABLE_MODES);\n                // 白平衡\n                int[] aa = characteristics.get(CameraCharacteristics.CONTROL_AWB_AVAILABLE_MODES);\n                // 最大白平衡数\n                Integer maxAwb = characteristics.get(CameraCharacteristics.CONTROL_MAX_REGIONS_AWB);\n                //获取曝光时间\n                etr = characteristics.get(CameraCharacteristics.SENSOR_INFO_EXPOSURE_TIME_RANGE);\n\n\n\n\n                // 静态图像捕获，选择最大可用大小。\n                largest = Collections.max(\n                        Arrays.asList(map.getOutputSizes(ImageFormat.JPEG)),\n                        new CompareSizesByArea());\n                // w: 720  h :960\n//                Size largest = Collections.max(\n//                        Arrays.asList(map.getOutputSizes(ImageFormat.YUV_420_888)),\n//                        new CompareSizesByArea());\n//                mImageReader = ImageReader.newInstance(largest.getWidth(), largest.getHeight(),\n//                        ImageFormat.YUV_420_888, 2);\n                mImageReader = ImageReader.newInstance(largest.getWidth(), largest.getHeight(),\n                        ImageFormat.JPEG, 1);\n                mImageReader.setOnImageAvailableListener(\n                        mOnImageAvailableListener, mBackgroundHandler);\n\n                //了解我们是否需要交换尺寸以获得相对于传感器的预览尺寸\n                int displayRotation = getWindowManager().getDefaultDisplay().getRotation();\n                mSensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);\n                boolean swappedDimensions = false;\n                switch (displayRotation) {\n                    case Surface.ROTATION_0:\n                    case Surface.ROTATION_180:\n                        if (mSensorOrientation == 90 || mSensorOrientation == 270) {\n                            swappedDimensions = true;\n                        }\n                        break;\n                    case Surface.ROTATION_90:\n                    case Surface.ROTATION_270:\n                        if (mSensorOrientation == 0 || mSensorOrientation == 180) {\n                            swappedDimensions = true;\n                        }\n                        break;\n                    default:\n                        Log.e(TAG, \"Display rotation is invalid: \" + displayRotation);\n                }\n                Point displaySize = new Point();\n                activity.getWindowManager().getDefaultDisplay().getSize(displaySize);\n                int rotatedPreviewWidth = width;\n                int rotatedPreviewHeight = height;\n                int maxPreviewWidth = displaySize.x;\n                int maxPreviewHeight = displaySize.y;\n                //如果需要颠倒方向\n                if (swappedDimensions) {\n                    rotatedPreviewWidth = height;\n                    rotatedPreviewHeight = width;\n                    maxPreviewWidth = displaySize.y;\n                    maxPreviewHeight = displaySize.x;\n                }\n\n                if (maxPreviewWidth > MAX_PREVIEW_WIDTH) {\n                    maxPreviewWidth = MAX_PREVIEW_WIDTH;\n                }\n                if (maxPreviewHeight > MAX_PREVIEW_HEIGHT) {\n                    maxPreviewHeight = MAX_PREVIEW_HEIGHT;\n                }\n\n                mPreviewSize = chooseOptimalSize(map.getOutputSizes(SurfaceTexture.class),\n                        rotatedPreviewWidth, rotatedPreviewHeight, maxPreviewWidth,\n                        maxPreviewHeight, largest);\n\n                // 将TextureView的宽高比与我们选择的预览大小相匹配。\n                int orientation = getResources().getConfiguration().orientation;\n                if (orientation == Configuration.ORIENTATION_LANDSCAPE) {\n                    mTextureView.setAspectRatio(\n                            mPreviewSize.getWidth(), mPreviewSize.getHeight());\n                } else {\n                    mTextureView.setAspectRatio(\n                            mPreviewSize.getHeight(), mPreviewSize.getWidth());\n                }\n\n                // 检查 远光灯\n                Boolean available = characteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE);\n                mFlashSupported = available == null ? false : available;\n                mCameraId = cameraId;\n                return;\n            }\n        } catch (CameraAccessException e) {\n            e.printStackTrace();\n        } catch (NullPointerException ignored) {\n        }\n    }\n\n    /**\n     * 打开相机\n     *\n     * @param width  宽度\n     * @param height 长度\n     */\n    @RequiresApi(api = Build.VERSION_CODES.M)\n    private void openCamera(int width, int height) {\n        if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)\n                != PackageManager.PERMISSION_GRANTED) {\n            requestPermissions(new String[]{Manifest.permission.CAMERA}, REQUEST_CAMERA_PERMISSION);\n            return;\n        }\n        setUpCameraOutputs(width, height);\n        configureTransform(width, height);\n        manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);\n        try {\n            if (!mCameraOpenCloseLock.tryAcquire(2300, TimeUnit.MILLISECONDS)) {\n                throw new RuntimeException(\"Time out waiting to lock camera opening.\");\n            }\n            manager.openCamera(mCameraId, mStateCallback, mBackgroundHandler);\n        } catch (CameraAccessException e) {\n            e.printStackTrace();\n        } catch (InterruptedException e) {\n            throw new RuntimeException(\"Interrupted while trying to lock camera opening.\", e);\n        }\n    }\n\n    /**\n     * Closes the current {@link CameraDevice}.\n     */\n    private void closeCamera() {\n        try {\n            mCameraOpenCloseLock.acquire();\n            if (null != mCaptureSession) {\n                mCaptureSession.close();\n                mCaptureSession = null;\n            }\n            if (null != mCameraDevice) {\n                mCameraDevice.close();\n                mCameraDevice = null;\n            }\n            if (null != mImageReader) {\n                mImageReader.close();\n                mImageReader = null;\n            }\n        } catch (InterruptedException e) {\n            throw new RuntimeException(\"Interrupted while trying to lock camera closing.\", e);\n        } finally {\n            mCameraOpenCloseLock.release();\n        }\n    }\n\n    /**\n     * 打开 BackgroundThread\n     */\n    private void startBackgroundThread() {\n        mBackgroundThread = new HandlerThread(\"CameraBackground\");\n        mBackgroundThread.start();\n        mBackgroundHandler = new Handler(mBackgroundThread.getLooper());\n    }\n\n    /**\n     * 关闭 BackgroundThread\n     */\n    private void stopBackgroundThread() {\n        mBackgroundThread.quitSafely();\n        try {\n            mBackgroundThread.join();\n            mBackgroundThread = null;\n            mBackgroundHandler = null;\n        } catch (InterruptedException e) {\n            e.printStackTrace();\n        }\n    }\n\n    /**\n     * 创建一个新的相机预览\n     */\n    private void createCameraPreviewSession() {\n        try {\n            SurfaceTexture texture = mTextureView.getSurfaceTexture();\n            //将默认缓冲区的大小配置为相机预览的大小。\n            texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());\n            surface = new Surface(texture);\n            //使用Surface设置CaptureRequest.Builder\n            mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);\n            mPreviewRequestBuilder.addTarget(surface);\n            //添加这句话 可以在 mImageReader 监听回调中持续获取 预览图片\n//            mPreviewRequestBuilder.addTarget(mImageReader.getSurface());\n            mCameraDevice.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()),\n                    new CameraCaptureSession.StateCallback() {\n\n                        @Override\n                        public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {\n                            if (null == mCameraDevice) {\n                                return;\n                            }\n                            mCaptureSession = cameraCaptureSession;\n                            try {\n                                // 自动变焦是连续的\n                                mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,\n                                        CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);\n                                setAutoFlash(mPreviewRequestBuilder);\n                                //禁用所有自动设置\n//                                mPreviewRequestBuilder.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_OFF);\n                                //而 ISO 和 Exposure Time 与之相反，仅在 aeMode 关闭时才起作用\n                                //只是禁用自动曝光，白平衡继续开启,自己设置iso等值，必须禁用曝光\n                                mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_OFF);\n                                //设置曝光时间 ms单位\n//                                mPreviewRequestBuilder.set(CaptureRequest.SENSOR_EXPOSURE_TIME, 1000L);\n//                                mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_EXPOSURE_COMPENSATION, 1);\n                                // 设置 iso 灵敏度\n                                mPreviewRequestBuilder.set(CaptureRequest.SENSOR_SENSITIVITY, 800);\n//                                mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AWB_MODE, CaptureRequest.CONTROL_AWB_MODE_AUTO);\n                                //设置曝光补偿\n//                                mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_EXPOSURE_COMPENSATION, 10);\n                                // 设置帧 持续时长\n//                                mPreviewRequestBuilder.set(CaptureRequest.SENSOR_FRAME_DURATION, 1000L);\n                                mPreviewRequest = mPreviewRequestBuilder.build();\n                                mCaptureSession.setRepeatingRequest(mPreviewRequest,\n                                        mCaptureCallback, mBackgroundHandler);\n                                SetListener();\n                            } catch (CameraAccessException e) {\n                                e.printStackTrace();\n                            }\n                        }\n\n                        @Override\n                        public void onConfigureFailed(\n                                @NonNull CameraCaptureSession cameraCaptureSession) {\n                        }\n                    }, null\n            );\n        } catch (CameraAccessException e) {\n            e.printStackTrace();\n        }\n    }\n\n    /**\n     * Matrix 转换配置为 mTextureView\n     *\n     * @param viewWidth  mTextureView 宽度\n     * @param viewHeight mTextureView 高度\n     */\n    private void configureTransform(int viewWidth, int viewHeight) {\n        if (null == mTextureView || null == mPreviewSize) {\n            return;\n        }\n        int rotation = getWindowManager().getDefaultDisplay().getRotation();\n        Matrix matrix = new Matrix();\n        RectF viewRect = new RectF(0, 0, viewWidth, viewHeight);\n        RectF bufferRect = new RectF(0, 0, mPreviewSize.getHeight(), mPreviewSize.getWidth());\n        float centerX = viewRect.centerX();\n        float centerY = viewRect.centerY();\n        if (Surface.ROTATION_90 == rotation || Surface.ROTATION_270 == rotation) {\n            bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY());\n            matrix.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL);\n            float scale = Math.max(\n                    (float) viewHeight / mPreviewSize.getHeight(),\n                    (float) viewWidth / mPreviewSize.getWidth());\n            matrix.postScale(scale, scale, centerX, centerY);\n            matrix.postRotate(90 * (rotation - 2), centerX, centerY);\n        } else if (Surface.ROTATION_180 == rotation) {\n            matrix.postRotate(180, centerX, centerY);\n        }\n        mTextureView.setTransform(matrix);\n    }\n\n    /**\n     * 锁定焦点设置\n     */\n    public void lockFocus() {\n        try {\n            // 相机锁定的方法\n            mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,\n                    CameraMetadata.CONTROL_AF_TRIGGER_START);\n            // mCaptureCallback 等待锁定\n            mState = STATE_WAITING_LOCK;\n            mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback,\n                    mBackgroundHandler);\n        } catch (CameraAccessException e) {\n            e.printStackTrace();\n            Log.e(TAG, \"lockFocus: \" + e.getMessage());\n        }\n    }\n\n    /**\n     * 运行预捕获序列以捕获静止图像。 在调用此方法时调用\n     */\n    private void runPrecaptureSequence() {\n        try {\n            // 相机触发的方法\n            mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,\n                    CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START);\n            // mCaptureCallback等待设置预捕获序列。\n            mState = STATE_WAITING_PRECAPTURE;\n            mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback,\n                    mBackgroundHandler);\n        } catch (CameraAccessException e) {\n            e.printStackTrace();\n        }\n    }\n\n    /**\n     * 拍摄静止图片。 当我们得到响应时，应该调用此方法\n     */\n    private void captureStillPicture() {\n        try {\n            if (null == activity || null == mCameraDevice) {\n                return;\n            }\n            final CaptureRequest.Builder captureBuilder =\n                    mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);\n            captureBuilder.addTarget(mImageReader.getSurface());\n\n            // 使用与预览相同的AE和AF模式。\n            captureBuilder.set(CaptureRequest.CONTROL_AF_MODE,\n                    CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);\n            setAutoFlash(captureBuilder);\n\n            int rotation = getWindowManager().getDefaultDisplay().getRotation();\n            //对于方向为90的设备，我们只需从ORIENTATIONS返回我们的映射\n            //对于方向为270的设备，我们需要将JPEG旋转180度\n            captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, (ORIENTATIONS.get(rotation) + mSensorOrientation + 270) % 360);\n\n            CameraCaptureSession.CaptureCallback CaptureCallback\n                    = new CameraCaptureSession.CaptureCallback() {\n\n                @Override\n                public void onCaptureCompleted(@NonNull CameraCaptureSession session,\n                                               @NonNull CaptureRequest request,\n                                               @NonNull TotalCaptureResult result) {\n                    Log.e(TAG, mFile.toString());\n                    unlockFocus();\n                }\n            };\n\n            mCaptureSession.stopRepeating();\n            mCaptureSession.abortCaptures();\n            mCaptureSession.capture(captureBuilder.build(), CaptureCallback, mBackgroundHandler);\n        } catch (CameraAccessException e) {\n            e.printStackTrace();\n        }\n    }\n\n    /**\n     * 解锁焦点 在静止图像捕获序列时调用此方法\n     */\n    private void unlockFocus() {\n        try {\n            // Reset the auto-focus trigger\n            mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,\n                    CameraMetadata.CONTROL_AF_TRIGGER_CANCEL);\n            setAutoFlash(mPreviewRequestBuilder);\n            mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback,\n                    mBackgroundHandler);\n            // After this, the camera will go back to the normal state of preview.\n            mState = STATE_PREVIEW;\n            mCaptureSession.setRepeatingRequest(mPreviewRequest, mCaptureCallback,\n                    mBackgroundHandler);\n        } catch (CameraAccessException e) {\n            e.printStackTrace();\n        }\n    }\n\n    /**\n     * 更新 Preview\n     */\n    private void updatePreview() {\n        try {\n            mPreviewRequest = mPreviewRequestBuilder.build();\n            mCaptureSession.setRepeatingRequest(mPreviewRequest, mCaptureCallback,\n                    mBackgroundHandler);\n        } catch (CameraAccessException e) {\n            e.printStackTrace();\n        }\n    }\n\n    @SuppressLint(\"MissingPermission\")\n    @OnClick({R.id.iv_back_g, R.id.iv_flash, R.id.iv_ae, R.id.iv_awb, R.id.iv_iso,R.id.img_camera_g,\n            R.id.iv_zoom, R.id.iv_change_camera, R.id.iv_effect, R.id.iv_sense, R.id.iv_images})\n    public void onClick(View view) {\n        switch (view.getId()) {\n            case R.id.img_camera_g: {\n                lockFocus();\n                break;\n            }\n            case R.id.iv_back_g: {\n                finish();\n                break;\n            }\n            case R.id.iv_images: {\n                // 挑选 相册信息  https://www.jianshu.com/p/498c9d06c193\n                break;\n            }\n            case R.id.iv_zoom: {\n                showZoomFlag = !showZoomFlag;\n                showLayout(SHOW_ZOOM, showZoomFlag);\n                break;\n            }\n            case R.id.iv_ae: {\n                showAeFlag = !showAeFlag;\n                showLayout(SHOW_AE, showAeFlag);\n                break;\n            }\n            case R.id.iv_awb:\n                showAwbFlag = !showAwbFlag;\n                showLayout(SHOW_AWB, showAwbFlag);\n                break;\n            case R.id.iv_iso:\n                showIsoFlag = !showIsoFlag;\n                showLayout(SHOW_ISO, showIsoFlag);\n                break;\n            case R.id.iv_effect:\n                showEffectFlag = !showEffectFlag;\n                showLayout(SHOW_EFFECT, showEffectFlag);\n                break;\n            case R.id.iv_sense:\n                showSenseFlag = !showSenseFlag;\n                showLayout(SHOW_SENSE, showSenseFlag);\n                break;\n            case R.id.iv_change_camera: {\n                if (\"1\".equals(mCameraId)) {\n                    mCameraId = \"0\";\n                } else if (\"0\".equals(mCameraId)) {\n                    mCameraId = \"1\";\n                } else {\n                    mCameraId = \"0\";\n                }\n                //关闭相机再开启另外个摄像头\n                if (mCaptureSession != null) {\n                    mCaptureSession.close();\n                    mCaptureSession = null;\n                }\n                if (mCameraDevice != null) {\n                    mCameraDevice.close();\n                    mCameraDevice = null;\n                }\n                try {\n                    manager.openCamera(mCameraId, mStateCallback, mBackgroundHandler);\n                } catch (CameraAccessException e) {\n                    e.printStackTrace();\n                }\n                break;\n            }\n            case R.id.iv_flash: {\n                if (!mFlashSupported) {\n                    Log.e(TAG, \"该设备暂不支持 闪光灯\");\n                    return;\n                }\n                switch (flishType) {\n                    case 0:\n                        // 从关闭切换到打开\n                        flishType = 1;\n                        mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE,\n                                CameraMetadata.CONTROL_AE_MODE_ON);\n                        mPreviewRequestBuilder.set(CaptureRequest.FLASH_MODE,\n                                CameraMetadata.FLASH_MODE_SINGLE);\n                        ivFlash.setImageResource(R.mipmap.btn_flash_on_normal);\n                        break;\n                    case 1:\n                        //从打开切换到 自动\n                        flishType = 2;\n                        mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE,\n                                CameraMetadata.CONTROL_AE_MODE_ON_AUTO_FLASH);\n                        ivFlash.setImageResource(R.mipmap.btn_flash_auto_normal);\n                        break;\n                    case 2:\n                        //自动切换到关闭\n                        flishType = 0;\n                        mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE,\n                                CameraMetadata.CONTROL_AE_MODE_ON);\n                        mPreviewRequestBuilder.set(CaptureRequest.FLASH_MODE,\n                                CameraMetadata.FLASH_MODE_OFF);\n                        ivFlash.setImageResource(R.mipmap.btn_flash_off_normal);\n                        break;\n                    default:\n                        break;\n                }\n                updatePreview();\n            }\n            default:\n                break;\n        }\n    }\n\n    private void setAutoFlash(CaptureRequest.Builder requestBuilder) {\n        if (mFlashSupported) {\n            requestBuilder.set(CaptureRequest.CONTROL_AE_MODE,\n                    CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);\n        }\n    }\n\n    /**\n     * 显示和隐藏控件\n     *\n     * @param showWhat\n     * @param showOrNot\n     */\n    private void showLayout(int showWhat, boolean showOrNot) {\n        View v = mLayoutList.get(showWhat);\n        if (showOrNot) {\n            //全部隐藏但是AF/AE的显示出来\n            for (int i = 0; i < mLayoutBottom.getChildCount(); i++) {\n                if (mLayoutBottom.getChildAt(i).getVisibility() == View.VISIBLE) {\n                    mLayoutBottom.getChildAt(i).setVisibility(View.INVISIBLE);\n                }\n            }\n            v.startAnimation(mShowAction);\n            v.setVisibility(View.VISIBLE);\n        } else {\n            //全部隐藏但是capture的显示出来\n            for (int i = 0; i < mLayoutBottom.getChildCount(); i++) {\n                if (mLayoutBottom.getChildAt(i).getVisibility() == View.VISIBLE) {\n                    mLayoutBottom.getChildAt(i).setVisibility(View.INVISIBLE);\n                }\n            }\n            mLayoutCapture.startAnimation(mShowAction);\n            mLayoutCapture.setVisibility(View.VISIBLE);\n        }\n    }\n\n    /**\n     * switch 修改事件\n     *\n     * @param buttonView view\n     * @param isChecked  boolean\n     */\n    @OnCheckedChanged({R.id.switch_ae, R.id.switch_iso})\n    public void CameraOnCheckChangedListener(CompoundButton buttonView, boolean isChecked) {\n        //翻转的时候mPreviewRequestBuilder变为了null,会挂掉\n        if (mPreviewRequestBuilder == null) {\n            return;\n        }\n        switch (buttonView.getId()) {\n            case R.id.switch_ae: {\n                switchIso.setChecked(isChecked);\n                if (isChecked) {\n                    mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CameraMetadata.CONTROL_AE_MODE_ON);\n                    layoutIso.getChildAt(1).setEnabled(false);\n                } else {\n                    mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CameraMetadata.CONTROL_AE_MODE_OFF);\n                    layoutIso.getChildAt(1).setEnabled(true);\n                }\n                break;\n            }\n            case R.id.switch_iso: {\n                switchAe.setChecked(isChecked);\n                if (isChecked) {\n                    mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CameraMetadata.CONTROL_AE_MODE_ON);\n                    layoutIso.getChildAt(1).setEnabled(false);\n                } else {\n                    mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CameraMetadata.CONTROL_AE_MODE_OFF);\n                    layoutIso.getChildAt(1).setEnabled(true);\n                }\n                break;\n            }\n            default:\n                break;\n        }\n        updatePreview();\n    }\n\n    /**\n     * seekbar 滑动监听事件\n     */\n    private class CameraSeekBarListener implements SeekBar.OnSeekBarChangeListener {\n\n        @Override\n        public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {\n            switch (seekBar.getId()) {\n                case R.id.sb_ae: {\n                    if (switchAe.isChecked()) {\n                        // 曝光增益\n                        if (range1 == null) {\n                            break;\n                        }\n                        Log.e(TAG, \"曝光增益范围：\" + range1.toString());\n                        int maxmax = range1.getUpper();\n                        int minmin = range1.getLower();\n                        int all = maxmax - minmin;\n                        int time = 100 / all;\n                        int ae = ((progress / time) - maxmax) > maxmax ? maxmax :\n                                ((progress / time) - maxmax) < minmin ? minmin : ((progress / time) - maxmax);\n                        mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_EXPOSURE_COMPENSATION, ae);\n                        tvSbTxt.setText(\"曝光增益：\" + ae);\n                    } else {\n                        // 曝光时间\n                        if (etr == null) {\n                            tvSbTxt.setText(\"获取曝光时间失败\");\n                            break;\n                        }\n                        Log.e(TAG, \"曝光时间范围：\" + etr.toString());\n                        long max = etr.getUpper();\n                        long min = etr.getLower();\n                        long ae = ((progress * (max - min)) / 100 + min);\n                        mPreviewRequestBuilder.set(CaptureRequest.SENSOR_EXPOSURE_TIME, ae);\n                        tvSbTxt.setText(\"曝光时间：\" + ae);\n                    }\n                    break;\n                }\n                case R.id.sb_iso: {\n                    if (isoRange == null) {\n                        tvSbTxt.setText(\"获取iso失败\");\n                        break;\n                    }\n                    int max1 = isoRange.getUpper();\n                    int min1 = isoRange.getLower();\n                    int iso = ((progress * (max1 - min1)) / 100 + min1);\n                    mPreviewRequestBuilder.set(CaptureRequest.SENSOR_SENSITIVITY, iso);\n                    tvSbTxt.setText(\"灵敏度：\" + iso);\n                    break;\n                }\n                case R.id.sb_zoom: {\n                    Rect rect = characteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);\n                    int radio = characteristics.get(CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM).intValue() / 2;\n                    int realRadio = characteristics.get(CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM).intValue();\n                    int centerX = rect.centerX();\n                    int centerY = rect.centerY();\n                    int minMidth = (rect.right - ((progress * centerX) / 100 / radio) - 1) - ((progress * centerX / radio) / 100 + 8);\n                    int minHeight = (rect.bottom - ((progress * centerY) / 100 / radio) - 1) - ((progress * centerY / radio) / 100 + 16);\n                    if (minMidth < rect.right / realRadio || minHeight < rect.bottom / realRadio) {\n                        Log.e(\"sb_zoom\", \"sb_zoomsb_zoomsb_zoom\");\n                        return;\n                    }\n//                    Rect newRect = new Rect(20, 20, rect.right - ((i * centerX) / 100 / radio) - 1, rect.bottom - ((i * centerY) / 100 / radio) - 1);\n                    Rect newRect = new Rect((progress * centerX / radio) / 100 + 40,\n                            (progress * centerY / radio) / 100 + 40,\n                            rect.right - ((progress * centerX) / 100 / radio) - 1,\n                            rect.bottom - ((progress * centerY) / 100 / radio) - 1);\n                    Log.i(\"sb_zoom\", \"left--->\" + ((progress * centerX / radio) / 100 + 8)\n                            + \",,,top--->\" + ((progress * centerY / radio) / 100 + 16) + \",,,right--->\"\n                            + (rect.right - ((progress * centerX) / 100 / radio) - 1) + \",,,bottom--->\"\n                            + (rect.bottom - ((progress * centerY) / 100 / radio) - 1));\n                    mPreviewRequestBuilder.set(CaptureRequest.SCALER_CROP_REGION, newRect);\n                    tvSbTxt.setText(\"放大：\" + progress + \"%\");\n                    break;\n                }\n                default:\n                    break;\n            }\n            updatePreview();\n        }\n\n        @Override\n        public void onStartTrackingTouch(SeekBar seekBar) {\n            tvSbTxt.setVisibility(View.VISIBLE);\n            tvSbTxt.startAnimation(mAlphaInAnimation);\n        }\n\n        @Override\n        public void onStopTrackingTouch(SeekBar seekBar) {\n            tvSbTxt.startAnimation(mAlphaOutAnimation);\n            tvSbTxt.setVisibility(View.INVISIBLE);\n        }\n    }\n\n    /**\n     * 在系统相机 配置分配完整后 添加绑定事件\n     */\n    private void SetListener() {\n        // 配置 白平衡滑动事件\n        sbAwb.setmOnAwbSeekBarChangeListener(new AwbSeekBarChangeListener(GoogleCameraActivity.this,\n                tvSbTxt, mPreviewRequestBuilder, mCaptureSession, mBackgroundHandler, mCaptureCallback));\n\n        sAdapter.setSenseOnItemClickListener(new SenseAdapter.SenseOnItemClickListener() {\n            @Override\n            public void itemOnClick(int position) {\n                mPreviewRequestBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_USE_SCENE_MODE);\n                switch (position) {\n                    case 0:\n                        mPreviewRequestBuilder.set(CaptureRequest.CONTROL_SCENE_MODE, CameraMetadata.CONTROL_SCENE_MODE_DISABLED);\n                        break;\n                    case 1:\n                        mPreviewRequestBuilder.set(CaptureRequest.CONTROL_SCENE_MODE, CameraMetadata.CONTROL_SCENE_MODE_FACE_PRIORITY);\n                        break;\n                    case 2:\n                        mPreviewRequestBuilder.set(CaptureRequest.CONTROL_SCENE_MODE, CameraMetadata.CONTROL_SCENE_MODE_ACTION);\n                        break;\n                    case 3:\n                        mPreviewRequestBuilder.set(CaptureRequest.CONTROL_SCENE_MODE, CameraMetadata.CONTROL_SCENE_MODE_PORTRAIT);\n                        break;\n                    case 4:\n                        mPreviewRequestBuilder.set(CaptureRequest.CONTROL_SCENE_MODE, CameraMetadata.CONTROL_SCENE_MODE_LANDSCAPE);\n                        break;\n                    case 5:\n                        mPreviewRequestBuilder.set(CaptureRequest.CONTROL_SCENE_MODE, CameraMetadata.CONTROL_SCENE_MODE_NIGHT);\n                        break;\n                    case 6:\n                        mPreviewRequestBuilder.set(CaptureRequest.CONTROL_SCENE_MODE, CameraMetadata.CONTROL_SCENE_MODE_NIGHT_PORTRAIT);\n                        break;\n                    case 7:\n                        mPreviewRequestBuilder.set(CaptureRequest.CONTROL_SCENE_MODE, CameraMetadata.CONTROL_SCENE_MODE_THEATRE);\n                        break;\n                    case 8:\n                        mPreviewRequestBuilder.set(CaptureRequest.CONTROL_SCENE_MODE, CameraMetadata.CONTROL_SCENE_MODE_BEACH);\n                        break;\n                    case 9:\n                        mPreviewRequestBuilder.set(CaptureRequest.CONTROL_SCENE_MODE, CameraMetadata.CONTROL_SCENE_MODE_SNOW);\n                        break;\n                    case 10:\n                        mPreviewRequestBuilder.set(CaptureRequest.CONTROL_SCENE_MODE, CameraMetadata.CONTROL_SCENE_MODE_SUNSET);\n                        break;\n                    case 11:\n                        mPreviewRequestBuilder.set(CaptureRequest.CONTROL_SCENE_MODE, CameraMetadata.CONTROL_SCENE_MODE_STEADYPHOTO);\n                        break;\n                    case 12:\n                        mPreviewRequestBuilder.set(CaptureRequest.CONTROL_SCENE_MODE, CameraMetadata.CONTROL_SCENE_MODE_FIREWORKS);\n                        break;\n                    case 13:\n                        mPreviewRequestBuilder.set(CaptureRequest.CONTROL_SCENE_MODE, CameraMetadata.CONTROL_SCENE_MODE_SPORTS);\n                        break;\n                    case 14:\n                        mPreviewRequestBuilder.set(CaptureRequest.CONTROL_SCENE_MODE, CameraMetadata.CONTROL_SCENE_MODE_PARTY);\n                        break;\n                    case 15:\n                        mPreviewRequestBuilder.set(CaptureRequest.CONTROL_SCENE_MODE, CameraMetadata.CONTROL_SCENE_MODE_CANDLELIGHT);\n                        break;\n                    case 16:\n                        mPreviewRequestBuilder.set(CaptureRequest.CONTROL_SCENE_MODE, CameraMetadata.CONTROL_SCENE_MODE_BARCODE);\n                        break;\n                    default:\n                        break;\n                }\n                updatePreview();\n            }\n        });\n\n        effectAdapter.setEffectOnItemClickListener(new EffectAdapter.EffectOnItemClickListener() {\n            @Override\n            public void itemOnClick(int position) {\n                switch (position) {\n                    case 0:\n                        mPreviewRequestBuilder.set(CaptureRequest.CONTROL_EFFECT_MODE, CameraMetadata.CONTROL_EFFECT_MODE_AQUA);\n                        break;\n                    case 1:\n                        mPreviewRequestBuilder.set(CaptureRequest.CONTROL_EFFECT_MODE, CameraMetadata.CONTROL_EFFECT_MODE_BLACKBOARD);\n                        break;\n                    case 2:\n                        mPreviewRequestBuilder.set(CaptureRequest.CONTROL_EFFECT_MODE, CameraMetadata.CONTROL_EFFECT_MODE_MONO);\n                        break;\n                    case 3:\n                        mPreviewRequestBuilder.set(CaptureRequest.CONTROL_EFFECT_MODE, CameraMetadata.CONTROL_EFFECT_MODE_NEGATIVE);\n                        break;\n                    case 4:\n                        mPreviewRequestBuilder.set(CaptureRequest.CONTROL_EFFECT_MODE, CameraMetadata.CONTROL_EFFECT_MODE_POSTERIZE);\n                        break;\n                    case 5:\n                        mPreviewRequestBuilder.set(CaptureRequest.CONTROL_EFFECT_MODE, CameraMetadata.CONTROL_EFFECT_MODE_SEPIA);\n                        break;\n                    case 6:\n                        mPreviewRequestBuilder.set(CaptureRequest.CONTROL_EFFECT_MODE, CameraMetadata.CONTROL_EFFECT_MODE_SOLARIZE);\n                        break;\n                    case 7:\n                        mPreviewRequestBuilder.set(CaptureRequest.CONTROL_EFFECT_MODE, CameraMetadata.CONTROL_EFFECT_MODE_WHITEBOARD);\n                        break;\n                    case 8:\n                        mPreviewRequestBuilder.set(CaptureRequest.CONTROL_EFFECT_MODE, CameraMetadata.CONTROL_EFFECT_MODE_OFF);\n                        break;\n                    default:\n                        break;\n                }\n                updatePreview();\n            }\n        });\n    }\n\n    /**\n     * 录制预览\n     */\n    private void startRecordingVideo() {\n        if (null == mCameraDevice || !mTextureView.isAvailable() || null == mPreviewSize) {\n            return;\n        }\n        try {\n            if (null != mCaptureSession) {\n                mCaptureSession.close();\n                mCaptureSession = null;\n            }\n            setUpMediaRecorder();\n            SurfaceTexture mtexture = mTextureView.getSurfaceTexture();\n            assert mtexture != null;\n            mtexture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());\n            mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD);\n            List<Surface> surfaces = new ArrayList<>();\n\n            // Set up Surface for the camera preview\n            Surface previewSurface = new Surface(mtexture);\n            surfaces.add(previewSurface);\n            mPreviewRequestBuilder.addTarget(previewSurface);\n\n            // Set up Surface for the MediaRecorder\n            Surface recorderSurface = mMediaRecorder.getSurface();\n            surfaces.add(recorderSurface);\n            mPreviewRequestBuilder.addTarget(recorderSurface);\n\n            mCameraDevice.createCaptureSession(surfaces, new CameraCaptureSession.StateCallback() {\n\n                @Override\n                public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {\n                    //设置反复捕获数据的请求，这样预览界面就会一直有数据显示\n                    mCaptureSession = cameraCaptureSession;\n                    updatePreview();\n                    Log.e(TAG, \"onConfigured: \" + Thread.currentThread().getName());\n                    // Start recording\n                    mMediaRecorder.start();\n                }\n\n                @Override\n                public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) {\n                }\n            }, mBackgroundHandler);\n        } catch (CameraAccessException | IOException e) {\n            e.printStackTrace();\n        }\n    }\n\n\n    /**\n     * 录制结束\n     */\n    private void stopRecordingVideo() {\n        // Stop recording\n        mMediaRecorder.stop();\n        mMediaRecorder.reset();\n        Toast.makeText(this, \"Video saved: \" + mVideoPath.getAbsolutePath(),\n                Toast.LENGTH_SHORT).show();\n        createCameraPreviewSession();\n    }\n\n    /**\n     * 设置 MediaRecorder\n     *\n     * @throws IOException\n     */\n    private void setUpMediaRecorder() throws IOException {\n        mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);\n        mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);\n        mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);\n        mVideoPath = Utils.getOutputMediaFile(this,MEDIA_TYPE_VIDEO);\n        mMediaRecorder.setOutputFile(mVideoPath.getAbsolutePath());\n        mMediaRecorder.setVideoEncodingBitRate(10000000);\n        mMediaRecorder.setVideoFrameRate(30);\n        mMediaRecorder.setVideoSize(largest.getWidth(), largest.getHeight());\n        mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);\n        mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);\n        int rotation = getWindowManager().getDefaultDisplay().getRotation();\n        switch (mSensorOrientation) {\n            case 90:\n                mMediaRecorder.setOrientationHint(ORIENTATIONS.get(rotation));\n                break;\n            case 270:\n                mMediaRecorder.setOrientationHint(ORIENTATIONS.get(rotation));\n                break;\n            default:\n                break;\n        }\n        mMediaRecorder.prepare();\n    }\n\n\n    /**\n     * Start notify.\n     */\n    public void onServerStart(String ip) {\n        closeDialog();\n        if (!TextUtils.isEmpty(ip)) {\n            List<String> addressList = new LinkedList<>();\n            mRootUrl = \"http://\" + ip + \":8080/\";\n            addressList.add(mRootUrl);\n            addressList.add(\"http://\" + ip + \":8080/login.html\");\n            Log.e(TAG, \"onServerStart: \" + TextUtils.join(\"\\n\", addressList));\n        } else {\n            mRootUrl = null;\n            Log.e(TAG, \"onServerStart: \" + getString(R.string.server_ip_error));\n        }\n    }\n\n    /**\n     * Error notify.\n     */\n    public void onServerError(String message) {\n        closeDialog();\n        mRootUrl = null;\n        Log.e(TAG, \"onServerError: \" + message);\n    }\n\n    /**\n     * Stop notify.\n     */\n    public void onServerStop() {\n        closeDialog();\n        mRootUrl = null;\n    }\n\n    private void showDialog() {\n        if (mDialog == null) {\n            mDialog = new LoadingDialog(this);\n        }\n        if (!mDialog.isShowing()) {\n            mDialog.show();\n        }\n    }\n\n    private void closeDialog() {\n        if (mDialog != null && mDialog.isShowing()) {\n            mDialog.dismiss();\n        }\n    }\n\n    @Override\n    protected void onDestroy() {\n        mServerManager.unRegister();\n        EventBus.getDefault().unregister(this);\n        super.onDestroy();\n    }\n\n    private static final String LOGIN_ATTRIBUTE = \"USER.LOGIN.SIGN\";\n\n    public CaptureRequest.Builder getBuilder() {\n        return mPreviewRequestBuilder;\n    }\n\n    public CameraCaptureSession getSession() {\n        return mCaptureSession;\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/camera/cn/cameramaster/ui/MainActivity.java",
    "content": "package camera.cn.cameramaster.ui;\n\nimport android.Manifest;\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.net.ConnectivityManager;\nimport android.os.Build;\nimport android.support.annotation.RequiresApi;\nimport android.util.Log;\nimport android.view.View;\nimport android.widget.Button;\nimport android.widget.TextView;\n\nimport com.yanzhenjie.permission.Action;\nimport com.yanzhenjie.permission.AndPermission;\nimport com.yanzhenjie.permission.Rationale;\nimport com.yanzhenjie.permission.RequestExecutor;\n\nimport java.io.File;\nimport java.lang.reflect.Method;\nimport java.util.List;\n\nimport butterknife.BindView;\nimport butterknife.OnClick;\nimport camera.cn.cameramaster.R;\nimport camera.cn.cameramaster.base.BaseActivity;\nimport camera.cn.cameramaster.util.AppConstant;\n\n/**\n * 首页\n *\n * @author ymc\n */\n\npublic class MainActivity extends BaseActivity {\n    private final static String TAG = \"MainActivity\";\n    @BindView(R.id.btn_camera)\n    public Button btn;\n    @BindView(R.id.tv_message)\n    TextView tvMsg;\n\n    private File mD65File;\n    private File mFile;\n\n    @Override\n    protected int getLayoutId() {\n        return R.layout.activity_main;\n    }\n\n    @Override\n    protected void initView() {\n        mD65File = new File(getExternalFilesDir(\"\"), \"picD65.jpg\");\n        mFile = new File(getExternalFilesDir(null), \"pic.jpg\");\n    }\n\n    @Override\n    protected void initData() {\n        requestPermission();\n        // 设置关闭 移动网络\n        setDataConnectionState(this,false);\n    }\n\n\n    @SuppressLint(\"WrongConstant\")\n    public static void setDataConnectionState(Context cxt, boolean state) {\n        ConnectivityManager connectivityManager = null;\n        Class connectivityManagerClz = null;\n        try {\n            connectivityManager = (ConnectivityManager) cxt\n                    .getSystemService(\"connectivity\");\n            connectivityManagerClz = connectivityManager.getClass();\n            Method method = connectivityManagerClz.getMethod(\n                    \"setMobileDataEnabled\", new Class[] { boolean.class });\n            method.invoke(connectivityManager, state);\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n\n    @OnClick({R.id.btn_camera, R.id.btn_camera2, R.id.btn_filter_camera2, R.id.btn_camera2_video})\n    public void onClick(View view) {\n        switch (view.getId()) {\n            case R.id.btn_camera:\n                Intent intent = new Intent(this, CameraActivity.class);\n                startActivityForResult(intent, 0);\n                break;\n            case R.id.btn_camera2:\n                Intent intent2 = new Intent(this, GoogleCameraActivity.class);\n                startActivityForResult(intent2, 1);\n                break;\n            case R.id.btn_filter_camera2:\n                Intent intentFilter2 = new Intent(this, CameraSurfaceViewActivity.class);\n                startActivityForResult(intentFilter2, 0);\n                break;\n            case R.id.btn_camera2_video:\n                Intent intentVideo = new Intent(this, CameraVideoActivity.class);\n                startActivity(intentVideo);\n                break;\n            default:\n                break;\n        }\n    }\n\n\n    @Override\n    protected void onActivityResult(int requestCode, int resultCode, Intent data) {\n        super.onActivityResult(requestCode, resultCode, data);\n        if (resultCode != AppConstant.RESULT_CODE.RESULT_OK) {\n            return;\n        }\n        if (requestCode == 0) {\n            String imgPath = data.getStringExtra(AppConstant.KEY.IMG_PATH);\n            int picWidth = data.getIntExtra(AppConstant.KEY.PIC_WIDTH, 0);\n            int picHeight = data.getIntExtra(AppConstant.KEY.PIC_HEIGHT, 0);\n            Intent intent = new Intent(activity, ShowPicActivity.class);\n            intent.putExtra(AppConstant.KEY.PIC_WIDTH, picWidth);\n            intent.putExtra(AppConstant.KEY.PIC_HEIGHT, picHeight);\n            intent.putExtra(AppConstant.KEY.IMG_PATH, imgPath);\n            startActivity(intent);\n        } else if (requestCode == 1) {\n//            tvMsg.setText(\"图片 D65 光源处理中 请勿退出....\");\n//            new Thread(new Runnable() {\n//                @Override\n//                public void run() {\n//                    final long starttime = System.currentTimeMillis();\n//                    FileInputStream fis = null;\n//                    FileOutputStream output = null;\n//                    try {\n//                        fis = new FileInputStream(mFile);\n//                        Bitmap bitmap = BitmapFactory.decodeStream(fis);\n//                        Bitmap d65bitmap = BitmapUtils.ImgaeToNegative(bitmap);\n//                        output = new FileOutputStream(mD65File);\n//                        d65bitmap.compress(Bitmap.CompressFormat.JPEG, 100, output);\n//                        runOnUiThread(new Runnable() {\n//                            @Override\n//                            public void run() {\n//                                tvMsg.setText(\"处理完毕.耗时：\"+ (System.currentTimeMillis() - starttime)+ \" ms\");\n//                            }\n//                        });\n//                    } catch (FileNotFoundException e) {\n//                        e.printStackTrace();\n//                    }\n//                }\n//            }).start();\n        }\n    }\n\n    /**\n     * 动态申请  (电话/位置/存储)\n     */\n    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)\n    private void requestPermission() {\n        AndPermission.with(this)\n                .permission(Manifest.permission.CAMERA,\n                        Manifest.permission.READ_EXTERNAL_STORAGE,\n                        Manifest.permission.RECORD_AUDIO)\n                .rationale(new Rationale() {\n                    @Override\n                    public void showRationale(Context context, List<String> permissions, RequestExecutor executor) {\n                        executor.execute();\n                    }\n                })\n                .onGranted(new Action() {\n                    @Override\n                    public void onAction(List<String> permissions) {\n                        Log.e(TAG, \"用户给权限\");\n                    }\n                })\n                .onDenied(new Action() {\n                    @Override\n                    public void onAction(List<String> permissions) {\n                        if (AndPermission.hasAlwaysDeniedPermission(MainActivity.this, permissions)) {\n                            // 打开权限设置页\n                            AndPermission.permissionSetting(MainActivity.this).execute();\n                            return;\n                        }\n                        Log.e(TAG, \"用户拒绝权限\");\n                    }\n                })\n                .start();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/camera/cn/cameramaster/ui/ShowPicActivity.java",
    "content": "package camera.cn.cameramaster.ui;\n\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapFactory;\nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.graphics.ColorMatrix;\nimport android.graphics.ColorMatrixColorFilter;\nimport android.graphics.Matrix;\nimport android.graphics.Paint;\nimport android.widget.ImageView;\nimport android.widget.SeekBar;\n\nimport butterknife.BindView;\nimport camera.cn.cameramaster.R;\nimport camera.cn.cameramaster.base.BaseActivity;\nimport camera.cn.cameramaster.util.AppConstant;\n\n/**\n * 显示照片界面\n */\npublic class ShowPicActivity extends BaseActivity {\n    @BindView(R.id.img)\n    ImageView iv;\n    @BindView(R.id.seekBar1)\n    SeekBar seekBarRed;\n    @BindView(R.id.seekBar2)\n    SeekBar seekBarGreen;\n    @BindView(R.id.seekBar3)\n    SeekBar seekBarB;\n    @BindView(R.id.seekBar4)\n    SeekBar seekBarH;\n\n    private Canvas canvas;\n    //颜色矩阵\n    private ColorMatrix colorMatrix;\n    private Paint paint;\n    private int picWidth;\n    private int picHeight;\n    private Bitmap bitmap;\n    private Bitmap alterBitemp;\n\n    private int redProgress = 128;\n    private int greenProgress = 128;\n    private int blueProgress = 128;\n    private int aplaraProgress = 128;\n\n    @Override\n    protected int getLayoutId() {\n        return R.layout.activity_show_pic;\n    }\n\n    @Override\n    protected void initView() {\n        seekBarRed.setOnSeekBarChangeListener(new seekBar1Listen());\n        seekBarGreen.setOnSeekBarChangeListener(new seekBar2Listen());\n        seekBarB.setOnSeekBarChangeListener(new seekBar3Listen());\n        seekBarH.setOnSeekBarChangeListener(new seekBar4Listen());\n    }\n\n    @Override\n    protected void initData() {\n        picWidth = getIntent().getIntExtra(AppConstant.KEY.PIC_WIDTH, 0);\n        picHeight = getIntent().getIntExtra(AppConstant.KEY.PIC_HEIGHT, 0);\n//        iv.setImageURI(Uri.parse(getIntent().getStringExtra(AppConstant.KEY.IMG_PATH)));\n//        iv.setLayoutParams(new RelativeLayout.LayoutParams(picWidth, picHeight));\n        canvasBitmap(getIntent().getStringExtra(AppConstant.KEY.IMG_PATH));\n        colorMatrix.set(new float[]{\n                -1,0,0,0,255,\n                0,-1,0,0,255,\n                0,0,-1,0,255,\n                0,0,0,aplaraProgress/128.0f,0,\n        });\n        paint.setColorFilter(new ColorMatrixColorFilter(colorMatrix));\n        canvas.drawBitmap(bitmap, new Matrix(), paint);\n        iv.setImageBitmap(alterBitemp);\n    }\n\n    /**\n     *  画布-修改图片\n     */\n    private void canvasBitmap(String path) {\n        //返回图像bitmap对象\n        bitmap = BitmapFactory.decodeFile(path, null);\n        //可修改olterbitmap  属性与 bitmap一致\n        alterBitemp = Bitmap.createBitmap(bitmap.getWidth(),bitmap.getHeight(),bitmap.getConfig());\n        System.out.println(bitmap.getWidth()+\" ：\"+bitmap.getHeight());\n\n        //画布\n        canvas = new Canvas(alterBitemp);\n        //canvas.drawBitmap()画笔-合成模式\n        colorMatrix = new ColorMatrix();\n        paint = new Paint();\n        paint.setColor(Color.BLACK);\n        //设置画笔过滤器-new()的颜色矩阵\n        paint.setColorFilter(new ColorMatrixColorFilter(colorMatrix));\n        paint.setAntiAlias(true);\n        canvas.drawBitmap(bitmap, new Matrix(), paint);\n        //显示imageView\n        iv.setImageBitmap(alterBitemp);\n\n    }\n\n    /**\n     * Red 修改监听事件\n     */\n    class seekBar1Listen implements SeekBar.OnSeekBarChangeListener {\n\n        @Override\n        public void onProgressChanged(SeekBar seekBar, int progress,boolean fromUser) {\n            redProgress = progress;\n            colorMatrix.set(new float[]{\n                    redProgress/128.0f,0,0,0,0,\n                    0,greenProgress/128.0f,0,0,0,\n                    0,0,blueProgress/128.0f,0,0,\n                    0,0,0,aplaraProgress/128.0f,0,\n            });\n            paint.setColorFilter(new ColorMatrixColorFilter(colorMatrix));\n            canvas.drawBitmap(bitmap, new Matrix(), paint);\n            iv.setImageBitmap(alterBitemp);\n        }\n        @Override\n        public void onStartTrackingTouch(SeekBar seekBar) {}\n        @Override\n        public void onStopTrackingTouch(SeekBar seekBar) {}\n    }\n\n    /**\n     * green 修改监听事件\n     */\n    class seekBar2Listen implements SeekBar.OnSeekBarChangeListener {\n\n        @Override\n        public void onProgressChanged(SeekBar seekBar, int progress,boolean fromUser) {\n            greenProgress = progress;\n            colorMatrix.set(new float[]{\n                    redProgress/128.0f,0,0,0,0,\n                    0,greenProgress/128.0f,0,0,0,\n                    0,0,blueProgress/128.0f,0,0,\n                    0,0,0,aplaraProgress/128.0f,0,\n            });\n            paint.setColorFilter(new ColorMatrixColorFilter(colorMatrix));\n            canvas.drawBitmap(bitmap, new Matrix(), paint);\n            iv.setImageBitmap(alterBitemp);\n        }\n        @Override\n        public void onStartTrackingTouch(SeekBar seekBar) {}\n        @Override\n        public void onStopTrackingTouch(SeekBar seekBar) {}\n    }\n\n    /**\n     * blue 修改监听事件\n     */\n    class seekBar3Listen implements SeekBar.OnSeekBarChangeListener {\n\n        @Override\n        public void onProgressChanged(SeekBar seekBar, int progress,boolean fromUser) {\n            blueProgress = progress;\n            colorMatrix.set(new float[]{\n                    redProgress/128.0f,0,0,0,0,\n                    0,greenProgress/128.0f,0,0,0,\n                    0,0,blueProgress/128.0f,0,0,\n                    0,0,0,aplaraProgress/128.0f,0,\n            });\n            paint.setColorFilter(new ColorMatrixColorFilter(colorMatrix));\n            canvas.drawBitmap(bitmap, new Matrix(), paint);\n            iv.setImageBitmap(alterBitemp);\n        }\n        @Override\n        public void onStartTrackingTouch(SeekBar seekBar) {}\n        @Override\n        public void onStopTrackingTouch(SeekBar seekBar) {}\n    }\n\n    /**\n     * height 修改监听事件\n     */\n    class seekBar4Listen implements SeekBar.OnSeekBarChangeListener {\n\n        @Override\n        public void onProgressChanged(SeekBar seekBar, int progress,boolean fromUser) {\n            aplaraProgress = progress;\n            colorMatrix.set(new float[]{\n                    redProgress/128.0f,0,0,0,0,\n                    0,greenProgress/128.0f,0,0,0,\n                    0,0,blueProgress/128.0f,0,0,\n                    0,0,0,aplaraProgress/128.0f,0,\n            });\n            paint.setColorFilter(new ColorMatrixColorFilter(colorMatrix));\n            canvas.drawBitmap(bitmap, new Matrix(), paint);\n            iv.setImageBitmap(alterBitemp);\n        }\n        @Override\n        public void onStartTrackingTouch(SeekBar seekBar) {}\n        @Override\n        public void onStopTrackingTouch(SeekBar seekBar) {}\n    }\n\n\n}\n"
  },
  {
    "path": "app/src/main/java/camera/cn/cameramaster/util/AppConstant.java",
    "content": "package camera.cn.cameramaster.util;\n\n/**\n * 应用 常量类\n *\n * @packageName: cn.ymc.suncamera.util\n * @fileName: AppConstant\n * @date: 2019/1/24  16:54\n * @author: ymc\n * @QQ:745612618\n */\n\npublic class AppConstant {\n\n    /**\n     * 摄像头模式\n     */\n    public final static int CAMERA_MODE = 0;\n    /**\n     * 视频播放器模式\n     */\n    public final static int VIDEO_MODE = 1;\n\n    /**\n     * 视频最长的时长是10s\n     */\n    public final static int VIDEO_MAX_TIME = 10;\n\n    /**\n     * 视频播放模式\n     */\n    public final static int VIDEO_PLAY_MODE = 0;\n\n    /**\n     * 视频录像模式\n     */\n    public final static int VIDEO_RECORD_MODE = 1;\n\n    /**\n     * 拍照模式\n     */\n    public final static int VIDEO_TAKE_PHOTO = 2;\n\n    /**\n     * 当前面板是预览状态\n     */\n    public final static int TEXTURE_PREVIEW_STATE = 0;\n\n    /**\n     * 当前面板是录像状态\n     */\n    public final static int TEXTURE_RECORD_STATE = 1;\n\n    /**\n     * 当前面板是图片状态\n     */\n    public final static int TEXTURE_PHOTO_STATE = 2;\n\n    /**\n     * 当前面板是视频播放状态\n     */\n\n    public final static int TEXTURE_PLAY_STATE = 3;\n\n    /**\n     * 当前是摄像头模式还是视频播放模式\n     */\n    public int MODE;\n\n    /**\n     * 当前的模式，默认为拍照模式\n     */\n    public int NOW_MODE = VIDEO_TAKE_PHOTO;\n\n\n    /**\n     * 感觉数组\n     */\n    public static String[] senseArr = {\"DISABLED\", \"FACE_PRIORITY\", \"ACTION\", \"PORTRAIT\", \"LANDSCAPE\", \"NIGHT\"\n            , \"NIGHT_PORTRAIT\", \"THEATRE\", \"BEACH\", \"SNOW\", \"SUNSET\", \"STEADYPHOTO\", \"FIREWORKS\",\n            \"SPORTS\", \"PARTY\", \"CANDLELIGHT\", \"BARCODE\"};\n\n    public static String[] effectArr = {\"aqua\", \"blackboard\", \"monoColor\", \"negative\", \"posterization\", \"sepia\"\n            , \"solarisation\", \"whiteboard\", \"off\"};\n\n    public interface KEY{\n        String IMG_PATH = \"IMG_PATH\";\n        String VIDEO_PATH = \"VIDEO_PATH\";\n        String PIC_WIDTH = \"PIC_WIDTH\";\n        String PIC_HEIGHT = \"PIC_HEIGHT\";\n    }\n\n    public interface RESULT_CODE {\n        int RESULT_OK = -1;\n        int RESULT_CANCELED = 0;\n        int RESULT_ERROR = 1;\n    }\n\n    /**\n     * 底部状态 ： 曝光\n     */\n    public static final int SHOW_AE = 1;\n    /**\n     * 白平衡\n     */\n    public static final int SHOW_AWB = 2;\n    /**\n     * 感光度\n     */\n    public static final int SHOW_ISO = 3;\n    /**\n     * 放大 倍数\n     */\n    public static final int SHOW_ZOOM = 4;\n    /**\n     * effect\n     */\n    public static final int SHOW_EFFECT = 5;\n    /**\n     * sense\n     */\n    public static final int SHOW_SENSE = 6;\n\n    /**\n     * 手动设置\n     */\n    public static final int SHOW_SETTING = 6;\n\n\n    /**\n     * lab  rgb 数组\n     */\n    public static double[][] labmap = {{37.986,13.555,14.059},{65.711,18.13,17.81},{49.927,-4.88,-21.925},\n            {43.139,-13.095,21.905} ,{55.112,8.844,-25.399},{70.719,-33.397,-0.199},\n            {62.661,36.067,57.096},{40.02,10.41,-45.964},{51.124,48.239,16.248},\n            {30.325,22.976,-21.587},{72.532,-23.709,57.255},{71.941,19.363,67.857},\n            {28.778,14.179,-50.297},{55.261,-38.342,31.37},{42.101,53.378,28.19},\n            {81.733,4.039,79.819} ,{51.935,49.986,-14.574},{51.038,-28.631,-28.638},\n            {96.539,-0.425,1.186},{81.257,-0.638,-0.335},{66.766,-0.734,-0.504},\n            {50.867,-0.153,-0.27} ,{35.656,-0.421,-1.231},{20.461,-0.079,-0.973}};\n\n    public static double [][] rgbmap = {{115,82,68},{194,150,130},{98,122,157},{87,108,67},\n            {133,128,177},{103,189,170},{214,126,44},{80,91,166},{193,90,99},{94,60,108},\n            {157,188,64},{224,163,46},{56,61,150},{70,148,73},{175,54,60},{231,199,31},\n            {187,86,149},{8,133,161},{243,243,242},{200,200,200},{160,160,160},\n            {122,122,121},{85,85,85},{52,52,52}};\n\n}\n"
  },
  {
    "path": "app/src/main/java/camera/cn/cameramaster/util/BitmapUtils.java",
    "content": "package camera.cn.cameramaster.util;\n\nimport android.content.Context;\nimport android.content.res.Resources;\nimport android.graphics.Bitmap;\nimport android.graphics.Bitmap.Config;\nimport android.graphics.BitmapFactory;\nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.graphics.ColorMatrix;\nimport android.graphics.ColorMatrixColorFilter;\nimport android.graphics.Matrix;\nimport android.graphics.Paint;\nimport android.graphics.PixelFormat;\nimport android.graphics.PorterDuff.Mode;\nimport android.graphics.PorterDuffXfermode;\nimport android.graphics.Rect;\nimport android.graphics.RectF;\nimport android.graphics.drawable.BitmapDrawable;\nimport android.graphics.drawable.Drawable;\nimport android.media.ExifInterface;\nimport android.media.MediaScannerConnection;\nimport android.util.Log;\nimport android.view.View;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\n\n/**\n * Bitmap处理工具\n *\n * @date 2019年1月25日 14:27:33\n */\npublic class BitmapUtils {\n    private BitmapUtils() {\n    }\n\n    /**\n     * 800*480\n     */\n    private static final int CONFIG_480P = 1;\n    /**\n     * 1280*720\n     */\n    private static final int CONFIG_720P = 2;\n    /**\n     * 1920*1080\n     */\n    private static final int CONFIG_1080P = 3;\n    /**\n     * 2560*1440\n     */\n    private static final int CONFIG_2K = 4;\n\n    private static int getSize(int config) {\n        int size = 0;\n        switch (config) {\n            case CONFIG_480P:\n                size = 480;\n                break;\n            case CONFIG_720P:\n                size = 720;\n                break;\n            case CONFIG_1080P:\n                size = 1080;\n                break;\n            case CONFIG_2K:\n                size = 1440;\n                break;\n            default:\n                break;\n        }\n        return size;\n    }\n\n    /**\n     * 通过资源id转化成Bitmap\n     *\n     * @param context 对象\n     * @param resId   资源id\n     * @return bitmap\n     */\n    public static Bitmap ReadBitmapById(Context context, int resId) {\n        BitmapFactory.Options opt = new BitmapFactory.Options();\n        opt.inPreferredConfig = Bitmap.Config.RGB_565;\n        opt.inPurgeable = true;\n        opt.inInputShareable = true;\n        InputStream is = context.getResources().openRawResource(resId);\n        return BitmapFactory.decodeStream(is, null, opt);\n    }\n\n\n    /**\n     * Bitmap --> byte[]\n     *\n     * @param bmp Bitmap\n     * @return byte[]\n     */\n    public static byte[] readBitmap(Bitmap bmp) {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n        bmp.compress(Bitmap.CompressFormat.JPEG, 60, baos);\n        try {\n            baos.flush();\n            baos.close();\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n        return baos.toByteArray();\n    }\n\n\n    /**\n     * 旋转图片\n     *\n     * @param angle\n     * @param bitmap\n     * @return\n     */\n    public static Bitmap rotaingImageView(int angle, Bitmap bitmap) {\n        // 旋转图片 动作\n        Matrix matrix = new Matrix();\n        matrix.postRotate(angle);\n\n        // 创建新的图片\n        Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0,\n                bitmap.getWidth(), bitmap.getHeight(), matrix, true);\n        if (resizedBitmap != bitmap && bitmap != null && !bitmap.isRecycled()) {\n            bitmap.recycle();\n            bitmap = null;\n        }\n\n        return resizedBitmap;\n    }\n\n    /**\n     * 读取图片旋转的角度\n     *\n     * @param filename\n     * @return\n     */\n    public static void setPictureDegree(String filename, int degree) {\n        try {\n            if (degree == 0) {\n                return;\n            }\n\n            int rotate = android.support.media.ExifInterface.ORIENTATION_UNDEFINED;\n            switch (degree) {\n                case 90:\n                    rotate = android.support.media.ExifInterface.ORIENTATION_ROTATE_90;\n                    break;\n                case 180:\n                    rotate = android.support.media.ExifInterface.ORIENTATION_ROTATE_180;\n                    break;\n                case 270:\n                    rotate = android.support.media.ExifInterface.ORIENTATION_ROTATE_270;\n                    break;\n                default:\n                    break;\n            }\n\n            android.support.media.ExifInterface exifInterface = new android.support.media.ExifInterface(filename);\n            exifInterface.setAttribute(android.support.media.ExifInterface.TAG_ORIENTATION,\n                    String.valueOf(rotate));\n            exifInterface.saveAttributes();\n\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n\n    /**\n     * 返回适应屏幕尺寸的位图\n     *\n     * @param bit    bit\n     * @param config config\n     */\n    private static Bitmap getRightSzieBitmap(Bitmap bit, int config) {\n        // 得到理想宽度\n        int ww = getSize(config);\n        // 获取图片宽度\n        int w = bit.getWidth();\n        // 计算缩放率\n        float rate = 1f;\n        if (w > ww) {\n            rate = (float) ww / (float) w;\n        }\n        // 重新绘图\n        Bitmap bitmap = Bitmap.createBitmap((int) (bit.getWidth() * rate),\n                (int) (bit.getHeight() * rate), Config.ARGB_8888);\n        Canvas canvas = new Canvas(bitmap);\n        Rect rect = new Rect(0, 0, (int) (bit.getWidth() * rate),\n                (int) (bit.getHeight() * rate));\n        canvas.drawBitmap(bit, null, rect, null);\n        return bitmap;\n    }\n\n    /**\n     * 返回适应屏幕的位图 更节省内存\n     *\n     * @param fileName file name\n     * @param config   config\n     * @return Bitmap\n     */\n    public static Bitmap getRightSzieBitmap(String fileName, int config) {\n        BitmapFactory.Options options = new BitmapFactory.Options();\n        options.inJustDecodeBounds = true;\n        BitmapFactory.decodeFile(fileName, options);\n        options.inJustDecodeBounds = false;\n        int w = options.outWidth;\n        int ww = getSize(config);\n        if ((ww * 2) < w) {\n            options.inSampleSize = 2;\n        }\n        // 重新绘图\n        Bitmap bitmap = BitmapFactory.decodeFile(fileName, options);\n        return getRightSzieBitmap(bitmap, config);\n    }\n\n\n    /**\n     * 图片去色,返回灰度图片\n     *\n     * @param bmpOriginal 传入的图片\n     * @return 去色后的图片\n     */\n    private static Bitmap toGrayscale(Bitmap bmpOriginal) {\n        int width, height;\n        height = bmpOriginal.getHeight();\n        width = bmpOriginal.getWidth();\n        Bitmap bmpGrayscale = Bitmap.createBitmap(width, height,\n                Config.RGB_565);\n        Canvas c = new Canvas(bmpGrayscale);\n        Paint paint = new Paint();\n        ColorMatrix cm = new ColorMatrix();\n        cm.setSaturation(0);\n        ColorMatrixColorFilter f = new ColorMatrixColorFilter(cm);\n        paint.setColorFilter(f);\n        c.drawBitmap(bmpOriginal, 0, 0, paint);\n        return bmpGrayscale;\n    }\n\n    public static Bitmap replaceBitmapColor(Bitmap oldBitmap, int oldColor, int newColor) {\n        Bitmap mBitmap = oldBitmap.copy(Config.ARGB_8888, true);\n        int mBitmapWidth = mBitmap.getWidth();\n        int mBitmapHeight = mBitmap.getHeight();\n        for (int i = 0; i < mBitmapHeight; i++) {\n            for (int j = 0; j < mBitmapWidth; j++) {\n                int color = mBitmap.getPixel(j, i);\n                if (color == oldColor) {\n                    //将被替换色替换为需要替换成的颜色附近的值，都替换为相同的颜色略显单调\n                    mBitmap.setPixel(j, i, (int) (newColor + Math.random() * 100000));\n                }\n            }\n        }\n        return mBitmap;\n    }\n\n    /**\n     * 将图片 D65 转换 为位图\n     *\n     * @param bitmap 原来图片\n     * @return 新图片\n     */\n    public static Bitmap ImgaeToNegative(Bitmap bitmap) {\n        //其实我们获得宽和高就是图片像素的宽和高\n        //它们的乘积就是总共一张图片拥有的像素点数\n        int width = bitmap.getWidth();\n        int height = bitmap.getHeight();\n\n        Bitmap bmp = Bitmap.createBitmap(width, height, Config.ARGB_8888);\n        //用来存储旧的色素点的数组\n        int[] oldPx = new int[width * height];\n        //用来存储新的像素点的数组\n        int[] newPx = new int[width * height];\n        int color;//用来存储原来颜色值\n        int r, g, b, a;//存储颜色的四个分量：红，绿，蓝，透明度\n\n        //该方法用来将图片的像素写入到oldPx中，我们这样子设置，就会获取全部的像素点\n        //第一个参数为写入的数组，第二个参数为读取第一个的像素点的偏移量，一般设置为0\n        //第三个参数为写入时，多少个像素点作为一行,第三个和第四个参数为读取的起点坐标\n        //第五个参数表示读取的长度，第六个表示读取的高度\n        bitmap.getPixels(oldPx, 0, width, 0, 0, width, height);\n        // 存放 rgb\n        double[] rgbmap = new double[3];\n        //下面用循环来处理每一个像素点\n        long startTime = System.currentTimeMillis();\n        int index = 0;\n        for (int i = 0; i < width * height; i++) {\n            //获取一个原来的像素点\n            color = oldPx[i];\n            r = Color.red(color);\n            g = Color.green(color);\n            b = Color.blue(color);\n            a = Color.alpha(color);\n            rgbmap[0] = r;\n            rgbmap[1] = g;\n            rgbmap[2] = b;\n            // D65 光源 换算\n            double[] xyz = LabUtil.sRGB2XYZ(rgbmap);\n            double[] lab = LabUtil.XYZ2Lab(xyz);\n\n            double[] xyz2 = LabUtil.Lab2XYZ(lab);\n            double[] rgb = LabUtil.XYZ2sRGB(xyz2);\n\n            //下面计算生成新的颜色分量\n            r = (int) rgb[0];\n            g = (int) rgb[1];\n            b = (int) rgb[2];\n\n            if(rgbmap[0]!=r || rgbmap[1]!=g || rgbmap[2]!=b){\n                index ++;\n            }\n\n            //下面主要保证r g b 的值都必须在0~255之内\n            if (r > 255) {\n                r = 255;\n            } else if (r < 0) {\n                r = 0;\n            }\n            if (g > 255) {\n                g = 255;\n            } else if (g < 0) {\n                g = 0;\n            }\n            if (b > 255) {\n                b = 255;\n            } else if (b < 0) {\n                b = 0;\n            }\n            //下面合成新的像素点，并添加到newPx中\n            color = Color.argb(a, r, g, b);\n            newPx[i] = color;\n        }\n        //然后重要的一步，为bmp设置新颜色了,该方法中的参数意义与getPixels中的一样\n        //无非是将newPx写入到bmp中\n        bmp.setPixels(newPx, 0, width, 0, 0, width, height);\n        Log.e(\"camera2\", \"图片转换需要时间 ：\"+ (System.currentTimeMillis()-startTime)\n                +\" 修改次数：\"+ index);\n        return bmp;\n    }\n\n    /**\n     * 去色同时加圆角\n     *\n     * @param bmpOriginal 原图\n     * @param pixels      圆角弧度\n     * @return 修改后的图片\n     */\n    public static Bitmap toGrayscale(Bitmap bmpOriginal, int pixels) {\n        return toRoundCorner(toGrayscale(bmpOriginal), pixels);\n    }\n\n    /**\n     * 把图片变成圆角\n     *\n     * @param bitmap 需要修改的图片\n     * @param pixels 圆角的弧度\n     * @return 圆角图片\n     */\n    private static Bitmap toRoundCorner(Bitmap bitmap, int pixels) {\n\n        Bitmap output = Bitmap.createBitmap(bitmap.getWidth(),\n                bitmap.getHeight(), Config.ARGB_8888);\n        Canvas canvas = new Canvas(output);\n\n        final int color = 0xff424242;\n        final Paint paint = new Paint();\n        final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());\n        final RectF rectF = new RectF(rect);\n        final float roundPx = pixels;\n\n        paint.setAntiAlias(true);\n        canvas.drawARGB(0, 0, 0, 0);\n        paint.setColor(color);\n        canvas.drawRoundRect(rectF, roundPx, roundPx, paint);\n\n        paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));\n        canvas.drawBitmap(bitmap, rect, rect, paint);\n\n        return output;\n    }\n\n    /**\n     * 使圆角功能支持BitampDrawable\n     *\n     * @param bitmapDrawable bitmapDrawable\n     * @param pixels         pixels\n     * @return BitmapDrawable\n     */\n    @SuppressWarnings(\"deprecation\")\n    public static BitmapDrawable toRoundCorner(BitmapDrawable bitmapDrawable,\n                                               int pixels) {\n        Bitmap bitmap = bitmapDrawable.getBitmap();\n        bitmapDrawable = new BitmapDrawable(toRoundCorner(bitmap, pixels));\n        return bitmapDrawable;\n    }\n\n    /**\n     * 读取路径中的图片，然后将其转化为缩放后的bitmap返回\n     *\n     * @param path path\n     */\n    public static Bitmap saveBefore(String path) {\n        BitmapFactory.Options options = new BitmapFactory.Options();\n        options.inJustDecodeBounds = true;\n        // 获取这个图片的宽和高\n        Bitmap bitmap = BitmapFactory.decodeFile(path, options);\n        options.inJustDecodeBounds = false;\n        // 计算缩放比\n        int be = (int) (options.outHeight / (float) 200);\n        if (be <= 0)\n            be = 1;\n        options.inSampleSize = 2; // 图片长宽各缩小二分之一\n        // 重新读入图片，注意这次要把options.inJustDecodeBounds 设为 false哦\n        bitmap = BitmapFactory.decodeFile(path, options);\n        int w = bitmap.getWidth();\n        int h = bitmap.getHeight();\n        System.out.println(w + \"   \" + h);\n        // savePNG_After(bitmap,path);\n        saveJPGE_After(bitmap, path, 90);\n        return bitmap;\n    }\n\n    /**\n     * 将Bitmap转换成指定大小\n     *\n     * @param bitmap\n     * @param width\n     * @param height\n     * @return\n     */\n    public static Bitmap createBitmapBySize(Bitmap bitmap, int width, int height) {\n        return Bitmap.createScaledBitmap(bitmap, width, height, true);\n    }\n\n    // 图片按比例大小压缩方法\n    public static Bitmap getImageFromPath(String srcPath, float maxWidth, float maxHeight) {\n        /*if (!isFileAtPath(srcPath)) {\n            return null;\n        }*/\n        try {\n            BitmapFactory.Options newOpts = new BitmapFactory.Options();\n            // 开始读入图片，此时把options.inJustDecodeBounds 设回true了\n            newOpts.inJustDecodeBounds = true;\n            Bitmap bitmap = BitmapFactory.decodeFile(srcPath, newOpts);// 此时返回bm为空\n            newOpts.inJustDecodeBounds = false;\n            int w = newOpts.outWidth;\n            int h = newOpts.outHeight;\n            Log.d(\"getImageFromPath\", \"bSize:newOpts.out.w=\" + w + \" h=\" + h);\n\n            float aBili = (float) maxHeight / (float) maxWidth;\n            float bBili = (float) h / (float) w;\n            // be=1表示不缩放，be=2代表大小变成原来的1/2，注意be只能是2的次幂，即使算出的不是2的次幂，使用时也会自动转换成2的次幂\n            int be = 1;\n            if (aBili > bBili) {\n                if (w > maxWidth) {\n                    be = (int) (w / maxWidth);\n                }\n            } else {\n                if (h > maxHeight) {\n                    be = (int) (h / maxHeight);\n                }\n            }\n            if (be <= 1) {//如果是放大，则不放大\n                be = 1;\n            }\n            newOpts.inSampleSize = be;// 设置缩放比例\n            bitmap = BitmapFactory.decodeFile(srcPath, newOpts);\n\n            int degree = readPictureDegree(srcPath);\n            if (degree != 0) {\n                bitmap = rotaingImageView(degree, bitmap);\n            }\n            if (bitmap == null) {\n                return null;\n            }\n            return bitmap;\n        } catch (Exception e) {\n            return null;\n        }\n    }\n\n    public static Bitmap decodeBitmapFromResource(Resources res, int resId, int reqWidth, int reqHeight) {\n        BitmapFactory.Options options = new BitmapFactory.Options();\n        //可以只获取宽高而不加载\n        options.inJustDecodeBounds = true;\n        BitmapFactory.decodeResource(res, resId, options);\n\n        //计算压缩比例\n        options = calculateInSampleSize(options, reqWidth, reqHeight);\n        return BitmapFactory.decodeResource(res, resId, options);\n    }\n\n    /**\n     * 图片压缩处理（使用Options的方法）\n     *\n     * @param reqWidth  目标宽度\n     * @param reqHeight 目标高度\n     * @使用方法 首先你要将Options的inJustDecodeBounds属性设置为true，BitmapFactory.decode一次图片。\n     * 然后将Options连同期望的宽度和高度一起传递到到本方法中。\n     * 之后再使用本方法的返回值做参数调用BitmapFactory.decode创建图片。\n     * @explain BitmapFactory创建bitmap会尝试为已经构建的bitmap分配内存\n     * ，这时就会很容易导致OOM出现。为此每一种创建方法都提供了一个可选的Options参数\n     * ，将这个参数的inJustDecodeBounds属性设置为true就可以让解析方法禁止为bitmap分配内存\n     * ，返回值也不再是一个Bitmap对象， 而是null。虽然Bitmap是null了，但是Options的outWidth、\n     * outHeight和outMimeType属性都会被赋值。\n     */\n    public static BitmapFactory.Options calculateInSampleSize(\n            final BitmapFactory.Options options, int reqWidth, int reqHeight) {\n        // 源图片的高度和宽度\n        final int height = options.outHeight;\n        final int width = options.outWidth;\n        int inSampleSize = 1;\n        if (height > reqHeight || width > reqWidth) {\n            // 计算出实际宽高和目标宽高的比率\n            final int heightRatio = Math.round((float) height\n                    / (float) reqHeight);\n            final int widthRatio = Math.round((float) width / (float) reqWidth);\n            // 选择宽和高中最小的比率作为inSampleSize的值，这样可以保证最终图片的宽和高\n            // 一定都会大于等于目标的宽和高。\n            inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;\n        }\n        // 设置压缩比例\n        options.inSampleSize = inSampleSize;\n        options.inJustDecodeBounds = false;\n        return options;\n    }\n/*\n\n    public static BitmapFactory.Options createBitmap(BitmapFactory.Options options ,int bwidth, int bheight, int reqWidth, int reqHeight){\n        int inSampleSize = 1;\n        if (bheight > reqHeight || bwidth > reqWidth) {\n            // 计算出实际宽高和目标宽高的比率\n            final int heightRatio = Math.round((float) bheight\n                    / (float) reqHeight);\n            final int widthRatio = Math.round((float) bwidth / (float) reqWidth);\n            // 选择宽和高中最小的比率作为inSampleSize的值，这样可以保证最终图片的宽和高\n            // 一定都会大于等于目标的宽和高。\n            inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;\n        }\n        // 设置压缩比例\n        options.inSampleSize = inSampleSize;\n        options.inJustDecodeBounds = false;\n        return options;\n    }\n*/\n\n    //提取图像Alpha位图\n    public static Bitmap getAlphaBitmap(Bitmap mBitmap, int mColor) {\n        //BitmapDrawable的getIntrinsicWidth（）方法，Bitmap的getWidth（）方法\n        //注意这两个方法的区别\n        //Bitmap mAlphaBitmap = Bitmap.createBitmap(mBitmapDrawable.getIntrinsicWidth(), mBitmapDrawable.getIntrinsicHeight(), Config.ARGB_8888);\n        Bitmap mAlphaBitmap = Bitmap.createBitmap(mBitmap.getWidth(), mBitmap.getHeight(), Config.ARGB_8888);\n\n        Canvas mCanvas = new Canvas(mAlphaBitmap);\n        Paint mPaint = new Paint();\n\n        mPaint.setColor(mColor);\n        //从原位图中提取只包含alpha的位图\n        Bitmap alphaBitmap = mBitmap.extractAlpha();\n        //在画布上（mAlphaBitmap）绘制alpha位图\n        mCanvas.drawBitmap(alphaBitmap, 0, 0, mPaint);\n\n        return mAlphaBitmap;\n    }\n\n\n    /**\n     * 旋转 bitmap\n     *\n     * @param bmp bitmap\n     * @return 旋转后的 bitmap\n     */\n    public static Bitmap rotateMyBitmap(Bitmap bmp) {\n        //*****旋转一下\n        Matrix matrix = new Matrix();\n        matrix.postRotate(90);\n\n        Bitmap bitmap = Bitmap.createBitmap(bmp.getWidth(), bmp.getHeight(), Config.ARGB_8888);\n\n        Bitmap nbmp2 = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(), matrix, true);\n\n        return nbmp2;\n    }\n\n    /**\n     * 读取图片属性：旋转的角度\n     *\n     * @param path 图片绝对路径\n     * @return degree旋转的角度\n     */\n    public static int readPictureDegree(String path) {\n        int degree = 0;\n        try {\n            ExifInterface exifInterface = new ExifInterface(path);\n            int orientation = exifInterface.getAttributeInt(\n                    ExifInterface.TAG_ORIENTATION,\n                    ExifInterface.ORIENTATION_NORMAL);\n            switch (orientation) {\n                case ExifInterface.ORIENTATION_ROTATE_90:\n                    degree = 90;\n                    break;\n                case ExifInterface.ORIENTATION_ROTATE_180:\n                    degree = 180;\n                    break;\n                case ExifInterface.ORIENTATION_ROTATE_270:\n                    degree = 270;\n                    break;\n            }\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n        return degree;\n    }\n\n\n    /**\n     * 保存图片为PNG\n     *\n     * @param bitmap\n     * @param name\n     */\n    public static void savePNG_After(Bitmap bitmap, String name) {\n        File file = new File(name);\n        try {\n            FileOutputStream out = new FileOutputStream(file);\n            if (bitmap.compress(Bitmap.CompressFormat.PNG, 100, out)) {\n                out.flush();\n                out.close();\n            }\n        } catch (FileNotFoundException e) {\n            e.printStackTrace();\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n    }\n\n    /**\n     * 保存图片为JPEG\n     *\n     * @param bitmap\n     * @param path\n     */\n    public static boolean saveJPGE_After(Bitmap bitmap, String path, int quality) {\n        File file = new File(path);\n        makeDir(file);\n        try {\n            FileOutputStream out = new FileOutputStream(file);\n            if (bitmap.compress(Bitmap.CompressFormat.JPEG, quality, out)) {\n                out.flush();\n                out.close();\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n            return false;\n        }\n        return true;\n    }\n\n    /**\n     * 保存图片为JPEG\n     *\n     * @param bitmap\n     * @param path\n     */\n    public static void saveJPGE_After(Context context, Bitmap bitmap, String path, int quality) {\n        File file = new File(path);\n        makeDir(file);\n        try {\n            FileOutputStream out = new FileOutputStream(file);\n            if (bitmap.compress(Bitmap.CompressFormat.JPEG, quality, out)) {\n                out.flush();\n                out.close();\n            }\n            updateResources(context, file.getPath());\n        } catch (FileNotFoundException e) {\n            e.printStackTrace();\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n    }\n\n    /**\n     * 保存图片为PNG\n     *\n     * @param bitmap\n     * @param path\n     */\n    public static void saveJPGE_After_PNG(Context context, Bitmap bitmap, String path, int quality) {\n        File file = new File(path);\n        makeDir(file);\n        try {\n            FileOutputStream out = new FileOutputStream(file);\n            if (bitmap.compress(Bitmap.CompressFormat.PNG, quality, out)) {\n                out.flush();\n                out.close();\n            }\n            updateResources(context, file.getPath());\n        } catch (FileNotFoundException e) {\n            e.printStackTrace();\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n    }\n\n    /**\n     * 保存图片为PNG\n     *\n     * @param bitmap\n     * @param path\n     */\n    public static void saveJPGE_After_WebP(Context context, Bitmap bitmap, String path, int quality) {\n        File file = new File(path);\n        makeDir(file);\n        try {\n            FileOutputStream out = new FileOutputStream(file);\n            if (bitmap.compress(Bitmap.CompressFormat.WEBP, quality, out)) {\n                out.flush();\n                out.close();\n            }\n            updateResources(context, file.getPath());\n        } catch (FileNotFoundException e) {\n            e.printStackTrace();\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n    }\n\n    private static void makeDir(File file) {\n        File tempPath = new File(file.getParent());\n        if (!tempPath.exists()) {\n            tempPath.mkdirs();\n        }\n    }\n\n    /**\n     * 图片合成\n     *\n     * @param src\n     * @param watermark\n     * @return\n     */\n    public static Bitmap createBitmap(Bitmap src, Bitmap watermark) {\n        if (src == null) {\n            return null;\n        }\n        int w = src.getWidth();\n        int h = src.getHeight();\n        int ww = watermark.getWidth();\n        int wh = watermark.getHeight();\n        // create the new blank bitmap\n        Bitmap newb = Bitmap.createBitmap(w, h, Config.ARGB_8888);// 创建一个新的和SRC长度宽度一样的位图\n        Canvas cv = new Canvas(newb);\n        // draw src into\n        cv.drawBitmap(src, 0, 0, null);// 在 0，0坐标开始画入src\n        // draw watermark into\n        cv.drawBitmap(watermark, w - ww + 5, h - wh + 5, null);// 在src的右下角画入水印\n        // save all clip\n        cv.save(Canvas.ALL_SAVE_FLAG);// 保存\n        // store\n        cv.restore();// 存储\n        return newb;\n    }\n\n    /**\n     * Bitmap 转 Drawable\n     *\n     * @param bitmap\n     * @return\n     */\n    public static Drawable bitmapToDrawableByBD(Bitmap bitmap) {\n        @SuppressWarnings(\"deprecation\")\n        Drawable drawable = new BitmapDrawable(bitmap);\n        return drawable;\n    }\n\n    /**\n     * 将图片转换成byte[]以便能将其存到数据库\n     */\n    public static byte[] getByteFromBitmap(Bitmap bitmap) {\n        ByteArrayOutputStream out = new ByteArrayOutputStream();\n        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out);\n        try {\n            out.flush();\n            out.close();\n        } catch (IOException e) {\n            e.printStackTrace();\n            // Log.e(TAG, \"transform byte exception\");\n        }\n        return out.toByteArray();\n    }\n\n    /**\n     * 将数据库中的二进制图片转换成位图\n     *\n     * @param temp\n     * @return\n     */\n    public static Bitmap getBitmapFromByte(byte[] temp) {\n        if (temp != null) {\n            Bitmap bitmap = BitmapFactory.decodeByteArray(temp, 0, temp.length);\n            return bitmap;\n        } else {\n            // Bitmap bitmap=BitmapFactory.decodeResource(getResources(),\n            // R.drawable.contact_add_icon);\n            return null;\n        }\n    }\n\n    /**\n     * 将手机中的文件转换为Bitmap类型\n     *\n     * @param f\n     * @return\n     */\n    public static Bitmap getBitemapFromFile(File f) {\n        if (!f.exists())\n            return null;\n        try {\n            return BitmapFactory.decodeFile(f.getAbsolutePath());\n        } catch (Exception ex) {\n            return null;\n        }\n    }\n\n    /**\n     * 镜像水平翻转\n     *\n     * @param bmp\n     * @return\n     */\n    public Bitmap convertMirrorBmp(Bitmap bmp) {\n        int w = bmp.getWidth();\n        int h = bmp.getHeight();\n\n        Matrix matrix = new Matrix();\n        matrix.postScale(-1, 1); // 镜像水平翻转\n        Bitmap convertBmp = Bitmap.createBitmap(bmp, 0, 0, w, h, matrix, true);\n\n        return convertBmp;\n    }\n\n    /**\n     * 垂直翻转\n     *\n     * @param bmp\n     * @return\n     */\n    public static Bitmap convertVertical(Bitmap bmp) {\n        int w = bmp.getWidth();\n        int h = bmp.getHeight();\n\n        Matrix matrix = new Matrix();\n        matrix.postScale(1, -1); // 镜像垂直翻转\n        Bitmap convertBmp = Bitmap.createBitmap(bmp, 0, 0, w, h, matrix, true);\n\n        return convertBmp;\n    }\n\n    /**\n     * 将手机中的文件转换为Bitmap类型\n     *\n     * @param path 期望宽高\n     * @return\n     */\n    public static Bitmap decodeFile(String path, int screenWidth, int screenHeight) {\n        Bitmap bm = null;\n        BitmapFactory.Options opt = new BitmapFactory.Options();\n        //这个isjustdecodebounds很重要\n        opt.inJustDecodeBounds = true;\n        bm = BitmapFactory.decodeFile(path, opt);\n\n        //获取到这个图片的原始宽度和高度\n        int picWidth = opt.outWidth;\n        int picHeight = opt.outHeight;\n\n        //isSampleSize是表示对图片的缩放程度，比如值为2图片的宽度和高度都变为以前的1/2\n        opt.inSampleSize = 1;\n        //根据屏的大小和图片大小计算出缩放比例\n        if (picWidth > picHeight) {\n            if (picWidth > screenWidth) {\n                opt.inSampleSize = picWidth / screenWidth;\n            }\n        } else {\n            if (picHeight > screenHeight) {\n                opt.inSampleSize = picHeight / screenHeight;\n            }\n        }\n\n        //这次再真正地生成一个有像素的，经过缩放了的bitmap\n        opt.inJustDecodeBounds = false;\n        bm = BitmapFactory.decodeFile(path, opt);\n        return bm;\n    }\n\n    /**\n     * 把资源图片转换成Bitmap\n     *\n     * @param drawable 资源图片\n     * @return 位图\n     */\n    public static Bitmap getBitmapFromDrawable(Drawable drawable) {\n        int width = drawable.getBounds().width();\n        int height = drawable.getBounds().height();\n        Bitmap bitmap = Bitmap.createBitmap(width, height, drawable\n                .getOpacity() != PixelFormat.OPAQUE ? Config.ARGB_8888\n                : Config.RGB_565);\n        Canvas canvas = new Canvas(bitmap);\n        drawable.setBounds(0, 0, width, height);\n        drawable.draw(canvas);\n        return bitmap;\n    }\n\n\n    /**\n     * <<<<<<< HEAD\n     * 翻转\n     *\n     * @param bitmap\n     * @return\n     */\n    public static Bitmap flip(Bitmap bitmap) {\n        // 点中了翻转\n        Matrix m = new Matrix();\n        m.postScale(-1, 1);\n        bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), m, true);\n        return bitmap;\n    }\n\n    /**\n     * view turnto bitmap\n     * =======\n     * 将View转为Bitmap\n     * >>>>>>> master\n     *\n     * @param view\n     * @return\n     */\n    public static Bitmap getViewBitmap(View view) {\n        view.clearFocus(); // 清除视图焦点\n        view.setPressed(false);// 将视图设为不可点击\n\n        boolean willNotCache = view.willNotCacheDrawing();// 返回视图是否可以保存他的画图缓存\n        view.setWillNotCacheDrawing(false);\n\n        // Reset the drawing cache background color to fully transparent\n        // for the duration of this operation //将视图在此操作时置为透明\n        int color = view.getDrawingCacheBackgroundColor();// 获得绘制缓存位图的背景颜色\n        view.setDrawingCacheBackgroundColor(0);// 设置绘图背景颜色\n\n        if (color != 0) {// 如果获得的背景不是黑色的则释放以前的绘图缓存\n            view.destroyDrawingCache();// 释放绘图资源所使用的缓存\n        }\n        view.buildDrawingCache();// 重新创建绘图缓存，此时的背景色是黑色\n        Bitmap cacheBitmap = view.getDrawingCache();// 将绘图缓存得到的,注意这里得到的只是一个图像的引用\n        if (cacheBitmap == null) {\n            return null;\n        }\n\n        Bitmap bitmap = null;\n        try {\n            bitmap = Bitmap.createBitmap(cacheBitmap);// 将位图实例化\n\n        } catch (OutOfMemoryError e) {\n            while (bitmap == null) {\n                System.gc();\n                System.runFinalization();\n                bitmap = Bitmap.createBitmap(cacheBitmap);// 将位图实例化\n            }\n        }\n\n\n        view.destroyDrawingCache();// Restore the view //恢复视图\n        view.setWillNotCacheDrawing(willNotCache);// 返回以前缓存设置\n        view.setDrawingCacheBackgroundColor(color);// 返回以前的缓存颜色设置\n\n        return bitmap;\n    }\n\n\n    /**\n     * 将View转为Bitmap\n     *\n     * @param view\n     * @return\n     */\n    public static Bitmap convertViewToBitmap(View view) {\n        view.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),\n                View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));\n        view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());\n        view.buildDrawingCache();\n        Bitmap bitmap = view.getDrawingCache();\n        return bitmap;\n    }\n\n    /**\n     * 将View转为Bitmap\n     *\n     * @param view\n     * @return\n     */\n    public static Bitmap getBitmapFromView(View view) {\n        view.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);\n        Bitmap bitmap = Bitmap.createBitmap(view.getMeasuredWidth(), view.getMeasuredHeight(),\n                Config.ARGB_8888);\n        Canvas canvas = new Canvas(bitmap);\n        view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());\n        view.draw(canvas);\n        return bitmap;\n    }\n\n    public static void updateResources(Context context, String path) {\n        MediaScannerConnection.scanFile(context, new String[]{path}, null, null);\n    }\n\n    public static Bitmap returnSaturationBitmap(Context context, Bitmap bitmap, int screenWidth, int screenHeight) {\n        Bitmap bmp = null;\n/*\n        int maxWidth = MyApplication.getInstance().getScreenWidth() - SystemUtils.dp2px(context, 20);\n        int maxHeight = maxWidth * 4 / 3;*/\n\n        //  - SystemUtils.dp2px(context, 20)\n        int reqWidth = screenWidth;\n        int reqHeight = reqWidth * 4 / 3;\n\n        bmp = createBitmap(bitmap, reqWidth, reqHeight);\n\n        ColorMatrix cMatrix = new ColorMatrix();\n        // 设置饱和度\n        cMatrix.setSaturation(0.0f);\n\n        Paint paint = new Paint();\n        paint.setColorFilter(new ColorMatrixColorFilter(cMatrix));\n\n        Canvas canvas = new Canvas(bmp);\n        // 在Canvas上绘制一个已经存在的Bitmap。这样，dstBitmap就和srcBitmap一摸一样了\n        canvas.drawBitmap(bitmap, 0, 0, paint);\n        return bmp;\n    }\n\n    /**\n     * 创建期望大小的bitmap\n     *\n     * @param bitmap\n     * @param reqWidth\n     * @return\n     */\n    public static Bitmap createBitmap(Bitmap bitmap, int reqWidth, int reqHeight) {\n        Bitmap bmp = null;\n        int inSampleSize = 0;\n\n        int bWidth = bitmap.getWidth();\n        int bHeight = bitmap.getHeight();\n\n        if (bHeight > reqHeight || bWidth > reqWidth) {\n            // 计算出实际宽高和目标宽高的比率\n            final int heightRatio = Math.round((float) bHeight\n                    / (float) reqHeight);\n            final int widthRatio = Math.round((float) bWidth / (float) reqWidth);\n            // 选择宽和高中最小的比率作为inSampleSize的值，这样可以保证最终图片的宽和高\n            // 一定都会大于等于目标的宽和高。\n            inSampleSize = heightRatio < widthRatio ? widthRatio : heightRatio;\n        }\n        try {\n            if (inSampleSize != 0) {\n                bmp = Bitmap.createBitmap(bWidth / inSampleSize, bHeight / inSampleSize, Config.ARGB_8888);\n            } else {\n                bmp = Bitmap.createBitmap(bWidth, bHeight, Config.ARGB_8888);\n            }\n        } catch (OutOfMemoryError e) {\n            e.printStackTrace();\n            while (bmp == null) {\n                System.gc();\n                System.runFinalization();\n                if (inSampleSize != 0) {\n                    bmp = Bitmap.createBitmap(bWidth / inSampleSize, bHeight / inSampleSize, Config.ARGB_8888);\n                } else {\n                    bmp = Bitmap.createBitmap(bWidth, bHeight, Config.ARGB_8888);\n                }\n            }\n        }\n\n        return bmp;\n    }\n\n    /**\n     * 圆形Bitmap\n     *\n     * @param bitmap\n     * @return\n     */\n    public static Bitmap getRoundedCornerBitmap(Bitmap bitmap) {\n        Bitmap outBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Config.ARGB_8888);\n        Canvas canvas = new Canvas(outBitmap);\n        final int color = 0xff424242;\n        final Paint paint = new Paint();\n        final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());\n        final RectF rectF = new RectF(rect);\n        final float roundPX = bitmap.getWidth() / 2;\n        paint.setAntiAlias(true);\n        canvas.drawARGB(0, 0, 0, 0);\n        paint.setColor(color);\n        canvas.drawRoundRect(rectF, roundPX, roundPX, paint);\n        paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));\n        canvas.drawBitmap(bitmap, rect, rect, paint);\n        return outBitmap;\n    }\n\n    /**\n     * 改变bitmap 对比度\n     *\n     * @param bitmap\n     * @param progress\n     * @return\n     */\n    public static Bitmap returnContrastBitmap(Bitmap bitmap, int progress) {\n        //曝光度\n        Bitmap contrast_bmp = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(),\n                Config.ARGB_8888);\n        // int brightness = progress - 127;\n        float contrast = (float) ((progress + 64) / 128.0);\n        ColorMatrix contrast_cMatrix = new ColorMatrix();\n        contrast_cMatrix.set(new float[]{contrast, 0, 0, 0, 0, 0,\n                contrast, 0, 0, 0,// 改变对比度\n                0, 0, contrast, 0, 0, 0, 0, 0, 1, 0});\n\n        Paint contrast_paint = new Paint();\n        contrast_paint.setColorFilter(new ColorMatrixColorFilter(contrast_cMatrix));\n\n        Canvas contrast_canvas = new Canvas(contrast_bmp);\n        // 在Canvas上绘制一个已经存在的Bitmap。这样，dstBitmap就和srcBitmap一摸一样了\n        contrast_canvas.drawBitmap(bitmap, 0, 0, contrast_paint);\n\n        return contrast_bmp;\n    }\n\n}"
  },
  {
    "path": "app/src/main/java/camera/cn/cameramaster/util/Camera2Util.java",
    "content": "package camera.cn.cameramaster.util;\n\nimport android.graphics.ImageFormat;\nimport android.media.Image;\nimport android.os.Build;\nimport android.support.annotation.RequiresApi;\nimport android.util.Log;\n\nimport java.nio.ByteBuffer;\n\n/**\n * camera2 中 yuv 420 格式图片 转为 rgb 图片\n *\n * @packageName: cn.tongue.tonguecamera.util\n * @fileName: Camera2Util\n * @date: 2019/3/13  13:37\n * @author: ymc\n * @QQ:745612618\n */\n\npublic class Camera2Util {\n\n    public static final int YUV420P = 0;\n    public static final int YUV420SP = 1;\n    public static final int NV21 = 2;\n    private static final String TAG = \"Camera2Util\";\n\n    /***\n     * 此方法内注释以640*480为例\n     * 未考虑CropRect的\n     */\n    @RequiresApi(api = Build.VERSION_CODES.KITKAT)\n    public static byte[] getBytesFromImageAsType(Image image, int type) {\n        try {\n            //获取源数据，如果是YUV格式的数据planes.length = 3\n            //plane[i]里面的实际数据可能存在byte[].length <= capacity (缓冲区总大小)\n            final Image.Plane[] planes = image.getPlanes();\n            //数据有效宽度，一般的，图片width <= rowStride，这也是导致byte[].length <= capacity的原因\n            // 所以我们只取width部分\n            int width = image.getWidth();\n            int height = image.getHeight();\n\n            //此处用来装填最终的YUV数据，需要1.5倍的图片大小，因为Y U V 比例为 4:1:1\n            byte[] yuvBytes = new byte[width * height * ImageFormat.getBitsPerPixel(ImageFormat.YUV_420_888) / 8];\n            //目标数组的装填到的位置\n            int dstIndex = 0;\n\n            //临时存储uv数据的\n            byte uBytes[] = new byte[width * height / 4];\n            byte vBytes[] = new byte[width * height / 4];\n            int uIndex = 0;\n            int vIndex = 0;\n\n            int pixelsStride, rowStride;\n            for (int i = 0; i < planes.length; i++) {\n                pixelsStride = planes[i].getPixelStride();\n                rowStride = planes[i].getRowStride();\n\n                ByteBuffer buffer = planes[i].getBuffer();\n\n                //如果pixelsStride==2，一般的Y的buffer长度=640*480，UV的长度=640*480/2-1\n                //源数据的索引，y的数据是byte中连续的，u的数据是v向左移以为生成的，两者都是偶数位为有效数据\n                byte[] bytes = new byte[buffer.capacity()];\n                buffer.get(bytes);\n\n                int srcIndex = 0;\n                if (i == 0) {\n                    //直接取出来所有Y的有效区域，也可以存储成一个临时的bytes，到下一步再copy\n                    for (int j = 0; j < height; j++) {\n                        System.arraycopy(bytes, srcIndex, yuvBytes, dstIndex, width);\n                        srcIndex += rowStride;\n                        dstIndex += width;\n                    }\n                } else if (i == 1) {\n                    //根据pixelsStride取相应的数据\n                    for (int j = 0; j < height / 2; j++) {\n                        for (int k = 0; k < width / 2; k++) {\n                            uBytes[uIndex++] = bytes[srcIndex];\n                            srcIndex += pixelsStride;\n                        }\n                        if (pixelsStride == 2) {\n                            srcIndex += rowStride - width;\n                        } else if (pixelsStride == 1) {\n                            srcIndex += rowStride - width / 2;\n                        }\n                    }\n                } else if (i == 2) {\n                    //根据pixelsStride取相应的数据\n                    for (int j = 0; j < height / 2; j++) {\n                        for (int k = 0; k < width / 2; k++) {\n                            vBytes[vIndex++] = bytes[srcIndex];\n                            srcIndex += pixelsStride;\n                        }\n                        if (pixelsStride == 2) {\n                            srcIndex += rowStride - width;\n                        } else if (pixelsStride == 1) {\n                            srcIndex += rowStride - width / 2;\n                        }\n                    }\n                }\n            }\n            //   image.close();\n            //根据要求的结果类型进行填充\n            switch (type) {\n                case YUV420P:\n                    System.arraycopy(uBytes, 0, yuvBytes, dstIndex, uBytes.length);\n                    System.arraycopy(vBytes, 0, yuvBytes, dstIndex + uBytes.length, vBytes.length);\n                    break;\n                case YUV420SP:\n                    for (int i = 0; i < vBytes.length; i++) {\n                        yuvBytes[dstIndex++] = uBytes[i];\n                        yuvBytes[dstIndex++] = vBytes[i];\n                    }\n                    break;\n                case NV21:\n                    for (int i = 0; i < vBytes.length; i++) {\n                        yuvBytes[dstIndex++] = vBytes[i];\n                        yuvBytes[dstIndex++] = uBytes[i];\n                    }\n                    break;\n            }\n            return yuvBytes;\n        } catch (final Exception e) {\n            if (image != null) {\n                image.close();\n            }\n            Log.i(TAG, e.toString());\n        }\n        return null;\n    }\n\n    /***\n     * YUV420 转化成 RGB\n     */\n    public static int[] decodeYUV420SP(byte[] yuv420sp, int width, int height) {\n        final int frameSize = width * height;\n        int rgb[] = new int[frameSize];\n        for (int j = 0, yp = 0; j < height; j++) {\n            int uvp = frameSize + (j >> 1) * width, u = 0, v = 0;\n            for (int i = 0; i < width; i++, yp++) {\n                int y = (0xff & ((int) yuv420sp[yp])) - 16;\n                if (y < 0) {\n                    y = 0;\n                }\n                if ((i & 1) == 0) {\n                    v = (0xff & yuv420sp[uvp++]) - 128;\n                    u = (0xff & yuv420sp[uvp++]) - 128;\n                }\n                int y1192 = 1192 * y;\n                int r = (y1192 + 1634 * v);\n                int g = (y1192 - 833 * v - 400 * u);\n                int b = (y1192 + 2066 * u);\n                if (r < 0) {\n                    r = 0;\n                } else if (r > 262143) {\n                    r = 262143;\n                }\n                if (g < 0) {\n                    g = 0;\n                } else if (g > 262143) {\n                    g = 262143;\n                }\n                if (b < 0) {\n                    b = 0;\n                } else if (b > 262143) {\n                    b = 262143;\n                }\n                rgb[yp] = 0xff000000 | ((r << 6) & 0xff0000)\n                        | ((g >> 2) & 0xff00) | ((b >> 10) & 0xff);\n            }\n        }\n        return rgb;\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/camera/cn/cameramaster/util/CameraUtil.java",
    "content": "package camera.cn.cameramaster.util;\n\nimport android.app.Activity;\nimport android.graphics.Bitmap;\nimport android.graphics.Matrix;\nimport android.hardware.Camera;\nimport android.hardware.Camera.Size;\nimport android.util.Log;\nimport android.view.Surface;\n\nimport java.util.Collections;\nimport java.util.Comparator;\nimport java.util.List;\n\n\n/**\n * 拍照工具类\n */\npublic class CameraUtil {\n    private static final String TAG = \"CameraUtil\";\n    /**\n     * 降序\n     */\n    private CameraDropSizeComparator dropSizeComparator = new CameraDropSizeComparator();\n    /**\n     * 升序\n     */\n    private CameraAscendSizeComparator ascendSizeComparator = new CameraAscendSizeComparator();\n    private static CameraUtil instance = null;\n\n\n    private CameraUtil() {\n\n    }\n\n    public static CameraUtil getInstance() {\n        if (instance == null) {\n            instance = new CameraUtil();\n            return instance;\n        } else {\n            return instance;\n        }\n    }\n\n    private int getRecorderRotation(int cameraId) {\n        Camera.CameraInfo info =\n                new Camera.CameraInfo();\n        Camera.getCameraInfo(cameraId, info);\n        return info.orientation;\n    }\n\n    /**\n     * 获取所有支持的返回视频尺寸\n     *\n     * @param list      list\n     * @param minHeight minHeight\n     * @return Size\n     */\n    private Size getPropVideoSize(List<Size> list, int minHeight) {\n        Collections.sort(list, ascendSizeComparator);\n\n        int i = 0;\n        for (Size s : list) {\n            if ((s.height >= minHeight)) {\n                break;\n            }\n            i++;\n        }\n        if (i == list.size()) {\n            i = 0;\n        }\n        return list.get(i);\n    }\n\n    /**\n     * 保证预览方向正确\n     *\n     * @param activity activity\n     * @param cameraId cameraId\n     * @param camera   camera\n     */\n    public void setCameraDisplayOrientation(Activity activity,\n                                             int cameraId, Camera camera) {\n        Camera.CameraInfo info =\n                new Camera.CameraInfo();\n        Camera.getCameraInfo(cameraId, info);\n        int rotation = activity.getWindowManager().getDefaultDisplay()\n                .getRotation();\n        int degrees = 0;\n        switch (rotation) {\n            case Surface.ROTATION_0:\n                degrees = 0;\n                break;\n            case Surface.ROTATION_90:\n                degrees = 90;\n                break;\n            case Surface.ROTATION_180:\n                degrees = 180;\n                break;\n            case Surface.ROTATION_270:\n                degrees = 270;\n                break;\n            default:\n                break;\n        }\n        int result;\n        if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {\n            result = (info.orientation + degrees) % 360;\n            result = (360 - result) % 360;\n        } else {\n            result = (info.orientation - degrees + 360) % 360;\n        }\n        //设置角度\n        camera.setDisplayOrientation(result);\n    }\n\n\n    public Bitmap setTakePicktrueOrientation(int id, Bitmap bitmap) {\n        Camera.CameraInfo info = new Camera.CameraInfo();\n        Camera.getCameraInfo(id, info);\n        bitmap = rotaingImageView(id, info.orientation, bitmap);\n        return bitmap;\n    }\n\n    /**\n     * 把相机拍照返回照片转正\n     *\n     * @param angle 旋转角度\n     * @return bitmap 图片\n     */\n    private Bitmap rotaingImageView(int id, int angle, Bitmap bitmap) {\n        //矩阵\n        Matrix matrix = new Matrix();\n        matrix.postRotate(angle);\n        //加入翻转 把相机拍照返回照片转正\n        if (id == 1) {\n            matrix.postScale(-1, 1);\n        }\n        // 创建新的图片\n        Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0,\n                bitmap.getWidth(), bitmap.getHeight(), matrix, true);\n        return resizedBitmap;\n    }\n\n    /**\n     * 获取所有支持的预览尺寸\n     *\n     * @param list     list\n     * @param minWidth minWidth\n     * @return Size\n     */\n    private Size getPropPreviewSize(List<Size> list, int minWidth) {\n        Collections.sort(list, ascendSizeComparator);\n\n        int i = 0;\n        for (Size s : list) {\n            if ((s.width >= minWidth)) {\n                break;\n            }\n            i++;\n        }\n        if (i == list.size()) {\n            i = 0;\n        }\n        return list.get(i);\n    }\n\n    /**\n     * 获取所有支持的返回图片尺寸\n     *\n     * @param list     list\n     * @param minWidth minWidth\n     * @return Size\n     */\n    private Size getPropPictureSize(List<Size> list, int minWidth) {\n        Collections.sort(list, ascendSizeComparator);\n        int i = 0;\n        for (Size s : list) {\n            if ((s.width >= minWidth)) {\n                break;\n            }\n            i++;\n        }\n        if (i == list.size()) {\n            i = 0;\n        }\n        return list.get(i);\n    }\n\n    /**\n     * 获取所有支持的返回视频尺寸\n     *\n     * @param list      list\n     * @param minHeight minHeight\n     * @return Size\n     */\n    public Size getPropSizeForHeight(List<Size> list, int minHeight) {\n        Collections.sort(list, ascendSizeComparator);\n        int i = 0;\n        for (Size s : list) {\n            if ((s.height >= minHeight)) {\n                Log.e(TAG, \"getPropSizeForHeight: s.height=\" + s.height);\n                break;\n            }\n            i++;\n        }\n        if (i == list.size()) {\n            i = list.size();\n        }\n        return list.get(i);\n    }\n\n    /**\n     * 根据 宽度和高度找到是否有相等的 尺寸  如果没有 就获取最小的 值\n     * @param list list\n     * @param th 高度\n     * @param minWidth 宽度\n     * @return size\n     */\n    public  Size getPicPreviewSize(List<Size> list, int th, int minWidth){\n        Collections.sort(list, ascendSizeComparator);\n\n        int i = 0;\n        for(int x=0;x<list.size();x++){\n            Size s = list.get(x);\n            // camera 中的宽度和高度 相反 因为测试板子原因 这里暂时 替换 && 为 ||\n            if((s.width == th) && (s.height == minWidth)){\n                i = x;\n                break;\n            }\n        }\n        //如果没找到，就选最小的size 0\n        return list.get(i);\n    }\n\n    public Size getPropPictureSize(List<Size> list, float th, int minWidth){\n        Collections.sort(list, ascendSizeComparator);\n\n        int i = 0;\n        for(Size s:list){\n            if((s.width >= minWidth) && equalRate(s, th)){\n                Log.i(TAG, \"PictureSize : w = \" + s.width + \"h = \" + s.height);\n                break;\n            }\n            i++;\n        }\n        if(i == list.size()){\n            i = 0;//如果没找到，就选最小的size\n        }\n        return list.get(i);\n    }\n\n    /**\n     * 升序 按照高度\n     */\n    private class CameraAscendSizeComparatorForHeight implements Comparator<Size> {\n        @Override\n        public int compare(Size lhs, Size rhs) {\n            if (lhs.height == rhs.height) {\n                return 0;\n            } else if (lhs.height > rhs.height) {\n                return 1;\n            } else {\n                return -1;\n            }\n        }\n    }\n\n    private boolean equalRate(Size s, float rate) {\n        float r = (float) (s.width) / (float) (s.height);\n        return Math.abs(r - rate) <= 0.03;\n    }\n\n    /**\n     * 降序\n     */\n    private class CameraDropSizeComparator implements Comparator<Size> {\n        @Override\n        public int compare(Size lhs, Size rhs) {\n            if (lhs.width == rhs.width) {\n                return 0;\n            } else if (lhs.width < rhs.width) {\n                return 1;\n            } else {\n                return -1;\n            }\n        }\n    }\n\n    /**\n     * 升序\n     */\n    private class CameraAscendSizeComparator implements Comparator<Size> {\n        @Override\n        public int compare(Size lhs, Size rhs) {\n            if (lhs.width == rhs.width) {\n                return 0;\n            } else if (lhs.width > rhs.width) {\n                return 1;\n            } else {\n                return -1;\n            }\n        }\n    }\n\n    /**\n     * 打印支持的previewSizes\n     *\n     * @param params\n     */\n    private void printSupportPreviewSize(Camera.Parameters params) {\n        List<Size> previewSizes = params.getSupportedPreviewSizes();\n        for (int i = 0; i < previewSizes.size(); i++) {\n            Size size = previewSizes.get(i);\n        }\n\n    }\n\n    /**\n     * 打印支持的pictureSizes\n     *\n     * @param params\n     */\n    private void printSupportPictureSize(Camera.Parameters params) {\n        List<Size> pictureSizes = params.getSupportedPictureSizes();\n        for (int i = 0; i < pictureSizes.size(); i++) {\n            Size size = pictureSizes.get(i);\n        }\n    }\n\n    /**\n     * 打印支持的聚焦模式\n     *\n     * @param params params\n     */\n    private void printSupportFocusMode(Camera.Parameters params) {\n        List<String> focusModes = params.getSupportedFocusModes();\n        for (String mode : focusModes) {\n            Log.e(TAG, \"printSupportFocusMode: \" + mode);\n        }\n    }\n\n    /**\n     * 打开闪关灯\n     *\n     * @param mCamera mCamera\n     */\n    public void turnLightOn(Camera mCamera) {\n        if (mCamera == null) {\n            return;\n        }\n        Camera.Parameters parameters = mCamera.getParameters();\n        if (parameters == null) {\n            return;\n        }\n        List<String> flashModes = parameters.getSupportedFlashModes();\n        if (flashModes == null) {\n            return;\n        }\n        String flashMode = parameters.getFlashMode();\n        if (!Camera.Parameters.FLASH_MODE_ON.equals(flashMode)) {\n            // Turn on the flash\n            if (flashModes.contains(Camera.Parameters.FLASH_MODE_TORCH)) {\n                parameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);\n                mCamera.setParameters(parameters);\n            }\n        }\n    }\n\n    /**\n     * 自动模式闪光灯\n     *\n     * @param mCamera mCamera\n     */\n    public void turnLightAuto(Camera mCamera) {\n        if (mCamera == null) {\n            return;\n        }\n        Camera.Parameters parameters = mCamera.getParameters();\n        if (parameters == null) {\n            return;\n        }\n        List<String> flashModes = parameters.getSupportedFlashModes();\n        if (flashModes == null) {\n            return;\n        }\n        String flashMode = parameters.getFlashMode();\n        if (!Camera.Parameters.FLASH_MODE_AUTO.equals(flashMode)) {\n            // Turn on the flash\n            if (flashModes.contains(Camera.Parameters.FLASH_MODE_TORCH)) {\n                parameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);\n                mCamera.setParameters(parameters);\n            }\n        }\n    }\n\n    /**\n     * 关闭闪光灯\n     *\n     * @param mCamera mCamera\n     */\n    public void turnLightOff(Camera mCamera) {\n        if (mCamera == null) {\n            return;\n        }\n        Camera.Parameters parameters = mCamera.getParameters();\n        if (parameters == null) {\n            return;\n        }\n        List<String> flashModes = parameters.getSupportedFlashModes();\n        String flashMode = parameters.getFlashMode();\n        if (flashModes == null) {\n            return;\n        }\n        if (!Camera.Parameters.FLASH_MODE_OFF.equals(flashMode)) {\n            if (flashModes.contains(Camera.Parameters.FLASH_MODE_TORCH)) {\n                parameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);\n                mCamera.setParameters(parameters);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/camera/cn/cameramaster/util/CameraV2.java",
    "content": "package camera.cn.cameramaster.util;\n\nimport android.Manifest;\nimport android.app.Activity;\nimport android.content.Context;\nimport android.content.pm.PackageManager;\nimport android.graphics.ImageFormat;\nimport android.graphics.Point;\nimport android.graphics.SurfaceTexture;\nimport android.hardware.camera2.CameraAccessException;\nimport android.hardware.camera2.CameraCaptureSession;\nimport android.hardware.camera2.CameraCharacteristics;\nimport android.hardware.camera2.CameraDevice;\nimport android.hardware.camera2.CameraManager;\nimport android.hardware.camera2.CameraMetadata;\nimport android.hardware.camera2.CaptureRequest;\nimport android.hardware.camera2.CaptureResult;\nimport android.hardware.camera2.TotalCaptureResult;\nimport android.hardware.camera2.params.StreamConfigurationMap;\nimport android.media.Image;\nimport android.media.ImageReader;\nimport android.os.Build;\nimport android.os.Handler;\nimport android.os.HandlerThread;\nimport android.support.annotation.NonNull;\nimport android.support.annotation.RequiresApi;\nimport android.support.v4.app.ActivityCompat;\nimport android.util.Log;\nimport android.util.Size;\nimport android.util.SparseIntArray;\nimport android.view.Surface;\nimport android.widget.Toast;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.Comparator;\nimport java.util.List;\nimport java.util.concurrent.Semaphore;\nimport java.util.concurrent.TimeUnit;\n\nimport camera.cn.cameramaster.view.CameraV2GLSurfaceView;\n\n\n/**\n * camera2 拍照工具类\n *\n * 参考url ： [https://blog.csdn.net/lb377463323/article/details/78054892]\n *\n * @author ymc\n * @date 2019年2月12日 13:59:30\n *\n */\n\npublic class CameraV2 {\n    private static final String TAG = \"CameraV2\";\n    private Activity mActivity;\n    private CameraDevice mCameraDevice;\n    private String mCameraId;\n    /**\n     * 预览尺寸\n     */\n    private Size mPreviewSize;\n    private HandlerThread mBackgroundThread;\n    private Handler mBackgroundHandler;\n    private SurfaceTexture mSurfaceTexture;\n    /**\n     * 相机预览\n     */\n    private CaptureRequest.Builder mPreviewRequestBuilder;\n    private CaptureRequest mPreviewRequest;\n    private CameraCaptureSession mCaptureSession;\n    private ImageReader mImageReader;\n    /**\n     * Camera2 API保证的最大预览宽度\n     */\n    private static final int MAX_PREVIEW_WIDTH = 1920;\n    /**\n     * Camera2 API保证的最大预览高度\n     */\n    private static final int MAX_PREVIEW_HEIGHT = 1280;\n    /**\n     * 相机传感器的方向\n     */\n    private int mSensorOrientation;\n    private File mFile;\n    /**\n     * 当前相机状态.\n     */\n    private int mState = STATE_PREVIEW;\n    /**\n     * 相机预览状态\n     */\n    private static final int STATE_PREVIEW = 0;\n    /**\n     * 等待相机锁定\n     */\n    private static final int STATE_WAITING_LOCK = 1;\n    /**\n     * 相机状态：等待曝光处于预捕获状态。\n     */\n    private static final int STATE_WAITING_PRECAPTURE = 2;\n    /**\n     * 相机状态：等待曝光状态不是预捕获。\n     */\n    private static final int STATE_WAITING_NON_PRECAPTURE = 3;\n    /**\n     * 相机状态：已拍摄照片。\n     */\n    private static final int STATE_PICTURE_TAKEN = 4;\n    /**\n     * 屏幕旋转转换为JPEG方向。\n     */\n    private static final SparseIntArray ORIENTATIONS = new SparseIntArray();\n\n    static {\n        ORIENTATIONS.append(Surface.ROTATION_0, 90);\n        ORIENTATIONS.append(Surface.ROTATION_90, 0);\n        ORIENTATIONS.append(Surface.ROTATION_180, 270);\n        ORIENTATIONS.append(Surface.ROTATION_270, 180);\n    }\n\n    /**\n     * 在关闭相机之前阻止应用程序退出\n     */\n    private Semaphore mCameraOpenCloseLock = new Semaphore(1);\n\n    /**\n     * 当前相机设备是否支持Flash\n     */\n    private boolean mFlashSupported;\n    /**\n     * 绘制容器\n     */\n    private Surface surface;\n\n    public CameraV2(Activity activity) {\n        mActivity = activity;\n    }\n\n    /**\n     * 设置与摄像头相关的成员变量。\n     *\n     * @param width  摄像机预览的可用大小宽度\n     * @param height 相机预览的可用尺寸高度\n     */\n    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)\n    public Size setUpCameraOutputs(int width, int height) {\n        mFile = new File(mActivity.getExternalFilesDir(null), \"pic.png\");\n        CameraManager manager = (CameraManager) mActivity.getSystemService(Context.CAMERA_SERVICE);\n        try {\n            for (String cameraId : manager.getCameraIdList()) {\n                CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);\n                // 不使用前置摄像头\n                Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING);\n                if (facing != null && facing == CameraCharacteristics.LENS_FACING_FRONT) {\n                    continue;\n                }\n\n                StreamConfigurationMap map = characteristics.get(\n                        CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);\n                if (map == null) {\n                    continue;\n                }\n                // 静态图像捕获，选择最大可用大小。\n                Size largest = Collections.max(\n                        Arrays.asList(map.getOutputSizes(ImageFormat.JPEG)),\n                        new CompareSizesByArea());\n                mImageReader = ImageReader.newInstance(largest.getWidth(),\n                        largest.getHeight(), ImageFormat.JPEG, 2);\n                mImageReader.setOnImageAvailableListener(\n                        mOnImageAvailableListener, mBackgroundHandler);\n\n                //了解我们是否需要交换尺寸以获得相对于传感器的预览尺寸\n                int displayRotation = mActivity.getWindowManager().getDefaultDisplay().getRotation();\n                mSensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);\n                boolean swappedDimensions = false;\n                switch (displayRotation) {\n                    case Surface.ROTATION_0:\n                    case Surface.ROTATION_180:\n                        if (mSensorOrientation == 90 || mSensorOrientation == 270) {\n                            swappedDimensions = true;\n                        }\n                        break;\n                    case Surface.ROTATION_90:\n                    case Surface.ROTATION_270:\n                        if (mSensorOrientation == 0 || mSensorOrientation == 180) {\n                            swappedDimensions = true;\n                        }\n                        break;\n                    default:\n                        Log.e(TAG, \"Display rotation is invalid: \" + displayRotation);\n                }\n                Point displaySize = new Point();\n                mActivity.getWindowManager().getDefaultDisplay().getSize(displaySize);\n                int rotatedPreviewWidth = width;\n                int rotatedPreviewHeight = height;\n                int maxPreviewWidth = displaySize.x;\n                int maxPreviewHeight = displaySize.y;\n\n                if (swappedDimensions) {\n                    rotatedPreviewWidth = height;\n                    rotatedPreviewHeight = width;\n                    maxPreviewWidth = displaySize.y;\n                    maxPreviewHeight = displaySize.x;\n                }\n\n                if (maxPreviewWidth > MAX_PREVIEW_WIDTH) {\n                    maxPreviewWidth = MAX_PREVIEW_WIDTH;\n                }\n                if (maxPreviewHeight > MAX_PREVIEW_HEIGHT) {\n                    maxPreviewHeight = MAX_PREVIEW_HEIGHT;\n                }\n                mPreviewSize = chooseOptimalSize(map.getOutputSizes(SurfaceTexture.class),\n                        rotatedPreviewWidth, rotatedPreviewHeight, maxPreviewWidth,\n                        maxPreviewHeight, largest);\n\n                // 将TextureView的宽高比与我们选择的预览大小相匹配。\n                int orientation = mActivity.getResources().getConfiguration().orientation;\n\n//                if (orientation == Configuration.ORIENTATION_LANDSCAPE) {\n//                    mTextureView.setAspectRatio(\n//                            mPreviewSize.getWidth(), mPreviewSize.getHeight());\n//                } else {\n//                    mTextureView.setAspectRatio(\n//                            mPreviewSize.getHeight(), mPreviewSize.getWidth());\n//                }\n                // 检查 远光灯\n                Boolean available = characteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE);\n                mFlashSupported = available == null ? false : available;\n                mCameraId = cameraId;\n            }\n        } catch (CameraAccessException e) {\n            e.printStackTrace();\n        } catch (NullPointerException ignored) {\n        }\n        return mPreviewSize;\n    }\n\n    public void startBackgroundThread() {\n        mBackgroundThread = new HandlerThread(\"CameraThread\");\n        mBackgroundThread.start();\n        mBackgroundHandler = new Handler(mBackgroundThread.getLooper());\n    }\n\n    /**\n     * 关闭 BackgroundThread\n     */\n    public void stopBackgroundThread() {\n        mBackgroundThread.quitSafely();\n        try {\n            mBackgroundThread.join();\n            mBackgroundThread = null;\n            mBackgroundHandler = null;\n        } catch (InterruptedException e) {\n            e.printStackTrace();\n        }\n    }\n\n    /**\n     * 打开相机\n     *\n     * @return boolean\n     */\n    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)\n    public boolean openCamera() {\n        CameraManager cameraManager = (CameraManager) mActivity.getSystemService(Context.CAMERA_SERVICE);\n        try {\n            if (ActivityCompat.checkSelfPermission(mActivity, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {\n                return false;\n            }\n            cameraManager.openCamera(mCameraId, mStateCallback, mBackgroundHandler);\n            if (!mCameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) {\n                throw new RuntimeException(\"Time out waiting to lock camera opening.\");\n            }\n        } catch (CameraAccessException | InterruptedException e) {\n            e.printStackTrace();\n            return false;\n        }\n        return true;\n    }\n\n    /**\n     * CameraDevice 改变状态时候 调用\n     */\n    private CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {\n        @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)\n        @Override\n        public void onOpened(@NonNull CameraDevice camera) {\n            mCameraDevice = camera;\n            //打开相机时会调用此方法。 我们在这里开始相机预览。\n            mCameraOpenCloseLock.release();\n//            createCameraPreviewSession();\n        }\n\n        @Override\n        public void onDisconnected(@NonNull CameraDevice camera) {\n            mCameraOpenCloseLock.release();\n            camera.close();\n            mCameraDevice = null;\n        }\n\n        @Override\n        public void onError(@NonNull CameraDevice camera, int error) {\n            mCameraOpenCloseLock.release();\n            camera.close();\n            mCameraDevice = null;\n            mActivity.finish();\n        }\n    };\n\n    /**\n     * 赋值surfaceTexture\n     *\n     * @param surfaceTexture surfaceTexture\n     */\n    public void setPreviewTexture(SurfaceTexture surfaceTexture) {\n        mSurfaceTexture = surfaceTexture;\n    }\n\n    /**\n     * 创建相机 并打开预览\n     */\n    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)\n    public void createCameraPreviewSession() {\n        mSurfaceTexture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());\n        surface = new Surface(mSurfaceTexture);\n        try {\n            mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);\n            mPreviewRequestBuilder.addTarget(surface);\n            mCameraDevice.createCaptureSession(Arrays.asList(surface,mImageReader.getSurface()), new CameraCaptureSession.StateCallback() {\n                @Override\n                public void onConfigured(@NonNull CameraCaptureSession session) {\n                    if (null == mCameraDevice) {\n                        return;\n                    }\n                    mCaptureSession = session;\n                    try {\n                        // 自动变焦是连续的\n                        mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,\n                                CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);\n                        if (mFlashSupported) {\n                            mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE,\n                                    CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);\n                        }\n                        // 显示相机预览\n                        mPreviewRequest = mPreviewRequestBuilder.build();\n                        mCaptureSession.setRepeatingRequest(mPreviewRequest,\n                                mCaptureCallback, mBackgroundHandler);\n                    } catch (CameraAccessException e) {\n                        e.printStackTrace();\n                    }\n                }\n\n                @Override\n                public void onConfigureFailed(@NonNull CameraCaptureSession session) {\n\n                }\n            }, mBackgroundHandler);\n        } catch (CameraAccessException e) {\n            e.printStackTrace();\n        }\n    }\n\n    /**\n     * ImageReader 的回调对象。 静止图像已准备好保存。\n     */\n    private final ImageReader.OnImageAvailableListener mOnImageAvailableListener\n            = new ImageReader.OnImageAvailableListener() {\n        @Override\n        public void onImageAvailable(ImageReader reader) {\n            Toast.makeText(mActivity,\"camera2 ok\",Toast.LENGTH_SHORT).show();\n            mBackgroundHandler.post(new ImageSaver(reader.acquireNextImage(), mFile));\n            CameraV2GLSurfaceView.shouldTakePic = true;\n        }\n    };\n\n    /**\n     * 比较 两个 size\n     */\n    static class CompareSizesByArea implements Comparator<Size> {\n\n        @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)\n        @Override\n        public int compare(Size lhs, Size rhs) {\n            // 在这里投射以确保乘法不会溢出\n            return Long.signum((long) lhs.getWidth() * lhs.getHeight() -\n                    (long) rhs.getWidth() * rhs.getHeight());\n        }\n    }\n\n    /**\n     * 给定摄像机支持的尺寸 否则选择最小的一个尺寸\n     *\n     * @param choices           相机支持预期输出的尺寸列表\n     * @param textureViewWidth  纹理视图相对于传感器坐标的宽度\n     * @param textureViewHeight 纹理视图相对于传感器坐标的高度\n     * @param maxWidth          最大宽度\n     * @param maxHeight         最大高度\n     * @param aspectRatio       纵横比\n     * @return size\n     */\n    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)\n    private static Size chooseOptimalSize(Size[] choices, int textureViewWidth,\n                                          int textureViewHeight, int maxWidth, int maxHeight, Size aspectRatio) {\n\n        // 收集至少与预览Surface一样大的支持的分辨率\n        List<Size> bigEnough = new ArrayList<>();\n        // 收集小于预览Surface的支持的分辨率\n        List<Size> notBigEnough = new ArrayList<>();\n        int w = aspectRatio.getWidth();\n        int h = aspectRatio.getHeight();\n        for (Size option : choices) {\n            if (option.getWidth() <= maxWidth && option.getHeight() <= maxHeight &&\n                    option.getHeight() == option.getWidth() * h / w) {\n                if (option.getWidth() >= textureViewWidth &&\n                        option.getHeight() >= textureViewHeight) {\n                    bigEnough.add(option);\n                } else {\n                    notBigEnough.add(option);\n                }\n            }\n        }\n        // 挑选适合的尺寸\n        if (bigEnough.size() > 0) {\n            return Collections.min(bigEnough, new CompareSizesByArea());\n        } else if (notBigEnough.size() > 0) {\n            return Collections.max(notBigEnough, new CompareSizesByArea());\n        } else {\n            Log.e(TAG, \"Couldn't find any suitable preview size\");\n            return choices[0];\n        }\n    }\n\n    /**\n     * 锁定焦点设置\n     */\n    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)\n    public void lockFocus() {\n        try {\n            // 相机锁定的方法\n            mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,\n                    CameraMetadata.CONTROL_AF_TRIGGER_START);\n            // mCaptureCallback 等待锁定\n            mState = STATE_WAITING_LOCK;\n            mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback,\n                    mBackgroundHandler);\n        } catch (CameraAccessException e) {\n            e.printStackTrace();\n        }\n    }\n\n    /**\n     * Closes the current {@link CameraDevice}.\n     */\n    public void closeCamera() {\n        try {\n            mCameraOpenCloseLock.acquire();\n            if (null != mCaptureSession) {\n                mCaptureSession.close();\n                mCaptureSession = null;\n            }\n            if (null != mCameraDevice) {\n                mCameraDevice.close();\n                mCameraDevice = null;\n            }\n            if (null != mImageReader) {\n                mImageReader.close();\n                mImageReader = null;\n            }\n        } catch (InterruptedException e) {\n            e.printStackTrace();\n        } finally {\n            mCameraOpenCloseLock.release();\n        }\n    }\n\n\n    /**\n     * 处理与jpg文件捕捉的事件监听(预览)\n     */\n    private CameraCaptureSession.CaptureCallback mCaptureCallback\n            = new CameraCaptureSession.CaptureCallback() {\n\n        @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)\n        private void process(CaptureResult result) {\n            switch (mState) {\n                case STATE_PREVIEW: {\n                    // 预览正常\n                    break;\n                }\n                case STATE_WAITING_LOCK: {\n                    Integer afState = result.get(CaptureResult.CONTROL_AF_STATE);\n                    if (afState == null) {\n                        captureStillPicture();\n                    } else if (CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED == afState ||\n                            CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED == afState) {\n                        Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);\n                        if (aeState == null ||\n                                aeState == CaptureResult.CONTROL_AE_STATE_CONVERGED) {\n                            mState = STATE_PICTURE_TAKEN;\n                            captureStillPicture();\n                        } else {\n                            runPrecaptureSequence();\n                        }\n                    }\n                    break;\n                }\n                case STATE_WAITING_PRECAPTURE: {\n                    Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);\n                    if (aeState == null ||\n                            aeState == CaptureResult.CONTROL_AE_STATE_PRECAPTURE ||\n                            aeState == CaptureRequest.CONTROL_AE_STATE_FLASH_REQUIRED) {\n                        mState = STATE_WAITING_NON_PRECAPTURE;\n                    }\n                    break;\n                }\n                case STATE_WAITING_NON_PRECAPTURE: {\n                    Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);\n                    if (aeState == null || aeState != CaptureResult.CONTROL_AE_STATE_PRECAPTURE) {\n                        mState = STATE_PICTURE_TAKEN;\n                        captureStillPicture();\n                    }\n                    break;\n                }\n                default:\n                    break;\n            }\n        }\n\n        @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)\n        @Override\n        public void onCaptureProgressed(@NonNull CameraCaptureSession session,\n                                        @NonNull CaptureRequest request,\n                                        @NonNull CaptureResult partialResult) {\n            process(partialResult);\n        }\n\n        @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)\n        @Override\n        public void onCaptureCompleted(@NonNull CameraCaptureSession session,\n                                       @NonNull CaptureRequest request,\n                                       @NonNull TotalCaptureResult result) {\n            process(result);\n        }\n\n    };\n\n\n    /**\n     * 拍摄静止图片。 当我们得到响应时，应该调用此方法\n     */\n    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)\n    private void captureStillPicture() {\n        try {\n            if (null == mActivity || null == mCameraDevice) {\n                return;\n            }\n            final CaptureRequest.Builder captureBuilder =\n                    mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);\n            captureBuilder.addTarget(mImageReader.getSurface());\n\n            // 使用与预览相同的AE和AF模式。\n            captureBuilder.set(CaptureRequest.CONTROL_AF_MODE,\n                    CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);\n            // 查看使用支持 flash\n            if (mFlashSupported) {\n                captureBuilder.set(CaptureRequest.CONTROL_AE_MODE,\n                        CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);\n            }\n            int rotation = mActivity.getWindowManager().getDefaultDisplay().getRotation();\n            captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, getOrientation(rotation));\n\n            CameraCaptureSession.CaptureCallback capturecallback\n                    = new CameraCaptureSession.CaptureCallback() {\n\n                @Override\n                public void onCaptureCompleted(@NonNull CameraCaptureSession session,\n                                               @NonNull CaptureRequest request,\n                                               @NonNull TotalCaptureResult result) {\n                    Log.e(TAG, \"--------------------:\" + mFile.toString());\n                    unlockFocus();\n                }\n            };\n            mCaptureSession.stopRepeating();\n            mCaptureSession.abortCaptures();\n            mCaptureSession.capture(captureBuilder.build(), capturecallback, mBackgroundHandler);\n        } catch (CameraAccessException e) {\n            e.printStackTrace();\n            Log.e(TAG, \"capture err: \" + e.getMessage());\n        }\n    }\n\n    /**\n     * 解锁焦点 在静止图像捕获序列时调用此方法\n     */\n    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)\n    private void unlockFocus() {\n        try {\n            mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,\n                    CameraMetadata.CONTROL_AF_TRIGGER_CANCEL);\n            if (mFlashSupported) {\n                mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE,\n                        CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);\n            }\n            mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback,\n                    mBackgroundHandler);\n            // 相机转为正常状态\n            mState = STATE_PREVIEW;\n            mCaptureSession.setRepeatingRequest(mPreviewRequest, mCaptureCallback,\n                    mBackgroundHandler);\n        } catch (CameraAccessException e) {\n            e.printStackTrace();\n        }\n    }\n\n    /**\n     * 从指定的屏幕旋转中检索JPEG方向。\n     */\n    private int getOrientation(int rotation) {\n        //对于方向为90的设备，我们只需从ORIENTATIONS返回我们的映射\n        //对于方向为270的设备，我们需要将JPEG旋转180度\n        return (ORIENTATIONS.get(rotation) + mSensorOrientation + 270) % 360;\n    }\n\n    /**\n     * 保存文件\n     */\n    private static class ImageSaver implements Runnable {\n        private final Image mImage;\n        private final File mFile;\n\n        ImageSaver(Image image, File file) {\n            mImage = image;\n            mFile = file;\n        }\n\n        @Override\n        public void run() {\n            ByteBuffer buffer = mImage.getPlanes()[0].getBuffer();\n            byte[] bytes = new byte[buffer.remaining()];\n            buffer.get(bytes);\n            FileOutputStream output = null;\n            try {\n                output = new FileOutputStream(mFile);\n                output.write(bytes);\n            } catch (IOException e) {\n                e.printStackTrace();\n            } finally {\n                mImage.close();\n                if (null != output) {\n                    try {\n                        output.close();\n                    } catch (IOException e) {\n                        e.printStackTrace();\n                    }\n                }\n            }\n        }\n    }\n\n\n    /**\n     * 运行预捕获序列以捕获静止图像。 在调用此方法时调用\n     */\n    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)\n    private void runPrecaptureSequence() {\n        try {\n            // 相机触发的方法\n            mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,\n                    CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START);\n            // mCaptureCallback等待设置预捕获序列。\n            mState = STATE_WAITING_PRECAPTURE;\n            mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback,\n                    mBackgroundHandler);\n        } catch (CameraAccessException e) {\n            e.printStackTrace();\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/camera/cn/cameramaster/util/CompareSizesByArea.java",
    "content": "package camera.cn.cameramaster.util;\n\nimport android.os.Build;\nimport android.support.annotation.RequiresApi;\nimport android.util.Size;\n\nimport java.util.Comparator;\n\n/**\n * 比较 工具\n *\n * @packageName: cn.tongue.tonguecamera.util\n * @fileName: CompareSizesByArea\n * @date: 2019/4/16  13:42\n * @author: ymc\n * @QQ:745612618\n */\n\npublic class CompareSizesByArea implements Comparator<Size> {\n\n    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)\n    @Override\n    public int compare(Size lhs, Size rhs) {\n        // 在这里投射以确保乘法不会溢出\n        return Long.signum((long) lhs.getWidth() * lhs.getHeight() -\n                (long) rhs.getWidth() * rhs.getHeight());\n    }\n}"
  },
  {
    "path": "app/src/main/java/camera/cn/cameramaster/util/FilterEngine.java",
    "content": "package camera.cn.cameramaster.util;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.opengl.GLES11Ext;\nimport android.opengl.GLES20;\n\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\nimport java.nio.FloatBuffer;\n\n\nimport camera.cn.cameramaster.R;\n\nimport static android.opengl.GLES20.GL_FLOAT;\nimport static android.opengl.GLES20.GL_FRAGMENT_SHADER;\nimport static android.opengl.GLES20.GL_TRIANGLES;\nimport static android.opengl.GLES20.GL_VERTEX_SHADER;\nimport static android.opengl.GLES20.glActiveTexture;\nimport static android.opengl.GLES20.glAttachShader;\nimport static android.opengl.GLES20.glBindTexture;\nimport static android.opengl.GLES20.glCompileShader;\nimport static android.opengl.GLES20.glCreateProgram;\nimport static android.opengl.GLES20.glCreateShader;\nimport static android.opengl.GLES20.glDrawArrays;\nimport static android.opengl.GLES20.glEnableVertexAttribArray;\nimport static android.opengl.GLES20.glGetAttribLocation;\nimport static android.opengl.GLES20.glGetError;\nimport static android.opengl.GLES20.glGetUniformLocation;\nimport static android.opengl.GLES20.glLinkProgram;\nimport static android.opengl.GLES20.glShaderSource;\nimport static android.opengl.GLES20.glUniform1i;\nimport static android.opengl.GLES20.glUniformMatrix4fv;\nimport static android.opengl.GLES20.glUseProgram;\nimport static android.opengl.GLES20.glVertexAttribPointer;\n\n/**\n * 滤镜 工具\n * 参考url ： [https://blog.csdn.net/lb377463323/article/details/78054892]\n *\n * @date 2019年2月12日 14:10:07\n * @author ymc\n */\n\npublic class FilterEngine {\n\n    @SuppressLint(\"StaticFieldLeak\")\n    private static FilterEngine filterEngine = null;\n\n    private Context mContext;\n    /**\n     * 存放顶点的Color数组\n     */\n    private FloatBuffer mBuffer;\n    private int mOESTextureId = -1;\n    private int vertexShader = -1;\n    private int fragmentShader = -1;\n\n    private int mShaderProgram = -1;\n\n    private int aPositionLocation = -1;\n    private int aTextureCoordLocation = -1;\n    private int uTextureMatrixLocation = -1;\n    private int uTextureSamplerLocation = -1;\n    /**\n     * 每行前两个值为顶点坐标，后两个为纹理坐标\n     */\n    private static final float[] VERTEX_DATA = {\n            1f, 1f, 1f, 1f,\n            -1f, 1f, 0f, 1f,\n            -1f, -1f, 0f, 0f,\n            1f, 1f, 1f, 1f,\n            -1f, -1f, 0f, 0f,\n            1f, -1f, 1f, 0f\n    };\n\n    public static final String POSITION_ATTRIBUTE = \"aPosition\";\n    public static final String TEXTURE_COORD_ATTRIBUTE = \"aTextureCoordinate\";\n    public static final String TEXTURE_MATRIX_UNIFORM = \"uTextureMatrix\";\n    public static final String TEXTURE_SAMPLER_UNIFORM = \"uTextureSampler\";\n    public static final String COLOR_TYPE = \"vColorType\";\n\n    /**\n     * 构造方法\n     * @param oestextureid oes id\n     * @param context 上下文\n     */\n    public FilterEngine(int oestextureid, Context context) {\n        mContext = context;\n        mOESTextureId = oestextureid;\n        mBuffer = createBuffer(VERTEX_DATA);\n        /**\n         * 预览相机的着色器，顶点着色器不变，需要修改片元着色器，不再用sampler2D采样，\n         * 需要使用samplerExternalOES 纹理采样器，并且要在头部增加使用扩展纹理的声明\n         * #extension GL_OES_EGL_image_external : require。\n         */\n        fragmentShader = loadShader(GL_FRAGMENT_SHADER, Utils.readShaderFromResource(mContext, R.raw.base_fragment_shader));\n        vertexShader = loadShader(GL_VERTEX_SHADER, Utils.readShaderFromResource(mContext, R.raw.base_vertex_shader));\n        mShaderProgram = linkProgram(vertexShader, fragmentShader);\n    }\n\n    /**\n     * 创建 FloatBuffer 数组 (防止内存回收)\n     * @param vertexData float 数组\n     * @return FloatBuffer\n     */\n    private FloatBuffer createBuffer(float[] vertexData) {\n        FloatBuffer buffer = ByteBuffer.allocateDirect(vertexData.length * 4)\n                .order(ByteOrder.nativeOrder())\n                .asFloatBuffer();\n        buffer.put(vertexData, 0, vertexData.length).position(0);\n        return buffer;\n    }\n\n    /**\n     * 加载着色器\n     * GL_VERTEX_SHADER 代表生成顶点着色器\n     * GL_FRAGMENT_SHADER 代表生成片段着色器\n     *\n     * @param type 类型\n     * @param shaderSource shader string\n     * @return shader\n     */\n    private int loadShader(int type, String shaderSource) {\n        int shader = glCreateShader(type);\n        if (shader == 0) {\n            throw new RuntimeException(\"Create Shader Failed!\" + glGetError());\n        }\n        glShaderSource(shader, shaderSource);\n        glCompileShader(shader);\n        return shader;\n    }\n\n    /**\n     * 将两个Shader链接至program中\n     * @param verShader verShader\n     * @param fragShader fragShader\n     * @return program\n     */\n    private int linkProgram(int verShader, int fragShader) {\n        int program = glCreateProgram();\n        if (program == 0) {\n            throw new RuntimeException(\"Create Program Failed!\" + glGetError());\n        }\n        //附着顶点和片段着色器\n        glAttachShader(program, verShader);\n        glAttachShader(program, fragShader);\n        // 绑定 program\n        glLinkProgram(program);\n        //告诉OpenGL ES使用此program\n        glUseProgram(program);\n        return program;\n    }\n\n    public void drawTexture(float[] transformMatrix) {\n        aPositionLocation = glGetAttribLocation(mShaderProgram, FilterEngine.POSITION_ATTRIBUTE);\n        aTextureCoordLocation = glGetAttribLocation(mShaderProgram, FilterEngine.TEXTURE_COORD_ATTRIBUTE);\n        uTextureMatrixLocation = glGetUniformLocation(mShaderProgram, FilterEngine.TEXTURE_MATRIX_UNIFORM);\n        uTextureSamplerLocation = glGetUniformLocation(mShaderProgram, FilterEngine.TEXTURE_SAMPLER_UNIFORM);\n\n        glActiveTexture(GLES20.GL_TEXTURE0);\n        glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, mOESTextureId);\n        glUniform1i(uTextureSamplerLocation, 0);\n        glUniformMatrix4fv(uTextureMatrixLocation, 1, false, transformMatrix, 0);\n\n        if (mBuffer != null) {\n            mBuffer.position(0);\n            glEnableVertexAttribArray(aPositionLocation);\n            glVertexAttribPointer(aPositionLocation, 2, GL_FLOAT, false, 16, mBuffer);\n\n            mBuffer.position(2);\n            glEnableVertexAttribArray(aTextureCoordLocation);\n            glVertexAttribPointer(aTextureCoordLocation, 2, GL_FLOAT, false, 16, mBuffer);\n\n            glDrawArrays(GL_TRIANGLES, 0, 6);\n        }\n    }\n\n    public int getShaderProgram() {\n        return mShaderProgram;\n    }\n\n    public FloatBuffer getBuffer() {\n        return mBuffer;\n    }\n\n    public int getOESTextureId() {\n        return mOESTextureId;\n    }\n\n    public void setOESTextureId(int OESTextureId) {\n        mOESTextureId = OESTextureId;\n    }\n}\n\n"
  },
  {
    "path": "app/src/main/java/camera/cn/cameramaster/util/LabUtil.java",
    "content": "package camera.cn.cameramaster.util;\n\n\nimport java.util.Arrays;\n\n/**\n * rgb 转 lab 工具类\n *\n * @fileName: LabUtil\n * @date: 2019/4/3  13:38\n * @author: ymc\n * @QQ:745612618\n */\n\npublic class LabUtil {\n\n    public static void main(String[] args) {\n        for (int i = 0; i < 24; i++) {\n            double[] a = AppConstant.rgbmap[i];\n            int fx = 0;\n            int fx1 = -30;\n            double rrr = a[0] + fx > 255 ? 255 :a[0] + fx;\n            double ggg = a[1] + fx > 255 ? 255 :a[1] + fx;\n            double bbb = a[2] + fx1 > 255 ? 255 :a[2] + fx1;\n            double[] xyz = LabUtil.sRGB2XYZ(new double[]{rrr,ggg,bbb});\n            double[] lab = LabUtil.XYZ2Lab(xyz);\n            double cha = Math.sqrt(Math.pow((lab[0] - AppConstant.labmap[i][0]), 2)\n                    + Math.pow((lab[1] - AppConstant.labmap[i][1]), 2)\n                    + Math.pow((lab[2] - AppConstant.labmap[i][2]), 2));\n            System.out.println(Arrays.toString(new double[]{rrr,ggg,bbb}) + \"   lab[]:\"+ Arrays.toString(lab) + \"  色差:\"+cha);\n            System.out.println(\"lab误差 l: \"+(lab[0] - AppConstant.labmap[i][0]) +\n                    \"  a: \"+(lab[1] - AppConstant.labmap[i][1])+\"  b: \"+(lab[2] - AppConstant.labmap[i][2]));\n//            Log.e(\"\", a.toString() + \"   lab[]:\"+lab.toString() + \"  色差:\"+cha);\n        }\n    }\n\n    /**\n     * D65  or  D50\n     */\n    private static boolean hasD50 = false;\n\n    /**\n     * lab 转 xyz\n     *\n     * @param Lab\n     * @return\n     */\n    public static double[] Lab2XYZ(double[] Lab) {\n        double[] XYZ = new double[3];\n        double L, a, b;\n        double fx, fy, fz;\n        double Xn, Yn, Zn;\n        // D50\n        if (hasD50) {\n            Xn = 96.42;\n            Yn = 100;\n            Zn = 82.51;\n        } else {\n            // D65\n            Xn = 95.04;\n            Yn = 100;\n            Zn = 108.89;\n        }\n        L = Lab[0];\n        a = Lab[1];\n        b = Lab[2];\n\n        fy = (L + 16) / 116;\n        fx = a / 500 + fy;\n        fz = fy - b / 200;\n\n        if (fx > 0.2069) {\n            XYZ[0] = Xn * Math.pow(fx, 3);\n        } else {\n            XYZ[0] = Xn * (fx - 0.1379) * 0.1284;\n        }\n\n        if ((fy > 0.2069) || (L > 8)) {\n            XYZ[1] = Yn * Math.pow(fy, 3);\n        } else {\n            XYZ[1] = Yn * (fy - 0.1379) * 0.1284;\n        }\n\n        if (fz > 0.2069) {\n            XYZ[2] = Zn * Math.pow(fz, 3);\n        } else {\n            XYZ[2] = Zn * (fz - 0.1379) * 0.1284;\n        }\n\n        return XYZ;\n    }\n\n    /**\n     * xyz 转为 lab\n     *\n     * @param XYZ\n     * @return\n     */\n    public static double[] XYZ2Lab(double[] XYZ) {\n        double[] Lab = new double[3];\n        double X, Y, Z;\n        X = XYZ[0];\n        Y = XYZ[1];\n        Z = XYZ[2];\n        double Xn, Yn, Zn;\n        if (hasD50) {\n            // D50\n            Xn = 96.42;\n            Yn = 100;\n            Zn = 82.51;\n        } else {\n            // D65\n            Xn = 95.04;\n            Yn = 100;\n            Zn = 108.89;\n        }\n        double XXn, YYn, ZZn;\n        XXn = X / Xn;\n        YYn = Y / Yn;\n        ZZn = Z / Zn;\n\n        double fx, fy, fz;\n        if (XXn > 0.008856) {\n            fx = Math.pow(XXn, 0.333333);\n        } else {\n            fx = 7.787 * XXn + 0.137931;\n        }\n        if (YYn > 0.008856) {\n            fy = Math.pow(YYn, 0.333333);\n        } else {\n            fy = 7.787 * YYn + 0.137931;\n        }\n        if (ZZn > 0.008856) {\n            fz = Math.pow(ZZn, 0.333333);\n        } else {\n            fz = 7.787 * ZZn + 0.137931;\n        }\n        Lab[0] = 116 * fy - 16;\n        Lab[1] = 500 * (fx - fy);\n        Lab[2] = 200 * (fy - fz);\n\n        return Lab;\n    }\n\n    /**\n     * rgb 转 xyz\n     *\n     * @return double[]\n     */\n    public static double[] sRGB2XYZ(double[] RGB) {\n        double[] XYZ = new double[3];\n        double sR, sG, sB;\n        sR = RGB[0];\n        sG = RGB[1];\n        sB = RGB[2];\n        sR /= 255;\n        sG /= 255;\n        sB /= 255;\n\n        if (sR <= 0.04045) {\n            sR = sR / 12.92;\n        } else {\n            sR = Math.pow(((sR + 0.055) / 1.055), 2.4);\n        }\n\n        if (sG <= 0.04045) {\n            sG = sG / 12.92;\n        } else {\n            sG = Math.pow(((sG + 0.055) / 1.055), 2.4);\n        }\n\n        if (sB <= 0.04045) {\n            sB = sB / 12.92;\n        } else {\n            sB = Math.pow(((sB + 0.055) / 1.055), 2.4);\n        }\n        if (hasD50) {\n            // D50\n            XYZ[0] = 43.6052025 * sR + 38.5081593 * sG + 14.3087414 * sB;\n            XYZ[1] = 22.2491598 * sR + 71.6886060 * sG + 6.0621486 * sB;\n            XYZ[2] = 1.3929122 * sR + 9.7097002 * sG + 71.4185470 * sB;\n        } else {\n            // D65\n            XYZ[0] = 41.24 * sR + 35.76 * sG + 18.05 * sB;\n            XYZ[1] = 21.26 * sR + 71.52 * sG + 7.22 * sB;\n            XYZ[2] = 1.93 * sR + 11.92 * sG + 95.05 * sB;\n        }\n        return XYZ;\n    }\n\n    /**\n     * xyz 转 rgb\n     *\n     * @param XYZ double[]\n     * @return double[]\n     */\n    public static double[] XYZ2sRGB(double[] XYZ) {\n        double[] sRGB = new double[3];\n        double X, Y, Z;\n        double dr = 0, dg = 0, db = 0;\n        X = XYZ[0];\n        Y = XYZ[1];\n        Z = XYZ[2];\n\n        if (hasD50) {\n            // TODO: 2019/4/3 D50格式暂时没有找到 D50格式\n        } else {\n            dr = 0.032406 * X - 0.015371 * Y - 0.0049895 * Z;\n            dg = -0.0096891 * X + 0.018757 * Y + 0.00041914 * Z;\n            db = 0.00055708 * X - 0.0020401 * Y + 0.01057 * Z;\n        }\n\n        if (dr <= 0.00313) {\n            dr = dr * 12.92;\n        } else {\n            dr = Math.exp(Math.log(dr) / 2.4) * 1.055 - 0.055;\n        }\n\n        if (dg <= 0.00313) {\n            dg = dg * 12.92;\n        } else {\n            dg = Math.exp(Math.log(dg) / 2.4) * 1.055 - 0.055;\n        }\n\n        if (db <= 0.00313) {\n            db = db * 12.92;\n        } else {\n            db = Math.exp(Math.log(db) / 2.4) * 1.055 - 0.055;\n        }\n\n        dr = dr * 255;\n        dg = dg * 255;\n        db = db * 255;\n\n        dr = Math.min(255, dr);\n        dg = Math.min(255, dg);\n        db = Math.min(255, db);\n\n        sRGB[0] = dr + 0.5;\n        sRGB[1] = dg + 0.5;\n        sRGB[2] = db + 0.5;\n\n        return sRGB;\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/camera/cn/cameramaster/util/MatrixUtils.java",
    "content": "/*\n *\n * FastDrawerHelper.java\n * \n * Created by Wuwang on 2016/11/17\n * Copyright © 2016年 深圳哎吖科技. All rights reserved.\n */\npackage camera.cn.cameramaster.util;\n\nimport android.opengl.Matrix;\n\n/**\n * 矩阵 工具类\n */\npublic enum MatrixUtils {\n    ;\n    public static final int TYPE_FITXY=0;\n    public static final int TYPE_CENTERCROP=1;\n    public static final int TYPE_CENTERINSIDE=2;\n    public static final int TYPE_FITSTART=3;\n    public static final int TYPE_FITEND=4;\n\n    MatrixUtils(){\n\n    }\n\n    /**\n     * use {@link #getMatrix} instead\n     */\n    @Deprecated\n    public static void getShowMatrix(float[] matrix,int imgWidth,int imgHeight,int viewWidth,int\n        viewHeight){\n        if(imgHeight>0&&imgWidth>0&&viewWidth>0&&viewHeight>0){\n            float sWhView=(float)viewWidth/viewHeight;\n            float sWhImg=(float)imgWidth/imgHeight;\n            float[] projection=new float[16];\n            float[] camera=new float[16];\n            if(sWhImg>sWhView){\n                Matrix.orthoM(projection,0,-sWhView/sWhImg,sWhView/sWhImg,-1,1,1,3);\n            }else{\n                Matrix.orthoM(projection,0,-1,1,-sWhImg/sWhView,sWhImg/sWhView,1,3);\n            }\n            Matrix.setLookAtM(camera,0,0,0,1,0,0,0,0,1,0);\n            Matrix.multiplyMM(matrix,0,projection,0,camera,0);\n        }\n    }\n\n    public static void getMatrix(float[] matrix,int type,int imgWidth,int imgHeight,int viewWidth,\n                                 int viewHeight){\n        if(imgHeight>0&&imgWidth>0&&viewWidth>0&&viewHeight>0){\n            float[] projection=new float[16];\n            float[] camera=new float[16];\n            if(type==TYPE_FITXY){\n                Matrix.orthoM(projection,0,-1,1,-1,1,1,3);\n                Matrix.setLookAtM(camera,0,0,0,1,0,0,0,0,1,0);\n                Matrix.multiplyMM(matrix,0,projection,0,camera,0);\n            }\n            float sWhView=(float)viewWidth/viewHeight;\n            float sWhImg=(float)imgWidth/imgHeight;\n            if(sWhImg>sWhView){\n                switch (type){\n                    case TYPE_CENTERCROP:\n                        Matrix.orthoM(projection,0,-sWhView/sWhImg,sWhView/sWhImg,-1,1,1,3);\n                        break;\n                    case TYPE_CENTERINSIDE:\n                        Matrix.orthoM(projection,0,-1,1,-sWhImg/sWhView,sWhImg/sWhView,1,3);\n                        break;\n                    case TYPE_FITSTART:\n                        Matrix.orthoM(projection,0,-1,1,1-2*sWhImg/sWhView,1,1,3);\n                        break;\n                    case TYPE_FITEND:\n                        Matrix.orthoM(projection,0,-1,1,-1,2*sWhImg/sWhView-1,1,3);\n                        break;\n                }\n            }else{\n                switch (type){\n                    case TYPE_CENTERCROP:\n                        Matrix.orthoM(projection,0,-1,1,-sWhImg/sWhView,sWhImg/sWhView,1,3);\n                        break;\n                    case TYPE_CENTERINSIDE:\n                        Matrix.orthoM(projection,0,-sWhView/sWhImg,sWhView/sWhImg,-1,1,1,3);\n                        break;\n                    case TYPE_FITSTART:\n                        Matrix.orthoM(projection,0,-1,2*sWhView/sWhImg-1,-1,1,1,3);\n                        break;\n                    case TYPE_FITEND:\n                        Matrix.orthoM(projection,0,1-2*sWhView/sWhImg,1,-1,1,1,3);\n                        break;\n                }\n            }\n            Matrix.setLookAtM(camera,0,0,0,1,0,0,0,0,1,0);\n            Matrix.multiplyMM(matrix,0,projection,0,camera,0);\n        }\n    }\n\n    public static void getCenterInsideMatrix(float[] matrix,int imgWidth,int imgHeight,int viewWidth,int\n            viewHeight){\n        if(imgHeight>0&&imgWidth>0&&viewWidth>0&&viewHeight>0){\n            float sWhView=(float)viewWidth/viewHeight;\n            float sWhImg=(float)imgWidth/imgHeight;\n            float[] projection=new float[16];\n            float[] camera=new float[16];\n            if(sWhImg>sWhView){\n                Matrix.orthoM(projection,0,-1,1,-sWhImg/sWhView,sWhImg/sWhView,1,3);\n            }else{\n                Matrix.orthoM(projection,0,-sWhView/sWhImg,sWhView/sWhImg,-1,1,1,3);\n            }\n            Matrix.setLookAtM(camera,0,0,0,1,0,0,0,0,1,0);\n            Matrix.multiplyMM(matrix,0,projection,0,camera,0);\n        }\n    }\n\n    public static float[] rotate(float[] m,float angle){\n        Matrix.rotateM(m,0,angle,0,0,1);\n        return m;\n    }\n\n    public static float[] flip(float[] m,boolean x,boolean y){\n        if(x||y){\n            Matrix.scaleM(m,0,x?-1:1,y?-1:1,1);\n        }\n        return m;\n    }\n\n    public static float[] scale(float[] m,float x,float y){\n        Matrix.scaleM(m,0,x,y,1);\n        return m;\n    }\n\n    public static float[] getOriginalMatrix(){\n        return new float[]{\n            1,0,0,0,\n            0,1,0,0,\n            0,0,1,0,\n            0,0,0,1\n        };\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/camera/cn/cameramaster/util/Utils.java",
    "content": "package camera.cn.cameramaster.util;\n\nimport android.content.Context;\nimport android.opengl.GLES11Ext;\nimport android.opengl.GLES20;\nimport android.os.Environment;\nimport android.util.Log;\n\nimport java.io.BufferedReader;\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\n\nimport javax.microedition.khronos.opengles.GL10;\n\nimport static android.provider.MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE;\nimport static android.provider.MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO;\n\n/**\n * opengles utils\n *\n * @date  2019年2月12日 14:03:59\n * @author ymc\n */\n\npublic class Utils {\n\n    private static final String TAG = \"Utils\";\n\n    /**\n     * 创建 oes id\n     * @return oesId\n     */\n    public static int createOESTextureObject() {\n        int[] tex = new int[1];\n        //生成一个纹理\n        GLES20.glGenTextures(1, tex, 0);\n        //将此纹理绑定到外部纹理上\n        GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, tex[0]);\n        //设置纹理过滤参数\n        GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,\n                GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);\n        GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,\n                GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);\n        GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,\n                GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE);\n        GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,\n                GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE);\n        //解除纹理绑定\n        GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 0);\n        return tex[0];\n    }\n\n    public static String readShaderFromResource(Context context, int resourceId) {\n        StringBuilder builder = new StringBuilder();\n        InputStream is = null;\n        InputStreamReader isr = null;\n        BufferedReader br = null;\n        try {\n            is = context.getResources().openRawResource(resourceId);\n            isr = new InputStreamReader(is);\n            br = new BufferedReader(isr);\n            String line;\n            while ((line = br.readLine()) != null) {\n                builder.append(line).append(\"\\n\");\n            }\n        } catch (IOException e) {\n            e.printStackTrace();\n        } finally {\n            try {\n                if (is != null) {\n                    is.close();\n                    is = null;\n                }\n                if (isr != null) {\n                    isr.close();\n                    isr = null;\n                }\n                if (br != null) {\n                    br.close();\n                    br = null;\n                }\n            } catch (IOException e) {\n                e.printStackTrace();\n            }\n        }\n        return builder.toString();\n    }\n\n\n    /**\n     * 获取输出照片视频路径\n     * @param mContext 上下文\n     * @param mediaType 拍照视频类型\n     * @return 文件地址\n     */\n    public static File getOutputMediaFile(Context mContext, int mediaType) {\n        String timeStamp = new SimpleDateFormat(\"yyyyMMdd_HHmmss\").format(new Date());\n        String fileName = null;\n        File storageDir = null;\n        if (mediaType == MEDIA_TYPE_IMAGE) {\n            fileName = \"JPEG_\" + timeStamp + \"_\";\n            storageDir = mContext.getExternalFilesDir(Environment.DIRECTORY_PICTURES);\n        } else if (mediaType == MEDIA_TYPE_VIDEO) {\n            fileName = \"MP4_\" + timeStamp + \"_\";\n            storageDir = mContext.getExternalFilesDir(Environment.DIRECTORY_MOVIES);\n        }\n\n        // Create the storage directory if it does not exist\n        if (!storageDir.exists()) {\n            if (!storageDir.mkdirs()) {\n                Log.d(TAG, \"failed to create directory\");\n                return null;\n            }\n        }\n\n        File file = null;\n        try {\n            file = File.createTempFile(\n                    fileName,  /* prefix */\n                    (mediaType == MEDIA_TYPE_IMAGE) ? \".jpg\" : \".mp4\",         /* suffix */\n                    storageDir      /* directory */\n            );\n            Log.d(TAG, \"getOutputMediaFile: absolutePath==\" + file.getAbsolutePath());\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n        return file;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/camera/cn/cameramaster/util/cameravideo/CameraHelper.java",
    "content": "package camera.cn.cameramaster.util.cameravideo;\n\nimport android.annotation.SuppressLint;\nimport android.app.Activity;\nimport android.content.Context;\nimport android.graphics.ImageFormat;\nimport android.graphics.Point;\nimport android.graphics.Rect;\nimport android.graphics.RectF;\nimport android.graphics.SurfaceTexture;\nimport android.hardware.camera2.CameraAccessException;\nimport android.hardware.camera2.CameraCaptureSession;\nimport android.hardware.camera2.CameraCharacteristics;\nimport android.hardware.camera2.CameraDevice;\nimport android.hardware.camera2.CameraManager;\nimport android.hardware.camera2.CameraMetadata;\nimport android.hardware.camera2.CaptureFailure;\nimport android.hardware.camera2.CaptureRequest;\nimport android.hardware.camera2.CaptureResult;\nimport android.hardware.camera2.TotalCaptureResult;\nimport android.hardware.camera2.params.MeteringRectangle;\nimport android.hardware.camera2.params.StreamConfigurationMap;\nimport android.media.Image;\nimport android.media.ImageReader;\nimport android.media.MediaRecorder;\nimport android.net.Uri;\nimport android.os.Build;\nimport android.os.Environment;\nimport android.os.Handler;\nimport android.os.HandlerThread;\nimport android.support.annotation.RequiresApi;\nimport android.support.v4.content.FileProvider;\nimport android.util.Log;\nimport android.util.Range;\nimport android.util.Size;\nimport android.util.SparseIntArray;\nimport android.view.Surface;\nimport android.view.TextureView;\nimport android.view.View;\nimport android.view.animation.Animation;\nimport android.view.animation.AnimationUtils;\nimport android.widget.SeekBar;\nimport android.widget.TextView;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.Comparator;\nimport java.util.List;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport camera.cn.cameramaster.R;\nimport camera.cn.cameramaster.view.AutoFitTextureView;\nimport camera.cn.cameramaster.view.AwbSeekBar;\n\n\n/**\n * 摄像头整合帮助类\n *\n * @date 2019年5月9日 17:08:21\n */\n\n@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)\npublic class CameraHelper implements ICamera2, AwbSeekBar.OnAwbSeekBarChangeListener {\n\n    private static final SparseIntArray ORIENTATIONS = new SparseIntArray();\n\n    static {\n        ORIENTATIONS.append(Surface.ROTATION_0, 90);\n        ORIENTATIONS.append(Surface.ROTATION_90, 0);\n        ORIENTATIONS.append(Surface.ROTATION_180, 270);\n        ORIENTATIONS.append(Surface.ROTATION_270, 180);\n    }\n\n    /**\n     * 淡入 淡出 动画\n     */\n    private final Animation mAlphaInAnimation;\n    private final Animation mAlphaOutAnimation;\n\n    /**\n     * 设备旋转方向\n     */\n    private int mDeviceRotation;\n\n    private int mPhotoRotation;\n\n    /**\n     * 光强\n     */\n    private float mLight;\n\n    private AtomicBoolean mIsCameraOpen;\n\n    private CameraManager mCameraManager;\n\n    private TakePhotoListener mTakePhotoListener;\n\n    private CameraReady mCameraReady;\n\n    /**\n     * 摄像头的id集合\n     */\n    private String[] mCameraIds;\n\n    /**\n     * 摄像头支持的最大size\n     */\n    private Size mLargest;\n\n    /**\n     * 可缩放区域\n     */\n    private Size mZoomSize;\n\n    private Size mVideoSize;\n\n    private Context mContext;\n\n    /**\n     * 相机 曝光 范围\n     */\n    private Range<Integer> range1;\n\n    /**\n     * 需要打开的摄像头id\n     */\n    private String mCameraId;\n\n    private MediaRecorder mMediaRecorder;\n\n    private CaptureRequest.Builder mPreviewBuilder;\n\n    private CameraDevice mCameraDevice;\n\n    private CameraCaptureSession mPreviewSession;\n\n    private TextureView mTextureView;\n    /**\n     * 后台线程\n     */\n    private HandlerThread mBackgroundThread;\n\n    /**\n     * 后台handle\n     */\n    private Handler mBackgroundHandler;\n\n    private AtomicBoolean mIsRecordVideo = new AtomicBoolean();\n\n    private CameraType mNowCameraType;\n\n    /**\n     * 拍照的图片读取类\n     */\n    private ImageReader mImageReader;\n\n    /**\n     * 是否支持闪光灯\n     */\n    private boolean mFlashSupported;\n\n    /**\n     * 图片的路径\n     */\n    private String mPhotoPath;\n\n    /**\n     * Orientation of the camera sensor\n     */\n    private int mSensorOrientation;\n\n    /**\n     * 最大的放大倍数\n     */\n    private float mMaxZoom = 0;\n\n    /**\n     * 放大的矩阵，拍照使用\n     */\n    private Rect mZoomRect;\n\n    /**\n     * 摄像头支持的分辨率流集合\n     */\n    private StreamConfigurationMap mMap;\n\n    private FlashState mNowFlashState = FlashState.CLOSE;\n\n    private boolean mIsCapture = false;\n\n    private CameraCharacteristics mCharacteristics;\n\n    private boolean mNoAFRun = false;\n\n    private boolean mIsAFRequest = false;\n\n    private CameraMode CAMERA_STATE = CameraMode.TAKE_PHOTO;\n\n    private Surface mPreViewSurface;\n\n    private Surface mRecordSurface;\n\n    private CoordinateTransformer mCoordinateTransformer;\n\n    private Rect mPreviewRect;\n    private Rect mFocusRect;\n    /**\n     * iso 范围\n     */\n    private Range<Integer> isoRange;\n\n    public Range<Integer> getIsoRange() {\n        return isoRange;\n    }\n\n    /**\n     * 根据摄像头管理器获取一个帮助类\n     *\n     * @param context 实体类\n     */\n    public CameraHelper(Context context) {\n        this.mContext = context;\n        mIsCameraOpen = new AtomicBoolean(false);\n        CameraManager cameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);\n        mCameraManager = cameraManager;\n        try {\n            mCameraIds = mCameraManager.getCameraIdList();\n        } catch (CameraAccessException e) {\n            e.printStackTrace();\n        }\n        mFocusRect = new Rect();\n\n        mAlphaInAnimation = AnimationUtils.loadAnimation(mContext, R.anim.alpha_in);\n        mAlphaOutAnimation = AnimationUtils.loadAnimation(mContext, R.anim.alpha_out);\n    }\n\n    private TextView mTextView;\n\n    /**\n     * 状态文字 赋值\n     * @param mTextView tv\n     */\n    public void setShowTextView(TextView mTextView){\n        this.mTextView = mTextView;\n    }\n\n\n    @Override\n    public void cameraZoom(float scale) {\n        if (scale < 1.0f) {\n            scale = 1.0f;\n        }\n        if (scale <= mMaxZoom) {\n            int cropW = (int) ((mZoomSize.getWidth() / (mMaxZoom * 2.6)) * scale);\n            int cropH = (int) ((mZoomSize.getHeight() / (mMaxZoom * 2.6)) * scale);\n\n            Rect zoom = new Rect(cropW, cropH,\n                    mZoomSize.getWidth() - cropW,\n                    mZoomSize.getHeight() - cropH);\n            mPreviewBuilder.set(CaptureRequest.SCALER_CROP_REGION, zoom);\n            mZoomRect = zoom;\n            updatePreview();   //重复更新预览请求\n        }\n    }\n\n    /**\n     * 获取最大zoom\n     *\n     * @return 放大数值\n     */\n    public float getMaxZoom() {\n        return mMaxZoom;\n    }\n\n    /**\n     * 初始化拍照的图片读取类\n     */\n    private void initImageReader() {\n        //取最大的分辨率\n        Size largest = Collections.max(Arrays.asList(mMap.getOutputSizes(ImageFormat.JPEG)),\n                new CompareSizesByArea());\n        mZoomSize = largest;\n        //实例化拍照用的图片读取类\n        if (mImageReader != null) {\n            mImageReader.close();\n        }\n        mImageReader = ImageReader.newInstance(largest.getWidth(),\n                largest.getHeight(), ImageFormat.JPEG, 2);\n    }\n\n    /**\n     * 初始化一个适合的预览尺寸\n     */\n    private void initSize() {\n        Size largest = Collections.max(\n                Arrays.asList(mMap.getOutputSizes(ImageFormat.JPEG)),\n                new CompareSizesByArea());\n\n        Point displaySize = new Point();\n        ((Activity) mContext).getWindowManager().getDefaultDisplay().getSize(displaySize);\n\n        mLargest = chooseOptimalSize(mMap.getOutputSizes(SurfaceTexture.class),\n                this.mTextureView.getWidth(),\n                this.mTextureView.getHeight(),\n                displaySize.x,\n                displaySize.y,\n                largest\n        );\n    }\n\n    @RequiresApi(api = Build.VERSION_CODES.M)\n    @SuppressLint(\"MissingPermission\")\n    @Override\n    public boolean openCamera(CameraType cameraType) {\n\n        if (mIsCameraOpen.get()) {\n            return true;\n        }\n        mIsCameraOpen.set(true);\n        mZoomRect = null;\n        this.mNowCameraType = cameraType;\n        int cameraTypeId;\n        switch (cameraType) {\n            default:\n            case BACK:\n                cameraTypeId = CameraCharacteristics.LENS_FACING_BACK;\n                break;\n            case FRONT:\n                cameraTypeId = CameraCharacteristics.LENS_FACING_FRONT;\n                break;\n            case USB:\n                cameraTypeId = CameraCharacteristics.LENS_FACING_EXTERNAL;\n                break;\n        }\n\n        try {\n            for (String cameraId : mCameraIds) {\n                mCharacteristics = mCameraManager.getCameraCharacteristics(cameraId);\n                Integer facing = mCharacteristics.get(CameraCharacteristics.LENS_FACING);\n                // 曝光增益 范围\n                range1 = mCharacteristics.get(CameraCharacteristics.CONTROL_AE_COMPENSATION_RANGE);\n                //获取支持的iso范围\n                isoRange = mCharacteristics.get(CameraCharacteristics.SENSOR_INFO_SENSITIVITY_RANGE);\n                // 自动曝光模式\n                int[] avails = mCharacteristics.get(CameraCharacteristics.CONTROL_AE_AVAILABLE_MODES);\n                // 白平衡mode 列表\n                int[] aa = mCharacteristics.get(CameraCharacteristics.CONTROL_AWB_AVAILABLE_MODES);\n                // 最大白平衡数\n                Integer maxAwb = mCharacteristics.get(CameraCharacteristics.CONTROL_MAX_REGIONS_AWB);\n                //获取曝光时间 范围\n                etr = mCharacteristics.get(CameraCharacteristics.SENSOR_INFO_EXPOSURE_TIME_RANGE);\n\n                Boolean awbAva = mCharacteristics.get(CameraCharacteristics.CONTROL_AWB_LOCK_AVAILABLE);\n\n                if (facing != null && facing != cameraTypeId) {\n                    continue;\n                }\n\n                // 获取最大 放大倍数\n                Float maxZoom = mCharacteristics.get(CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM);\n                if (maxZoom != null) {\n                    mMaxZoom = maxZoom;\n                }\n\n                //获取摄像头支持的流配置信息\n                mMap = mCharacteristics\n                        .get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);\n                if (mMap == null) {\n                    return false;\n                }\n                //初始化拍照的图片读取类\n                initImageReader();\n                //初始化尺寸\n                initSize();\n\n                //获取摄像头角度\n                mSensorOrientation = mCharacteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);\n\n                mVideoSize = chooseVideoSize(mMap.getOutputSizes(MediaRecorder.class));\n                if (mTextureView != null) {\n                    ((AutoFitTextureView) mTextureView).setAspectRatio(mLargest.getHeight(), mLargest.getWidth());\n                }\n\n                //检查是否这个摄像头是否支持闪光灯，拍照模式的时候使用\n                Boolean available = mCharacteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE);\n                mFlashSupported = available == null ? false : available;\n\n                this.mCameraId = cameraId;\n                mPreviewRect = new Rect(0, 0, mTextureView.getWidth(), mTextureView.getHeight());\n                mCoordinateTransformer = new CoordinateTransformer(mCharacteristics, new RectF(mPreviewRect));\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return openCamera(mCameraId);\n    }\n\n    @SuppressLint(\"MissingPermission\")\n    private boolean openCamera(String cameraId) {\n        try {\n            mCameraManager.openCamera(cameraId, mStateCallback, null);\n        } catch (CameraAccessException e) {\n            e.printStackTrace();\n            return false;\n        }\n        return true;\n    }\n\n    @Override\n    public void closeCamera() {\n        Log.e(\"camera\", \"关闭摄像头\");\n        mIsCameraOpen.set(false);\n\n        closePreviewSession();\n        if (mCameraDevice != null) {\n            mCameraDevice.close();\n            mCameraDevice = null;\n        }\n        if (mImageReader != null) {\n            mImageReader.close();\n            mImageReader = null;\n        }\n    }\n\n    @RequiresApi(api = Build.VERSION_CODES.M)\n    @Override\n    public boolean switchCamera(CameraType cameraType) {\n        closeCamera();\n        return openCamera(cameraType);\n    }\n\n    @Override\n    public boolean startPreview() {\n        if (mBackgroundHandler == null) {\n            return false;\n        }\n        try {\n\n            //初始化预览的尺寸\n            initSize();\n\n            SurfaceTexture surfaceTexture = mTextureView.getSurfaceTexture();\n            surfaceTexture.setDefaultBufferSize(mLargest.getWidth(), mLargest.getHeight());\n            mPreViewSurface = new Surface(surfaceTexture);\n            //创建一个预览请求\n            mPreviewBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);\n            //添加预览输出目标画面\n            mPreviewBuilder.addTarget(mPreViewSurface);\n\n            if (mZoomRect != null) {\n                //放大的矩阵\n                mPreviewBuilder.set(CaptureRequest.SCALER_CROP_REGION, mZoomRect);\n            }\n            //当前线程创建一个预览请求\n            mCameraDevice.createCaptureSession(Arrays.asList(mPreViewSurface,\n                    mImageReader.getSurface()), new CameraCaptureSession.StateCallback() {\n                @Override\n                public void onConfigured(CameraCaptureSession session) {\n                    mPreviewSession = session;\n                    setup3AControlsLocked(mPreviewBuilder);\n                    //重复更新预览请求\n                    updatePreview();\n                    if (mCameraReady != null) {\n                        mCameraReady.onCameraReady();\n                    }\n                }\n\n                @Override\n                public void onConfigureFailed(CameraCaptureSession session) {\n\n                }\n            }, mBackgroundHandler);\n        } catch (CameraAccessException e) {\n            e.printStackTrace();\n            return false;\n        }\n        return true;\n    }\n\n    /**\n     * 更新预览界面\n     */\n    private void updatePreview() {\n        if (mCameraDevice == null) {\n            return;\n        }\n        try {\n            //  mPreviewBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);\n            mPreviewSession.setRepeatingRequest(\n                    mPreviewBuilder.build(),\n                    null,\n                    mBackgroundHandler\n            );\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n\n\n    @Override\n    public void resumePreview() {\n        try {\n            if (!mNoAFRun) {\n                mPreviewBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,\n                        CameraMetadata.CONTROL_AF_TRIGGER_CANCEL);\n                mPreviewBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,\n                        CameraMetadata.CONTROL_AF_TRIGGER_IDLE);\n            }\n            if (!isLegacyLocked()) {\n                // Tell the camera to lock focus.\n                mPreviewBuilder.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,\n                        CameraMetadata.CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL);\n                mPreviewBuilder.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,\n                        CameraMetadata.CONTROL_AE_PRECAPTURE_TRIGGER_IDLE);\n            }\n            mIsAFRequest = false;\n            mCameraState = 0;\n            mPreviewSession.capture(mPreviewBuilder.build(), null,\n                    mBackgroundHandler);\n            updatePreview();\n        } catch (CameraAccessException e) {\n            e.printStackTrace();\n        }\n    }\n\n    @Override\n    public boolean startVideoRecord(String path, int mediaType) {\n        if (mIsRecordVideo.get()){\n            new Throwable(\"video record is recording\");\n        }\n        if (path == null){\n            new Throwable(\"path can not null\");\n        }\n        if (mediaType != MediaRecorder.OutputFormat.MPEG_4){\n            new Throwable(\"this mediaType can not support\");\n        }\n        if (!setVideoRecordParam(path)){\n            return false;\n        }\n        startRecordVideo();\n        return true;\n    }\n\n    /**\n     * 设置录像的参数\n     *\n     * @param path\n     * @return\n     */\n    private boolean setVideoRecordParam(String path) {\n        mMediaRecorder = new MediaRecorder();\n\n        mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);\n        mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);\n        mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);\n        mMediaRecorder.setOutputFile(path);\n\n        int bitRate = mVideoSize.getWidth() * mVideoSize.getHeight();\n        bitRate = mVideoSize.getWidth() < 1080 ? bitRate * 2 : bitRate;\n\n        mMediaRecorder.setVideoEncodingBitRate(bitRate);\n        mMediaRecorder.setVideoFrameRate(15);\n        mMediaRecorder.setVideoSize(mVideoSize.getWidth(), mVideoSize.getHeight());\n        mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);\n\n        mMediaRecorder.setAudioEncodingBitRate(8000);\n        mMediaRecorder.setAudioChannels(1);\n        mMediaRecorder.setAudioSamplingRate(8000);\n        mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);\n\n        if (mNowCameraType == CameraType.BACK) {\n            //后置摄像头图像要旋转90度\n            mMediaRecorder.setOrientationHint(90);\n        } else {\n            //前置摄像头图像要旋转270度\n            mMediaRecorder.setOrientationHint(270);\n        }\n        try {\n            mMediaRecorder.prepare();\n        } catch (IOException e) {\n            e.printStackTrace();\n            return false;\n        }\n        return true;\n    }\n\n    @Override\n    public void stopVideoRecord() {\n        if (mIsRecordVideo.get()) {\n            mIsRecordVideo.set(false);\n        } else {\n            return;\n        }\n        mMediaRecorder.setOnErrorListener(null);\n        mMediaRecorder.setOnInfoListener(null);\n        mMediaRecorder.setPreviewDisplay(null);\n        mMediaRecorder.stop();\n        mMediaRecorder.reset();\n        mMediaRecorder.release();\n        // startPreview();\n    }\n\n    @Override\n    public boolean takePhone(String path, MediaType mediaType) {\n        this.mPhotoPath = path;\n        setTakePhotoFlashMode(mPreviewBuilder);\n        updatePreview();\n        // lockFocus();\n\n        if (!mNoAFRun) {\n            if (mIsAFRequest) {\n                mPreviewBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_AUTO);\n                mPreviewBuilder.set(CaptureRequest.CONTROL_AF_REGIONS, AFRegions);\n                mPreviewBuilder.set(CaptureRequest.CONTROL_AE_REGIONS, AERegions);\n            }\n            mPreviewBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,\n                    CameraMetadata.CONTROL_AF_TRIGGER_START);\n        }\n        if (!isLegacyLocked()) {\n            // Tell the camera to lock focus.\n            mPreviewBuilder.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,\n                    CameraMetadata.CONTROL_AE_PRECAPTURE_TRIGGER_START);\n        }\n        mCameraState = WAITING_LOCK;\n        if (!mFlashSupported) {\n            capturePhoto();\n        } else {\n            switch (mNowFlashState) {\n                case CLOSE:\n                    capturePhoto();\n                    break;\n                case OPEN:\n                case AUTO:\n                    mBackgroundHandler.postDelayed(new Runnable() {\n                        @Override\n                        public void run() {\n                            try {\n                                mPreviewSession.capture(mPreviewBuilder.build(), mCaptureCallback,\n                                        mBackgroundHandler);\n                            } catch (CameraAccessException e) {\n                                e.printStackTrace();\n                            }\n                        }\n                    }, 800);\n                    break;\n                default:\n                    break;\n            }\n        }\n        return true;\n    }\n\n    private boolean isLegacyLocked() {\n        return mCharacteristics.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL) ==\n                CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY;\n    }\n\n    private void setup3AControlsLocked(CaptureRequest.Builder builder) {\n        // Enable auto-magical 3A run by camera device\n        builder.set(CaptureRequest.CONTROL_MODE,\n                CaptureRequest.CONTROL_MODE_AUTO);\n\n        Float minFocusDist =\n                mCharacteristics.get(CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE);\n\n        // If MINIMUM_FOCUS_DISTANCE is 0, lens is fixed-focus and we need to skip the AF run.\n        mNoAFRun = (minFocusDist == null || minFocusDist == 0);\n\n        if (!mNoAFRun) {\n            // If there is a \"continuous picture\" mode available, use it, otherwise default to AUTO.\n            if (contains(mCharacteristics.get(\n                    CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES),\n                    CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE)) {\n                builder.set(CaptureRequest.CONTROL_AF_MODE,\n                        CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);\n            } else {\n                builder.set(CaptureRequest.CONTROL_AF_MODE,\n                        CaptureRequest.CONTROL_AF_MODE_AUTO);\n            }\n        }\n\n        // If there is an auto-magical flash control mode available, use it, otherwise default to\n        // the \"on\" mode, which is guaranteed to always be available.\n        if (mNowFlashState != FlashState.CLOSE) {\n            if (contains(mCharacteristics.get(\n                    CameraCharacteristics.CONTROL_AE_AVAILABLE_MODES),\n                    CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH)) {\n                builder.set(CaptureRequest.CONTROL_AE_MODE,\n                        CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);\n            } else {\n                builder.set(CaptureRequest.CONTROL_AE_MODE,\n                        CaptureRequest.CONTROL_AE_MODE_ON);\n            }\n        }\n\n        // If there is an auto-magical white balance control mode available, use it.\n        if (contains(mCharacteristics.get(\n                CameraCharacteristics.CONTROL_AWB_AVAILABLE_MODES),\n                CaptureRequest.CONTROL_AWB_MODE_AUTO)) {\n            // Allow AWB to run auto-magically if this device supports this\n            builder.set(CaptureRequest.CONTROL_AWB_MODE,\n                    CaptureRequest.CONTROL_AWB_MODE_AUTO);\n        }\n    }\n\n    /**\n     * 真正拍照\n     */\n    private void capturePhoto() {\n        mIsCapture = true;\n        final CaptureRequest.Builder captureBuilder;\n        try {\n            //设置拍照后的回调监听\n            mImageReader.setOnImageAvailableListener(mOnImageAvailableListener, mBackgroundHandler);\n            captureBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);\n            captureBuilder.addTarget(mImageReader.getSurface());\n            //设置自动对焦\n            captureBuilder.set(CaptureRequest.CONTROL_AF_MODE,\n                    CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);\n            // Use the same AE and AF modes as the preview.\n      /*      if(mNowFlashState != FlashState.CLOSE) {\n                if(mFlashSupported)\n                    setup3AControlsLocked(captureBuilder);\n            }*/\n\n            mPhotoRotation = getOrientation(mDeviceRotation);\n            captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, mPhotoRotation);\n\n            //放大的矩阵\n            if (mZoomRect != null) {\n                captureBuilder.set(CaptureRequest.SCALER_CROP_REGION, mZoomRect);\n            }\n            setTakePhotoFlashMode(captureBuilder);\n            captureBuilder.setTag(1);\n            mPreviewSession.stopRepeating();\n            mPreviewSession.abortCaptures();\n            mBackgroundHandler.postDelayed(new Runnable() {\n                @Override\n                public void run() {\n                    try {\n                        mPreviewSession.capture(captureBuilder.build(), new CameraCaptureSession.CaptureCallback() {\n                            @Override\n                            public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) {\n                            }\n\n                            @Override\n                            public void onCaptureFailed(CameraCaptureSession session, CaptureRequest request, CaptureFailure failure) {\n\n                            }\n\n\n                        }, mBackgroundHandler);\n                    } catch (CameraAccessException e) {\n                        e.printStackTrace();\n                    }\n                }\n            }, 200);\n        } catch (CameraAccessException e) {\n            e.printStackTrace();\n        }\n    }\n\n    @Override\n    public Size getPreViewSize() {\n        return mLargest;\n    }\n\n    @Override\n    public void setSurface(Surface surface) {\n        //this.mSurface = surface;\n    }\n\n    /**\n     * 如果设置了textureView则不用设置Surface\n     *\n     * @param textureView textureView\n     */\n    @Override\n    public void setTextureView(TextureView textureView) {\n        this.mTextureView = textureView;\n    }\n\n    @Override\n    public void setTakePhotoListener(TakePhotoListener mTakePhotoListener) {\n        this.mTakePhotoListener = mTakePhotoListener;\n    }\n\n    @Override\n    public void setCameraReady(CameraReady cameraReady) {\n        this.mCameraReady = cameraReady;\n    }\n\n    @Override\n    public void flashSwitchState(FlashState mFlashState) {\n        mNowFlashState = mFlashState;\n        if (CAMERA_STATE == CameraMode.TAKE_PHOTO) {\n            setTakePhotoFlashMode(mPreviewBuilder);\n            updatePreview();\n        }\n    }\n\n    @Override\n    public void setCameraState(CameraMode cameraMode) {\n        CAMERA_STATE = cameraMode;\n        if (CAMERA_STATE == CameraMode.TAKE_PHOTO) {\n            setTakePhotoFlashMode(mPreviewBuilder);\n            updatePreview();\n        }\n    }\n\n    private void toFocusRect(RectF rectF) {\n        mFocusRect.left = Math.round(rectF.left);\n        mFocusRect.top = Math.round(rectF.top);\n        mFocusRect.right = Math.round(rectF.right);\n        mFocusRect.bottom = Math.round(rectF.bottom);\n    }\n\n    private MeteringRectangle calcTapAreaForCamera2(int areaSize, int weight, float x, float y) {\n        int left = clamp((int) x - areaSize / 2,\n                mPreviewRect.left, mPreviewRect.right - areaSize);\n        int top = clamp((int) y - areaSize / 2,\n                mPreviewRect.top, mPreviewRect.bottom - areaSize);\n        RectF rectF = new RectF(left, top, left + areaSize, top + areaSize);\n        toFocusRect(mCoordinateTransformer.toCameraSpace(rectF));\n        return new MeteringRectangle(mFocusRect, weight);\n    }\n\n    private MeteringRectangle[] AFRegions;\n    private MeteringRectangle[] AERegions;\n\n    @Override\n    public void requestFocus(float x, float y) {\n        mIsAFRequest = true;\n        MeteringRectangle rect = calcTapAreaForCamera2(\n                mTextureView.getWidth() / 5,\n                1000, x, y);\n\n        AFRegions = new MeteringRectangle[]{rect};\n        AERegions = new MeteringRectangle[]{rect};\n\n        Log.e(\"AFRegions\", \"AFRegions:\" + AFRegions[0].toString());\n\n        try {\n            final CaptureRequest.Builder mFocusBuilder =\n                    mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);\n\n            mFocusBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_AUTO);\n            mFocusBuilder.set(CaptureRequest.CONTROL_AF_REGIONS, AFRegions);\n            mFocusBuilder.set(CaptureRequest.CONTROL_AE_REGIONS, AERegions);\n            if (mZoomRect != null) {\n                mFocusBuilder.set(CaptureRequest.SCALER_CROP_REGION, mZoomRect);\n            }\n\n            mFocusBuilder.addTarget(mPreViewSurface);\n\n            if (CAMERA_STATE == CameraMode.RECORD_VIDEO) {\n                if (mRecordSurface != null) {\n                    mFocusBuilder.addTarget(mRecordSurface);\n                    setRecordVideoFlashMode(mFocusBuilder);\n                }\n            }\n\n            mPreviewSession.setRepeatingRequest(mFocusBuilder.build(),\n                    null, mBackgroundHandler);\n\n            //      mFocusBuilder.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, CameraMetadata.CONTROL_AE_PRECAPTURE_TRIGGER_START);\n            mFocusBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_START);\n\n            mPreviewSession.capture(mFocusBuilder.build(),\n                    null, mBackgroundHandler);\n\n        } catch (CameraAccessException e) {\n            e.printStackTrace();\n        }\n    }\n\n    /**\n     * 开启后台线程\n     */\n    public void startBackgroundThread() {\n        mBackgroundThread = new HandlerThread(CameraHelper.class.getSimpleName());\n        mBackgroundThread.start();\n        mBackgroundHandler = new Handler(mBackgroundThread.getLooper());\n    }\n\n    /**\n     * 停止后台进程\n     */\n    public void stopBackgroundThread() {\n        if (mBackgroundThread != null){\n            mBackgroundThread.quitSafely();\n        }\n        try {\n            if (mBackgroundThread != null){\n                mBackgroundThread.join();\n            }\n            mBackgroundThread = null;\n            mBackgroundHandler = null;\n        } catch (InterruptedException e) {\n            e.printStackTrace();\n        }\n    }\n\n    private void setTakePhotoFlashMode(CaptureRequest.Builder builder) {\n        if (!mFlashSupported){\n            return;\n        }\n        switch (mNowFlashState) {\n            case CLOSE:\n                builder.set(CaptureRequest.CONTROL_AE_MODE,\n                        CaptureRequest.CONTROL_AE_MODE_ON);\n                builder.set(CaptureRequest.FLASH_MODE,\n                        CaptureRequest.FLASH_MODE_OFF);\n                break;\n            case OPEN:\n                builder.set(CaptureRequest.CONTROL_AE_MODE,\n                        CaptureRequest.CONTROL_AE_MODE_ON_ALWAYS_FLASH);\n                break;\n            case AUTO:\n                builder.set(CaptureRequest.CONTROL_AE_MODE,\n                        CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);\n                Log.e(\"mode\", \"自动闪光灯\");\n                break;\n            default:\n                break;\n        }\n    }\n\n    /**\n     * 设置 录像闪光灯\n     * @param builder\n     */\n    private void setRecordVideoFlashMode(CaptureRequest.Builder builder) {\n        if (!mFlashSupported){\n            return;\n        }\n        switch (mNowFlashState) {\n            case CLOSE:\n                builder.set(CaptureRequest.FLASH_MODE,\n                        CaptureRequest.FLASH_MODE_OFF);\n                break;\n            case OPEN:\n                builder.set(CaptureRequest.FLASH_MODE,\n                        CaptureRequest.FLASH_MODE_TORCH);\n                break;\n            case AUTO:\n                if (mLight < 10.0f) {\n                    builder.set(CaptureRequest.FLASH_MODE,\n                            CaptureRequest.FLASH_MODE_TORCH);\n                }\n                break;\n        }\n    }\n\n    /**\n     * 设置光线强度\n     */\n    public void setLight(float light) {\n        this.mLight = light;\n    }\n\n    /**\n     * 开始录像\n     */\n    private void startRecordVideo() {\n        try {\n            closePreviewSession();\n\n            //录像的时候 取最大的分辨率\n            mLargest = Collections.max(Arrays.asList(mMap.getOutputSizes(SurfaceTexture.class)),\n                    new CompareSizesByArea());\n\n            if (mCameraDevice == null) {\n                return;\n            }\n\n            mPreviewBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD);\n\n            setRecordVideoFlashMode(mPreviewBuilder);\n\n            SurfaceTexture surfaceTexture = mTextureView.getSurfaceTexture();\n            surfaceTexture.setDefaultBufferSize(mLargest.getWidth(), mLargest.getHeight());\n           /* if(mSurface != null)\n                mSurface.release();*/\n            mPreViewSurface = new Surface(surfaceTexture);\n\n            mPreviewBuilder.addTarget(mPreViewSurface);\n            mRecordSurface = mMediaRecorder.getSurface();\n            mPreviewBuilder.addTarget(mRecordSurface);\n            List<Surface> surfaceList = new ArrayList<>();\n            surfaceList.add(mPreViewSurface);\n            surfaceList.add(mRecordSurface);\n            if (mZoomRect != null){\n                //放大的矩阵\n                mPreviewBuilder.set(CaptureRequest.SCALER_CROP_REGION, mZoomRect);\n            }\n            mCameraDevice.createCaptureSession(surfaceList, new CameraCaptureSession.StateCallback() {\n                @Override\n                public void onConfigured(CameraCaptureSession session) {\n                    mPreviewSession = session;\n                    updatePreview();\n                    mIsRecordVideo.set(true);\n                    mMediaRecorder.start();\n                }\n\n                @Override\n                public void onConfigureFailed(CameraCaptureSession session) {\n\n                }\n            }, mBackgroundHandler);\n        } catch (CameraAccessException e) {\n            e.printStackTrace();\n        }\n    }\n\n    private void closePreviewSession() {\n        if (mPreviewSession != null) {\n            mPreviewSession.close();\n            mPreviewSession = null;\n        }\n    }\n\n    /**\n     * 释放资源\n     */\n    public void destroy() {\n        //mSurface.release();\n    }\n\n    private int getOrientation(int rotation) {\n        return (ORIENTATIONS.get(rotation) + mSensorOrientation + 270) % 360;\n    }\n\n    /**\n     * 设置当前相机位置\n     *\n     * @param rotation 角度\n     */\n    public void setDeviceRotation(int rotation) {\n        this.mDeviceRotation = rotation;\n    }\n\n\n    /**\n     * seekBar 滑动监听事件\n     */\n    @Override\n    public void doInProgress1() {\n        mTextView.setText(\"自动\");\n        mPreviewBuilder.set(CaptureRequest.CONTROL_AWB_MODE, CameraMetadata.CONTROL_AWB_MODE_AUTO);\n        updatePreview();\n    }\n\n    @Override\n    public void doInProgress2() {\n        mTextView.setText(\"多云\");\n        mPreviewBuilder.set(CaptureRequest.CONTROL_AWB_MODE, CameraMetadata.CONTROL_AWB_MODE_CLOUDY_DAYLIGHT);\n        updatePreview();\n    }\n\n    @Override\n    public void doInProgress3() {\n        mTextView.setText(\"白天\");\n        mPreviewBuilder.set(CaptureRequest.CONTROL_AWB_MODE, CameraMetadata.CONTROL_AWB_MODE_DAYLIGHT);\n        updatePreview();\n    }\n\n    @Override\n    public void doInProgress4() {\n        mTextView.setText(\"日光灯\");\n        mPreviewBuilder.set(CaptureRequest.CONTROL_AWB_MODE, CameraMetadata.CONTROL_AWB_MODE_FLUORESCENT);\n        updatePreview();\n    }\n\n    @Override\n    public void doInProgress5() {\n        mTextView.setText(\"白炽灯\");\n        mPreviewBuilder.set(CaptureRequest.CONTROL_AWB_MODE, CameraMetadata.CONTROL_AWB_MODE_INCANDESCENT);\n        updatePreview();\n    }\n\n    @Override\n    public void doInProgress6() {\n        mTextView.setText(\"阴影\");\n        mPreviewBuilder.set(CaptureRequest.CONTROL_AWB_MODE, CameraMetadata.CONTROL_AWB_MODE_SHADE);\n        updatePreview();\n    }\n\n    @Override\n    public void doInProgress7() {\n        mTextView.setText(\"黄昏\");\n        mPreviewBuilder.set(CaptureRequest.CONTROL_AWB_MODE, CameraMetadata.CONTROL_AWB_MODE_TWILIGHT);\n        updatePreview();\n    }\n\n    @Override\n    public void doInProgress8() {\n        mTextView.setText(\"暖光\");\n        mPreviewBuilder.set(CaptureRequest.CONTROL_AWB_MODE, CameraMetadata.CONTROL_AWB_MODE_WARM_FLUORESCENT);\n        updatePreview();\n    }\n\n    @Override\n    public void onStopTrackingTouch(int num) {\n        switch (num) {\n            case 0:\n                mTextView.setText(\"自动\");\n                mPreviewBuilder.set(CaptureRequest.CONTROL_AWB_MODE, CameraMetadata.CONTROL_AWB_MODE_AUTO);\n                break;\n            case 10:\n                mTextView.setText(\"多云\");\n                mPreviewBuilder.set(CaptureRequest.CONTROL_AWB_MODE, CameraMetadata.CONTROL_AWB_MODE_CLOUDY_DAYLIGHT);\n                break;\n            case 20:\n                mTextView.setText(\"白天\");\n                mPreviewBuilder.set(CaptureRequest.CONTROL_AWB_MODE, CameraMetadata.CONTROL_AWB_MODE_DAYLIGHT);\n                break;\n            case 30:\n                mTextView.setText(\"日光灯\");\n                mPreviewBuilder.set(CaptureRequest.CONTROL_AWB_MODE, CameraMetadata.CONTROL_AWB_MODE_FLUORESCENT);\n                break;\n            case 40:\n                mTextView.setText(\"白炽灯\");\n                mPreviewBuilder.set(CaptureRequest.CONTROL_AWB_MODE, CameraMetadata.CONTROL_AWB_MODE_INCANDESCENT);\n                break;\n            case 50:\n                mTextView.setText(\"阴影\");\n                mPreviewBuilder.set(CaptureRequest.CONTROL_AWB_MODE, CameraMetadata.CONTROL_AWB_MODE_SHADE);\n                break;\n            case 60:\n                mTextView.setText(\"黄昏\");\n                mPreviewBuilder.set(CaptureRequest.CONTROL_AWB_MODE, CameraMetadata.CONTROL_AWB_MODE_TWILIGHT);\n                break;\n            case 70:\n                mTextView.setText(\"暖光\");\n                mPreviewBuilder.set(CaptureRequest.CONTROL_AWB_MODE, CameraMetadata.CONTROL_AWB_MODE_WARM_FLUORESCENT);\n                break;\n        }\n        updatePreview();\n        mTextView.startAnimation(mAlphaOutAnimation);\n        mTextView.setVisibility(View.INVISIBLE);\n    }\n\n    @Override\n    public void onStartTrackingTouch(SeekBar seekBar) {\n        mTextView.setVisibility(View.VISIBLE);\n        mTextView.startAnimation(mAlphaInAnimation);\n    }\n\n\n\n    /**\n     * 异步保存照片\n     */\n    private class PhotoSaver implements Runnable {\n\n        /**\n         * 图片文件\n         */\n        private File mFile;\n\n        /**\n         * 拍照的图片\n         */\n        private Image mImage;\n\n        public PhotoSaver(Image image, File file) {\n            this.mImage = image;\n            this.mFile = file;\n        }\n\n        @Override\n        public void run() {\n            ByteBuffer byteBuffer = mImage.getPlanes()[0].getBuffer();\n            byte[] buffer = new byte[byteBuffer.remaining()];\n            byteBuffer.get(buffer);\n            FileOutputStream fileOutputStream = null;\n            try {\n                fileOutputStream = new FileOutputStream(mFile);\n                fileOutputStream.write(buffer);\n            } catch (Exception e) {\n                e.printStackTrace();\n            } finally {\n                mImage.close();\n                byteBuffer.clear();\n                if (fileOutputStream != null) {\n                    try {\n                        fileOutputStream.close();\n                    } catch (IOException e) {\n                        e.printStackTrace();\n                    }\n                }\n                resumePreview();\n                if (mTakePhotoListener != null){\n                    mTakePhotoListener.onTakePhotoFinish(mFile, mPhotoRotation, 0, 0);\n                }\n            }\n        }\n    }\n\n\n    private static final int WAITING_LOCK = 1;\n    private int mCameraState = 0;\n\n    private CameraCaptureSession.CaptureCallback mCaptureCallback\n            = new CameraCaptureSession.CaptureCallback() {\n\n        @Override\n        public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) {\n            process(result);\n        }\n\n        @Override\n        public void onCaptureProgressed(CameraCaptureSession session, CaptureRequest request, CaptureResult partialResult) {\n            process(partialResult);\n        }\n\n        private void process(CaptureResult result) {\n            switch (mCameraState) {\n                case WAITING_LOCK:\n                    boolean readyToCapture = true;\n                    if (!mNoAFRun) {\n                        Integer afState = result.get(CaptureResult.CONTROL_AF_STATE);\n                        if (afState == null) {\n                            break;\n                        }\n\n                        // If auto-focus has reached locked state, we are ready to capture\n                        readyToCapture =\n                                (afState == CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED ||\n                                        afState == CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED);\n                    }\n\n                    // If we are running on an non-legacy device, we should also wait until\n                    // auto-exposure and auto-white-balance have converged as well before\n                    // taking a picture.\n                    if (!isLegacyLocked()) {\n                        Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);\n                        Integer awbState = result.get(CaptureResult.CONTROL_AWB_STATE);\n                        if (aeState == null || awbState == null) {\n                            break;\n                        }\n\n                        readyToCapture = readyToCapture &&\n                                aeState == CaptureResult.CONTROL_AE_STATE_CONVERGED &&\n                                awbState == CaptureResult.CONTROL_AWB_STATE_CONVERGED;\n                    }\n\n                    // If we haven't finished the pre-capture sequence but have hit our maximum\n                    // wait timeout, too bad! Begin capture anyway.\n                    if (!readyToCapture) {\n                        readyToCapture = true;\n                    }\n\n                    if (readyToCapture) {\n                        // Capture once for each user tap of the \"Picture\" button.\n                        capturePhoto();\n                        // After this, the camera will go back to the normal state of preview.\n                        mCameraState = 0;\n                    }\n            }\n        }\n    };\n\n    /**\n     * 拍照的有效回调\n     */\n    private ImageReader.OnImageAvailableListener mOnImageAvailableListener = new ImageReader.OnImageAvailableListener() {\n        @Override\n        public void onImageAvailable(ImageReader reader) {\n            if (mIsCapture) {\n                Image image = reader.acquireNextImage();\n                new Thread(new PhotoSaver(image, new File(mPhotoPath))).start();\n                mIsCapture = false;\n            }\n        }\n    };\n\n    /**\n     * 打开摄像头状态回调\n     */\n    private CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {\n        @Override\n        public void onOpened(CameraDevice camera) {\n            mCameraDevice = camera;\n            startPreview();\n        }\n\n        @Override\n        public void onDisconnected(CameraDevice camera) {\n            camera.close();\n            mCameraDevice = null;\n        }\n\n        @Override\n        public void onError(CameraDevice camera, int error) {\n            camera.close();\n            mCameraDevice = null;\n        }\n    };\n\n    private static Size chooseVideoSize(Size[] choices) {\n        for (Size size : choices) {\n            if (size.getWidth() == size.getHeight() * 4 / 3 && size.getWidth() <= 1080) {\n                return size;\n            }\n        }\n        return choices[choices.length - 1];\n    }\n\n\n    /**\n     * 选择一个适合的预览尺寸，不然有一些机型不支持\n     *\n     * @param choices\n     * @param textureViewWidth\n     * @param textureViewHeight\n     * @param maxWidth\n     * @param maxHeight\n     * @param aspectRatio\n     * @return\n     */\n    private static Size chooseOptimalSize(Size[] choices, int textureViewWidth,\n                                          int textureViewHeight, int maxWidth, int maxHeight, Size aspectRatio) {\n\n        // Collect the supported resolutions that are at least as big as the preview Surface\n        List<Size> bigEnough = new ArrayList<>();\n        // Collect the supported resolutions that are smaller than the preview Surface\n        List<Size> notBigEnough = new ArrayList<>();\n        int w = aspectRatio.getWidth();\n        int h = aspectRatio.getHeight();\n        for (Size option : choices) {\n            if (option.getWidth() <= maxWidth && option.getHeight() <= maxHeight &&\n                    option.getHeight() == option.getWidth() * h / w) {\n                if (option.getWidth() >= textureViewWidth &&\n                        option.getHeight() >= textureViewHeight) {\n                    bigEnough.add(option);\n                } else {\n                    notBigEnough.add(option);\n                }\n            }\n        }\n\n        // Pick the smallest of those big enough. If there is no one big enough, pick the\n        // largest of those not big enough.\n        if (bigEnough.size() > 0) {\n            return Collections.min(bigEnough, new CompareSizesByArea());\n        } else if (notBigEnough.size() > 0) {\n            return Collections.max(notBigEnough, new CompareSizesByArea());\n        } else {\n            return choices[0];\n        }\n    }\n\n    /**\n     * Compares two {@code Size}s based on their areas.\n     */\n    static class CompareSizesByArea implements Comparator<Size> {\n\n        @Override\n        public int compare(Size lhs, Size rhs) {\n            // We cast here to ensure the multiplications won't overflow\n            return Long.signum((long) lhs.getWidth() * lhs.getHeight() -\n                    (long) rhs.getWidth() * rhs.getHeight());\n        }\n\n    }\n\n    /**\n     * Return true if the given array contains the given integer.\n     *\n     * @param modes array to check.\n     * @param mode  integer to get for.\n     * @return true if the array contains the given integer, otherwise false.\n     */\n    private static boolean contains(int[] modes, int mode) {\n        if (modes == null) {\n            return false;\n        }\n        for (int i : modes) {\n            if (i == mode) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    private static int clamp(int x, int min, int max) {\n        if (x > max) {\n            return max;\n        }\n        if (x < min) {\n            return min;\n        }\n        return x;\n    }\n\n\n    /**\n     * 视频录像保存的路径\n     *\n     * @return\n     */\n    public String getVideoFilePath() {\n//        File dir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).getAbsoluteFile();\n//        return (dir == null ? \"\" : (dir.getAbsolutePath() + \"/\"))\n//                + System.currentTimeMillis() + \".mp4\";\n        return String.valueOf(new File(mContext.getExternalFilesDir(null), System.currentTimeMillis() + \".mp4\"));\n    }\n\n    /**\n     * 图片拍照的路径\n     *\n     * @return 图片路径\n     */\n    public String getPhotoFilePath() {\n//        File dir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).getAbsoluteFile();\n//        return (dir == null ? \"\" : (dir.getAbsolutePath() + \"/\")) + System.currentTimeMillis() + \".jpeg\";\n        return String.valueOf(new File(mContext.getExternalFilesDir(null), System.currentTimeMillis() + \".jpg\"));\n    }\n\n    /**\n     * dip 转 px\n     * @param context 上下文\n     * @param dipValue dip\n     * @return px\n     */\n    public int dip2px(Context context, float dipValue) {\n        return (int) (dipValue * context.getResources().getDisplayMetrics().density + 0.5f);\n    }\n\n    /**\n     * 整数s转 xx:xx:xx\n     *\n     * @param time time\n     * @return time\n     */\n    public String secToTime(int time) {\n        String timeStr;\n        int hour;\n        int minute;\n        int second;\n        if (time <= 0){\n            return \"00:00\";\n        }\n        else {\n            minute = time / 60;\n            if (minute < 60) {\n                second = time % 60;\n                timeStr = unitFormat(minute) + \":\" + unitFormat(second);\n            } else {\n                hour = minute / 60;\n                if (hour > 99){\n                    return \"99:59:59\";\n                }\n                minute = minute % 60;\n                second = time - hour * 3600 - minute * 60;\n                timeStr = unitFormat(hour) + \":\" + unitFormat(minute) + \":\" + unitFormat(second);\n            }\n        }\n        return timeStr;\n    }\n\n    /**\n     * 格式化 时间\n     * @param i 时间\n     * @return 格式化时间\n     */\n    private String unitFormat(int i) {\n        String retStr;\n        if (i >= 0 && i < 10){\n            retStr = \"0\" + Integer.toString(i);\n        }else{\n            retStr = \"\" + i;\n        }\n        return retStr;\n    }\n\n    /**\n     * 根据 文件获取uri\n     * @param context 上下文对象\n     * @param file 文件\n     * @return uri\n     */\n    public Uri getUriFromFile(Context context, File file) {\n        if (Build.VERSION.SDK_INT >= 24) {\n            return FileProvider.getUriForFile(context, context.getPackageName() + \".fileprovider\", file);\n        } else {\n            return Uri.fromFile(file);\n        }\n    }\n\n    public Range<Integer> getRange1 (){\n        return range1;\n    }\n\n    /**\n     * 设置ae 属性\n     */\n    public void setAERegions(int ae){\n        mPreviewBuilder.set(CaptureRequest.CONTROL_AE_EXPOSURE_COMPENSATION, ae);\n        updatePreview();\n    }\n\n    /**\n     * 曝光时间\n     */\n    private Range<Long> etr;\n\n    public Range<Long> getEtr(){\n        return etr;\n    }\n\n    /**\n     * 设置ae 属性\n     */\n    public void setAeTime(long aeTime){\n        mPreviewBuilder.set(CaptureRequest.SENSOR_EXPOSURE_TIME, aeTime);\n        updatePreview();\n    }\n\n    /**\n     * 设置 mPreviewBuilder 种类\n     * @param key CaptureRequest\n     * @param value v\n     * @param <T>\n     */\n    public <T> void setCameraBuilerMode(CaptureRequest.Key<T> key, T value) {\n        mPreviewBuilder.set(key, value);\n        updatePreview();\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/camera/cn/cameramaster/util/cameravideo/CoordinateTransformer.java",
    "content": "package camera.cn.cameramaster.util.cameravideo;\n\nimport android.graphics.Matrix;\nimport android.graphics.Rect;\nimport android.graphics.RectF;\nimport android.hardware.camera2.CameraCharacteristics;\nimport android.os.Build;\nimport android.support.annotation.RequiresApi;\n\n/**\n * 将坐标转换为预览坐标空间和相机驱动程序坐标空间。\n * @author ymc\n */\n\n@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)\npublic class CoordinateTransformer {\n\n    private final Matrix mPreviewToCameraTransform;\n    private RectF mDriverRectF;\n\n    /**\n     * 将矩形转换为相机坐标或从相机坐标转换并预览坐标空间。\n     * @param chr camera characteristics\n     * @param previewRect the preview rectangle size and position.\n     */\n\n    public CoordinateTransformer(CameraCharacteristics chr, RectF previewRect) {\n        if (!hasNonZeroArea(previewRect)) {\n            throw new IllegalArgumentException(\"previewRect\");\n        }\n        Rect rect = chr.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);\n        Integer sensorOrientation = chr.get(CameraCharacteristics.SENSOR_ORIENTATION);\n        int rotation = sensorOrientation == null ? 90 : sensorOrientation;\n        mDriverRectF = new RectF(rect);\n        Integer face = chr.get(CameraCharacteristics.LENS_FACING);\n        boolean mirrorX = face != null && face == CameraCharacteristics.LENS_FACING_FRONT;\n        mPreviewToCameraTransform = previewToCameraTransform(mirrorX, rotation, previewRect);\n    }\n\n    /**\n     * 将预览视图空间中的矩形转换为新的矩形相机视图空间。\n     *\n     * @param source the rectangle in preview view space\n     * @return the rectangle in camera view space.\n     */\n    public RectF toCameraSpace(RectF source) {\n        RectF result = new RectF();\n        mPreviewToCameraTransform.mapRect(result, source);\n        return result;\n    }\n\n    private Matrix previewToCameraTransform(boolean mirrorX, int sensorOrientation,\n                                            RectF previewRect) {\n        Matrix transform = new Matrix();\n        // Need mirror for front camera.\n        transform.setScale(mirrorX ? -1 : 1, 1);\n        // Because preview orientation is different  form sensor orientation,\n        // rotate to same orientation, Counterclockwise.\n        transform.postRotate(-sensorOrientation);\n        // Map rotated matrix to preview rect\n        transform.mapRect(previewRect);\n        // Map  preview coordinates to driver coordinates\n        Matrix fill = new Matrix();\n        fill.setRectToRect(previewRect, mDriverRectF, Matrix.ScaleToFit.FILL);\n        // Concat the previous transform on top of the fill behavior.\n        transform.setConcat(fill, transform);\n        // finally get transform matrix\n        return transform;\n    }\n\n    private boolean hasNonZeroArea(RectF rect) {\n        return rect.width() != 0 && rect.height() != 0;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/camera/cn/cameramaster/util/cameravideo/ICamera2.java",
    "content": "package camera.cn.cameramaster.util.cameravideo;\n\nimport android.util.Size;\nimport android.view.Surface;\nimport android.view.TextureView;\n\nimport java.io.File;\n\n/**\n * 相机 接口类\n */\n\npublic interface ICamera2 {\n\n    /**\n     * 缩放\n     * @param zoom 缩放比例\n     */\n    void cameraZoom(float zoom);\n\n    /**\n     * 打开摄像头\n     */\n    boolean openCamera(CameraType cameraType);\n\n    /**\n     * 关闭摄像头\n     */\n    void closeCamera();\n\n    /**\n     * 切换摄像头\n     * @param cameraType 切换摄像头类型\n     * @return boolean 是否切换成功\n     */\n    boolean switchCamera(CameraType cameraType);\n\n    /**\n     * 开启相机的预览模式\n     */\n    boolean startPreview();\n\n    /**\n     * 停止预览\n     */\n    void resumePreview();\n\n    /**\n     * 开始视频的录制\n     * @param path  存储路径\n     * @param mediaType  文件类型\n     */\n    boolean startVideoRecord(String path, int mediaType);\n\n    /**\n     * 停止视频录制\n     */\n    void stopVideoRecord();\n\n    /**\n     * 拍照\n     * @param path 存储路径\n     * @param mediaType  文件类型\n     */\n    boolean takePhone(String path, MediaType mediaType);\n\n    /**\n     * 获取预览大小\n     * @return\n     */\n    Size getPreViewSize();\n\n    void setSurface(Surface surface);\n\n    void setTextureView(TextureView textureView);\n\n    void setTakePhotoListener(TakePhotoListener mTakePhotoListener);\n\n    void setCameraReady(CameraReady mCameraReady);\n\n    void flashSwitchState(FlashState mFlashState);\n\n    void setCameraState(CameraMode cameraMode);\n\n    /**\n     * 手动请求对焦\n     * @param x\n     * @param y\n     */\n    void requestFocus(float x, float y);\n\n    /**\n     * 摄像头模式类型\n     */\n    enum CameraMode\n    {\n        RECORD_VIDEO,\n        TAKE_PHOTO\n    }\n\n    /**\n     * 当前只有mp4类型\n     */\n    enum MediaType\n    {\n        MP4,\n        JPEG,\n    }\n\n    /**\n     * 摄像头类型\n     */\n    enum CameraType\n    {\n        FRONT,\n        BACK,\n        USB\n    }\n\n    /**\n     * 灯光状态\n     */\n    enum FlashState\n    {\n        CLOSE,\n        AUTO,\n        OPEN\n    }\n\n    interface TakePhotoListener{\n        void onTakePhotoFinish(File file, int photoRotation, int width, int height);\n    }\n\n    interface CameraReady\n    {\n        void onCameraReady();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/camera/cn/cameramaster/util/cameravideo/IVideoControl.java",
    "content": "package camera.cn.cameramaster.util.cameravideo;\n\n/**\n * 视频接口\n */\n\npublic interface IVideoControl {\n\n    /**\n     * 播放视频\n     */\n    void play();\n\n    /**\n     * 暂停视频播放\n     */\n    void pause();\n\n    /**\n     * 继续播放视频，前提是暂停了视频\n     */\n    void resume();\n\n    /**\n     * 停止播放视频\n     */\n    void stop();\n\n    /**\n     * 进度条快进\n     * @param timeStamp\n     */\n    void seekTo(int timeStamp);\n\n    void setPlaySeekTimeListener(PlaySeekTimeListener mPlaySeekTimeListener);\n\n    void setPlayStateListener(PlayStateListener mPlayStateListener);\n\n    interface PlaySeekTimeListener\n    {\n        void onSeekTime(int allTime, int time);\n    }\n\n    /**\n     * 播放状态\n     */\n    interface PlayStateListener{\n\n        void onStartListener(int width, int height);\n\n        void onCompletionListener();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/camera/cn/cameramaster/util/cameravideo/VideoPlayer.java",
    "content": "package camera.cn.cameramaster.util.cameravideo;\n\nimport android.content.Context;\nimport android.media.MediaPlayer;\nimport android.net.Uri;\nimport android.os.Build;\nimport android.os.Handler;\nimport android.os.HandlerThread;\nimport android.support.annotation.RequiresApi;\nimport android.view.Surface;\n\nimport java.io.IOException;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\n\n/**\n * 视频播放器\n *\n * @author ymc\n */\npublic class VideoPlayer implements IVideoControl {\n\n    private MediaPlayer mMediaPlayer;\n    private Surface mSurface;\n    private String mVideoFilePath;\n\n    private IVideoControl.PlaySeekTimeListener mPlaySeekTimeListener;\n    private IVideoControl.PlayStateListener mPlayStateListener;\n\n    private HandlerThread mHandlerThread;\n    private Handler mHandle;\n\n    private AtomicBoolean mIsNowSeekTime;\n\n    private boolean mIsLoop = false;\n\n    public VideoPlayer()\n    {\n        mMediaPlayer = new MediaPlayer();\n        mHandlerThread = new HandlerThread(VideoPlayer.class.getSimpleName());\n        mHandlerThread.start();\n        mHandle = new Handler(mHandlerThread.getLooper());\n        mIsNowSeekTime = new AtomicBoolean(false);\n    }\n\n    public void setLoopPlay(boolean isLoop)\n    {\n   //     mMediaPlayer.setLooping(isLoop);\n        this.mIsLoop = isLoop;\n    }\n\n    public void setDataSourceAndPlay(Context context, Uri uri)\n    {\n        try {\n            mMediaPlayer.setDataSource(context,uri);\n            mMediaPlayer.setSurface(this.mSurface);\n            mMediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {\n                @Override\n                public boolean onError(MediaPlayer mp, int what, int extra) {\n                    stopVideoSeekTime();\n                    return false;\n                }\n            });\n            mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {\n                @Override\n                public void onPrepared(MediaPlayer mp) {\n                    play();\n                    startVideoSeekTime();\n                }\n            });\n            mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {\n                @Override\n                public void onCompletion(MediaPlayer mp) {\n                    if(mPlayStateListener != null){\n                        mPlayStateListener.onCompletionListener();\n                    }\n                    if(mIsLoop){\n                        play();\n                    }\n                }\n            });\n            mMediaPlayer.prepareAsync();\n        } catch (IOException e) {\n            e.printStackTrace();\n            mMediaPlayer = null;\n        }\n    }\n\n    public void setDataSourceAndPlay(String path)\n    {\n        mVideoFilePath = path;\n        try {\n            mMediaPlayer.setDataSource(mVideoFilePath);\n            mMediaPlayer.setSurface(this.mSurface);\n            mMediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {\n                @Override\n                public boolean onError(MediaPlayer mp, int what, int extra) {\n                    stopVideoSeekTime();\n                    return false;\n                }\n            });\n            mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {\n                @Override\n                public void onPrepared(MediaPlayer mp) {\n                    play();\n                    startVideoSeekTime();\n                }\n            });\n            mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {\n                @Override\n                public void onCompletion(MediaPlayer mp) {\n                    if(mPlayStateListener != null){\n                        mPlayStateListener.onCompletionListener();\n                    }\n                    if(mIsLoop){\n                        play();\n                    }\n                }\n            });\n            mMediaPlayer.prepareAsync();\n        } catch (IOException e) {\n            e.printStackTrace();\n            mMediaPlayer = null;\n        }\n    }\n\n    @Override\n    public void play() {\n        if(mMediaPlayer != null && !mMediaPlayer.isPlaying()) {\n            mMediaPlayer.start();\n            if(mPlayStateListener != null){\n                mPlayStateListener.onStartListener(mMediaPlayer.getVideoWidth(), mMediaPlayer.getVideoHeight());\n            }\n        }\n    }\n\n    @Override\n    public void pause() {\n        if(mMediaPlayer != null && mMediaPlayer.isPlaying()){\n            mMediaPlayer.pause();\n        }\n    }\n\n    @Override\n    public void resume() {\n        if(mMediaPlayer != null && !mMediaPlayer.isPlaying()){\n            mMediaPlayer.start();\n        }\n    }\n\n    @Override\n    public void stop() {\n        if(mMediaPlayer != null) {\n            mMediaPlayer.stop();\n            mMediaPlayer.reset();\n            stopVideoSeekTime();\n        }\n    }\n\n    @Override\n    public void seekTo(int timeStamp) {\n        if(mMediaPlayer != null){\n            mMediaPlayer.seekTo(timeStamp);\n        }\n    }\n\n    @Override\n    public void setPlaySeekTimeListener(IVideoControl.PlaySeekTimeListener playSeekTimeListener) {\n        this.mPlaySeekTimeListener = playSeekTimeListener;\n    }\n\n    @Override\n    public void setPlayStateListener(PlayStateListener playStateListener) {\n        this.mPlayStateListener = playStateListener;\n    }\n\n    public void setVideoPlayWindow(Surface surface)\n    {\n        this.mSurface = surface;\n    }\n\n    public boolean isPlaying(){\n        return mMediaPlayer!=null && mMediaPlayer.isPlaying();\n    }\n\n    /**\n     * 视频播放进度\n     */\n    private void startVideoSeekTime()\n    {\n        if(mPlaySeekTimeListener == null){\n            return;\n        }\n        mIsNowSeekTime.set(true);\n        mHandle.post(new Runnable() {\n            @Override\n            public void run() {\n                while (mIsNowSeekTime.get())\n                {\n                    try {\n                        Thread.sleep(20);\n                    } catch (InterruptedException e) {\n                        e.printStackTrace();\n                    }\n                    if (mMediaPlayer == null){\n                        return;\n                    }\n                    synchronized (mMediaPlayer) {\n                        if (mMediaPlayer == null){\n                            return;\n                        }\n                        mPlaySeekTimeListener.onSeekTime(mMediaPlayer.getDuration(), mMediaPlayer.getCurrentPosition());\n                    }\n                }\n            }\n        });\n    }\n\n    private void stopVideoSeekTime()\n    {\n        mIsNowSeekTime.set(false);\n    }\n\n    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)\n    public void destroy()\n    {\n        mHandlerThread.quitSafely();\n        if(mMediaPlayer != null) {\n            synchronized (mMediaPlayer) {\n                mMediaPlayer.release();\n                mMediaPlayer = null;\n            }\n        }\n        mSurface.release();\n    }\n\n\n}\n"
  },
  {
    "path": "app/src/main/java/camera/cn/cameramaster/util/render/CameraV2Renderer.java",
    "content": "package camera.cn.cameramaster.util.render;\n\nimport android.content.Context;\nimport android.graphics.Bitmap;\nimport android.graphics.SurfaceTexture;\nimport android.opengl.GLES11Ext;\nimport android.opengl.GLES20;\nimport android.opengl.GLSurfaceView;\nimport android.os.Build;\nimport android.support.annotation.RequiresApi;\nimport android.util.Log;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.nio.FloatBuffer;\nimport java.nio.IntBuffer;\n\nimport javax.microedition.khronos.egl.EGLConfig;\nimport javax.microedition.khronos.opengles.GL10;\n\n\nimport camera.cn.cameramaster.util.CameraV2;\nimport camera.cn.cameramaster.util.FilterEngine;\nimport camera.cn.cameramaster.util.Utils;\nimport camera.cn.cameramaster.view.CameraV2GLSurfaceView;\n\nimport static android.opengl.GLES11Ext.GL_TEXTURE_EXTERNAL_OES;\nimport static android.opengl.GLES20.GL_FLOAT;\nimport static android.opengl.GLES20.GL_FRAMEBUFFER;\nimport static android.opengl.GLES20.GL_TRIANGLES;\nimport static android.opengl.GLES20.glActiveTexture;\nimport static android.opengl.GLES20.glBindFramebuffer;\nimport static android.opengl.GLES20.glBindTexture;\nimport static android.opengl.GLES20.glClearColor;\nimport static android.opengl.GLES20.glDrawArrays;\nimport static android.opengl.GLES20.glEnableVertexAttribArray;\nimport static android.opengl.GLES20.glGenFramebuffers;\nimport static android.opengl.GLES20.glGetAttribLocation;\nimport static android.opengl.GLES20.glGetUniformLocation;\nimport static android.opengl.GLES20.glUniform1i;\nimport static android.opengl.GLES20.glUniformMatrix4fv;\nimport static android.opengl.GLES20.glVertexAttribPointer;\nimport static android.opengl.GLES20.glViewport;\n\n/**\n * camera render\n * 参考url ： [https://blog.csdn.net/lb377463323/article/details/78054892]\n *\n * @author ymc\n * @date 2019年2月12日 13:39:55\n */\n\npublic class CameraV2Renderer implements GLSurfaceView.Renderer {\n    private static final String TAG = \"CameraV2Renderer\";\n    private int surfaceWidth;\n    private int surfaceHeight;\n    private Context mContext;\n    private CameraV2GLSurfaceView mCameraV2GLSurfaceView;\n    private CameraV2 mCamera;\n    private boolean bIsPreviewStarted;\n    private int mOESTextureId = -1;\n    private SurfaceTexture mSurfaceTexture;\n    private float[] transformMatrix = new float[16];\n    /**\n     * 存放顶点的Color数组\n     */\n    private FloatBuffer mDataBuffer;\n    private int mShaderProgram = -1;\n    private int aPositionLocation = -1;\n    private int aTextureCoordLocation = -1;\n    private int uTextureMatrixLocation = -1;\n    private int uTextureSamplerLocation = -1;\n    private int uColorType = -1;\n    private int[] mFBOIds = new int[1];\n    private int[] fFrame = new int[1];\n    private int[] fTexture = new int[1];\n    float[] arrays1 ={1.0f,2.0f,3.0f,4.0f};\n    float[] arrays2 ={4,5,6};\n    float[] arrays3 ={7,8,9};\n    int arraysSize = 4;\n    private int hChangeColor = -1;\n    private int hChangeColor2 = -1;\n    private int hChangeColor3 = -1;\n    private int hArraySize = -1;\n\n    public void init(CameraV2GLSurfaceView surfaceView, CameraV2 camera,\n                     boolean isPreviewStarted, Context context) {\n        mContext = context;\n        mCameraV2GLSurfaceView = surfaceView;\n        mCamera = camera;\n        bIsPreviewStarted = isPreviewStarted;\n    }\n\n    /**\n     * GLSurfaceView 创建\n     *\n     * @param gl GL10\n     * @param config EGLConfig\n     */\n    @Override\n    public void onSurfaceCreated(GL10 gl, EGLConfig config) {\n        mOESTextureId = Utils.createOESTextureObject();\n        FilterEngine mFilterEngine = new FilterEngine(mOESTextureId, mContext);\n        mDataBuffer = mFilterEngine.getBuffer();\n        mShaderProgram = mFilterEngine.getShaderProgram();\n        glGenFramebuffers(1, mFBOIds, 0);\n        glBindFramebuffer(GL_FRAMEBUFFER, mFBOIds[0]);\n        uColorType = glGetUniformLocation(mShaderProgram, FilterEngine.COLOR_TYPE);\n        hChangeColor = GLES20.glGetUniformLocation(mShaderProgram, \"vChangeColor\");\n        hChangeColor2 = GLES20.glGetUniformLocation(mShaderProgram, \"vChangeColorB\");\n        hChangeColor3 = GLES20.glGetUniformLocation(mShaderProgram, \"vChangeColorC\");\n        hArraySize = GLES20.glGetUniformLocation(mShaderProgram, \"vArraysSize\");\n    }\n\n    /**\n     * GLSurfaceView 改变\n     * @param gl GL10\n     * @param width 宽度\n     * @param height 长度\n     */\n    @Override\n    public void onSurfaceChanged(GL10 gl, int width, int height) {\n        glViewport(0, 0, width, height);\n        surfaceWidth = width;\n        surfaceHeight = height;\n    }\n\n    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)\n    @Override\n    public void onDrawFrame(GL10 gl) {\n        Long t1 = System.currentTimeMillis();\n        if (mSurfaceTexture != null) {\n            //更新纹理图像\n            mSurfaceTexture.updateTexImage();\n            //获取外部纹理的矩阵，用来确定纹理的采样位置，没有此矩阵可能导致图像翻转等问题\n            mSurfaceTexture.getTransformMatrix(transformMatrix);\n        }\n\n        if (!bIsPreviewStarted) {\n            // 创建 SurfaceTexture\n            bIsPreviewStarted = initSurfaceTexture();\n            bIsPreviewStarted = true;\n            return;\n        }\n        //glClear(GL_COLOR_BUFFER_BIT);\n        glClearColor(0.0f, 0.0f, 0.0f, 0.0f);\n\n        //获取Shader中定义的变量在program中的位置\n        aPositionLocation = glGetAttribLocation(mShaderProgram, FilterEngine.POSITION_ATTRIBUTE);\n        aTextureCoordLocation = glGetAttribLocation(mShaderProgram, FilterEngine.TEXTURE_COORD_ATTRIBUTE);\n        uTextureMatrixLocation = glGetUniformLocation(mShaderProgram, FilterEngine.TEXTURE_MATRIX_UNIFORM);\n\n        // 激活纹理单位\n        glActiveTexture(GL_TEXTURE_EXTERNAL_OES);\n        // 绑定外部纹理到纹理单元0\n        glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, mOESTextureId);\n        //将此纹理单元床位片段着色器的uTextureSampler外部纹理采样器\n        glUniform1i(uTextureSamplerLocation, 0);\n        glUniform1i(uColorType,1);\n        glUniform1i(hArraySize,1);\n        GLES20.glUniform3fv(hChangeColor,1, arrays1,0);\n        GLES20.glUniform3fv(hChangeColor2,1, arrays2,0);\n        GLES20.glUniform3fv(hChangeColor3,1, arrays3,0);\n\n        //将纹理矩阵传给片段着色器\n        glUniformMatrix4fv(uTextureMatrixLocation, 1,\n                false, transformMatrix, 0);\n\n        if (mDataBuffer != null) {\n\n            //顶点坐标从位置0开始读取\n            mDataBuffer.position(0);\n            glEnableVertexAttribArray(aPositionLocation);\n            glVertexAttribPointer(aPositionLocation, 2, GL_FLOAT,\n                    false, 16, mDataBuffer);\n            //纹理坐标从位置2开始读取\n            mDataBuffer.position(2);\n            glEnableVertexAttribArray(aTextureCoordLocation);\n            glVertexAttribPointer(aTextureCoordLocation, 2, GL_FLOAT,\n                    false, 16, mDataBuffer);\n        }\n        //glDrawElements(GL_TRIANGLE_FAN, 6,GL_UNSIGNED_INT, 0);\n        //glDrawArrays(GL_TRIANGLE_FAN, 0 , 6);\n        //绘制两个三角形（6个顶点）\n        glDrawArrays(GL_TRIANGLES, 0, 6);\n        //glDrawArrays(GL_TRIANGLES, 3, 3);\n        glBindFramebuffer(GL_FRAMEBUFFER, 0);\n        /**\n         * 根据标识 是否截图\n         * 参考url： [http://hounychang.github.io/2015/05/13/%E5%AF%B9GLSurfaceView%E6%88%AA%E5%9B%BE/]\n         */\n        if (CameraV2GLSurfaceView.shouldTakePic) {\n            CameraV2GLSurfaceView.shouldTakePic = false;\n//            bindfbo();\n            int w = surfaceWidth;\n            int h = surfaceHeight;\n            int b[] = new int[w * h];\n            int bt[] = new int[w * h];\n            IntBuffer buffer = IntBuffer.wrap(b);\n            buffer.position(0);\n            GLES20.glReadPixels(0, 0, w, h, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, buffer);\n            for (int i = 0; i < h; i++) {\n                for (int j = 0; j < w; j++) {\n                    int pix = b[i * w + j];\n                    int pb = (pix >> 16) & 0xff;\n                    int pr = (pix << 16) & 0x00ff0000;\n                    int pix1 = (pix & 0xff00ff00) | pr | pb;\n                    bt[(h - i - 1) * w + j] = pix1;\n                }\n            }\n            Bitmap inBitmap;\n            inBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);\n            //为了图像能小一点，使用了RGB_565而不是ARGB_8888\n            inBitmap.copyPixelsFromBuffer(buffer);\n            inBitmap = Bitmap.createBitmap(bt, w, h, Bitmap.Config.ARGB_8888);\n            ByteArrayOutputStream bos = new ByteArrayOutputStream();\n            inBitmap.compress(Bitmap.CompressFormat.PNG, 90, bos);\n            byte[] bitmapData = bos.toByteArray();\n            ByteArrayInputStream fis = new ByteArrayInputStream(bitmapData);\n            File mFile = new File(mContext.getExternalFilesDir(null), \"pic1.png\");\n            try {\n                FileOutputStream fos = new FileOutputStream(mFile);\n                byte[] buf = new byte[1024];\n                int len;\n                while ((len = fis.read(buf)) > 0) {\n                    fos.write(buf, 0, len);\n                }\n                fis.close();\n                fos.close();\n\n            } catch (IOException e) {\n                e.printStackTrace();\n            } finally {\n                //旋转角度\n//                int rotate = BitmapRotating.readPictureDegree(mFile.getPath());\n//                BitmapRotating.rotaingImageView(rotate,inBitmap);\n                inBitmap.recycle();\n//                unbindfbo();\n            }\n        }\n        long t2 = System.currentTimeMillis();\n        long t = t2 - t1;\n        Log.i(TAG, \"onDrawFrame: time: \" + t);\n    }\n\n    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)\n    private boolean initSurfaceTexture() {\n        if (mCamera == null || mCameraV2GLSurfaceView == null) {\n            Log.i(TAG, \"mCamera or mGLSurfaceView is null!\");\n            return false;\n        }\n        // 根据 oesId 创建 SurfaceTexture\n        mSurfaceTexture = new SurfaceTexture(mOESTextureId);\n        mSurfaceTexture.setOnFrameAvailableListener(new SurfaceTexture.OnFrameAvailableListener() {\n            @Override\n            public void onFrameAvailable(SurfaceTexture surfaceTexture) {\n                // 每获取到一帧数据时请求OpenGL ES进行渲染\n                mCameraV2GLSurfaceView.requestRender();\n            }\n        });\n        //讲此SurfaceTexture作为相机预览输出 （相互绑定）\n        mCamera.setPreviewTexture(mSurfaceTexture);\n        mCamera.createCameraPreviewSession();\n        return true;\n    }\n\n    /**\n     * 改变截图时候界面卡顿的现象\n     * 参考url ： [https://blog.csdn.net/SXH_Android/article/details/78835966]\n     * <p>\n     * 问题：加上后确实没有卡顿现象 但是截图会是 黑屏\n     */\n    private void bindfbo() {\n        GLES20.glGenFramebuffers(1, fFrame, 0);\n\n        GLES20.glGenTextures(1, fTexture, 0);\n        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, fTexture[0]);\n        GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA,\n                surfaceWidth, surfaceHeight, 0,\n                GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null);\n\n        GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);\n        GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);\n        GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);\n        GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);\n\n        GLES20.glBindFramebuffer(GL_FRAMEBUFFER, fFrame[0]);\n        GLES20.glFramebufferTexture2D(GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D, fTexture[0], 0);\n\n        int status = GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER);\n        if (status != GLES20.GL_FRAMEBUFFER_COMPLETE) {\n            throw new RuntimeException(\"status:\" + status + \", hex:\" + Integer.toHexString(status));\n        }\n    }\n\n    private void unbindfbo() {\n        GLES20.glBindFramebuffer(GL_FRAMEBUFFER, 0);\n        GLES20.glDeleteTextures(1, fTexture, 0);\n        GLES20.glDeleteFramebuffers(1, fFrame, 0);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/camera/cn/cameramaster/view/AnimationTextView.java",
    "content": "package camera.cn.cameramaster.view;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.os.Build;\nimport android.os.Handler;\nimport android.support.annotation.RequiresApi;\nimport android.util.AttributeSet;\nimport android.view.animation.Animation;\nimport android.widget.TextView;\n\n/**\n * 文字显示 一秒后消失\n */\n\n@SuppressLint(\"AppCompatCustomView\")\npublic class AnimationTextView extends TextView {\n    private Handler mMainHandler;\n    private Animation mAnimation;\n    /**\n     * 防止又换了个text，但是上次哪个还没有消失即将小时就把新的text的给消失了\n     */\n    public int mTimes = 0;\n\n    public AnimationTextView(Context context) {\n        super(context);\n    }\n\n    public AnimationTextView(Context context, AttributeSet attrs) {\n        super(context, attrs);\n    }\n\n    public AnimationTextView(Context context, AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n    }\n\n    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)\n    public AnimationTextView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {\n        super(context, attrs, defStyleAttr, defStyleRes);\n    }\n\n    public void setmMainHandler(Handler mMainHandler) {\n        this.mMainHandler = mMainHandler;\n    }\n\n    public void setmAnimation(Animation mAnimation) {\n        this.mAnimation = mAnimation;\n    }\n\n    public void start(String text, int message) {\n        if (mAnimation == null || mMainHandler == null) {\n            return;\n        }\n        this.setVisibility(VISIBLE);\n        mTimes++;\n        this.setText(text);\n        this.startAnimation(mAnimation);\n        new Thread(new SleepThread(mMainHandler, message, 1000, Integer.valueOf(mTimes))).start();\n    }\n\n    public void stop() {\n        this.setVisibility(GONE);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/camera/cn/cameramaster/view/AutoFitTextureView.java",
    "content": "package camera.cn.cameramaster.view;\n\nimport android.content.Context;\nimport android.graphics.Matrix;\nimport android.util.AttributeSet;\nimport android.view.TextureView;\n\n/**\n * 自定义 TextureView\n * 重新计算预览宽高\n *\n * @fileName: AutoFitTextureView\n * @date: 2019/1/28  17:00\n * @author: ymc\n * @QQ:745612618\n */\n\npublic class AutoFitTextureView extends TextureView {\n\n    private int mRatioWidth = 0;\n    private int mRatioHeight = 0;\n\n    public AutoFitTextureView(Context context) {\n        this(context, null);\n    }\n\n    public AutoFitTextureView(Context context, AttributeSet attrs) {\n        this(context, attrs, 0);\n    }\n\n    public AutoFitTextureView(Context context, AttributeSet attrs, int defStyle) {\n        super(context, attrs, defStyle);\n    }\n\n    /**\n     * 设置此视图的纵横比。将根据比率测量视图的大小 根据参数计算。注意，参数的实际大小无关紧要\n     * 调用setAspectRatio（2,3）和setAspectRatio（4,6）会产生相同的结果。\n     *\n     * @param width  Relative horizontal size\n     * @param height Relative vertical size\n     */\n    public void setAspectRatio(int width, int height) {\n        if (width < 0 || height < 0) {\n            throw new IllegalArgumentException(\"Size cannot be negative.\");\n        }\n        mRatioWidth = width;\n        mRatioHeight = height;\n\n        float mRatio = (float) mRatioWidth / (float) mRatioHeight;   //算出相机的缩放比例\n\n        float w = mRatio * getHeight();\n        float scale;\n        if (w > getWidth())\n            scale = w / (float) getWidth();\n        else\n            scale = (float) getWidth() / w;\n\n        Matrix matrix = new Matrix();\n        matrix.postScale(scale, 1, getWidth() / 2, getHeight() / 2);\n        setTransform(matrix);\n    }\n\n    /**\n     * 视频宽度适配\n     * @param width\n     * @param height\n     */\n    public void setVideoAspectRatio(int width, int height)\n    {\n        if (width < 0 || height < 0) {\n            throw new IllegalArgumentException(\"Size cannot be negative.\");\n        }\n        mRatioWidth = width;\n        mRatioHeight = height;\n\n        float mRatio = (float) mRatioWidth / (float) mRatioHeight;   //算出相机的缩放比例\n        if(mRatio < 1.0)\n        {\n            setAspectRatio(width, height);\n        }else {\n            float h = getWidth() / mRatio;\n            float scale;\n            if (h > getHeight())\n                scale = (float) getHeight() / h;\n            else\n                scale = h / (float) getHeight();\n\n            Matrix matrix = new Matrix();\n            matrix.postScale(1, scale, getWidth() / 2, getHeight() / 2);\n            setTransform(matrix);\n        }\n    }\n\n}"
  },
  {
    "path": "app/src/main/java/camera/cn/cameramaster/view/AutoLocateHorizontalView.java",
    "content": "package camera.cn.cameramaster.view;\n\nimport android.content.Context;\nimport android.support.annotation.Nullable;\nimport android.support.v7.widget.LinearLayoutManager;\nimport android.support.v7.widget.RecyclerView;\nimport android.util.AttributeSet;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.view.ViewTreeObserver;\nimport android.widget.Scroller;\n\n/**\n * 横向recyclerView\n *\n * @author ymc\n */\n\npublic class AutoLocateHorizontalView extends RecyclerView {\n    /**\n     * 一个屏幕中显示多少个item，必须为奇数\n     */\n    private int itemCount = 5;\n    /**\n     * 初始时选中的位置\n     */\n    private int initPos = 0;\n\n    private int deltaX;\n    private WrapperAdapter wrapAdapter;\n    private Adapter adapter;\n    private LinearLayoutManager linearLayoutManager;\n    private boolean isInit;\n    private OnSelectedPositionChangedListener listener;\n    /**\n     * 刚初始化时是否触发位置改变的监听\n     */\n    private boolean isFirstPosChanged = true;\n    /**\n     * 记录上次选中的位置\n     */\n    private int oldSelectedPos = initPos;\n    /**\n     * 当前被选中的位置\n     */\n    private int selectPos = initPos;\n\n    private Scroller mScroller;\n\n    /**\n     * 当要调用moveToPosition()方法时要先记录已经移动了多少位置\n     */\n    private int oldMoveX;\n\n    private boolean isMoveFinished = true;\n\n    public AutoLocateHorizontalView(Context context) {\n        super(context);\n    }\n\n    public AutoLocateHorizontalView(Context context, @Nullable AttributeSet attrs) {\n        super(context, attrs);\n        init();\n    }\n\n    public AutoLocateHorizontalView(Context context, @Nullable AttributeSet attrs, int defStyle) {\n        super(context, attrs, defStyle);\n    }\n\n    private void init() {\n        mScroller = new Scroller(getContext());\n        getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {\n            @Override\n            public void onGlobalLayout() {\n                if (isInit) {\n                    if (initPos >= adapter.getItemCount()) {\n                        initPos = adapter.getItemCount() - 1;\n                    }\n                    if (isFirstPosChanged && listener != null) {\n                        listener.selectedPositionChanged(initPos);\n                    }\n                    linearLayoutManager.scrollToPositionWithOffset(0,\n                            -initPos * (wrapAdapter.getItemWidth()));\n                    isInit = false;\n                }\n            }\n        });\n    }\n\n    /**\n     * 设置初始化时选中的位置,该方法必须在\n     * {@link AutoLocateHorizontalView#setAdapter(android.support.v7.widget.RecyclerView.Adapter) }\n     * 之前调用\n     *\n     * @param initPos 初始位置，如果位置超过了item的数量则默认选中最后一项item\n     */\n    public void setInitPos(int initPos) {\n        if (adapter != null) {\n            throw new RuntimeException(\"This method should be called before setAdapter()!\");\n        }\n        this.initPos = initPos;\n        selectPos = initPos;\n        oldSelectedPos = initPos;\n    }\n\n    /**\n     * 设置每次显示多少个item,该方法必须在{@link AutoLocateHorizontalView#setAdapter(android.support.v7.widget.RecyclerView.Adapter) }之前调用\n     *\n     * @param itemCount 必须为奇数，否则默认会设置成小于它的最大奇数\n     */\n    public void setItemCount(int itemCount) {\n        if (adapter != null) {\n            throw new RuntimeException(\"This method should be called before setAdapter()!\");\n        }\n        if (itemCount % 2 == 0) {\n            this.itemCount = itemCount - 1;\n        } else {\n            this.itemCount = itemCount;\n        }\n    }\n\n    /**\n     * 删除item后偏移距离可能需要重新计算，从而保证selectPos的正确\n     *\n     * @param adapter\n     */\n    private void correctDeltax(Adapter adapter) {\n        if (adapter.getItemCount() <= selectPos) {\n            deltaX -= wrapAdapter.getItemWidth() * (selectPos - adapter.getItemCount() + 1);\n        }\n        calculateSelectedPos();\n    }\n\n    /**\n     * 删除时选中的数据发生改变，要重新回调方法\n     *\n     * @param startPos\n     */\n    private void reCallListenerWhenRemove(int startPos) {\n        if (startPos <= selectPos && listener != null) {\n            correctDeltax(adapter);\n            listener.selectedPositionChanged(selectPos);\n        } else {\n            correctDeltax(adapter);\n        }\n    }\n\n    /**\n     * 添加数据时选中的数据发生改变，要重新回调方法\n     *\n     * @param startPos\n     */\n    private void reCallListenerWhenAdd(int startPos) {\n        if (startPos <= selectPos && listener != null) {\n            listener.selectedPositionChanged(selectPos);\n        }\n    }\n\n    /**\n     * 当使用整体刷新时要重新回调方法\n     */\n    private void reCallListenerWhenChanged() {\n        if (listener != null) {\n            listener.selectedPositionChanged(selectPos);\n        }\n    }\n\n    @Override\n    public void setAdapter(final Adapter adapter) {\n        this.adapter = adapter;\n        this.wrapAdapter = new WrapperAdapter(adapter, getContext(), itemCount);\n        adapter.registerAdapterDataObserver(new AdapterDataObserver() {\n\n            @Override\n            public void onChanged() {\n                super.onChanged();\n                wrapAdapter.notifyDataSetChanged();\n                reCallListenerWhenChanged();\n            }\n\n            @Override\n            public void onItemRangeInserted(int positionStart, int itemCount) {\n                wrapAdapter.notifyDataSetChanged();\n                reCallListenerWhenAdd(positionStart);\n            }\n\n            @Override\n            public void onItemRangeRemoved(int positionStart, int itemCount) {\n                wrapAdapter.notifyDataSetChanged();\n                reCallListenerWhenRemove(positionStart);\n            }\n        });\n        deltaX = 0;\n        if (linearLayoutManager == null) {\n            linearLayoutManager = new LinearLayoutManager(getContext());\n        }\n        linearLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);\n        super.setLayoutManager(linearLayoutManager);\n        super.setAdapter(this.wrapAdapter);\n        isInit = true;\n    }\n\n    @Override\n    public void setLayoutManager(LayoutManager layout) {\n        if (!(layout instanceof LinearLayoutManager)) {\n            throw new IllegalStateException(\"The LayoutManager here must be LinearLayoutManager!\");\n        }\n        this.linearLayoutManager = (LinearLayoutManager) layout;\n    }\n\n    @Override\n    public void onScrollStateChanged(int state) {\n        super.onScrollStateChanged(state);\n\n        if (state == SCROLL_STATE_IDLE) {\n            if (wrapAdapter == null) {\n                return;\n            }\n            int itemWidth = wrapAdapter.getItemWidth();\n            int headerFooterWidth = wrapAdapter.getHeaderFooterWidth();\n            if (itemWidth == 0 || headerFooterWidth == 0) {\n                //此时adapter还没有准备好，忽略此次调用\n                return;\n            }\n            //超出上个item的位置\n            int overLastPosOffset = deltaX % itemWidth;\n            if (overLastPosOffset == 0) {\n                //刚好处于一个item选中位置，无需滑动偏移纠正\n            } else if (Math.abs(overLastPosOffset) <= itemWidth / 2) {\n                scrollBy(-overLastPosOffset, 0);\n            } else if (overLastPosOffset > 0) {\n                scrollBy((itemWidth - overLastPosOffset), 0);\n            } else {\n                scrollBy(-(itemWidth + overLastPosOffset), 0);\n            }\n            calculateSelectedPos();\n            //此处通知刷新是为了重新绘制之前被选中的位置以及刚刚被选中的位置\n            wrapAdapter.notifyItemChanged(oldSelectedPos + 1);\n            wrapAdapter.notifyItemChanged(selectPos + 1);\n            oldSelectedPos = selectPos;\n            if (listener != null) {\n                listener.selectedPositionChanged(selectPos);\n            }\n        }\n    }\n\n    public void moveToPosition(int position) {\n        if(position < 0 || position > adapter.getItemCount() - 1){\n            throw new IllegalArgumentException(\"Your position should be from 0 to \"+(adapter.getItemCount()-1));\n        }\n        oldMoveX = 0;\n        isMoveFinished = false;\n        int itemWidth = wrapAdapter.getItemWidth();\n        if (position != selectPos) {\n            int deltx = (position - selectPos) * itemWidth;\n            mScroller.startScroll(getScrollX(), getScrollY(), deltx, 0);\n            postInvalidate();\n        }\n    }\n\n    @Override\n    public void computeScroll() {\n        super.computeScroll();\n        if (mScroller.computeScrollOffset()) {\n            int x = mScroller.getCurrX() - oldMoveX;\n            oldMoveX += x;\n            scrollBy(x, 0);\n        } else if (mScroller.isFinished()) {\n            //此处通知刷新是为了重新绘制之前被选中的位置以及刚刚被选中的位置\n            if (isMoveFinished) {\n                return;\n            }\n            wrapAdapter.notifyItemChanged(oldSelectedPos + 1);\n            wrapAdapter.notifyItemChanged(selectPos + 1);\n            oldSelectedPos = selectPos;\n            if (listener != null) {\n                listener.selectedPositionChanged(selectPos);\n            }\n            isMoveFinished = true;\n        }\n    }\n\n    @Override\n    public void onScrolled(int dx, int dy) {\n        super.onScrolled(dx, dy);\n        deltaX += dx;\n        calculateSelectedPos();\n    }\n\n    private void calculateSelectedPos() {\n        int itemWidth = wrapAdapter.getItemWidth();\n        if (deltaX > 0) {\n            selectPos = (deltaX) / itemWidth + initPos;\n        } else {\n            selectPos = initPos + (deltaX) / itemWidth;\n        }\n    }\n\n    class WrapperAdapter extends RecyclerView.Adapter {\n        private Context context;\n        private RecyclerView.Adapter adapter;\n        private int itemCount;\n        private static final int HEADER_FOOTER_TYPE = -1;\n        private View itemView;\n        /**\n         * 头部或尾部的宽度\n         */\n        private int headerFooterWidth;\n\n        /**\n         * 每个item的宽度\n         */\n        private int itemWidth;\n\n        public WrapperAdapter(Adapter adapter, Context context, int itemCount) {\n            this.adapter = adapter;\n            this.context = context;\n            this.itemCount = itemCount;\n            if (adapter instanceof IAutoLocateHorizontalView) {\n                itemView = ((IAutoLocateHorizontalView) adapter).getItemView();\n            } else {\n                throw new RuntimeException(adapter.getClass().getSimpleName() + \" should implements com.jianglei.view.AutoLocateHorizontalView.IAutoLocateHorizontalView !\");\n            }\n        }\n\n        @Override\n        public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {\n            if (viewType == HEADER_FOOTER_TYPE) {\n                View view = new View(context);\n                headerFooterWidth = parent.getMeasuredWidth() / 2 - (parent.getMeasuredWidth() / itemCount) / 2;\n                RecyclerView.LayoutParams params = new LayoutParams(headerFooterWidth, ViewGroup.LayoutParams.MATCH_PARENT);\n                view.setLayoutParams(params);\n                return new HeaderFooterViewHolder(view);\n            }\n            ViewHolder holder = adapter.onCreateViewHolder(parent, viewType);\n            itemView = ((IAutoLocateHorizontalView) adapter).getItemView();\n            int width = parent.getMeasuredWidth() / itemCount;\n            ViewGroup.LayoutParams params = itemView.getLayoutParams();\n            if (params != null) {\n                params.width = width;\n                itemWidth = width;\n                itemView.setLayoutParams(params);\n            }\n            return holder;\n        }\n\n        @SuppressWarnings(\"unchecked\")\n        @Override\n        public void onBindViewHolder(ViewHolder holder, int position) {\n            if (!isHeaderOrFooter(position)) {\n                adapter.onBindViewHolder(holder, position - 1);\n                if (selectPos == position - 1) {\n                    ((IAutoLocateHorizontalView) adapter).onViewSelected(true, position - 1, holder, itemWidth);\n                } else {\n                    ((IAutoLocateHorizontalView) adapter).onViewSelected(false, position - 1, holder, itemWidth);\n                }\n            }\n        }\n\n\n        @Override\n        public int getItemCount() {\n            return adapter.getItemCount() + 2;\n        }\n\n        @Override\n        public int getItemViewType(int position) {\n            if (position == 0 || position == getItemCount() - 1) {\n                return HEADER_FOOTER_TYPE;\n            }\n            return adapter.getItemViewType(position - 1);\n        }\n\n\n        private boolean isHeaderOrFooter(int pos) {\n            if (pos == 0 || pos == getItemCount() - 1) {\n                return true;\n            }\n            return false;\n        }\n\n        public int getHeaderFooterWidth() {\n            return headerFooterWidth;\n        }\n\n        public int getItemWidth() {\n            return itemWidth;\n        }\n\n        class HeaderFooterViewHolder extends RecyclerView.ViewHolder {\n\n            HeaderFooterViewHolder(View itemView) {\n                super(itemView);\n            }\n        }\n\n\n    }\n\n\n    public interface IAutoLocateHorizontalView {\n        /**\n         * 获取item的根布局\n         */\n        View getItemView();\n\n        /**\n         * 当item被选中时会触发这个回调，可以修改被选中时的样式\n         *\n         * @param isSelected 是否被选中\n         * @param pos        当前view的位置\n         * @param holder\n         * @param itemWidth  当前整个item的宽度\n         */\n        void onViewSelected(boolean isSelected, int pos, ViewHolder holder, int itemWidth);\n    }\n\n    /***\n     * 选中位置改变时的监听\n     */\n    public interface OnSelectedPositionChangedListener {\n        void selectedPositionChanged(int pos);\n    }\n\n    public void setOnSelectedPositionChangedListener(OnSelectedPositionChangedListener listener) {\n        this.listener = listener;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/camera/cn/cameramaster/view/AutoTextureView.java",
    "content": "package camera.cn.cameramaster.view;\n\nimport android.content.Context;\nimport android.util.AttributeSet;\nimport android.view.TextureView;\n\n/**\n * 自定义 正方形预览界面\n *\n * @packageName: camera.cn.cameramaster.view\n * @fileName: AutoTextureView\n * @date: 2019/5/9  16:15\n * @author: ymc\n * @QQ:745612618\n */\n\npublic class AutoTextureView extends TextureView {\n\n    private int mRatioWidth = 0;\n    private int mRatioHeight = 0;\n\n    public AutoTextureView(Context context) {\n        super(context);\n    }\n\n    public AutoTextureView(Context context, AttributeSet attrs) {\n        super(context, attrs);\n    }\n\n    public AutoTextureView(Context context, AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n    }\n    /**\n     * Sets the aspect ratio for this view. The size of the view will be measured based on the ratio\n     * calculated from the parameters. Note that the actual sizes of parameters don't matter, that\n     * is, calling setAspectRatio(2, 3) and setAspectRatio(4, 6) make the same result.\n     *\n     * @param width  Relative horizontal size\n     * @param height Relative vertical size\n     */\n    public void setAspectRatio(int width, int height) {\n        if (width < 0 || height < 0) {\n            throw new IllegalArgumentException(\"Size cannot be negative.\");\n        }\n        mRatioWidth = width;\n        mRatioHeight = height;\n        requestLayout();\n    }\n\n    @Override\n    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\n        super.onMeasure(widthMeasureSpec, heightMeasureSpec);\n        int width = MeasureSpec.getSize(widthMeasureSpec);\n        int height = MeasureSpec.getSize(heightMeasureSpec);\n        if (0 == mRatioWidth || 0 == mRatioHeight) {\n            setMeasuredDimension(width, height);\n        } else {\n            if (width < height * mRatioWidth / mRatioHeight) {\n                setMeasuredDimension(width, width * mRatioHeight / mRatioWidth);\n            } else {\n                setMeasuredDimension(height * mRatioWidth / mRatioHeight, height);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/camera/cn/cameramaster/view/AwbSeekBar.java",
    "content": "package camera.cn.cameramaster.view;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.os.Build;\nimport android.support.annotation.RequiresApi;\nimport android.util.AttributeSet;\nimport android.widget.SeekBar;\n\n/**\n * 自定义 8种白平衡状态 选择 seekBar\n *\n * @author ymc\n */\n\n@SuppressLint(\"AppCompatCustomView\")\npublic class AwbSeekBar extends SeekBar {\n\n    private int mProgress;\n    private AwbSeekBar mAwbSeekBar = this;\n    private OnAwbSeekBarChangeListener mOnAwbSeekBarChangeListener;\n\n    public AwbSeekBar(Context context) {\n        super(context);\n        init();\n    }\n\n    public AwbSeekBar(Context context, AttributeSet attrs) {\n        super(context, attrs);\n        init();\n    }\n\n    public AwbSeekBar(Context context, AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n        init();\n    }\n\n    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)\n    public AwbSeekBar(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {\n        super(context, attrs, defStyleAttr, defStyleRes);\n        init();\n    }\n    public void setmOnAwbSeekBarChangeListener(OnAwbSeekBarChangeListener mOnAwbSeekBarChangeListener) {\n        this.mOnAwbSeekBarChangeListener = mOnAwbSeekBarChangeListener;\n    }\n\n    private void init() {\n        this.setMax(70);\n        this.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {\n            @Override\n            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {\n                mProgress = progress;\n                if (mOnAwbSeekBarChangeListener != null) {\n                    if (0 <= mProgress && mProgress < 5) {\n                        mOnAwbSeekBarChangeListener.doInProgress1();\n                    } else if (5 <= mProgress && mProgress < 15) {\n                        mOnAwbSeekBarChangeListener.doInProgress2();\n                    } else if (15 <= mProgress && mProgress < 25) {\n                        mOnAwbSeekBarChangeListener.doInProgress3();\n                    } else if (25 <= mProgress && mProgress < 35) {\n                        mOnAwbSeekBarChangeListener.doInProgress4();\n                    } else if (35 <= mProgress && mProgress < 45) {\n                        mOnAwbSeekBarChangeListener.doInProgress5();\n                    } else if (45 <= mProgress && mProgress < 55) {\n                        mOnAwbSeekBarChangeListener.doInProgress6();\n                    } else if (55 <= mProgress && mProgress < 65) {\n                        mOnAwbSeekBarChangeListener.doInProgress7();\n                    } else if (65 <= mProgress && mProgress < 70) {\n                        mOnAwbSeekBarChangeListener.doInProgress8();\n                    }\n                }\n            }\n\n            @Override\n            public void onStartTrackingTouch(SeekBar seekBar) {\n                mOnAwbSeekBarChangeListener.onStartTrackingTouch(seekBar);\n            }\n\n            @Override\n            public void onStopTrackingTouch(SeekBar seekBar) {\n                int num = 0;\n                if (0 <= mProgress && mProgress < 5) {\n                    mAwbSeekBar.setProgress(0);\n                    num = 0;\n                } else if (5 <= mProgress && mProgress < 15) {\n                    mAwbSeekBar.setProgress(10);\n                    num = 10;\n                } else if (15 <= mProgress && mProgress < 25) {\n                    mAwbSeekBar.setProgress(20);\n                    num = 20;\n                } else if (25 <= mProgress && mProgress < 35) {\n                    mAwbSeekBar.setProgress(30);\n                    num = 30;\n                } else if (35 <= mProgress && mProgress < 45) {\n                    mAwbSeekBar.setProgress(40);\n                    num = 40;\n                } else if (45 <= mProgress && mProgress < 55) {\n                    mAwbSeekBar.setProgress(50);\n                    num = 50;\n                } else if (55 <= mProgress && mProgress < 65) {\n                    mAwbSeekBar.setProgress(60);\n                    num = 60;\n                } else if (65 <= mProgress && mProgress < 70) {\n                    mAwbSeekBar.setProgress(70);\n                    num = 70;\n                }\n                if (mOnAwbSeekBarChangeListener != null) {\n                    mOnAwbSeekBarChangeListener.onStopTrackingTouch(num);\n                }\n            }\n        });\n    }\n\n    public interface OnAwbSeekBarChangeListener {\n        public abstract void doInProgress1();\n\n        public abstract void doInProgress2();\n\n        public abstract void doInProgress3();\n\n        public abstract void doInProgress4();\n\n        public abstract void doInProgress5();\n\n        public abstract void doInProgress6();\n\n        public abstract void doInProgress7();\n\n        public abstract void doInProgress8();\n\n        public abstract void onStopTrackingTouch(int num);\n\n        public abstract void onStartTrackingTouch(SeekBar seekBar);\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/camera/cn/cameramaster/view/AwbSeekBarChangeListener.java",
    "content": "package camera.cn.cameramaster.view;\n\nimport android.content.Context;\nimport android.hardware.camera2.CameraAccessException;\nimport android.hardware.camera2.CameraCaptureSession;\nimport android.hardware.camera2.CameraMetadata;\nimport android.hardware.camera2.CaptureRequest;\nimport android.os.Build;\nimport android.os.Handler;\nimport android.support.annotation.RequiresApi;\nimport android.util.Log;\nimport android.view.View;\nimport android.view.animation.Animation;\nimport android.view.animation.AnimationUtils;\nimport android.widget.SeekBar;\nimport android.widget.TextView;\n\nimport camera.cn.cameramaster.R;\nimport camera.cn.cameramaster.view.AwbSeekBar;\n\n\n/**\n *  自定义 seekbar 滑动监听事件\n *  @author ymc\n */\n\n@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)\npublic class AwbSeekBarChangeListener implements AwbSeekBar.OnAwbSeekBarChangeListener {\n    private TextView mTextView;\n    private CaptureRequest.Builder mPreviewBuilder;\n    private CameraCaptureSession mCameraCaptureSession;\n    private Handler mHandler;\n    private CameraCaptureSession.CaptureCallback mPreviewSessionCallback;\n\n    private Animation mAlphaInAnimation;\n    private Animation mAlphaOutAnimation;\n\n    public AwbSeekBarChangeListener(Context mContext, TextView mTextView, CaptureRequest.Builder mPreviewBuilder,\n                                    CameraCaptureSession mCameraCaptureSession, Handler mHandler,\n                                    CameraCaptureSession.CaptureCallback mPreviewSessionCallback) {\n        this.mTextView = mTextView;\n        this.mPreviewBuilder = mPreviewBuilder;\n        this.mCameraCaptureSession = mCameraCaptureSession;\n        this.mHandler = mHandler;\n        this.mPreviewSessionCallback = mPreviewSessionCallback;\n        mAlphaInAnimation = AnimationUtils.loadAnimation(mContext, R.anim.alpha_in);\n        mAlphaOutAnimation = AnimationUtils.loadAnimation(mContext, R.anim.alpha_out);\n    }\n\n    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)\n    @Override\n    public void doInProgress1() {\n        mTextView.setText(\"自动\");\n        mPreviewBuilder.set(CaptureRequest.CONTROL_AWB_MODE, CameraMetadata.CONTROL_AWB_MODE_AUTO);\n        updatePreview();\n    }\n\n    @Override\n    public void doInProgress2() {\n        mTextView.setText(\"多云\");\n        mPreviewBuilder.set(CaptureRequest.CONTROL_AWB_MODE, CameraMetadata.CONTROL_AWB_MODE_CLOUDY_DAYLIGHT);\n        updatePreview();\n    }\n\n    @Override\n    public void doInProgress3() {\n        mTextView.setText(\"白天\");\n        mPreviewBuilder.set(CaptureRequest.CONTROL_AWB_MODE, CameraMetadata.CONTROL_AWB_MODE_DAYLIGHT);\n        updatePreview();\n    }\n\n\n    @Override\n    public void doInProgress4() {\n        mTextView.setText(\"日光灯\");\n        mPreviewBuilder.set(CaptureRequest.CONTROL_AWB_MODE, CameraMetadata.CONTROL_AWB_MODE_FLUORESCENT);\n        updatePreview();\n    }\n\n    @Override\n    public void doInProgress5() {\n        mTextView.setText(\"白炽灯\");\n        mPreviewBuilder.set(CaptureRequest.CONTROL_AWB_MODE, CameraMetadata.CONTROL_AWB_MODE_INCANDESCENT);\n        updatePreview();\n    }\n\n    @Override\n    public void doInProgress6() {\n        mTextView.setText(\"阴影\");\n        mPreviewBuilder.set(CaptureRequest.CONTROL_AWB_MODE, CameraMetadata.CONTROL_AWB_MODE_SHADE);\n        updatePreview();\n    }\n\n    @Override\n    public void doInProgress7() {\n        mTextView.setText(\"黄昏\");\n        mPreviewBuilder.set(CaptureRequest.CONTROL_AWB_MODE, CameraMetadata.CONTROL_AWB_MODE_TWILIGHT);\n        updatePreview();\n    }\n\n    @Override\n    public void doInProgress8() {\n        mTextView.setText(\"暖光\");\n        mPreviewBuilder.set(CaptureRequest.CONTROL_AWB_MODE, CameraMetadata.CONTROL_AWB_MODE_WARM_FLUORESCENT);\n        updatePreview();\n    }\n\n    @Override\n    public void onStopTrackingTouch(int num) {\n        switch (num) {\n            case 0:\n                mTextView.setText(\"自动\");\n                mPreviewBuilder.set(CaptureRequest.CONTROL_AWB_MODE, CameraMetadata.CONTROL_AWB_MODE_AUTO);\n                break;\n            case 10:\n                mTextView.setText(\"多云\");\n                mPreviewBuilder.set(CaptureRequest.CONTROL_AWB_MODE, CameraMetadata.CONTROL_AWB_MODE_CLOUDY_DAYLIGHT);\n                break;\n            case 20:\n                mTextView.setText(\"白天\");\n                mPreviewBuilder.set(CaptureRequest.CONTROL_AWB_MODE, CameraMetadata.CONTROL_AWB_MODE_DAYLIGHT);\n                break;\n            case 30:\n                mTextView.setText(\"日光灯\");\n                mPreviewBuilder.set(CaptureRequest.CONTROL_AWB_MODE, CameraMetadata.CONTROL_AWB_MODE_FLUORESCENT);\n                break;\n            case 40:\n                mTextView.setText(\"白炽灯\");\n                mPreviewBuilder.set(CaptureRequest.CONTROL_AWB_MODE, CameraMetadata.CONTROL_AWB_MODE_INCANDESCENT);\n                break;\n            case 50:\n                mTextView.setText(\"阴影\");\n                mPreviewBuilder.set(CaptureRequest.CONTROL_AWB_MODE, CameraMetadata.CONTROL_AWB_MODE_SHADE);\n                break;\n            case 60:\n                mTextView.setText(\"黄昏\");\n                mPreviewBuilder.set(CaptureRequest.CONTROL_AWB_MODE, CameraMetadata.CONTROL_AWB_MODE_TWILIGHT);\n                break;\n            case 70:\n                mTextView.setText(\"暖光\");\n                mPreviewBuilder.set(CaptureRequest.CONTROL_AWB_MODE, CameraMetadata.CONTROL_AWB_MODE_WARM_FLUORESCENT);\n                break;\n        }\n        updatePreview();\n        mTextView.startAnimation(mAlphaOutAnimation);\n        mTextView.setVisibility(View.INVISIBLE);\n    }\n\n    @Override\n    public void onStartTrackingTouch(SeekBar seekBar) {\n        mTextView.setVisibility(View.VISIBLE);\n        mTextView.startAnimation(mAlphaInAnimation);\n    }\n\n    /**\n     * 更新预览\n     */\n    private void updatePreview() {\n        try {\n            mCameraCaptureSession.setRepeatingRequest(mPreviewBuilder.build(), mPreviewSessionCallback, mHandler);\n        } catch (CameraAccessException e) {\n            e.printStackTrace();\n        } catch (Exception e) {\n            e.printStackTrace();\n            Log.i(\"updatePreview\", \"ExceptionExceptionException\");\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/camera/cn/cameramaster/view/CameraV2GLSurfaceView.java",
    "content": "package camera.cn.cameramaster.view;\n\nimport android.content.Context;\nimport android.opengl.GLSurfaceView;\n\nimport camera.cn.cameramaster.util.render.CameraV2Renderer;\nimport camera.cn.cameramaster.util.CameraV2;\n\n\n/**\n * CameraV2 GLSurfaceView\n * 参考url ： [https://blog.csdn.net/lb377463323/article/details/78054892]\n *\n * @date 2019年2月12日 13:41:16\n * @author ymc\n */\n\npublic class CameraV2GLSurfaceView extends GLSurfaceView {\n    public static boolean shouldTakePic = false;\n\n    public void init(CameraV2 camera, boolean isPreviewStarted, Context context) {\n        setEGLContextClientVersion(2);\n        CameraV2Renderer mCameraV2Renderer = new CameraV2Renderer();\n        mCameraV2Renderer.init(this, camera, isPreviewStarted, context);\n        setRenderer(mCameraV2Renderer);\n        setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);\n    }\n\n    public CameraV2GLSurfaceView(Context context) {\n        super(context);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/camera/cn/cameramaster/view/ShowSurfaceView.java",
    "content": "package camera.cn.cameramaster.view;\n\nimport android.content.Context;\nimport android.graphics.Bitmap;\nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.graphics.Paint;\nimport android.util.AttributeSet;\nimport android.view.SurfaceHolder;\nimport android.view.SurfaceView;\n\n/**\n * @packageName: cn.tongue.tonguecamera.view\n * @fileName: ShowSurfaceView\n * @date: 2019/3/7  13:17\n * @author: ymc\n * @QQ:745612618\n */\n\npublic class ShowSurfaceView extends SurfaceView implements SurfaceHolder.Callback, Runnable {\n    private SurfaceHolder mSurfaceHolder;\n    /**\n     * 绘图的Canvas\n     */\n    private Canvas mCanvas;\n    /**\n     * 子线程标志位\n     */\n    private boolean mIsDrawing;\n    private Bitmap bitmap;\n    private Paint mPaint;\n\n    public ShowSurfaceView(Context context) {\n        this(context, null);\n    }\n\n    public ShowSurfaceView(Context context, AttributeSet attrs) {\n        this(context, attrs, 0);\n    }\n\n    public ShowSurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n        mSurfaceHolder = getHolder();\n        mSurfaceHolder.addCallback(this);\n        setFocusable(true);\n        setKeepScreenOn(true);\n        setFocusableInTouchMode(true);\n        mPaint = new Paint();\n        mPaint.setColor(Color.BLACK);\n        mPaint.setStyle(Paint.Style.STROKE);\n        mPaint.setAntiAlias(true);\n        mPaint.setStrokeWidth(5);\n    }\n\n    @Override\n    public void surfaceCreated(SurfaceHolder holder) {\n        mIsDrawing = true;\n        //开启子线程\n        new Thread(this).start();\n    }\n\n    @Override\n    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {\n        //改变\n    }\n\n    @Override\n    public void surfaceDestroyed(SurfaceHolder holder) {\n        mIsDrawing = false;\n    }\n\n    @Override\n    public void run() {\n        while (mIsDrawing) {\n            drawSomething();\n        }\n    }\n\n    //绘图逻辑\n    private void drawSomething() {\n        try {\n            //获得canvas对象\n            mCanvas = mSurfaceHolder.lockCanvas();\n//            Bitmap bitmap1= BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);\n            if (bitmap != null) {\n                mCanvas.drawBitmap(bitmap, 0, 0, mPaint);\n            }\n            //绘图\n        } catch (Exception e) {\n\n        } finally {\n            if (mCanvas != null) {\n                //释放canvas对象并提交画布\n                mSurfaceHolder.unlockCanvasAndPost(mCanvas);\n            }\n        }\n    }\n\n    public Bitmap getBitmap() {\n        return bitmap;\n    }\n\n    public void setBitmap(Bitmap bitmap) {\n        this.bitmap = bitmap;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/camera/cn/cameramaster/view/SleepThread.java",
    "content": "package camera.cn.cameramaster.view;\n\nimport android.os.Handler;\nimport android.os.Message;\n\n/**\n * 睡眠线程\n *\n * @author ymc\n */\npublic class SleepThread implements Runnable {\n    private Handler mMainHandler;\n    private int what;\n    private long mTime;\n    private Object mObject;\n\n    public SleepThread(Handler mainHandler, int what, long mTime, Object mObject) {\n        this.mMainHandler = mainHandler;\n        this.what = what;\n        this.mTime = mTime;\n        this.mObject = mObject;\n    }\n\n    @Override\n    public void run() {\n        try {\n            Thread.sleep(mTime);\n        } catch (InterruptedException e) {\n            e.printStackTrace();\n        }\n        Message message = mMainHandler.obtainMessage();\n        message.what = what;\n        message.obj = mObject;\n        mMainHandler.sendMessage(message);\n\n    }\n}\n"
  },
  {
    "path": "app/src/main/res/anim/alpha_in.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<alpha xmlns:android=\"http://schemas.android.com/apk/res/android\"\n       android:duration=\"500\"\n       android:fillAfter=\"true\"\n       android:fromAlpha=\"0.0\"\n       android:toAlpha=\"1.0\">\n</alpha>"
  },
  {
    "path": "app/src/main/res/anim/alpha_out.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<alpha xmlns:android=\"http://schemas.android.com/apk/res/android\"\n       android:duration=\"500\"\n       android:fillAfter=\"true\"\n       android:fromAlpha=\"1.0\"\n       android:toAlpha=\"0.0\">\n</alpha>"
  },
  {
    "path": "app/src/main/res/drawable/ic_camera.xml",
    "content": "<vector android:height=\"16dp\" android:viewportHeight=\"1024.0\"\n    android:viewportWidth=\"1024.0\" android:width=\"16dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"#ffffff\" android:pathData=\"M512,100.1C287.7,100.1 105.3,279.4 100.2,502.5v19.1c5.1,223.1 187.5,402.4 411.8,402.4 227.5,0 411.9,-184.4 411.9,-411.9 0,-227.5 -184.4,-412 -411.9,-412z\"/>\n    <path android:fillColor=\"#ffffff\" android:pathData=\"M953.8,253.4c-44.3,-75.4 -107.3,-138.5 -182.6,-182.9C695.1,25.7 606.5,0 511.9,0c-94.5,0 -183.1,25.7 -259.2,70.6C178,114.6 115.4,177 71.2,251.6 27.9,324.6 2.2,409.3 0.1,499.7v24.5c2.1,90.4 27.8,175.1 71.1,248.2 44.4,74.9 107.4,137.6 182.5,181.6 75.8,44.4 164.1,70 258.2,70 94.1,0 182.3,-25.5 258.2,-70 75.8,-44.4 139.2,-107.8 183.6,-183.5 44.6,-75.9 70.2,-164.3 70.2,-258.6 0,-94.3 -25.6,-182.6 -70.2,-258.6zM511.9,970.1c-252.9,0 -458.2,-205.3 -458.2,-458.1 0,-252.9 205.3,-458.2 458.2,-458.2 252.9,0 458.1,205.3 458.1,458.2 0,252.9 -205.3,458.1 -458.1,458.1z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_fouces.xml",
    "content": "<vector android:height=\"24dp\" android:viewportHeight=\"1024.0\"\n    android:viewportWidth=\"1228.0\" android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"#ffffff\" android:pathData=\"M843.2,68.3H989.9a170.7,170.7 0,0 1,170.7 170.7v152.9a34.1,34.1 0,1 0,68.3 0V238.9a238.9,238.9 0,0 0,-238.9 -238.9h-146.7a34.1,34.1 0,0 0,0 68.3zM1160.5,629.4V785.1a170.7,170.7 0,0 1,-170.7 170.7h-123.6a34.1,34.1 0,0 0,0 68.3H989.9a238.9,238.9 0,0 0,238.9 -238.9v-155.7a34.1,34.1 0,1 0,-68.3 0zM393.4,955.7H238.9a170.7,170.7 0,0 1,-170.7 -170.7v-155.1a34.1,34.1 0,0 0,-68.3 0V785.1a238.9,238.9 0,0 0,238.9 238.9h154.5a34.1,34.1 0,0 0,0 -68.3zM68.3,393V238.9a170.7,170.7 0,0 1,170.7 -170.7h147.9a34.1,34.1 0,0 0,0 -68.3H238.9a238.9,238.9 0,0 0,-238.9 238.9v154.1a34.1,34.1 0,1 0,68.3 0z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_launcher_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"108dp\"\n    android:height=\"108dp\"\n    android:viewportHeight=\"108\"\n    android:viewportWidth=\"108\">\n    <path\n        android:fillColor=\"#26A69A\"\n        android:pathData=\"M0,0h108v108h-108z\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M9,0L9,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,0L19,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M29,0L29,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M39,0L39,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M49,0L49,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M59,0L59,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M69,0L69,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M79,0L79,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M89,0L89,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M99,0L99,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,9L108,9\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,19L108,19\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,29L108,29\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,39L108,39\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,49L108,49\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,59L108,59\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,69L108,69\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,79L108,79\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,89L108,89\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,99L108,99\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,29L89,29\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,39L89,39\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,49L89,49\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,59L89,59\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,69L89,69\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,79L89,79\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M29,19L29,89\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M39,19L39,89\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M49,19L49,89\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M59,19L59,89\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M69,19L69,89\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M79,19L79,89\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_launcher_camera.xml",
    "content": "<vector android:height=\"64dp\" android:viewportHeight=\"1024.0\"\n    android:viewportWidth=\"1024.0\" android:width=\"64dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"#BABABA\" android:pathData=\"M962.6,0c33.8,0 60.9,27.6 60.9,61.4v901.1c0,33.8 -27.6,61.4 -61.4,61.4h0.5c33.8,0 61.4,-27.6 61.4,-61.4V61.4c0,-33.8 -27.6,-61.4 -61.4,-61.4z\"/>\n    <path android:fillColor=\"#E59248\" android:pathData=\"M972.3,573.4h0.5V450.6h-0.5z\"/>\n    <path android:fillColor=\"#D1D1D1\" android:pathData=\"M51.2,153.6V862.7c97.8,-16.4 315.9,-62.5 473.6,-166.4H51.7v-368.6H788.5c43,-112.1 64.5,-217.1 74.8,-276.5H153.6c-56.3,0 -102.4,46.1 -102.4,102.4z\"/>\n    <path android:fillColor=\"#A8A8A8\" android:pathData=\"M972.3,327.7v368.6h-447.5C367.1,800.8 149,846.8 51.2,862.7V870.4c0,56.3 46.1,102.4 102.4,102.4h716.8c56.3,0 102.4,-46.1 102.4,-102.4V153.6c0,-56.3 -46.1,-102.4 -102.4,-102.4h-7.7c-10.2,59.4 -32.3,164.4 -74.8,276.5h184.3z\"/>\n    <path android:fillColor=\"#606060\" android:pathData=\"M51.2,153.6c0,-56.3 46.1,-102.4 102.4,-102.4h709.1c5.6,-32.3 7.7,-51.2 7.7,-51.2H153.6c-84.5,0 -153.6,69.1 -153.6,153.6V870.4s18.9,-2 51.2,-7.7V153.6z\"/>\n    <path android:fillColor=\"#606060\" android:pathData=\"M870.4,0s-2,18.9 -7.7,51.2h7.7c56.3,0 102.4,46.1 102.4,102.4V870.4c0,56.3 -46.1,102.4 -102.4,102.4H153.6c-56.3,0 -102.4,-46.1 -102.4,-102.4v-7.7c-32.3,5.1 -51.2,7.7 -51.2,7.7 0,84.5 69.1,153.6 153.6,153.6h716.8c84.5,0 153.6,-69.1 153.6,-153.6V153.6c0,-84.5 -69.1,-153.6 -153.6,-153.6z\"/>\n    <path android:fillColor=\"#FF6F4D\" android:pathData=\"M788,327.7H51.2v122.9h681.5c22,-41 39.9,-82.4 55.3,-122.9z\"/>\n    <path android:fillColor=\"#DD5C43\" android:pathData=\"M972.3,450.6v-122.9h-184.3c-15.4,40.4 -33.8,81.9 -54.8,122.9h239.1z\"/>\n    <path android:fillColor=\"#FFA750\" android:pathData=\"M733.2,450.6H51.7v122.9h604.7c29.2,-38.9 54.8,-80.4 76.8,-122.9z\"/>\n    <path android:fillColor=\"#E09048\" android:pathData=\"M655.9,573.4H972.3V450.6h-239.1c-22,42.5 -47.6,84 -77.3,122.9z\"/>\n    <path android:fillColor=\"#FFDE52\" android:pathData=\"M631.3,604.2c8.7,-10.2 16.9,-20.5 24.6,-30.7h-604.2v122.9h473.1c40.4,-26.6 77.3,-57.3 106.5,-92.2z\"/>\n    <path android:fillColor=\"#E2C444\" android:pathData=\"M972.3,573.4H655.9c-7.7,10.2 -15.9,20.5 -24.6,30.7 -29.7,34.8 -66,65.5 -106.5,92.2h447.5V573.4z\"/>\n    <path android:fillColor=\"#E5C74C\" android:pathData=\"M972.3,573.4h0.5v122.9h-0.5z\"/>\n    <path android:fillColor=\"#494949\" android:pathData=\"M511.5,512m-308.2,0a308.2,308.2 0,1 0,616.4 0,308.2 308.2,0 1,0 -616.4,0Z\"/>\n    <path android:fillColor=\"#636363\" android:pathData=\"M511.5,244.7c147.5,0 267.3,119.8 267.3,267.3s-119.8,267.3 -267.3,267.3 -267.3,-119.8 -267.3,-267.3 120.3,-267.3 267.3,-267.3m0,-41c-170,0 -308.2,137.7 -308.2,308.2s137.7,308.2 308.2,308.2 308.2,-137.7 308.2,-308.2 -138.2,-308.2 -308.2,-308.2z\"/>\n    <path android:fillColor=\"#FFFCD2\" android:pathData=\"M237.1,228.9H174.1c-22.5,0 -41,-18.4 -41,-41v-10.2c0,-22.5 18.4,-41 41,-41h63c22.5,0 41,18.4 41,41v10.2c0,22.5 -18.4,41 -41,41z\"/>\n    <path android:fillColor=\"#FFDE55\" android:pathData=\"M237.1,121.3L174.1,121.3c-31.2,0 -56.3,25.1 -56.3,56.3v10.2c0,31.2 25.1,56.3 56.3,56.3h63c31.2,0 56.3,-25.1 56.3,-56.3v-10.2c0,-31.2 -25.1,-56.3 -56.3,-56.3zM262.7,187.9c0,14.3 -11.3,25.6 -25.6,25.6L174.1,213.5c-14.3,0 -25.6,-11.3 -25.6,-25.6v-10.2c0,-14.3 11.3,-25.6 25.6,-25.6h63c14.3,0 25.6,11.3 25.6,25.6v10.2z\"/>\n    <path android:fillColor=\"#FFFFFF\" android:pathData=\"M313.9,522.2c-11.3,0 -20.5,-9.2 -20.5,-20.5 0,-111.6 91.1,-202.8 202.8,-202.8 11.3,0 20.5,9.2 20.5,20.5s-9.2,20.5 -20.5,20.5c-89.1,0 -161.8,72.7 -161.8,161.8 0,11.3 -9.2,20.5 -20.5,20.5z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable-v24/ic_launcher_foreground.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:aapt=\"http://schemas.android.com/aapt\"\n    android:width=\"108dp\"\n    android:height=\"108dp\"\n    android:viewportHeight=\"108\"\n    android:viewportWidth=\"108\">\n    <path\n        android:fillType=\"evenOdd\"\n        android:pathData=\"M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z\"\n        android:strokeColor=\"#00000000\"\n        android:strokeWidth=\"1\">\n        <aapt:attr name=\"android:fillColor\">\n            <gradient\n                android:endX=\"78.5885\"\n                android:endY=\"90.9159\"\n                android:startX=\"48.7653\"\n                android:startY=\"61.0927\"\n                android:type=\"linear\">\n                <item\n                    android:color=\"#44000000\"\n                    android:offset=\"0.0\" />\n                <item\n                    android:color=\"#00000000\"\n                    android:offset=\"1.0\" />\n            </gradient>\n        </aapt:attr>\n    </path>\n    <path\n        android:fillColor=\"#FFFFFF\"\n        android:fillType=\"nonZero\"\n        android:pathData=\"M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z\"\n        android:strokeColor=\"#00000000\"\n        android:strokeWidth=\"1\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/layout/activity_camera.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"@android:color/black\">\n\n    <LinearLayout\n        android:layout_width=\"1dp\"\n        android:layout_height=\"1dp\"\n        android:layout_alignParentEnd=\"true\">\n\n        <SurfaceView\n            android:id=\"@+id/surfaceView\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\" />\n\n    </LinearLayout>\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:layout_alignParentStart=\"true\"\n        android:weightSum=\"1\"\n        android:orientation=\"horizontal\">\n\n        <camera.cn.cameramaster.view.ShowSurfaceView\n            android:id=\"@+id/surfaceView2\"\n            android:layout_width=\"0dp\"\n            android:layout_weight=\"1\"\n            android:layout_height=\"match_parent\" />\n\n    </LinearLayout>\n\n\n    <RelativeLayout\n        android:id=\"@+id/homecamera_bottom_relative\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:background=\"#00ffffff\"\n        android:layout_alignParentBottom=\"true\">\n\n        <ImageView\n            android:id=\"@+id/iv_back\"\n            android:layout_width=\"40dp\"\n            android:layout_height=\"30dp\"\n            android:scaleType=\"centerInside\"\n            android:layout_marginBottom=\"20dp\"\n            android:layout_marginStart=\"20dp\"\n            android:layout_centerVertical=\"true\"\n            android:background=\"@mipmap/icon_back\" />\n\n        <ImageView\n            android:id=\"@+id/img_camera\"\n            android:layout_width=\"80dp\"\n            android:layout_height=\"80dp\"\n            android:scaleType=\"centerInside\"\n            android:layout_marginBottom=\"20dp\"\n            android:layout_centerInParent=\"true\"\n            android:background=\"@drawable/ic_camera\" />\n\n    </RelativeLayout>\n\n    <LinearLayout\n        android:id=\"@+id/home_custom_top_relative\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"50dp\"\n        android:gravity=\"center_vertical\"\n        android:orientation=\"horizontal\"\n        android:background=\"#00ffffff\"\n        android:layout_alignParentTop=\"true\"\n        >\n\n        <ImageView\n            android:id=\"@+id/camera_flash\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:padding=\"10dp\"\n            android:src=\"@mipmap/icon_camera_off\" />\n\n        <View\n            android:layout_width=\"0dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"5\"/>\n\n        <ImageView\n            android:id=\"@+id/camera_switch\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:padding=\"10dp\"\n            android:src=\"@mipmap/btn_camera_turn_n\" />\n\n    </LinearLayout>\n\n\n</RelativeLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/activity_camera2.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <FrameLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\">\n\n        <TextureView\n            android:id=\"@+id/textureView\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\" />\n\n    </FrameLayout>\n\n    <RelativeLayout\n        android:id=\"@+id/homecamera_bottom_relative2\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:background=\"#00ffffff\"\n        android:layout_alignParentBottom=\"true\">\n\n        <ImageView\n            android:id=\"@+id/iv_back2\"\n            android:layout_width=\"40dp\"\n            android:layout_height=\"30dp\"\n            android:scaleType=\"centerInside\"\n            android:layout_marginBottom=\"20dp\"\n            android:layout_marginStart=\"20dp\"\n            android:layout_centerVertical=\"true\"\n            android:background=\"@mipmap/icon_back\" />\n\n        <ImageView\n            android:id=\"@+id/img_camera2\"\n            android:layout_width=\"80dp\"\n            android:layout_height=\"80dp\"\n            android:scaleType=\"centerInside\"\n            android:layout_marginBottom=\"20dp\"\n            android:layout_centerInParent=\"true\"\n            android:background=\"@drawable/ic_camera\" />\n\n    </RelativeLayout>\n\n    <LinearLayout\n        android:id=\"@+id/home_custom_top_relative\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"50dp\"\n        android:gravity=\"center_vertical\"\n        android:orientation=\"horizontal\"\n        android:background=\"#00ffffff\"\n        android:layout_alignParentTop=\"true\"\n        >\n\n        <ImageView\n            android:id=\"@+id/camera_flash2\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:padding=\"10dp\"\n            android:src=\"@mipmap/icon_camera_off\" />\n\n        <View\n            android:layout_width=\"0dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"5\"/>\n\n        <ImageView\n            android:id=\"@+id/camera_switch2\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:padding=\"10dp\"\n            android:src=\"@mipmap/btn_camera_turn_n\" />\n\n    </LinearLayout>\n\n\n</RelativeLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/activity_camera_sv.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"@android:color/black\">\n\n    <FrameLayout\n        android:id=\"@+id/frame_layout\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\">\n\n    </FrameLayout>\n\n    <RelativeLayout\n        android:id=\"@+id/homecamera_bottom_relative\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:background=\"#00ffffff\"\n        android:layout_alignParentBottom=\"true\">\n\n        <ImageView\n            android:id=\"@+id/iv_back\"\n            android:layout_width=\"40dp\"\n            android:layout_height=\"30dp\"\n            android:scaleType=\"centerInside\"\n            android:layout_marginBottom=\"20dp\"\n            android:layout_marginStart=\"20dp\"\n            android:layout_centerVertical=\"true\"\n            android:background=\"@mipmap/icon_back\" />\n\n        <ImageView\n            android:id=\"@+id/img_camera\"\n            android:layout_width=\"80dp\"\n            android:layout_height=\"80dp\"\n            android:scaleType=\"centerInside\"\n            android:layout_marginBottom=\"20dp\"\n            android:layout_centerInParent=\"true\"\n            android:background=\"@drawable/ic_camera\" />\n\n    </RelativeLayout>\n\n    <LinearLayout\n        android:id=\"@+id/home_custom_top_relative\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"50dp\"\n        android:gravity=\"center_vertical\"\n        android:orientation=\"horizontal\"\n        android:visibility=\"gone\"\n        android:background=\"#00ffffff\"\n        android:layout_alignParentTop=\"true\"\n        >\n\n        <ImageView\n            android:id=\"@+id/camera_flash\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:padding=\"10dp\"\n            android:src=\"@mipmap/icon_camera_off\" />\n\n        <View\n            android:layout_width=\"0dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"5\"/>\n\n        <ImageView\n            android:id=\"@+id/camera_switch\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:padding=\"10dp\"\n            android:src=\"@mipmap/btn_camera_turn_n\" />\n\n    </LinearLayout>\n\n\n</RelativeLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/activity_camera_video.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    tools:context=\".ui.CameraVideoActivity\">\n\n    <ImageView\n        android:id=\"@+id/video_photo\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:scaleType=\"fitCenter\"\n        android:visibility=\"gone\" />\n\n    <camera.cn.cameramaster.view.AutoFitTextureView\n        android:id=\"@+id/video_texture\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\" />\n\n    <SeekBar\n        android:id=\"@+id/video_record_seek_bar\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"top\"\n        android:max=\"10\"\n        android:maxHeight=\"3dp\"\n        android:minHeight=\"3dp\"\n        android:splitTrack=\"false\"\n        android:visibility=\"gone\" />\n\n\n    <TextView\n        android:id=\"@+id/video_time\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_alignTop=\"@+id/video_switch_flash\"\n        android:layout_centerHorizontal=\"true\"\n        android:textColor=\"@android:color/white\"\n        android:textSize=\"18sp\"\n        android:textStyle=\"bold\"\n        android:visibility=\"gone\" />\n\n    <ImageView\n        android:id=\"@+id/video_switch_flash\"\n        android:layout_width=\"32dp\"\n        android:layout_height=\"32dp\"\n        android:layout_alignParentStart=\"true\"\n        android:layout_marginStart=\"20dp\"\n        android:layout_marginTop=\"16dp\"\n        android:scaleType=\"center\"\n        android:background=\"@mipmap/flash_close\" />\n\n    <ImageView\n        android:id=\"@+id/video_switch_camera\"\n        android:layout_width=\"30dp\"\n        android:layout_height=\"24dp\"\n        android:layout_alignParentRight=\"true\"\n        android:layout_marginEnd=\"16dp\"\n        android:layout_marginTop=\"16dp\"\n        android:scaleType=\"center\"\n        android:background=\"@mipmap/ic_switch_camera\"\n        tools:ignore=\"RtlHardcoded\" />\n\n    <ImageButton\n        android:id=\"@+id/video_play\"\n        android:layout_width=\"83dp\"\n        android:layout_height=\"83dp\"\n        android:layout_centerInParent=\"true\"\n        android:background=\"@null\"\n        android:scaleType=\"fitXY\"\n        android:src=\"@mipmap/ic_play\"\n        android:visibility=\"gone\" />\n\n    <ImageButton\n        android:id=\"@+id/video_delete\"\n        android:layout_width=\"58dp\"\n        android:layout_height=\"58dp\"\n        android:layout_alignParentStart=\"true\"\n        android:layout_alignParentBottom=\"true\"\n        android:layout_marginBottom=\"36dp\"\n        android:layout_marginStart=\"45dp\"\n        android:background=\"@null\"\n        android:scaleType=\"fitXY\"\n        android:src=\"@mipmap/ic_delete\"\n        android:visibility=\"gone\" />\n\n    <camera.cn.cameramaster.view.AutoLocateHorizontalView\n        android:id=\"@+id/video_menu\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:layout_gravity=\"bottom\"\n        android:layout_marginBottom=\"106dp\"\n        android:layout_marginTop=\"60dp\"\n        android:overScrollMode=\"never\" />\n\n    <ImageButton\n        android:id=\"@+id/video_save\"\n        android:layout_width=\"58dp\"\n        android:layout_height=\"58dp\"\n        android:layout_alignParentBottom=\"true\"\n        android:layout_alignParentEnd=\"true\"\n        android:layout_marginBottom=\"36dp\"\n        android:layout_marginEnd=\"45dp\"\n        android:background=\"@null\"\n        android:scaleType=\"fitXY\"\n        android:src=\"@mipmap/ic_save\"\n        android:visibility=\"gone\" />\n\n    <ImageButton\n        android:id=\"@+id/video_mine_play\"\n        android:layout_width=\"34dp\"\n        android:layout_height=\"34dp\"\n        android:layout_alignParentBottom=\"true\"\n        android:layout_alignParentStart=\"true\"\n        android:layout_marginBottom=\"19dp\"\n        android:layout_marginStart=\"19dp\"\n        android:background=\"@null\"\n        android:scaleType=\"fitXY\"\n        android:src=\"@mipmap/ic_play\"\n        android:visibility=\"gone\" />\n\n    <SeekBar\n        android:id=\"@+id/video_seek_bar\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"bottom\"\n        android:layout_marginBottom=\"30dp\"\n        android:layout_marginStart=\"58dp\"\n        android:maxHeight=\"2dp\"\n        android:minHeight=\"2dp\"\n        android:splitTrack=\"false\"\n        android:visibility=\"gone\" />\n\n    <TextView\n        android:id=\"@+id/video_seek_time\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_alignParentTop=\"true\"\n        android:layout_centerHorizontal=\"true\"\n        android:layout_marginBottom=\"12dp\"\n        android:layout_marginEnd=\"20dp\"\n        android:textColor=\"@android:color/white\"\n        android:textSize=\"15sp\"\n        android:visibility=\"gone\" />\n\n\n    <ImageView\n        android:id=\"@+id/video_fouces\"\n        android:layout_width=\"65dp\"\n        android:layout_height=\"65dp\"\n        android:scaleType=\"fitCenter\"\n        android:src=\"@drawable/ic_fouces\"\n        android:visibility=\"gone\" />\n\n    <RelativeLayout\n        android:id=\"@+id/video_scale_bar_layout\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_alignParentBottom=\"true\"\n        android:layout_marginBottom=\"150dp\"\n        android:paddingLeft=\"40dp\"\n        android:paddingRight=\"40dp\"\n        android:visibility=\"gone\">\n\n        <ImageView\n            android:id=\"@+id/video_minus\"\n            android:layout_width=\"24dp\"\n            android:layout_height=\"24dp\"\n            android:layout_alignParentStart=\"true\"\n            android:scaleType=\"fitXY\"\n            android:src=\"@mipmap/ic_minus\" />\n\n        <SeekBar\n            android:id=\"@+id/video_scale\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_centerVertical=\"true\"\n            android:layout_toEndOf=\"@+id/video_minus\"\n            android:layout_toStartOf=\"@+id/video_add\"\n            android:maxHeight=\"4dp\"\n            android:minHeight=\"4dp\"\n            android:splitTrack=\"false\" />\n\n        <ImageView\n            android:id=\"@+id/video_add\"\n            android:layout_width=\"24dp\"\n            android:layout_height=\"24dp\"\n            android:layout_alignParentEnd=\"true\"\n            android:scaleType=\"fitXY\"\n            android:src=\"@mipmap/ic_add\" />\n    </RelativeLayout>\n\n    <RelativeLayout\n        android:id=\"@+id/layout_bottom\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"90dp\"\n        android:layout_alignParentBottom=\"true\"\n        android:layout_centerHorizontal=\"true\"\n        android:layout_marginBottom=\"10dp\">\n\n        <RelativeLayout\n            android:id=\"@+id/rl_camera\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\">\n\n            <ImageButton\n                android:id=\"@+id/video_record\"\n                android:layout_width=\"58dp\"\n                android:layout_height=\"58dp\"\n                android:layout_alignParentBottom=\"true\"\n                android:layout_centerHorizontal=\"true\"\n                android:layout_marginBottom=\"30dp\"\n                android:background=\"@null\"\n                android:scaleType=\"fitXY\"\n                android:src=\"@drawable/ic_camera\" />\n\n            <TextView\n                android:id=\"@+id/video_hint_text\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_alignParentBottom=\"true\"\n                android:layout_centerHorizontal=\"true\"\n                android:text=\"点击拍照\"\n                android:textColor=\"@android:color/white\"\n                android:textSize=\"14sp\" />\n\n        </RelativeLayout>\n\n\n        <LinearLayout\n            android:id=\"@+id/layout_ae\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_centerHorizontal=\"true\"\n            android:layout_centerVertical=\"true\"\n            android:orientation=\"vertical\"\n            android:visibility=\"gone\">\n\n            <Switch\n                android:id=\"@+id/switch_ae\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center\"\n                android:layout_marginBottom=\"5dp\"\n                android:gravity=\"center\"/>\n\n            <SeekBar\n                android:id=\"@+id/sb_ae\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center\"\n                android:layout_marginTop=\"5dp\"\n                android:max=\"100\"\n                android:progress=\"50\"\n                android:gravity=\"center\"/>\n\n        </LinearLayout>\n\n        <LinearLayout\n            android:id=\"@+id/layout_awb\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_centerHorizontal=\"true\"\n            android:layout_centerVertical=\"true\"\n            android:orientation=\"vertical\"\n            android:visibility=\"gone\">\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:orientation=\"horizontal\">\n\n                <ImageView\n                    android:layout_width=\"0dp\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_weight=\"1\"\n                    android:src=\"@mipmap/ic_camera_wb_auto\"/>\n\n                <ImageView\n                    android:layout_width=\"0dp\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_weight=\"1\"\n                    android:src=\"@mipmap/ic_camera_wb_cloudy_daylight\"/>\n\n                <ImageView\n                    android:layout_width=\"0dp\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_weight=\"1\"\n                    android:src=\"@mipmap/ic_camera_wb_daylight\"/>\n\n                <ImageView\n                    android:layout_width=\"0dp\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_weight=\"1\"\n                    android:src=\"@mipmap/ic_camera_wb_fluorescent\"/>\n\n                <ImageView\n                    android:layout_width=\"0dp\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_weight=\"1\"\n                    android:src=\"@mipmap/ic_camera_wb_incandescent\"/>\n\n                <ImageView\n                    android:layout_width=\"0dp\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_weight=\"1\"\n                    android:src=\"@mipmap/ic_camera_wb_shade\"/>\n\n                <ImageView\n                    android:layout_width=\"0dp\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_weight=\"1\"\n                    android:src=\"@mipmap/ic_camera_wb_twilight\"/>\n\n                <ImageView\n                    android:layout_width=\"0dp\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_weight=\"1\"\n                    android:src=\"@mipmap/ic_camera_wb_warm_fluorescent\"/>\n            </LinearLayout>\n\n            <camera.cn.cameramaster.view.AwbSeekBar\n                android:id=\"@+id/sb_awb\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center\"\n                android:layout_marginTop=\"5dp\"\n                android:gravity=\"center\"/>\n\n        </LinearLayout>\n\n        <LinearLayout\n            android:id=\"@+id/layout_effect\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_centerHorizontal=\"true\"\n            android:layout_centerVertical=\"true\"\n            android:orientation=\"vertical\"\n            android:visibility=\"gone\">\n\n            <android.support.v7.widget.RecyclerView\n                android:id=\"@+id/rv_effect_list\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"60dp\">\n\n            </android.support.v7.widget.RecyclerView>\n\n        </LinearLayout>\n\n        <LinearLayout\n            android:id=\"@+id/layout_sense\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_centerHorizontal=\"true\"\n            android:layout_centerVertical=\"true\"\n            android:orientation=\"vertical\"\n            android:visibility=\"gone\">\n\n            <android.support.v7.widget.RecyclerView\n                android:id=\"@+id/rv_sense_list\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"60dp\">\n\n            </android.support.v7.widget.RecyclerView>\n\n        </LinearLayout>\n\n        <LinearLayout\n            android:id=\"@+id/layout_setting\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_centerHorizontal=\"true\"\n            android:layout_centerVertical=\"true\"\n            android:orientation=\"vertical\"\n            android:visibility=\"gone\">\n\n            <SeekBar\n                android:id=\"@+id/awb_seek_bar\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"top\"\n                android:max=\"8000\"\n                android:maxHeight=\"3dp\"\n                android:minHeight=\"3dp\"\n                android:splitTrack=\"false\"\n                android:visibility=\"visible\" />\n\n        </LinearLayout>\n\n    </RelativeLayout>\n\n    <TextView\n        android:id=\"@+id/txt_sb_txt\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_above=\"@+id/layout_bottom\"\n        android:layout_centerHorizontal=\"true\"\n        android:layout_gravity=\"center\"\n        android:layout_marginBottom=\"50dp\"\n        android:textColor=\"@android:color/white\"\n        android:textSize=\"25sp\" />\n\n</RelativeLayout>"
  },
  {
    "path": "app/src/main/res/layout/activity_google_camera.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"@android:color/black\">\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_alignParentEnd=\"true\"\n        android:layout_height=\"match_parent\">\n\n        <camera.cn.cameramaster.view.AutoTextureView\n            android:id=\"@+id/textureView_g\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\" />\n\n    </LinearLayout>\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:layout_alignParentStart=\"true\"\n        android:visibility=\"gone\"\n        android:orientation=\"horizontal\">\n\n        <camera.cn.cameramaster.view.ShowSurfaceView\n            android:id=\"@+id/surfaceView2\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\" />\n\n    </LinearLayout>\n\n    <RelativeLayout\n        android:id=\"@+id/layout_bottom\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"90dp\"\n        android:layout_alignParentBottom=\"true\"\n        android:layout_centerHorizontal=\"true\"\n        android:layout_marginBottom=\"20dp\">\n\n        <RelativeLayout\n            android:id=\"@+id/homecamera_bottom_relative2\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_alignParentBottom=\"true\">\n\n            <ImageView\n                android:id=\"@+id/iv_back_g\"\n                android:layout_width=\"40dp\"\n                android:layout_height=\"30dp\"\n                android:scaleType=\"centerInside\"\n                android:layout_marginBottom=\"20dp\"\n                android:layout_marginStart=\"20dp\"\n                android:layout_centerVertical=\"true\"\n                android:background=\"@mipmap/icon_back\" />\n\n            <ImageView\n                android:id=\"@+id/img_camera_g\"\n                android:layout_width=\"60dp\"\n                android:layout_height=\"60dp\"\n                android:scaleType=\"centerInside\"\n                android:layout_marginBottom=\"20dp\"\n                android:layout_centerInParent=\"true\"\n                android:background=\"@drawable/ic_camera\" />\n\n            <ImageView\n                android:id=\"@+id/iv_images\"\n                android:layout_width=\"40dp\"\n                android:layout_height=\"30dp\"\n                android:layout_alignParentEnd=\"true\"\n                android:layout_marginEnd=\"20dp\"\n                android:layout_centerVertical=\"true\"\n                android:background=\"@mipmap/btn_album\"\n                android:scaleType=\"centerInside\" />\n\n        </RelativeLayout>\n\n\n        <LinearLayout\n            android:id=\"@+id/layout_ae\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_centerHorizontal=\"true\"\n            android:layout_centerVertical=\"true\"\n            android:orientation=\"vertical\"\n            android:visibility=\"invisible\">\n\n            <Switch\n                android:id=\"@+id/switch_ae\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center\"\n                android:layout_marginBottom=\"5dp\"\n                android:gravity=\"center\"/>\n\n            <SeekBar\n                android:id=\"@+id/sb_ae\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center\"\n                android:layout_marginTop=\"5dp\"\n                android:max=\"100\"\n                android:progress=\"50\"\n                android:gravity=\"center\"/>\n\n        </LinearLayout>\n\n        <LinearLayout\n            android:id=\"@+id/layout_zoom\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_centerHorizontal=\"true\"\n            android:layout_centerVertical=\"true\"\n            android:orientation=\"vertical\"\n            android:visibility=\"invisible\">\n\n            <SeekBar\n                android:id=\"@+id/sb_zoom\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center\"\n                android:max=\"100\"\n                android:progress=\"0\"\n                android:layout_marginTop=\"5dp\"\n                android:gravity=\"center\"/>\n\n        </LinearLayout>\n\n        <LinearLayout\n            android:id=\"@+id/layout_awb\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_centerHorizontal=\"true\"\n            android:layout_centerVertical=\"true\"\n            android:orientation=\"vertical\"\n            android:visibility=\"invisible\">\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:orientation=\"horizontal\">\n\n                <ImageView\n                    android:layout_width=\"0dp\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_weight=\"1\"\n                    android:src=\"@mipmap/ic_camera_wb_auto\"/>\n\n                <ImageView\n                    android:layout_width=\"0dp\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_weight=\"1\"\n                    android:src=\"@mipmap/ic_camera_wb_cloudy_daylight\"/>\n\n                <ImageView\n                    android:layout_width=\"0dp\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_weight=\"1\"\n                    android:src=\"@mipmap/ic_camera_wb_daylight\"/>\n\n                <ImageView\n                    android:layout_width=\"0dp\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_weight=\"1\"\n                    android:src=\"@mipmap/ic_camera_wb_fluorescent\"/>\n\n                <ImageView\n                    android:layout_width=\"0dp\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_weight=\"1\"\n                    android:src=\"@mipmap/ic_camera_wb_incandescent\"/>\n\n                <ImageView\n                    android:layout_width=\"0dp\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_weight=\"1\"\n                    android:src=\"@mipmap/ic_camera_wb_shade\"/>\n\n                <ImageView\n                    android:layout_width=\"0dp\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_weight=\"1\"\n                    android:src=\"@mipmap/ic_camera_wb_twilight\"/>\n\n                <ImageView\n                    android:layout_width=\"0dp\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_weight=\"1\"\n                    android:src=\"@mipmap/ic_camera_wb_warm_fluorescent\"/>\n            </LinearLayout>\n\n            <camera.cn.cameramaster.view.AwbSeekBar\n                android:id=\"@+id/sb_awb\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center\"\n                android:layout_marginTop=\"5dp\"\n                android:gravity=\"center\"/>\n\n        </LinearLayout>\n\n        <LinearLayout\n            android:id=\"@+id/layout_iso\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_centerHorizontal=\"true\"\n            android:layout_centerVertical=\"true\"\n            android:orientation=\"vertical\"\n            android:visibility=\"invisible\">\n\n            <Switch\n                android:id=\"@+id/switch_iso\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center\"\n                android:layout_marginBottom=\"5dp\"\n                android:gravity=\"center\"/>\n\n            <SeekBar\n                android:id=\"@+id/sb_iso\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center\"\n                android:layout_marginTop=\"5dp\"\n                android:max=\"100\"\n                android:progress=\"0\"\n                android:gravity=\"center\"/>\n\n        </LinearLayout>\n\n        <LinearLayout\n            android:id=\"@+id/layout_effect\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_centerHorizontal=\"true\"\n            android:layout_centerVertical=\"true\"\n            android:orientation=\"vertical\"\n            android:visibility=\"invisible\">\n\n            <android.support.v7.widget.RecyclerView\n                android:id=\"@+id/rv_effect_list\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"60dp\">\n\n            </android.support.v7.widget.RecyclerView>\n\n        </LinearLayout>\n\n        <LinearLayout\n            android:id=\"@+id/layout_sense\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_centerHorizontal=\"true\"\n            android:layout_centerVertical=\"true\"\n            android:orientation=\"vertical\"\n            android:visibility=\"invisible\">\n\n            <android.support.v7.widget.RecyclerView\n                android:id=\"@+id/rv_sense_list\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"60dp\">\n\n            </android.support.v7.widget.RecyclerView>\n\n        </LinearLayout>\n\n    </RelativeLayout>\n\n    <LinearLayout\n        android:id=\"@+id/layout_menu\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_above=\"@+id/layout_bottom\"\n        android:orientation=\"horizontal\">\n\n        <ImageView\n            android:id=\"@+id/iv_flash\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginStart=\"8dp\"\n            android:layout_marginEnd=\"5dp\"\n            android:layout_gravity=\"center\"\n            android:background=\"@mipmap/btn_flash_off_normal\"/>\n\n        <ImageView\n            android:id=\"@+id/iv_ae\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center\"\n            android:layout_marginStart=\"6dp\"\n            android:layout_marginEnd=\"8dp\"\n            android:background=\"@mipmap/btn_ae\"/>\n\n        <ImageView\n            android:id=\"@+id/iv_awb\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center\"\n            android:layout_marginLeft=\"8dp\"\n            android:layout_marginRight=\"8dp\"\n            android:background=\"@mipmap/btn_awb\"/>\n\n        <ImageView\n            android:id=\"@+id/iv_iso\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center\"\n            android:layout_marginLeft=\"8dp\"\n            android:layout_marginRight=\"8dp\"\n            android:background=\"@mipmap/btn_iso\"/>\n\n        <ImageView\n            android:id=\"@+id/iv_zoom\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center\"\n            android:background=\"@mipmap/btn_zoom\"/>\n\n        <ImageView\n            android:id=\"@+id/iv_effect\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center\"\n            android:layout_marginLeft=\"8dp\"\n            android:layout_marginRight=\"8dp\"\n            android:background=\"@mipmap/btn_effect\"/>\n\n\n        <ImageView\n            android:id=\"@+id/iv_sense\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginStart=\"15dp\"\n            android:layout_marginEnd=\"5dp\"\n            android:layout_gravity=\"center\"\n            android:background=\"@mipmap/btn_sense\"/>\n\n        <ImageView\n            android:id=\"@+id/iv_change_camera\"\n            android:layout_width=\"wrap_content\"\n            android:layout_marginLeft=\"8dp\"\n            android:layout_marginRight=\"8dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center\"\n            android:background=\"@mipmap/btn_change_camera_normal\"/>\n\n    </LinearLayout>\n\n    <camera.cn.cameramaster.view.AnimationTextView\n        android:id=\"@+id/txt_window_txt\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_centerInParent=\"true\"\n        android:layout_gravity=\"center\"\n        android:textColor=\"@android:color/white\"\n        android:textSize=\"25sp\"/>\n\n    <TextView\n        android:id=\"@+id/txt_sb_txt\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_above=\"@+id/layout_bottom\"\n        android:layout_centerHorizontal=\"true\"\n        android:layout_gravity=\"center\"\n        android:layout_marginBottom=\"50dp\"\n        android:textColor=\"@android:color/white\"\n        android:textSize=\"25sp\" />\n\n</RelativeLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/activity_look_camera.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:keepScreenOn=\"true\"\n    android:layout_height=\"match_parent\">\n    <FrameLayout android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\">\n        <SurfaceView android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:id=\"@+id/mSurface\" />\n    </FrameLayout>\n    <ImageButton\n        android:layout_width=\"70dp\"\n        android:layout_height=\"70dp\"\n        android:contentDescription=\"@string/app_name\"\n        android:background=\"@drawable/ic_camera\"\n        android:id=\"@+id/mShutter\"\n        android:onClick=\"onClick\"\n        android:layout_alignParentBottom=\"true\"\n        android:layout_marginBottom=\"30dp\"\n        android:layout_centerHorizontal=\"true\"/>\n</RelativeLayout>"
  },
  {
    "path": "app/src/main/res/layout/activity_main.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<android.support.constraint.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <Button\n        android:id=\"@+id/btn_camera\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"拍照版本 - 1\"\n        android:visibility=\"gone\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintLeft_toLeftOf=\"parent\"\n        app:layout_constraintRight_toRightOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"parent\" />\n\n    <Button\n        android:id=\"@+id/btn_camera2\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"拍照版本 - 2\"\n        android:layout_marginTop=\"20dp\"\n        app:layout_constraintTop_toBottomOf=\"@+id/btn_camera\"\n        app:layout_constraintLeft_toLeftOf=\"parent\"\n        app:layout_constraintRight_toRightOf=\"parent\"/>\n\n    <Button\n        android:id=\"@+id/btn_camera2_video\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"拍照 录像\"\n        android:layout_marginTop=\"20dp\"\n        app:layout_constraintTop_toBottomOf=\"@+id/btn_camera2\"\n        app:layout_constraintLeft_toLeftOf=\"parent\"\n        app:layout_constraintRight_toRightOf=\"parent\"/>\n\n    <Button\n        android:id=\"@+id/btn_filter_camera2\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"GL 拍照版本 - 2 \"\n        android:layout_marginTop=\"20dp\"\n        app:layout_constraintTop_toBottomOf=\"@+id/btn_camera2_video\"\n        app:layout_constraintLeft_toLeftOf=\"parent\"\n        app:layout_constraintRight_toRightOf=\"parent\"/>\n\n    <Button\n        android:id=\"@+id/btn_look_camera2\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"美颜拍照 - 2\"\n        android:layout_marginBottom=\"20dp\"\n        android:visibility=\"gone\"\n        app:layout_constraintBottom_toTopOf=\"@+id/btn_camera\"\n        app:layout_constraintLeft_toLeftOf=\"parent\"\n        app:layout_constraintRight_toRightOf=\"parent\"/>\n\n    <TextView\n        android:id=\"@+id/tv_message\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"\"\n        android:layout_marginBottom=\"20dp\"\n        android:textSize=\"16sp\"\n        app:layout_constraintBottom_toTopOf=\"@+id/btn_camera\"\n        app:layout_constraintLeft_toLeftOf=\"parent\"\n        app:layout_constraintRight_toRightOf=\"parent\"/>\n\n</android.support.constraint.ConstraintLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/activity_show_pic.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:id=\"@+id/activity_show_pic\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <LinearLayout\n        android:id=\"@+id/ll_1\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginStart=\"5dp\"\n        android:orientation=\"horizontal\">\n\n        <TextView\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"R:\" />\n\n        <SeekBar\n            android:id=\"@+id/seekBar1\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:progress=\"128\"\n            android:max=\"255\"\n            android:padding=\"5dp\" />\n    </LinearLayout>\n\n    <LinearLayout\n        android:id=\"@+id/ll_2\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_below=\"@+id/ll_1\"\n        android:layout_marginStart=\"5dp\"\n        android:orientation=\"horizontal\">\n\n        <TextView\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"G:\" />\n\n        <SeekBar\n            android:id=\"@+id/seekBar2\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:progress=\"128\"\n            android:max=\"255\"\n            android:padding=\"5dp\" />\n\n    </LinearLayout>\n\n    <LinearLayout\n        android:id=\"@+id/ll_3\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_below=\"@+id/ll_2\"\n        android:layout_marginStart=\"5dp\"\n        android:orientation=\"horizontal\">\n\n        <TextView\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"B:\" />\n\n        <SeekBar\n            android:id=\"@+id/seekBar3\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:progress=\"128\"\n            android:max=\"255\"\n            android:padding=\"5dp\" />\n    </LinearLayout>\n\n    <LinearLayout\n        android:id=\"@+id/ll_4\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_below=\"@+id/ll_3\"\n        android:layout_marginStart=\"5dp\"\n        android:orientation=\"horizontal\">\n\n        <TextView\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"H:\" />\n\n        <SeekBar\n            android:id=\"@+id/seekBar4\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:progress=\"128\"\n            android:max=\"255\"\n            android:padding=\"5dp\" />\n    </LinearLayout>\n\n\n    <ImageView\n        android:id=\"@+id/img\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_below=\"@+id/ll_4\" />\n\n</RelativeLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/item_age.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:orientation=\"horizontal\"\n    android:layout_width=\"wrap_content\"\n    android:gravity=\"center\"\n    android:layout_height=\"match_parent\">\n\n    <TextView\n        android:id=\"@+id/tv_age\"\n        android:gravity=\"center\"\n        android:layout_gravity=\"bottom\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:textStyle=\"bold\"\n        />\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/item_rv_text.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<android.support.v7.widget.CardView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:card_view=\"http://schemas.android.com/apk/res-auto\"\n    android:id=\"@+id/cv_item\"\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"50dp\"\n    android:layout_gravity=\"center\"\n    android:layout_margin=\"8dp\"\n    card_view:cardCornerRadius=\"4dp\">\n\n    <TextView\n        android:id=\"@+id/text_view\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:gravity=\"center\"\n        android:padding=\"8dp\"\n        android:text=\"测试文字\"\n        android:textColor=\"@android:color/black\"\n        android:textSize=\"16sp\" />\n\n</android.support.v7.widget.CardView>"
  },
  {
    "path": "app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@drawable/ic_launcher_background\" />\n    <foreground android:drawable=\"@drawable/ic_launcher_foreground\" />\n</adaptive-icon>"
  },
  {
    "path": "app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@drawable/ic_launcher_background\" />\n    <foreground android:drawable=\"@drawable/ic_launcher_foreground\" />\n</adaptive-icon>"
  },
  {
    "path": "app/src/main/res/mipmap-xhdpi/ic_launcher_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"108dp\"\n    android:height=\"108dp\"\n    android:viewportHeight=\"108\"\n    android:viewportWidth=\"108\">\n    <path\n        android:fillColor=\"#26A69A\"\n        android:pathData=\"M0,0h108v108h-108z\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M9,0L9,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,0L19,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M29,0L29,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M39,0L39,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M49,0L49,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M59,0L59,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M69,0L69,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M79,0L79,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M89,0L89,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M99,0L99,108\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,9L108,9\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,19L108,19\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,29L108,29\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,39L108,39\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,49L108,49\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,59L108,59\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,69L108,69\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,79L108,79\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,89L108,89\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M0,99L108,99\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,29L89,29\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,39L89,39\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,49L89,49\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,59L89,59\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,69L89,69\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M19,79L89,79\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M29,19L29,89\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M39,19L39,89\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M49,19L49,89\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M59,19L59,89\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M69,19L69,89\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M79,19L79,89\"\n        android:strokeColor=\"#33FFFFFF\"\n        android:strokeWidth=\"0.8\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/mipmap-xhdpi/icon_back.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"1024dp\"\n    android:height=\"1024dp\"\n    android:viewportWidth=\"1024\"\n    android:viewportHeight=\"1024\">\n\n    <path\n        android:fillColor=\"#ffffff\"\n        android:pathData=\"M918.8 411.9c-61.6-45.5-146.1-69.6-244.5-69.6H53.4L311.9 130c9.5-7.8 10.9-21.8 3.1-31.3-7.8-9.5-21.8-10.9-31.3-3.1L24 308.8l-1.6 1.5C8 324.7 0 344 0 364.6s8 39.9 22.4 54.3l0.8 0.8 260.4 213.9c4.1 3.4 9.1 5.1 14.1 5.1 6.4 0 12.8-2.8 17.2-8.1 7.8-9.5 6.4-23.5-3.1-31.3L53.4 386.9h620.9c147.5 0 305.2 63.9 305.2 243.3 0 178.7-153.3 258.8-305.2 258.8H328.8c-12.3 0-22.3 10-22.3 22.3s10 22.3 22.3 22.3h345.5c95.7 0 182.8-27.7 245.2-77.9 68.4-55 104.5-132.9 104.5-225.4 0-92-36.4-167.5-105.2-218.4z\" />\n</vector>"
  },
  {
    "path": "app/src/main/res/raw/base_fragment_shader.glsl",
    "content": "#extension GL_OES_EGL_image_external : require\nuniform samplerExternalOES uTextureSampler;\nprecision mediump float;\nuniform int vColorType;\nvarying vec2 vTextureCoord;\nuniform int vArraysSize;\nuniform vec3 vChangeColor;\nuniform vec3 vChangeColorB;\nuniform vec3 vChangeColorC;\n\nfloat debugFloatA;\nfloat debugFloatB;\n\nvoid main()\n{\n    vec4 vCameraColor = texture2D(uTextureSampler, vTextureCoord);\n    gl_FragColor = vec4(vCameraColor.r, vCameraColor.g, vCameraColor.b, 1.0);\n    for(int i = 0;i<vArraysSize;++i){\n        debugFloatA =  vCameraColor.r * 255.0 - 1.0 ;\n        debugFloatB = vCameraColor.r * 255.0 + 1.0 ;\n        if( debugFloatA <= vChangeColor[i] ){\n            if(  vChangeColor[i] <= debugFloatB ){\n                gl_FragColor = vec4(1.0-vCameraColor.r,  1.0-vCameraColor.g,1.0- vCameraColor.b, 1.0);\n            }\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/res/raw/base_vertex_shader.glsl",
    "content": "attribute vec4 aPosition;\nuniform mat4 uTextureMatrix;\nattribute vec4 aTextureCoordinate;\nvarying vec2 vTextureCoord;\nvoid main()\n{\n  vTextureCoord = (uTextureMatrix * aTextureCoordinate).xy;\n  gl_Position = aPosition;\n}"
  },
  {
    "path": "app/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"colorPrimary\">#3F51B5</color>\n    <color name=\"colorPrimaryDark\">#303F9F</color>\n    <color name=\"colorAccent\">#FF4081</color>\n\n    <color name=\"theme\">#FF03A9F4</color>\n    <color name=\"theme_pressed\">#44a7d4</color>\n\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">SunCamera</string>\n    <string name=\"start_server\">启动服务器</string>\n    <string name=\"stop_server\">停止服务器</string>\n    <string name=\"start_browse\">在浏览器中打开</string>\n\n    <string name=\"server_stop_succeed\">服务器停止了</string>\n    <string name=\"server_ip_error\">没有获取到服务器IP地址</string>\n\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/styles.xml",
    "content": "<resources>\n\n    <!-- Base application theme. -->\n    <style name=\"AppTheme\" parent=\"Theme.AppCompat.Light.DarkActionBar\">\n        <!-- Customize your theme here. -->\n        <item name=\"colorPrimary\">@color/colorPrimary</item>\n        <item name=\"colorPrimaryDark\">@color/colorPrimaryDark</item>\n        <item name=\"colorAccent\">@color/colorAccent</item>\n    </style>\n\n</resources>\n"
  },
  {
    "path": "app/src/main/res/xml/file_paths.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <paths>\n        <root-path path=\"\" name=\"camera_photos\" />\n        <external-path name=\"external_files\" path=\".\"/>\n    </paths>\n</resources>"
  },
  {
    "path": "app/src/test/java/camera/cn/cameramaster/ExampleUnitTest.java",
    "content": "package camera.cn.cameramaster;\n\nimport org.junit.Test;\n\nimport static org.junit.Assert.*;\n\n/**\n * Example local unit test, which will execute on the development machine (host).\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\n */\npublic class ExampleUnitTest {\n    @Test\n    public void addition_isCorrect() throws Exception {\n        assertEquals(4, 2 + 2);\n    }\n}"
  },
  {
    "path": "build.gradle",
    "content": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\n\nbuildscript {\n\n    repositories {\n        google()\n        jcenter()\n    }\n    dependencies {\n        classpath 'com.android.tools.build:gradle:4.0.2'\n//        classpath 'com.jakewharton:butterknife-gradle-plugin:8.4.0'\n\n        // NOTE: Do not place your application dependencies here; they belong\n        // in the individual module build.gradle files\n    }\n}\n\nallprojects {\n    repositories {\n        google()\n        jcenter()\n        maven { url \"https://jitpack.io\" }\n        maven { url 'https://maven.google.com' }\n    }\n}\n\ntask clean(type: Delete) {\n    delete rootProject.buildDir\n}\n"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "content": "#Wed Dec 09 09:54:58 CST 2020\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-6.1.1-all.zip\n"
  },
  {
    "path": "gradle.properties",
    "content": "# Project-wide Gradle settings.\n\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will override*\n# any settings specified in this file.\n\n# For more details on how to configure your build environment visit\n# http://www.gradle.org/docs/current/userguide/build_environment.html\n\n# Specifies the JVM arguments used for the daemon process.\n# The setting is particularly useful for tweaking memory settings.\norg.gradle.jvmargs=-Xmx1536m\n\n# When configured, Gradle will run in incubating parallel mode.\n# This option should only be used with decoupled projects. More details, visit\n# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects\n# org.gradle.parallel=true\nandroid.enableAapt2=true\nandroid.useAndroidX=true"
  },
  {
    "path": "gradlew",
    "content": "#!/usr/bin/env bash\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS=\"\"\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn ( ) {\n    echo \"$*\"\n}\n\ndie ( ) {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\nesac\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >/dev/null\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n        JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=\"java\"\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n    JAVACMD=`cygpath --unix \"$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=$((i+1))\n    done\n    case $i in\n        (0) set -- ;;\n        (1) set -- \"$args0\" ;;\n        (2) set -- \"$args0\" \"$args1\" ;;\n        (3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        (4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        (5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        (6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        (7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        (8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        (9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules\nfunction splitJvmOpts() {\n    JVM_OPTS=(\"$@\")\n}\neval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS\nJVM_OPTS[${#JVM_OPTS[*]}]=\"-Dorg.gradle.appname=$APP_BASE_NAME\"\n\nexec \"$JAVACMD\" \"${JVM_OPTS[@]}\" -classpath \"$CLASSPATH\" org.gradle.wrapper.GradleWrapperMain \"$@\"\n"
  },
  {
    "path": "gradlew.bat",
    "content": "@if \"%DEBUG%\" == \"\" @echo off\n@rem ##########################################################################\n@rem\n@rem  Gradle startup script for Windows\n@rem\n@rem ##########################################################################\n\n@rem Set local scope for the variables with windows NT shell\nif \"%OS%\"==\"Windows_NT\" setlocal\n\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nset DEFAULT_JVM_OPTS=\n\nset DIRNAME=%~dp0\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\nset APP_BASE_NAME=%~n0\nset APP_HOME=%DIRNAME%\n\n@rem Find java.exe\nif defined JAVA_HOME goto findJavaFromJavaHome\n\nset JAVA_EXE=java.exe\n%JAVA_EXE% -version >NUL 2>&1\nif \"%ERRORLEVEL%\" == \"0\" goto init\n\necho.\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:findJavaFromJavaHome\nset JAVA_HOME=%JAVA_HOME:\"=%\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\n\nif exist \"%JAVA_EXE%\" goto init\n\necho.\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:init\n@rem Get command-line arguments, handling Windowz variants\n\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\nif \"%@eval[2+2]\" == \"4\" goto 4NT_args\n\n:win9xME_args\n@rem Slurp the command line arguments.\nset CMD_LINE_ARGS=\nset _SKIP=2\n\n:win9xME_args_slurp\nif \"x%~1\" == \"x\" goto execute\n\nset CMD_LINE_ARGS=%*\ngoto execute\n\n:4NT_args\n@rem Get arguments from the 4NT Shell from JP Software\nset CMD_LINE_ARGS=%$\n\n:execute\n@rem Setup the command line\n\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\n\n@rem Execute Gradle\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\n\n:end\n@rem End local scope for the variables with windows NT shell\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\n\n:fail\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\nrem the _cmd.exe /c_ return code!\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\nexit /b 1\n\n:mainEnd\nif \"%OS%\"==\"Windows_NT\" endlocal\n\n:omega\n"
  },
  {
    "path": "settings.gradle",
    "content": "include ':app'\n"
  }
]