├── .gitignore ├── .idea ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── encodings.xml ├── gradle.xml ├── inspectionProfiles │ ├── Project_Default.xml │ └── profiles_settings.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── LICENSE ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── cjt2325 │ │ └── cameraview │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── cjt2325 │ │ │ └── cameraview │ │ │ └── MainActivity.java │ └── res │ │ ├── drawable │ │ ├── ic_camera_enhance_black_24dp.xml │ │ └── ic_repeat_black_24dp.xml │ │ ├── layout │ │ └── activity_main.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── cjt2325 │ └── cameraview │ └── ExampleUnitTest.java ├── assets ├── 65A0.tmp.jpg ├── QRcode.png ├── screenshot_0.jpg ├── screenshot_1.jpg ├── screenshot_2.jpg └── video.gif ├── build.gradle ├── camera ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── cjt2325 │ │ └── cameralibrary │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── cjt2325 │ │ │ └── cameralibrary │ │ │ ├── CameraInterface.java │ │ │ ├── CaptureButton.java │ │ │ ├── CaptureLayout.java │ │ │ ├── FoucsView.java │ │ │ ├── JCameraView.java │ │ │ ├── ReturnButton.java │ │ │ ├── TypeButton.java │ │ │ ├── listener │ │ │ ├── CaptureListener.java │ │ │ ├── ClickListener.java │ │ │ ├── ErrorListener.java │ │ │ ├── JCameraListener.java │ │ │ ├── ResultListener.java │ │ │ ├── ReturnListener.java │ │ │ └── TypeListener.java │ │ │ ├── state │ │ │ ├── BorrowPictureState.java │ │ │ ├── BorrowVideoState.java │ │ │ ├── CameraMachine.java │ │ │ ├── PreviewState.java │ │ │ └── State.java │ │ │ ├── util │ │ │ ├── AngleUtil.java │ │ │ ├── AudioUtil.java │ │ │ ├── CameraParamUtil.java │ │ │ ├── CheckPermission.java │ │ │ ├── DeviceUtil.java │ │ │ ├── FileUtil.java │ │ │ ├── LogUtil.java │ │ │ └── ScreenUtils.java │ │ │ └── view │ │ │ └── CameraView.java │ └── res │ │ ├── drawable │ │ ├── ic_camera.xml │ │ ├── ic_flash_auto.xml │ │ ├── ic_flash_off.xml │ │ ├── ic_flash_on.xml │ │ └── ic_photo.xml │ │ ├── layout │ │ └── camera_view.xml │ │ └── values │ │ ├── attrs.xml │ │ └── strings.xml │ └── test │ └── java │ └── com │ └── cjt2325 │ └── cameralibrary │ └── ExampleUnitTest.java ├── cameraapplication ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── zxing │ │ └── cameraapplication │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── zxing │ │ │ └── cameraapplication │ │ │ ├── CameraActivity.java │ │ │ ├── CameraApplication.java │ │ │ └── MainActivity.java │ └── res │ │ ├── drawable │ │ ├── ic_back.xml │ │ ├── ic_camera_enhance_black_24dp.xml │ │ ├── ic_capture.xml │ │ └── ic_photo.xml │ │ ├── layout │ │ ├── activity_camera.xml │ │ └── activity_main.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── zxing │ └── cameraapplication │ └── ExampleUnitTest.java ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── kotlin-jcameraview ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── cjt2325 │ │ └── kotlin_jcameraview │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── cjt2325 │ │ │ └── kotlin_jcameraview │ │ │ ├── AutoFitTextureView.kt │ │ │ ├── CameraNewInterface.kt │ │ │ ├── CaptureButton.kt │ │ │ ├── CaptureLayout.kt │ │ │ ├── JCameraView.kt │ │ │ ├── QuitButton.kt │ │ │ ├── TypeButton.kt │ │ │ ├── listener │ │ │ ├── CaptureListener.kt │ │ │ ├── JCameraListener.kt │ │ │ ├── QuitListener.kt │ │ │ └── TypeListener.kt │ │ │ └── util │ │ │ ├── CompareSizesByArea.kt │ │ │ ├── ImageSaver.kt │ │ │ ├── JLog.kt │ │ │ └── ScreenUtil.kt │ └── res │ │ ├── drawable │ │ ├── ic_brightness.xml │ │ └── ic_camera.xml │ │ └── values │ │ └── strings.xml │ └── test │ └── java │ └── com │ └── cjt2325 │ └── kotlin_jcameraview │ └── ExampleUnitTest.java ├── lib └── src │ └── main │ └── java │ └── com │ └── cameraview │ ├── AudioUtil.java │ ├── CaptureButtom.java │ ├── FileUtil.java │ ├── ImageUtil.java │ └── JCameraView.java └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 20 | 21 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 11 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 46 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # JCameraView(1.1.9)   2 | ## 使用方法 3 | - Gradle依赖: compile 'cjt.library.wheel:camera :1.1.9' 4 | - 引用源码 :  clone源码后 引入lib -> camera 5 | - 尝试运行 :  导入源码 运行cameraapplication这个model(!!!) 6 | - 扫描二维码:  apk比较旧 7 | 8 | [![Download](https://api.bintray.com/packages/cjt/maven/cameraView/images/download.svg)](https://bintray.com//cjt/maven/cameraView/_latestVersion) [![API 14+](https://img.shields.io/badge/API-14%2B-green.svg)](https://github.com/CJT2325/CameraView) 9 | 10 | 这是一个模仿微信拍照的Android开源控件 11 | 12 | - 点击拍照 13 | 14 | - 10s的视频大概1.9M左右 15 | 16 | - 长按录视频(视频长度可设置) 17 | 18 | - 长按录视频的时候,手指上滑可以放大视频 19 | 20 | - 录制完视频可以浏览并且重复播放 21 | 22 | - 前后摄像头的切换 23 | 24 | - 可以设置小视频保存路径 25 | 26 | ## 示例截图 27 | 28 | ![image](https://github.com/CJT2325/CameraView/blob/master/assets/screenshot_0.jpg) 29 | ![image](https://github.com/CJT2325/CameraView/blob/master/assets/screenshot_1.jpg) 30 | ![image](https://github.com/CJT2325/CameraView/blob/master/assets/screenshot_2.jpg) 31 | 32 | ## GIF图 33 | 34 | ![image](https://github.com/CJT2325/CameraView/blob/master/assets/video.gif) 35 | 36 | ## 使用步骤(Android Studio) 37 | 38 | **添加下列代码到 module gradle** 39 | 40 | > 最新版本(1.1.9)更新内容: 41 | ```gradle 42 | compile 'cjt.library.wheel:camera:1.1.9' 43 | //添加闪关灯,自定义左右按钮图标资源 44 | ``` 45 | **如果获取依赖失败则添加下列代码到 project gradle** 46 | ```gradle 47 | allprojects { 48 |    repositories { 49 | jcenter() 50 | maven { 51 | url 'https://dl.bintray.com/cjt/maven' 52 | } 53 | } 54 | } 55 | ``` 56 | 57 | ### 旧版本 58 | ```gradle 59 | compile 'cjt.library.wheel:camera:1.1.6' 60 | //修复BUG 61 | ``` 62 | 63 | ```gradle 64 | compile 'cjt.library.wheel:camera:1.1.3' 65 | //fix bug 66 | ``` 67 | 68 | ```gradle 69 | compile 'cjt.library.wheel:camera:1.1.1' 70 | //fix bug 71 | 72 | compile 'cjt.library.wheel:camera:1.0.9' 73 | //fix bug 74 | 75 | compile 'cjt.library.wheel:camera:1.0.5' 76 | //浏览界面能使用两根手指进行缩放 77 | //切换摄像头的按钮会根据手持手机方向进行旋转 78 | //修复内存泄露 79 | 80 | compile 'cjt.library.wheel:camera:1.0.4' 81 | //换回VideoView 82 | //摄像上滑放大 83 | 84 | compile 'cjt.library.wheel:camera:1.0.2' 85 | //TextureView替换VideoView 86 | //根据手机拍照方向旋转图片(仅后置摄像头) 87 | 88 | compile 'cjt.library.wheel:camera:1.0.0' 89 | //代码重构 90 | //修复频繁切换摄像头崩溃的问题 91 | //修复获取不到supportedVideoSizes的问题 92 | //可以设置最长录像时间 93 | //修复按钮错乱BUG 94 | 95 | compile 'cjt.library.wheel:camera:0.1.9' //修复BUG 96 | 97 | compile 'cjt.library.wheel:camera:0.1.7' //修复无法获取最佳分辨率导致的StackOverFlowError 98 | 99 | compile 'cjt.library.wheel:camera:0.1.6' //修复部分机型切换前置摄像头崩溃问题和添加动态权限申请 100 | 101 | compile 'cjt.library.wheel:camera:0.1.2' //修复部分机型不支持缩放导致崩溃 102 | 103 | compile 'cjt.library.wheel:camera:0.1.1' //修复切换前置摄像头崩溃BUG 104 | 105 | compile 'cjt.library.wheel:camera:0.1.0' //修复BUG 106 | 107 | compile 'cjt.library.wheel:camera:0.0.9' //添加保持屏幕常亮唤醒状态 108 | //需新增权限 109 | 110 | compile 'cjt.library.wheel:camera:0.0.8' //添加手动对焦,对焦提示器,修复切换到前置摄像头崩溃的BUG 111 | 112 | compile 'cjt.library.wheel:camera:0.0.7' //修复了长按录视频崩溃的BUG和兼容到Android4.0 113 | 114 | compile 'cjt.library.wheel:camera:0.0.3' 115 | ``` 116 | ## 布局文件中添加 117 | ```xml 118 | //1.0.0+ 119 | 127 | ``` 128 | ### (1.0.0+) 129 | 属性 | 属性说明 130 | ---|--- 131 | iconSize | 右上角切换摄像头按钮的大小 132 | iconMargin | 右上角切换摄像头按钮到上、右边距 133 | iconSrc | 右上角切换摄像头按钮图片 134 | iconLeft | 左边按钮图片资源(1.1.9+) 135 | iconRight | 右边按钮图片资源(1.1.9+) 136 | duration_max | 设置最长录像时间(毫秒) 137 | 138 | ### AndroidManifest.xml中添加权限 139 | ```xml 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | ``` 148 | ### Activity全屏设置 149 | ```java 150 | if (Build.VERSION.SDK_INT >= 19) { 151 | View decorView = getWindow().getDecorView(); 152 | decorView.setSystemUiVisibility( 153 | View.SYSTEM_UI_FLAG_LAYOUT_STABLE 154 | | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 155 | | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN 156 | | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION 157 | | View.SYSTEM_UI_FLAG_FULLSCREEN 158 | | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); 159 | } else { 160 | View decorView = getWindow().getDecorView(); 161 | int option = View.SYSTEM_UI_FLAG_FULLSCREEN; 162 | decorView.setSystemUiVisibility(option); 163 | } 164 | ``` 165 | ### 初始化JCameraView控件 166 | ```java 167 | //1.1.1 168 | jCameraView = (JCameraView) findViewById(R.id.jcameraview); 169 | 170 | //设置视频保存路径 171 | jCameraView.setSaveVideoPath(Environment.getExternalStorageDirectory().getPath() + File.separator + "JCamera"); 172 | 173 | //设置只能录像或只能拍照或两种都可以(默认两种都可以) 174 | jCameraView.setFeatures(JCameraView.BUTTON_STATE_BOTH); 175 | 176 | //设置视频质量 177 | jCameraView.setMediaQuality(JCameraView.MEDIA_QUALITY_MIDDLE); 178 | 179 | //JCameraView监听 180 | jCameraView.setErrorLisenter(new ErrorLisenter() { 181 | @Override 182 | public void onError() { 183 |          //打开Camera失败回调 184 |          Log.i("CJT", "open camera error"); 185 | } 186 | @Override 187 | public void AudioPermissionError() { 188 |          //没有录取权限回调 189 |          Log.i("CJT", "AudioPermissionError"); 190 | } 191 | }); 192 | 193 | jCameraView.setJCameraLisenter(new JCameraLisenter() { 194 | @Override 195 | public void captureSuccess(Bitmap bitmap) { 196 |     //获取图片bitmap 197 | Log.i("JCameraView", "bitmap = " + bitmap.getWidth()); 198 | } 199 | @Override 200 | public void recordSuccess(String url,Bitmap firstFrame) { 201 | //获取视频路径 202 | Log.i("CJT", "url = " + url); 203 | } 204 | //@Override 205 | //public void quit() { 206 |    //   (1.1.9+后用左边按钮的点击事件替换) 207 |    //} 208 | }); 209 | //左边按钮点击事件 210 | jCameraView.setLeftClickListener(new ClickListener() { 211 | @Override 212 | public void onClick() { 213 | CameraActivity.this.finish(); 214 | } 215 | }); 216 | //右边按钮点击事件 217 | jCameraView.setRightClickListener(new ClickListener() { 218 | @Override 219 | Toast.makeText(CameraActivity.this,"Right",Toast.LENGTH_SHORT).show(); 220 | } 221 | }); 222 | ``` 223 | ### JCameraView生命周期 224 | ```java 225 | @Override 226 | protected void onResume() { 227 | super.onResume(); 228 | mJCameraView.onResume(); 229 | } 230 | @Override 231 | protected void onPause() { 232 | super.onPause(); 233 | mJCameraView.onPause(); 234 | } 235 | ``` 236 | 237 | ### APK Demo 238 | 扫码下载 239 | 240 | ![image](https://github.com/CJT2325/CameraView/blob/master/assets/QRcode.png) 241 | 242 | 二维码显示不出请点击 [下载Demo](http://fir.im/8xnw) 243 | 244 | 245 | 246 | ### LICENSE 247 | Copyright 2017 CJT2325 248 | 249 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at 250 | 251 | http://www.apache.org/licenses/LICENSE-2.0 252 | 253 | Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. 254 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 25 5 | buildToolsVersion "25.0.1" 6 | 7 | defaultConfig { 8 | applicationId "com.cjt2325.cameraview" 9 | minSdkVersion 14 10 | targetSdkVersion 25 11 | versionCode 2 12 | versionName "1.2" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(include: ['*.jar'], dir: 'libs') 24 | testCompile 'junit:junit:4.12' 25 | compile 'com.android.support:appcompat-v7:25.3.0' 26 | // compile 'cjt.library.wheel:camera:1.0.2' 27 | compile project(':camera') 28 | } 29 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in D:\AndroidStudio\AndroidSDK/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/cjt2325/cameraview/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.cjt2325.cameraview; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /app/src/main/java/com/cjt2325/cameraview/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.cjt2325.cameraview; 2 | 3 | import android.Manifest; 4 | import android.annotation.TargetApi; 5 | import android.content.pm.PackageManager; 6 | import android.graphics.Bitmap; 7 | import android.os.Build; 8 | import android.os.Bundle; 9 | import android.os.Environment; 10 | import android.support.v4.app.ActivityCompat; 11 | import android.support.v4.content.ContextCompat; 12 | import android.support.v7.app.AppCompatActivity; 13 | import android.util.Log; 14 | import android.view.View; 15 | import android.widget.Toast; 16 | 17 | import com.cjt2325.cameralibrary.JCameraView; 18 | import com.cjt2325.cameralibrary.lisenter.JCameraLisenter; 19 | 20 | import java.io.File; 21 | 22 | public class MainActivity extends AppCompatActivity { 23 | private final int GET_PERMISSION_REQUEST = 100; //权限申请自定义码 24 | private JCameraView jCameraView; 25 | private boolean granted = false; 26 | 27 | @Override 28 | protected void onCreate(Bundle savedInstanceState) { 29 | super.onCreate(savedInstanceState); 30 | setContentView(R.layout.activity_main); 31 | 32 | jCameraView = (JCameraView) findViewById(R.id.jcameraview); 33 | 34 | //设置视频保存路径 35 | jCameraView.setSaveVideoPath(Environment.getExternalStorageDirectory().getPath() + File.separator + "JCamera"); 36 | 37 | //JCameraView监听 38 | jCameraView.setJCameraLisenter(new JCameraLisenter() { 39 | @Override 40 | public void captureSuccess(Bitmap bitmap) { 41 | //获取图片bitmap 42 | Log.i("JCameraView", "bitmap = " + bitmap.getWidth()); 43 | } 44 | 45 | @Override 46 | public void recordSuccess(String url, Bitmap firstFrame) { 47 | 48 | } 49 | 50 | 51 | @Override 52 | public void quit() { 53 | //退出按钮 54 | MainActivity.this.finish(); 55 | } 56 | }); 57 | //6.0动态权限获取 58 | getPermissions(); 59 | } 60 | 61 | @Override 62 | protected void onStart() { 63 | super.onStart(); 64 | //全屏显示 65 | if (Build.VERSION.SDK_INT >= 19) { 66 | View decorView = getWindow().getDecorView(); 67 | decorView.setSystemUiVisibility( 68 | View.SYSTEM_UI_FLAG_LAYOUT_STABLE 69 | | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 70 | | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN 71 | | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION 72 | | View.SYSTEM_UI_FLAG_FULLSCREEN 73 | | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); 74 | } else { 75 | View decorView = getWindow().getDecorView(); 76 | int option = View.SYSTEM_UI_FLAG_FULLSCREEN; 77 | decorView.setSystemUiVisibility(option); 78 | } 79 | } 80 | 81 | @Override 82 | protected void onResume() { 83 | super.onResume(); 84 | if (granted) { 85 | jCameraView.onResume(); 86 | } 87 | } 88 | 89 | @Override 90 | protected void onPause() { 91 | super.onPause(); 92 | jCameraView.onPause(); 93 | } 94 | 95 | /** 96 | * 获取权限 97 | */ 98 | private void getPermissions() { 99 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 100 | if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED && 101 | ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED && 102 | ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) { 103 | //具有权限 104 | granted = true; 105 | } else { 106 | //不具有获取权限,需要进行权限申请 107 | ActivityCompat.requestPermissions(MainActivity.this, new String[]{ 108 | Manifest.permission.WRITE_EXTERNAL_STORAGE, 109 | Manifest.permission.RECORD_AUDIO, 110 | Manifest.permission.CAMERA}, GET_PERMISSION_REQUEST); 111 | granted = false; 112 | } 113 | } 114 | } 115 | 116 | @TargetApi(23) 117 | @Override 118 | public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { 119 | super.onRequestPermissionsResult(requestCode, permissions, grantResults); 120 | if (requestCode == GET_PERMISSION_REQUEST) { 121 | int size = 0; 122 | if (grantResults.length >= 1) { 123 | int writeResult = grantResults[0]; 124 | //读写内存权限 125 | boolean writeGranted = writeResult == PackageManager.PERMISSION_GRANTED;//读写内存权限 126 | if (!writeGranted) { 127 | size++; 128 | } 129 | //录音权限 130 | int recordPermissionResult = grantResults[1]; 131 | boolean recordPermissionGranted = recordPermissionResult == PackageManager.PERMISSION_GRANTED; 132 | if (!recordPermissionGranted) { 133 | size++; 134 | } 135 | //相机权限 136 | int cameraPermissionResult = grantResults[2]; 137 | boolean cameraPermissionGranted = cameraPermissionResult == PackageManager.PERMISSION_GRANTED; 138 | if (!cameraPermissionGranted) { 139 | size++; 140 | } 141 | if (size == 0) { 142 | granted = true; 143 | jCameraView.onResume(); 144 | }else{ 145 | Toast.makeText(this, "请到设置-权限管理中开启", Toast.LENGTH_SHORT).show(); 146 | finish(); 147 | } 148 | } 149 | } 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_camera_enhance_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_repeat_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CJT2325/CameraView/c9d291102a2e1a883d8dd4f657977bd94dd750b2/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CJT2325/CameraView/c9d291102a2e1a883d8dd4f657977bd94dd750b2/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CJT2325/CameraView/c9d291102a2e1a883d8dd4f657977bd94dd750b2/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CJT2325/CameraView/c9d291102a2e1a883d8dd4f657977bd94dd750b2/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CJT2325/CameraView/c9d291102a2e1a883d8dd4f657977bd94dd750b2/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | CameraView 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/test/java/com/cjt2325/cameraview/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.cjt2325.cameraview; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * To work on unit tests, switch the Test Artifact in the Build Variants view. 9 | */ 10 | public class ExampleUnitTest { 11 | @Test 12 | public void addition_isCorrect() throws Exception { 13 | assertEquals(4, 2 + 2); 14 | } 15 | } -------------------------------------------------------------------------------- /assets/65A0.tmp.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CJT2325/CameraView/c9d291102a2e1a883d8dd4f657977bd94dd750b2/assets/65A0.tmp.jpg -------------------------------------------------------------------------------- /assets/QRcode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CJT2325/CameraView/c9d291102a2e1a883d8dd4f657977bd94dd750b2/assets/QRcode.png -------------------------------------------------------------------------------- /assets/screenshot_0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CJT2325/CameraView/c9d291102a2e1a883d8dd4f657977bd94dd750b2/assets/screenshot_0.jpg -------------------------------------------------------------------------------- /assets/screenshot_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CJT2325/CameraView/c9d291102a2e1a883d8dd4f657977bd94dd750b2/assets/screenshot_1.jpg -------------------------------------------------------------------------------- /assets/screenshot_2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CJT2325/CameraView/c9d291102a2e1a883d8dd4f657977bd94dd750b2/assets/screenshot_2.jpg -------------------------------------------------------------------------------- /assets/video.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CJT2325/CameraView/c9d291102a2e1a883d8dd4f657977bd94dd750b2/assets/video.gif -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:2.2.3' 9 | classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.6' 10 | classpath 'com.github.dcendents:android-maven-gradle-plugin:1.4.1' 11 | } 12 | } 13 | 14 | allprojects { 15 | repositories { 16 | jcenter() 17 | } 18 | } 19 | 20 | task clean(type: Delete) { 21 | delete rootProject.buildDir 22 | } 23 | -------------------------------------------------------------------------------- /camera/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /camera/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'com.github.dcendents.android-maven' 3 | apply plugin: 'com.jfrog.bintray' 4 | 5 | version = "1.1.8" 6 | 7 | android { 8 | compileSdkVersion 25 9 | buildToolsVersion "25.0.1" 10 | 11 | defaultConfig { 12 | minSdkVersion 14 13 | targetSdkVersion 25 14 | versionCode 1 15 | versionName "1.0" 16 | } 17 | buildTypes { 18 | release { 19 | minifyEnabled false 20 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 21 | } 22 | } 23 | lintOptions { 24 | abortOnError false 25 | } 26 | } 27 | 28 | dependencies { 29 | compile fileTree(include: ['*.jar'], dir: 'libs') 30 | testCompile 'junit:junit:4.12' 31 | compile('com.android.support:appcompat-v7:25.3.0') { exclude module: 'support-v4' } 32 | } 33 | def siteUrl = 'https://github.com/CJT2325/CameraView' // 项目的主页 34 | def gitUrl = 'https://github.com/CJT2325/CameraView.git' // Git仓库的url 35 | group = "cjt.library.wheel" // Maven Group ID for the artifact, 36 | install { 37 | repositories.mavenInstaller { 38 | // This generates POM.xml with proper parameters 39 | pom { 40 | project { 41 | packaging 'aar' 42 | // Add your description here 43 | name 'A simple camera view' //项目的描述 你可以多写一点 44 | url siteUrl 45 | // Set your license 46 | licenses { 47 | license { 48 | name 'The Apache Software License, Version 2.0' 49 | url 'http://www.apache.org/licenses/LICENSE-2.0.txt' 50 | } 51 | } 52 | developers { 53 | developer { 54 | id 'cjt' //填写的一些基本信息 55 | name 'JiaTong Chen' 56 | email '445263848@qq.com' 57 | } 58 | } 59 | scm { 60 | connection gitUrl 61 | developerConnection gitUrl 62 | url siteUrl 63 | } 64 | } 65 | } 66 | } 67 | } 68 | task sourcesJar(type: Jar) { 69 | from android.sourceSets.main.java.srcDirs 70 | classifier = 'sources' 71 | } 72 | task javadoc(type: Javadoc) { 73 | options.encoding = "UTF-8" 74 | source = android.sourceSets.main.java.srcDirs 75 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) 76 | } 77 | task javadocJar(type: Jar, dependsOn: javadoc) { 78 | classifier = 'javadoc' 79 | from javadoc.destinationDir 80 | } 81 | artifacts { 82 | archives javadocJar 83 | archives sourcesJar 84 | } 85 | 86 | File localProps = project.rootProject.file('local.properties') 87 | 88 | if (localProps.exists()) { 89 | Properties properties = new Properties() 90 | properties.load(localProps.newDataInputStream()) 91 | 92 | bintray { 93 | user = properties.getProperty("bintray.user") 94 | key = properties.getProperty("bintray.apikey") 95 | configurations = ['archives'] 96 | pkg { 97 | repo = "maven" 98 | name = "cameraView" 99 | websiteUrl = siteUrl 100 | vcsUrl = gitUrl 101 | licenses = ["Apache-2.0"] 102 | publish = true 103 | } 104 | } 105 | } 106 | 107 | -------------------------------------------------------------------------------- /camera/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in D:\AndroidStudio\AndroidSDK/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /camera/src/androidTest/java/com/cjt2325/cameralibrary/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.cjt2325.cameralibrary; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /camera/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /camera/src/main/java/com/cjt2325/cameralibrary/CaptureButton.java: -------------------------------------------------------------------------------- 1 | package com.cjt2325.cameralibrary; 2 | 3 | import android.animation.Animator; 4 | import android.animation.AnimatorListenerAdapter; 5 | import android.animation.AnimatorSet; 6 | import android.animation.ValueAnimator; 7 | import android.content.Context; 8 | import android.graphics.Canvas; 9 | import android.graphics.Paint; 10 | import android.graphics.RectF; 11 | import android.os.CountDownTimer; 12 | import android.view.MotionEvent; 13 | import android.view.View; 14 | 15 | import com.cjt2325.cameralibrary.listener.CaptureListener; 16 | import com.cjt2325.cameralibrary.util.CheckPermission; 17 | import com.cjt2325.cameralibrary.util.LogUtil; 18 | 19 | import static com.cjt2325.cameralibrary.JCameraView.BUTTON_STATE_BOTH; 20 | import static com.cjt2325.cameralibrary.JCameraView.BUTTON_STATE_ONLY_CAPTURE; 21 | import static com.cjt2325.cameralibrary.JCameraView.BUTTON_STATE_ONLY_RECORDER; 22 | 23 | 24 | /** 25 | * ===================================== 26 | * 作 者: 陈嘉桐 445263848@qq.com 27 | * 版 本:1.1.4 28 | * 创建日期:2017/4/25 29 | * 描 述:拍照按钮 30 | * ===================================== 31 | */ 32 | public class CaptureButton extends View { 33 | 34 | private int state; //当前按钮状态 35 | private int button_state; //按钮可执行的功能状态(拍照,录制,两者) 36 | 37 | public static final int STATE_IDLE = 0x001; //空闲状态 38 | public static final int STATE_PRESS = 0x002; //按下状态 39 | public static final int STATE_LONG_PRESS = 0x003; //长按状态 40 | public static final int STATE_RECORDERING = 0x004; //录制状态 41 | public static final int STATE_BAN = 0x005; //禁止状态 42 | 43 | private int progress_color = 0xEE16AE16; //进度条颜色 44 | private int outside_color = 0xEEDCDCDC; //外圆背景色 45 | private int inside_color = 0xFFFFFFFF; //内圆背景色 46 | 47 | 48 | private float event_Y; //Touch_Event_Down时候记录的Y值 49 | 50 | 51 | private Paint mPaint; 52 | 53 | private float strokeWidth; //进度条宽度 54 | private int outside_add_size; //长按外圆半径变大的Size 55 | private int inside_reduce_size; //长安内圆缩小的Size 56 | 57 | //中心坐标 58 | private float center_X; 59 | private float center_Y; 60 | 61 | private float button_radius; //按钮半径 62 | private float button_outside_radius; //外圆半径 63 | private float button_inside_radius; //内圆半径 64 | private int button_size; //按钮大小 65 | 66 | private float progress; //录制视频的进度 67 | private int duration; //录制视频最大时间长度 68 | private int min_duration; //最短录制时间限制 69 | private int recorded_time; //记录当前录制的时间 70 | 71 | private RectF rectF; 72 | 73 | private LongPressRunnable longPressRunnable; //长按后处理的逻辑Runnable 74 | private CaptureListener captureLisenter; //按钮回调接口 75 | private RecordCountDownTimer timer; //计时器 76 | 77 | public CaptureButton(Context context) { 78 | super(context); 79 | } 80 | 81 | public CaptureButton(Context context, int size) { 82 | super(context); 83 | this.button_size = size; 84 | button_radius = size / 2.0f; 85 | 86 | button_outside_radius = button_radius; 87 | button_inside_radius = button_radius * 0.75f; 88 | 89 | strokeWidth = size / 15; 90 | outside_add_size = size / 5; 91 | inside_reduce_size = size / 8; 92 | 93 | mPaint = new Paint(); 94 | mPaint.setAntiAlias(true); 95 | 96 | progress = 0; 97 | longPressRunnable = new LongPressRunnable(); 98 | 99 | state = STATE_IDLE; //初始化为空闲状态 100 | button_state = BUTTON_STATE_BOTH; //初始化按钮为可录制可拍照 101 | LogUtil.i("CaptureButtom start"); 102 | duration = 10 * 1000; //默认最长录制时间为10s 103 | LogUtil.i("CaptureButtom end"); 104 | min_duration = 1500; //默认最短录制时间为1.5s 105 | 106 | center_X = (button_size + outside_add_size * 2) / 2; 107 | center_Y = (button_size + outside_add_size * 2) / 2; 108 | 109 | rectF = new RectF( 110 | center_X - (button_radius + outside_add_size - strokeWidth / 2), 111 | center_Y - (button_radius + outside_add_size - strokeWidth / 2), 112 | center_X + (button_radius + outside_add_size - strokeWidth / 2), 113 | center_Y + (button_radius + outside_add_size - strokeWidth / 2)); 114 | 115 | timer = new RecordCountDownTimer(duration, duration / 360); //录制定时器 116 | } 117 | 118 | @Override 119 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 120 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 121 | setMeasuredDimension(button_size + outside_add_size * 2, button_size + outside_add_size * 2); 122 | } 123 | 124 | @Override 125 | protected void onDraw(Canvas canvas) { 126 | super.onDraw(canvas); 127 | mPaint.setStyle(Paint.Style.FILL); 128 | 129 | mPaint.setColor(outside_color); //外圆(半透明灰色) 130 | canvas.drawCircle(center_X, center_Y, button_outside_radius, mPaint); 131 | 132 | mPaint.setColor(inside_color); //内圆(白色) 133 | canvas.drawCircle(center_X, center_Y, button_inside_radius, mPaint); 134 | 135 | //如果状态为录制状态,则绘制录制进度条 136 | if (state == STATE_RECORDERING) { 137 | mPaint.setColor(progress_color); 138 | mPaint.setStyle(Paint.Style.STROKE); 139 | mPaint.setStrokeWidth(strokeWidth); 140 | canvas.drawArc(rectF, -90, progress, false, mPaint); 141 | } 142 | } 143 | 144 | 145 | @Override 146 | public boolean onTouchEvent(MotionEvent event) { 147 | switch (event.getAction()) { 148 | case MotionEvent.ACTION_DOWN: 149 | LogUtil.i("state = " + state); 150 | if (event.getPointerCount() > 1 || state != STATE_IDLE) 151 | break; 152 | event_Y = event.getY(); //记录Y值 153 | state = STATE_PRESS; //修改当前状态为点击按下 154 | 155 | //判断按钮状态是否为可录制状态 156 | if ((button_state == BUTTON_STATE_ONLY_RECORDER || button_state == BUTTON_STATE_BOTH)) 157 | postDelayed(longPressRunnable, 500); //同时延长500启动长按后处理的逻辑Runnable 158 | break; 159 | case MotionEvent.ACTION_MOVE: 160 | if (captureLisenter != null 161 | && state == STATE_RECORDERING 162 | && (button_state == BUTTON_STATE_ONLY_RECORDER || button_state == BUTTON_STATE_BOTH)) { 163 | //记录当前Y值与按下时候Y值的差值,调用缩放回调接口 164 | captureLisenter.recordZoom(event_Y - event.getY()); 165 | } 166 | break; 167 | case MotionEvent.ACTION_UP: 168 | //根据当前按钮的状态进行相应的处理 169 | handlerUnpressByState(); 170 | break; 171 | } 172 | return true; 173 | } 174 | 175 | //当手指松开按钮时候处理的逻辑 176 | private void handlerUnpressByState() { 177 | removeCallbacks(longPressRunnable); //移除长按逻辑的Runnable 178 | //根据当前状态处理 179 | switch (state) { 180 | //当前是点击按下 181 | case STATE_PRESS: 182 | if (captureLisenter != null && (button_state == BUTTON_STATE_ONLY_CAPTURE || button_state == 183 | BUTTON_STATE_BOTH)) { 184 | startCaptureAnimation(button_inside_radius); 185 | } else { 186 | state = STATE_IDLE; 187 | } 188 | break; 189 | //当前是长按状态 190 | case STATE_RECORDERING: 191 | timer.cancel(); //停止计时器 192 | recordEnd(); //录制结束 193 | break; 194 | } 195 | } 196 | 197 | //录制结束 198 | private void recordEnd() { 199 | if (captureLisenter != null) { 200 | if (recorded_time < min_duration) 201 | captureLisenter.recordShort(recorded_time);//回调录制时间过短 202 | else 203 | captureLisenter.recordEnd(recorded_time); //回调录制结束 204 | } 205 | resetRecordAnim(); //重制按钮状态 206 | } 207 | 208 | //重制状态 209 | private void resetRecordAnim() { 210 | state = STATE_BAN; 211 | progress = 0; //重制进度 212 | invalidate(); 213 | //还原按钮初始状态动画 214 | startRecordAnimation( 215 | button_outside_radius, 216 | button_radius, 217 | button_inside_radius, 218 | button_radius * 0.75f 219 | ); 220 | } 221 | 222 | //内圆动画 223 | private void startCaptureAnimation(float inside_start) { 224 | ValueAnimator inside_anim = ValueAnimator.ofFloat(inside_start, inside_start * 0.75f, inside_start); 225 | inside_anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 226 | @Override 227 | public void onAnimationUpdate(ValueAnimator animation) { 228 | button_inside_radius = (float) animation.getAnimatedValue(); 229 | invalidate(); 230 | } 231 | }); 232 | inside_anim.addListener(new AnimatorListenerAdapter() { 233 | @Override 234 | public void onAnimationEnd(Animator animation) { 235 | super.onAnimationEnd(animation); 236 | //回调拍照接口 237 | captureLisenter.takePictures(); 238 | state = STATE_BAN; 239 | } 240 | }); 241 | inside_anim.setDuration(100); 242 | inside_anim.start(); 243 | } 244 | 245 | //内外圆动画 246 | private void startRecordAnimation(float outside_start, float outside_end, float inside_start, float inside_end) { 247 | ValueAnimator outside_anim = ValueAnimator.ofFloat(outside_start, outside_end); 248 | ValueAnimator inside_anim = ValueAnimator.ofFloat(inside_start, inside_end); 249 | //外圆动画监听 250 | outside_anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 251 | @Override 252 | public void onAnimationUpdate(ValueAnimator animation) { 253 | button_outside_radius = (float) animation.getAnimatedValue(); 254 | invalidate(); 255 | } 256 | }); 257 | //内圆动画监听 258 | inside_anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 259 | @Override 260 | public void onAnimationUpdate(ValueAnimator animation) { 261 | button_inside_radius = (float) animation.getAnimatedValue(); 262 | invalidate(); 263 | } 264 | }); 265 | AnimatorSet set = new AnimatorSet(); 266 | //当动画结束后启动录像Runnable并且回调录像开始接口 267 | set.addListener(new AnimatorListenerAdapter() { 268 | @Override 269 | public void onAnimationEnd(Animator animation) { 270 | super.onAnimationEnd(animation); 271 | //设置为录制状态 272 | if (state == STATE_LONG_PRESS) { 273 | if (captureLisenter != null) 274 | captureLisenter.recordStart(); 275 | state = STATE_RECORDERING; 276 | timer.start(); 277 | } 278 | } 279 | }); 280 | set.playTogether(outside_anim, inside_anim); 281 | set.setDuration(100); 282 | set.start(); 283 | } 284 | 285 | 286 | //更新进度条 287 | private void updateProgress(long millisUntilFinished) { 288 | recorded_time = (int) (duration - millisUntilFinished); 289 | progress = 360f - millisUntilFinished / (float) duration * 360f; 290 | invalidate(); 291 | } 292 | 293 | //录制视频计时器 294 | private class RecordCountDownTimer extends CountDownTimer { 295 | RecordCountDownTimer(long millisInFuture, long countDownInterval) { 296 | super(millisInFuture, countDownInterval); 297 | } 298 | 299 | @Override 300 | public void onTick(long millisUntilFinished) { 301 | updateProgress(millisUntilFinished); 302 | } 303 | 304 | @Override 305 | public void onFinish() { 306 | updateProgress(0); 307 | recordEnd(); 308 | } 309 | } 310 | 311 | //长按线程 312 | private class LongPressRunnable implements Runnable { 313 | @Override 314 | public void run() { 315 | state = STATE_LONG_PRESS; //如果按下后经过500毫秒则会修改当前状态为长按状态 316 | //没有录制权限 317 | if (CheckPermission.getRecordState() != CheckPermission.STATE_SUCCESS) { 318 | state = STATE_IDLE; 319 | if (captureLisenter != null) { 320 | captureLisenter.recordError(); 321 | return; 322 | } 323 | } 324 | //启动按钮动画,外圆变大,内圆缩小 325 | startRecordAnimation( 326 | button_outside_radius, 327 | button_outside_radius + outside_add_size, 328 | button_inside_radius, 329 | button_inside_radius - inside_reduce_size 330 | ); 331 | } 332 | } 333 | 334 | /************************************************** 335 | * 对外提供的API * 336 | **************************************************/ 337 | 338 | //设置最长录制时间 339 | public void setDuration(int duration) { 340 | this.duration = duration; 341 | timer = new RecordCountDownTimer(duration, duration / 360); //录制定时器 342 | } 343 | 344 | //设置最短录制时间 345 | public void setMinDuration(int duration) { 346 | this.min_duration = duration; 347 | } 348 | 349 | //设置回调接口 350 | public void setCaptureLisenter(CaptureListener captureLisenter) { 351 | this.captureLisenter = captureLisenter; 352 | } 353 | 354 | //设置按钮功能(拍照和录像) 355 | public void setButtonFeatures(int state) { 356 | this.button_state = state; 357 | } 358 | 359 | //是否空闲状态 360 | public boolean isIdle() { 361 | return state == STATE_IDLE ? true : false; 362 | } 363 | 364 | //设置状态 365 | public void resetState() { 366 | state = STATE_IDLE; 367 | } 368 | } 369 | -------------------------------------------------------------------------------- /camera/src/main/java/com/cjt2325/cameralibrary/CaptureLayout.java: -------------------------------------------------------------------------------- 1 | package com.cjt2325.cameralibrary; 2 | 3 | import android.animation.Animator; 4 | import android.animation.AnimatorListenerAdapter; 5 | import android.animation.AnimatorSet; 6 | import android.animation.ObjectAnimator; 7 | import android.content.Context; 8 | import android.content.res.Configuration; 9 | import android.util.AttributeSet; 10 | import android.util.DisplayMetrics; 11 | import android.view.Gravity; 12 | import android.view.View; 13 | import android.view.WindowManager; 14 | import android.widget.FrameLayout; 15 | import android.widget.ImageView; 16 | import android.widget.TextView; 17 | 18 | import com.cjt2325.cameralibrary.listener.CaptureListener; 19 | import com.cjt2325.cameralibrary.listener.ClickListener; 20 | import com.cjt2325.cameralibrary.listener.ReturnListener; 21 | import com.cjt2325.cameralibrary.listener.TypeListener; 22 | 23 | 24 | /** 25 | * ===================================== 26 | * 作 者: 陈嘉桐 445263848@qq.com 27 | * 版 本:1.0.4 28 | * 创建日期:2017/4/26 29 | * 描 述:集成各个控件的布局 30 | * ===================================== 31 | */ 32 | 33 | public class CaptureLayout extends FrameLayout { 34 | 35 | private CaptureListener captureLisenter; //拍照按钮监听 36 | private TypeListener typeLisenter; //拍照或录制后接结果按钮监听 37 | private ReturnListener returnListener; //退出按钮监听 38 | private ClickListener leftClickListener; //左边按钮监听 39 | private ClickListener rightClickListener; //右边按钮监听 40 | 41 | public void setTypeLisenter(TypeListener typeLisenter) { 42 | this.typeLisenter = typeLisenter; 43 | } 44 | 45 | public void setCaptureLisenter(CaptureListener captureLisenter) { 46 | this.captureLisenter = captureLisenter; 47 | } 48 | 49 | public void setReturnLisenter(ReturnListener returnListener) { 50 | this.returnListener = returnListener; 51 | } 52 | 53 | private CaptureButton btn_capture; //拍照按钮 54 | private TypeButton btn_confirm; //确认按钮 55 | private TypeButton btn_cancel; //取消按钮 56 | private ReturnButton btn_return; //返回按钮 57 | private ImageView iv_custom_left; //左边自定义按钮 58 | private ImageView iv_custom_right; //右边自定义按钮 59 | private TextView txt_tip; //提示文本 60 | 61 | private int layout_width; 62 | private int layout_height; 63 | private int button_size; 64 | private int iconLeft = 0; 65 | private int iconRight = 0; 66 | 67 | private boolean isFirst = true; 68 | 69 | public CaptureLayout(Context context) { 70 | this(context, null); 71 | } 72 | 73 | public CaptureLayout(Context context, AttributeSet attrs) { 74 | this(context, attrs, 0); 75 | } 76 | 77 | public CaptureLayout(Context context, AttributeSet attrs, int defStyleAttr) { 78 | super(context, attrs, defStyleAttr); 79 | 80 | WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); 81 | DisplayMetrics outMetrics = new DisplayMetrics(); 82 | manager.getDefaultDisplay().getMetrics(outMetrics); 83 | 84 | if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { 85 | layout_width = outMetrics.widthPixels; 86 | } else { 87 | layout_width = outMetrics.widthPixels / 2; 88 | } 89 | button_size = (int) (layout_width / 4.5f); 90 | layout_height = button_size + (button_size / 5) * 2 + 100; 91 | 92 | initView(); 93 | initEvent(); 94 | } 95 | 96 | @Override 97 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 98 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 99 | setMeasuredDimension(layout_width, layout_height); 100 | } 101 | 102 | public void initEvent() { 103 | //默认Typebutton为隐藏 104 | iv_custom_right.setVisibility(GONE); 105 | btn_cancel.setVisibility(GONE); 106 | btn_confirm.setVisibility(GONE); 107 | } 108 | 109 | public void startTypeBtnAnimator() { 110 | //拍照录制结果后的动画 111 | if (this.iconLeft != 0) 112 | iv_custom_left.setVisibility(GONE); 113 | else 114 | btn_return.setVisibility(GONE); 115 | if (this.iconRight != 0) 116 | iv_custom_right.setVisibility(GONE); 117 | btn_capture.setVisibility(GONE); 118 | btn_cancel.setVisibility(VISIBLE); 119 | btn_confirm.setVisibility(VISIBLE); 120 | btn_cancel.setClickable(false); 121 | btn_confirm.setClickable(false); 122 | ObjectAnimator animator_cancel = ObjectAnimator.ofFloat(btn_cancel, "translationX", layout_width / 4, 0); 123 | ObjectAnimator animator_confirm = ObjectAnimator.ofFloat(btn_confirm, "translationX", -layout_width / 4, 0); 124 | 125 | AnimatorSet set = new AnimatorSet(); 126 | set.playTogether(animator_cancel, animator_confirm); 127 | set.addListener(new AnimatorListenerAdapter() { 128 | @Override 129 | public void onAnimationEnd(Animator animation) { 130 | super.onAnimationEnd(animation); 131 | btn_cancel.setClickable(true); 132 | btn_confirm.setClickable(true); 133 | } 134 | }); 135 | set.setDuration(200); 136 | set.start(); 137 | } 138 | 139 | 140 | private void initView() { 141 | setWillNotDraw(false); 142 | //拍照按钮 143 | btn_capture = new CaptureButton(getContext(), button_size); 144 | LayoutParams btn_capture_param = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); 145 | btn_capture_param.gravity = Gravity.CENTER; 146 | btn_capture.setLayoutParams(btn_capture_param); 147 | btn_capture.setCaptureLisenter(new CaptureListener() { 148 | @Override 149 | public void takePictures() { 150 | if (captureLisenter != null) { 151 | captureLisenter.takePictures(); 152 | } 153 | } 154 | 155 | @Override 156 | public void recordShort(long time) { 157 | if (captureLisenter != null) { 158 | captureLisenter.recordShort(time); 159 | } 160 | startAlphaAnimation(); 161 | } 162 | 163 | @Override 164 | public void recordStart() { 165 | if (captureLisenter != null) { 166 | captureLisenter.recordStart(); 167 | } 168 | startAlphaAnimation(); 169 | } 170 | 171 | @Override 172 | public void recordEnd(long time) { 173 | if (captureLisenter != null) { 174 | captureLisenter.recordEnd(time); 175 | } 176 | startAlphaAnimation(); 177 | startTypeBtnAnimator(); 178 | } 179 | 180 | @Override 181 | public void recordZoom(float zoom) { 182 | if (captureLisenter != null) { 183 | captureLisenter.recordZoom(zoom); 184 | } 185 | } 186 | 187 | @Override 188 | public void recordError() { 189 | if (captureLisenter != null) { 190 | captureLisenter.recordError(); 191 | } 192 | } 193 | }); 194 | 195 | //取消按钮 196 | btn_cancel = new TypeButton(getContext(), TypeButton.TYPE_CANCEL, button_size); 197 | final LayoutParams btn_cancel_param = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); 198 | btn_cancel_param.gravity = Gravity.CENTER_VERTICAL; 199 | btn_cancel_param.setMargins((layout_width / 4) - button_size / 2, 0, 0, 0); 200 | btn_cancel.setLayoutParams(btn_cancel_param); 201 | btn_cancel.setOnClickListener(new OnClickListener() { 202 | @Override 203 | public void onClick(View view) { 204 | if (typeLisenter != null) { 205 | typeLisenter.cancel(); 206 | } 207 | startAlphaAnimation(); 208 | // resetCaptureLayout(); 209 | } 210 | }); 211 | 212 | //确认按钮 213 | btn_confirm = new TypeButton(getContext(), TypeButton.TYPE_CONFIRM, button_size); 214 | LayoutParams btn_confirm_param = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); 215 | btn_confirm_param.gravity = Gravity.CENTER_VERTICAL | Gravity.RIGHT; 216 | btn_confirm_param.setMargins(0, 0, (layout_width / 4) - button_size / 2, 0); 217 | btn_confirm.setLayoutParams(btn_confirm_param); 218 | btn_confirm.setOnClickListener(new OnClickListener() { 219 | @Override 220 | public void onClick(View view) { 221 | if (typeLisenter != null) { 222 | typeLisenter.confirm(); 223 | } 224 | startAlphaAnimation(); 225 | // resetCaptureLayout(); 226 | } 227 | }); 228 | 229 | //返回按钮 230 | btn_return = new ReturnButton(getContext(), (int) (button_size / 2.5f)); 231 | LayoutParams btn_return_param = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); 232 | btn_return_param.gravity = Gravity.CENTER_VERTICAL; 233 | btn_return_param.setMargins(layout_width / 6, 0, 0, 0); 234 | btn_return.setLayoutParams(btn_return_param); 235 | btn_return.setOnClickListener(new OnClickListener() { 236 | @Override 237 | public void onClick(View v) { 238 | if (leftClickListener != null) { 239 | leftClickListener.onClick(); 240 | } 241 | } 242 | }); 243 | //左边自定义按钮 244 | iv_custom_left = new ImageView(getContext()); 245 | LayoutParams iv_custom_param_left = new LayoutParams((int) (button_size / 2.5f), (int) (button_size / 2.5f)); 246 | iv_custom_param_left.gravity = Gravity.CENTER_VERTICAL; 247 | iv_custom_param_left.setMargins(layout_width / 6, 0, 0, 0); 248 | iv_custom_left.setLayoutParams(iv_custom_param_left); 249 | iv_custom_left.setOnClickListener(new OnClickListener() { 250 | @Override 251 | public void onClick(View v) { 252 | if (leftClickListener != null) { 253 | leftClickListener.onClick(); 254 | } 255 | } 256 | }); 257 | 258 | //右边自定义按钮 259 | iv_custom_right = new ImageView(getContext()); 260 | LayoutParams iv_custom_param_right = new LayoutParams((int) (button_size / 2.5f), (int) (button_size / 2.5f)); 261 | iv_custom_param_right.gravity = Gravity.CENTER_VERTICAL | Gravity.RIGHT; 262 | iv_custom_param_right.setMargins(0, 0, layout_width / 6, 0); 263 | iv_custom_right.setLayoutParams(iv_custom_param_right); 264 | iv_custom_right.setOnClickListener(new OnClickListener() { 265 | @Override 266 | public void onClick(View v) { 267 | if (rightClickListener != null) { 268 | rightClickListener.onClick(); 269 | } 270 | } 271 | }); 272 | 273 | txt_tip = new TextView(getContext()); 274 | LayoutParams txt_param = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); 275 | txt_param.gravity = Gravity.CENTER_HORIZONTAL; 276 | txt_param.setMargins(0, 0, 0, 0); 277 | txt_tip.setText("轻触拍照,长按摄像"); 278 | txt_tip.setTextColor(0xFFFFFFFF); 279 | txt_tip.setGravity(Gravity.CENTER); 280 | txt_tip.setLayoutParams(txt_param); 281 | 282 | this.addView(btn_capture); 283 | this.addView(btn_cancel); 284 | this.addView(btn_confirm); 285 | this.addView(btn_return); 286 | this.addView(iv_custom_left); 287 | this.addView(iv_custom_right); 288 | this.addView(txt_tip); 289 | 290 | } 291 | 292 | /************************************************** 293 | * 对外提供的API * 294 | **************************************************/ 295 | public void resetCaptureLayout() { 296 | btn_capture.resetState(); 297 | btn_cancel.setVisibility(GONE); 298 | btn_confirm.setVisibility(GONE); 299 | btn_capture.setVisibility(VISIBLE); 300 | if (this.iconLeft != 0) 301 | iv_custom_left.setVisibility(VISIBLE); 302 | else 303 | btn_return.setVisibility(VISIBLE); 304 | if (this.iconRight != 0) 305 | iv_custom_right.setVisibility(VISIBLE); 306 | } 307 | 308 | 309 | public void startAlphaAnimation() { 310 | if (isFirst) { 311 | ObjectAnimator animator_txt_tip = ObjectAnimator.ofFloat(txt_tip, "alpha", 1f, 0f); 312 | animator_txt_tip.setDuration(500); 313 | animator_txt_tip.start(); 314 | isFirst = false; 315 | } 316 | } 317 | 318 | public void setTextWithAnimation(String tip) { 319 | txt_tip.setText(tip); 320 | ObjectAnimator animator_txt_tip = ObjectAnimator.ofFloat(txt_tip, "alpha", 0f, 1f, 1f, 0f); 321 | animator_txt_tip.setDuration(2500); 322 | animator_txt_tip.start(); 323 | } 324 | 325 | public void setDuration(int duration) { 326 | btn_capture.setDuration(duration); 327 | } 328 | 329 | public void setButtonFeatures(int state) { 330 | btn_capture.setButtonFeatures(state); 331 | } 332 | 333 | public void setTip(String tip) { 334 | txt_tip.setText(tip); 335 | } 336 | 337 | public void showTip() { 338 | txt_tip.setVisibility(VISIBLE); 339 | } 340 | 341 | public void setIconSrc(int iconLeft, int iconRight) { 342 | this.iconLeft = iconLeft; 343 | this.iconRight = iconRight; 344 | if (this.iconLeft != 0) { 345 | iv_custom_left.setImageResource(iconLeft); 346 | iv_custom_left.setVisibility(VISIBLE); 347 | btn_return.setVisibility(GONE); 348 | } else { 349 | iv_custom_left.setVisibility(GONE); 350 | btn_return.setVisibility(VISIBLE); 351 | } 352 | if (this.iconRight != 0) { 353 | iv_custom_right.setImageResource(iconRight); 354 | iv_custom_right.setVisibility(VISIBLE); 355 | } else { 356 | iv_custom_right.setVisibility(GONE); 357 | } 358 | } 359 | 360 | public void setLeftClickListener(ClickListener leftClickListener) { 361 | this.leftClickListener = leftClickListener; 362 | } 363 | 364 | public void setRightClickListener(ClickListener rightClickListener) { 365 | this.rightClickListener = rightClickListener; 366 | } 367 | } 368 | -------------------------------------------------------------------------------- /camera/src/main/java/com/cjt2325/cameralibrary/FoucsView.java: -------------------------------------------------------------------------------- 1 | package com.cjt2325.cameralibrary; 2 | 3 | import android.content.Context; 4 | import android.graphics.Canvas; 5 | import android.graphics.Paint; 6 | import android.support.annotation.Nullable; 7 | import android.util.AttributeSet; 8 | import android.view.View; 9 | 10 | import com.cjt2325.cameralibrary.util.ScreenUtils; 11 | 12 | /** 13 | * ===================================== 14 | * 作 者: 陈嘉桐 15 | * 版 本:1.1.4 16 | * 创建日期:2017/4/26 17 | * 描 述:对焦框 18 | * ===================================== 19 | */ 20 | public class FoucsView extends View { 21 | private int size; 22 | private int center_x; 23 | private int center_y; 24 | private int length; 25 | private Paint mPaint; 26 | 27 | public FoucsView(Context context) { 28 | this(context, null); 29 | } 30 | 31 | public FoucsView(Context context, @Nullable AttributeSet attrs) { 32 | this(context, attrs, 0); 33 | } 34 | 35 | public FoucsView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { 36 | super(context, attrs, defStyleAttr); 37 | this.size = ScreenUtils.getScreenWidth(context) / 3; 38 | mPaint = new Paint(); 39 | mPaint.setAntiAlias(true); 40 | mPaint.setDither(true); 41 | mPaint.setColor(0xEE16AE16); 42 | mPaint.setStrokeWidth(4); 43 | mPaint.setStyle(Paint.Style.STROKE); 44 | } 45 | 46 | @Override 47 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 48 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 49 | center_x = (int) (size / 2.0); 50 | center_y = (int) (size / 2.0); 51 | length = (int) (size / 2.0) - 2; 52 | setMeasuredDimension(size, size); 53 | } 54 | 55 | @Override 56 | protected void onDraw(Canvas canvas) { 57 | super.onDraw(canvas); 58 | canvas.drawRect(center_x - length, center_y - length, center_x + length, center_y + length, mPaint); 59 | canvas.drawLine(2, getHeight() / 2, size / 10, getHeight() / 2, mPaint); 60 | canvas.drawLine(getWidth() - 2, getHeight() / 2, getWidth() - size / 10, getHeight() / 2, mPaint); 61 | canvas.drawLine(getWidth() / 2, 2, getWidth() / 2, size / 10, mPaint); 62 | canvas.drawLine(getWidth() / 2, getHeight() - 2, getWidth() / 2, getHeight() - size / 10, mPaint); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /camera/src/main/java/com/cjt2325/cameralibrary/ReturnButton.java: -------------------------------------------------------------------------------- 1 | package com.cjt2325.cameralibrary; 2 | 3 | import android.content.Context; 4 | import android.graphics.Canvas; 5 | import android.graphics.Color; 6 | import android.graphics.Paint; 7 | import android.graphics.Path; 8 | import android.view.View; 9 | 10 | /** 11 | * ===================================== 12 | * 作 者: 陈嘉桐 445263848@qq.com 13 | * 版 本:1.0.4 14 | * 创建日期:2017/4/26 15 | * 描 述:向下箭头的退出按钮 16 | * ===================================== 17 | */ 18 | public class ReturnButton extends View { 19 | 20 | private int size; 21 | 22 | private int center_X; 23 | private int center_Y; 24 | private float strokeWidth; 25 | 26 | private Paint paint; 27 | Path path; 28 | 29 | public ReturnButton(Context context, int size) { 30 | this(context); 31 | this.size = size; 32 | center_X = size / 2; 33 | center_Y = size / 2; 34 | 35 | strokeWidth = size / 15f; 36 | 37 | paint = new Paint(); 38 | paint.setAntiAlias(true); 39 | paint.setColor(Color.WHITE); 40 | paint.setStyle(Paint.Style.STROKE); 41 | paint.setStrokeWidth(strokeWidth); 42 | 43 | path = new Path(); 44 | } 45 | 46 | public ReturnButton(Context context) { 47 | super(context); 48 | } 49 | 50 | @Override 51 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 52 | setMeasuredDimension(size, size / 2); 53 | } 54 | 55 | @Override 56 | protected void onDraw(Canvas canvas) { 57 | super.onDraw(canvas); 58 | path.moveTo(strokeWidth, strokeWidth/2); 59 | path.lineTo(center_X, center_Y - strokeWidth/2); 60 | path.lineTo(size - strokeWidth, strokeWidth/2); 61 | canvas.drawPath(path, paint); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /camera/src/main/java/com/cjt2325/cameralibrary/TypeButton.java: -------------------------------------------------------------------------------- 1 | package com.cjt2325.cameralibrary; 2 | 3 | import android.content.Context; 4 | import android.graphics.Canvas; 5 | import android.graphics.Color; 6 | import android.graphics.Paint; 7 | import android.graphics.Path; 8 | import android.graphics.RectF; 9 | import android.view.View; 10 | 11 | /** 12 | * ===================================== 13 | * 作 者: 陈嘉桐 445263848@qq.com 14 | * 版 本:1.0.4 15 | * 创建日期:2017/4/26 16 | * 描 述:拍照或录制完成后弹出的确认和返回按钮 17 | * ===================================== 18 | */ 19 | public class TypeButton extends View{ 20 | public static final int TYPE_CANCEL = 0x001; 21 | public static final int TYPE_CONFIRM = 0x002; 22 | private int button_type; 23 | private int button_size; 24 | 25 | private float center_X; 26 | private float center_Y; 27 | private float button_radius; 28 | 29 | private Paint mPaint; 30 | private Path path; 31 | private float strokeWidth; 32 | 33 | private float index; 34 | private RectF rectF; 35 | 36 | public TypeButton(Context context) { 37 | super(context); 38 | } 39 | 40 | public TypeButton(Context context, int type, int size) { 41 | super(context); 42 | this.button_type = type; 43 | button_size = size; 44 | button_radius = size / 2.0f; 45 | center_X = size / 2.0f; 46 | center_Y = size / 2.0f; 47 | 48 | mPaint = new Paint(); 49 | path = new Path(); 50 | strokeWidth = size / 50f; 51 | index = button_size / 12f; 52 | rectF = new RectF(center_X, center_Y - index, center_X + index * 2, center_Y + index); 53 | } 54 | 55 | @Override 56 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 57 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 58 | setMeasuredDimension(button_size, button_size); 59 | } 60 | 61 | @Override 62 | protected void onDraw(Canvas canvas) { 63 | super.onDraw(canvas); 64 | //如果类型为取消,则绘制内部为返回箭头 65 | if (button_type == TYPE_CANCEL) { 66 | mPaint.setAntiAlias(true); 67 | mPaint.setColor(0xEEDCDCDC); 68 | mPaint.setStyle(Paint.Style.FILL); 69 | canvas.drawCircle(center_X, center_Y, button_radius, mPaint); 70 | 71 | mPaint.setColor(Color.BLACK); 72 | mPaint.setStyle(Paint.Style.STROKE); 73 | mPaint.setStrokeWidth(strokeWidth); 74 | 75 | path.moveTo(center_X - index / 7, center_Y + index); 76 | path.lineTo(center_X + index, center_Y + index); 77 | 78 | path.arcTo(rectF, 90, -180); 79 | path.lineTo(center_X - index, center_Y - index); 80 | canvas.drawPath(path, mPaint); 81 | mPaint.setStyle(Paint.Style.FILL); 82 | path.reset(); 83 | path.moveTo(center_X - index, (float) (center_Y - index * 1.5)); 84 | path.lineTo(center_X - index, (float) (center_Y - index / 2.3)); 85 | path.lineTo((float) (center_X - index * 1.6), center_Y - index); 86 | path.close(); 87 | canvas.drawPath(path, mPaint); 88 | 89 | } 90 | //如果类型为确认,则绘制绿色勾 91 | if (button_type == TYPE_CONFIRM) { 92 | mPaint.setAntiAlias(true); 93 | mPaint.setColor(0xFFFFFFFF); 94 | mPaint.setStyle(Paint.Style.FILL); 95 | canvas.drawCircle(center_X, center_Y, button_radius, mPaint); 96 | mPaint.setAntiAlias(true); 97 | mPaint.setStyle(Paint.Style.STROKE); 98 | mPaint.setColor(0xFF00CC00); 99 | mPaint.setStrokeWidth(strokeWidth); 100 | 101 | path.moveTo(center_X - button_size / 6f, center_Y); 102 | path.lineTo(center_X - button_size / 21.2f, center_Y + button_size / 7.7f); 103 | path.lineTo(center_X + button_size / 4.0f, center_Y - button_size / 8.5f); 104 | path.lineTo(center_X - button_size / 21.2f, center_Y + button_size / 9.4f); 105 | path.close(); 106 | canvas.drawPath(path, mPaint); 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /camera/src/main/java/com/cjt2325/cameralibrary/listener/CaptureListener.java: -------------------------------------------------------------------------------- 1 | package com.cjt2325.cameralibrary.listener; 2 | 3 | /** 4 | * create by CJT2325 5 | * 445263848@qq.com. 6 | */ 7 | 8 | public interface CaptureListener { 9 | void takePictures(); 10 | 11 | void recordShort(long time); 12 | 13 | void recordStart(); 14 | 15 | void recordEnd(long time); 16 | 17 | void recordZoom(float zoom); 18 | 19 | void recordError(); 20 | } 21 | -------------------------------------------------------------------------------- /camera/src/main/java/com/cjt2325/cameralibrary/listener/ClickListener.java: -------------------------------------------------------------------------------- 1 | package com.cjt2325.cameralibrary.listener; 2 | 3 | /** 4 | * ===================================== 5 | * 作 者: 陈嘉桐 6 | * 版 本:1.1.9 7 | * 创建日期:2017/10/7 8 | * 描 述: 9 | * ===================================== 10 | */ 11 | public interface ClickListener { 12 | void onClick(); 13 | } 14 | -------------------------------------------------------------------------------- /camera/src/main/java/com/cjt2325/cameralibrary/listener/ErrorListener.java: -------------------------------------------------------------------------------- 1 | package com.cjt2325.cameralibrary.listener; 2 | 3 | /** 4 | * ===================================== 5 | * 作 者: 陈嘉桐 6 | * 版 本:1.1.4 7 | * 创建日期:2017/6/5 8 | * 描 述: 9 | * ===================================== 10 | */ 11 | public interface ErrorListener { 12 | void onError(); 13 | void AudioPermissionError(); 14 | } 15 | -------------------------------------------------------------------------------- /camera/src/main/java/com/cjt2325/cameralibrary/listener/JCameraListener.java: -------------------------------------------------------------------------------- 1 | package com.cjt2325.cameralibrary.listener; 2 | 3 | import android.graphics.Bitmap; 4 | 5 | /** 6 | * ===================================== 7 | * 作 者: 陈嘉桐 8 | * 版 本:1.1.4 9 | * 创建日期:2017/4/26 10 | * 描 述: 11 | * ===================================== 12 | */ 13 | public interface JCameraListener { 14 | 15 | void captureSuccess(Bitmap bitmap); 16 | 17 | void recordSuccess(String url, Bitmap firstFrame); 18 | 19 | } 20 | -------------------------------------------------------------------------------- /camera/src/main/java/com/cjt2325/cameralibrary/listener/ResultListener.java: -------------------------------------------------------------------------------- 1 | package com.cjt2325.cameralibrary.listener; 2 | 3 | /** 4 | * ===================================== 5 | * 作 者: 陈嘉桐 6 | * 版 本:1.1.4 7 | * 创建日期:2017/9/8 8 | * 描 述: 9 | * ===================================== 10 | */ 11 | public interface ResultListener { 12 | void callback(); 13 | } 14 | -------------------------------------------------------------------------------- /camera/src/main/java/com/cjt2325/cameralibrary/listener/ReturnListener.java: -------------------------------------------------------------------------------- 1 | package com.cjt2325.cameralibrary.listener; 2 | 3 | /** 4 | * ===================================== 5 | * 作 者: 陈嘉桐 6 | * 版 本:1.1.4 7 | * 创建日期:2017/4/26 8 | * 描 述: 9 | * ===================================== 10 | */ 11 | public interface ReturnListener { 12 | void onReturn(); 13 | } 14 | -------------------------------------------------------------------------------- /camera/src/main/java/com/cjt2325/cameralibrary/listener/TypeListener.java: -------------------------------------------------------------------------------- 1 | package com.cjt2325.cameralibrary.listener; 2 | 3 | /** 4 | * ===================================== 5 | * 作 者: 陈嘉桐 6 | * 版 本:1.1.4 7 | * 创建日期:2017/4/25 8 | * 描 述: 9 | * ===================================== 10 | */ 11 | public interface TypeListener { 12 | void cancel(); 13 | 14 | void confirm(); 15 | } 16 | -------------------------------------------------------------------------------- /camera/src/main/java/com/cjt2325/cameralibrary/state/BorrowPictureState.java: -------------------------------------------------------------------------------- 1 | package com.cjt2325.cameralibrary.state; 2 | 3 | import android.view.Surface; 4 | import android.view.SurfaceHolder; 5 | 6 | import com.cjt2325.cameralibrary.CameraInterface; 7 | import com.cjt2325.cameralibrary.JCameraView; 8 | import com.cjt2325.cameralibrary.util.LogUtil; 9 | 10 | /** 11 | * ===================================== 12 | * 作 者: 陈嘉桐 13 | * 版 本:1.1.4 14 | * 创建日期:2017/9/8 15 | * 描 述: 16 | * ===================================== 17 | */ 18 | public class BorrowPictureState implements State { 19 | private final String TAG = "BorrowPictureState"; 20 | private CameraMachine machine; 21 | 22 | public BorrowPictureState(CameraMachine machine) { 23 | this.machine = machine; 24 | } 25 | 26 | @Override 27 | public void start(SurfaceHolder holder, float screenProp) { 28 | CameraInterface.getInstance().doStartPreview(holder, screenProp); 29 | machine.setState(machine.getPreviewState()); 30 | } 31 | 32 | @Override 33 | public void stop() { 34 | 35 | } 36 | 37 | 38 | @Override 39 | public void foucs(float x, float y, CameraInterface.FocusCallback callback) { 40 | } 41 | 42 | @Override 43 | public void swtich(SurfaceHolder holder, float screenProp) { 44 | 45 | } 46 | 47 | @Override 48 | public void restart() { 49 | 50 | } 51 | 52 | @Override 53 | public void capture() { 54 | 55 | } 56 | 57 | @Override 58 | public void record(Surface surface,float screenProp) { 59 | 60 | } 61 | 62 | @Override 63 | public void stopRecord(boolean isShort, long time) { 64 | } 65 | 66 | @Override 67 | public void cancle(SurfaceHolder holder, float screenProp) { 68 | CameraInterface.getInstance().doStartPreview(holder, screenProp); 69 | machine.getView().resetState(JCameraView.TYPE_PICTURE); 70 | machine.setState(machine.getPreviewState()); 71 | } 72 | 73 | @Override 74 | public void confirm() { 75 | machine.getView().confirmState(JCameraView.TYPE_PICTURE); 76 | machine.setState(machine.getPreviewState()); 77 | } 78 | 79 | @Override 80 | public void zoom(float zoom, int type) { 81 | LogUtil.i(TAG, "zoom"); 82 | } 83 | 84 | @Override 85 | public void flash(String mode) { 86 | 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /camera/src/main/java/com/cjt2325/cameralibrary/state/BorrowVideoState.java: -------------------------------------------------------------------------------- 1 | package com.cjt2325.cameralibrary.state; 2 | 3 | import android.view.Surface; 4 | import android.view.SurfaceHolder; 5 | 6 | import com.cjt2325.cameralibrary.CameraInterface; 7 | import com.cjt2325.cameralibrary.JCameraView; 8 | import com.cjt2325.cameralibrary.util.LogUtil; 9 | 10 | /** 11 | * ===================================== 12 | * 作 者: 陈嘉桐 13 | * 版 本:1.1.4 14 | * 创建日期:2017/9/8 15 | * 描 述: 16 | * ===================================== 17 | */ 18 | public class BorrowVideoState implements State { 19 | private final String TAG = "BorrowVideoState"; 20 | private CameraMachine machine; 21 | 22 | public BorrowVideoState(CameraMachine machine) { 23 | this.machine = machine; 24 | } 25 | 26 | @Override 27 | public void start(SurfaceHolder holder, float screenProp) { 28 | CameraInterface.getInstance().doStartPreview(holder, screenProp); 29 | machine.setState(machine.getPreviewState()); 30 | } 31 | 32 | @Override 33 | public void stop() { 34 | 35 | } 36 | 37 | @Override 38 | public void foucs(float x, float y, CameraInterface.FocusCallback callback) { 39 | 40 | } 41 | 42 | 43 | @Override 44 | public void swtich(SurfaceHolder holder, float screenProp) { 45 | 46 | } 47 | 48 | @Override 49 | public void restart() { 50 | 51 | } 52 | 53 | @Override 54 | public void capture() { 55 | 56 | } 57 | 58 | @Override 59 | public void record(Surface surface, float screenProp) { 60 | 61 | } 62 | 63 | @Override 64 | public void stopRecord(boolean isShort, long time) { 65 | 66 | } 67 | 68 | @Override 69 | public void cancle(SurfaceHolder holder, float screenProp) { 70 | machine.getView().resetState(JCameraView.TYPE_VIDEO); 71 | machine.setState(machine.getPreviewState()); 72 | } 73 | 74 | @Override 75 | public void confirm() { 76 | machine.getView().confirmState(JCameraView.TYPE_VIDEO); 77 | machine.setState(machine.getPreviewState()); 78 | } 79 | 80 | @Override 81 | public void zoom(float zoom, int type) { 82 | LogUtil.i(TAG, "zoom"); 83 | } 84 | 85 | @Override 86 | public void flash(String mode) { 87 | 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /camera/src/main/java/com/cjt2325/cameralibrary/state/CameraMachine.java: -------------------------------------------------------------------------------- 1 | package com.cjt2325.cameralibrary.state; 2 | 3 | import android.content.Context; 4 | import android.view.Surface; 5 | import android.view.SurfaceHolder; 6 | 7 | import com.cjt2325.cameralibrary.CameraInterface; 8 | import com.cjt2325.cameralibrary.view.CameraView; 9 | 10 | /** 11 | * ===================================== 12 | * 作 者: 陈嘉桐 13 | * 版 本:1.1.4 14 | * 创建日期:2017/9/8 15 | * 描 述: 16 | * ===================================== 17 | */ 18 | public class CameraMachine implements State { 19 | 20 | 21 | private Context context; 22 | private State state; 23 | private CameraView view; 24 | // private CameraInterface.CameraOpenOverCallback cameraOpenOverCallback; 25 | 26 | private State previewState; //浏览状态(空闲) 27 | private State borrowPictureState; //浏览图片 28 | private State borrowVideoState; //浏览视频 29 | 30 | public CameraMachine(Context context, CameraView view, CameraInterface.CameraOpenOverCallback 31 | cameraOpenOverCallback) { 32 | this.context = context; 33 | previewState = new PreviewState(this); 34 | borrowPictureState = new BorrowPictureState(this); 35 | borrowVideoState = new BorrowVideoState(this); 36 | //默认设置为空闲状态 37 | this.state = previewState; 38 | // this.cameraOpenOverCallback = cameraOpenOverCallback; 39 | this.view = view; 40 | } 41 | 42 | public CameraView getView() { 43 | return view; 44 | } 45 | 46 | public Context getContext() { 47 | return context; 48 | } 49 | 50 | public void setState(State state) { 51 | this.state = state; 52 | } 53 | 54 | //获取浏览图片状态 55 | State getBorrowPictureState() { 56 | return borrowPictureState; 57 | } 58 | 59 | //获取浏览视频状态 60 | State getBorrowVideoState() { 61 | return borrowVideoState; 62 | } 63 | 64 | //获取空闲状态 65 | State getPreviewState() { 66 | return previewState; 67 | } 68 | 69 | @Override 70 | public void start(SurfaceHolder holder, float screenProp) { 71 | state.start(holder, screenProp); 72 | } 73 | 74 | @Override 75 | public void stop() { 76 | state.stop(); 77 | } 78 | 79 | @Override 80 | public void foucs(float x, float y, CameraInterface.FocusCallback callback) { 81 | state.foucs(x, y, callback); 82 | } 83 | 84 | @Override 85 | public void swtich(SurfaceHolder holder, float screenProp) { 86 | state.swtich(holder, screenProp); 87 | } 88 | 89 | @Override 90 | public void restart() { 91 | state.restart(); 92 | } 93 | 94 | @Override 95 | public void capture() { 96 | state.capture(); 97 | } 98 | 99 | @Override 100 | public void record(Surface surface, float screenProp) { 101 | state.record(surface, screenProp); 102 | } 103 | 104 | @Override 105 | public void stopRecord(boolean isShort, long time) { 106 | state.stopRecord(isShort, time); 107 | } 108 | 109 | @Override 110 | public void cancle(SurfaceHolder holder, float screenProp) { 111 | state.cancle(holder, screenProp); 112 | } 113 | 114 | @Override 115 | public void confirm() { 116 | state.confirm(); 117 | } 118 | 119 | 120 | @Override 121 | public void zoom(float zoom, int type) { 122 | state.zoom(zoom, type); 123 | } 124 | 125 | @Override 126 | public void flash(String mode) { 127 | state.flash(mode); 128 | } 129 | 130 | public State getState() { 131 | return this.state; 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /camera/src/main/java/com/cjt2325/cameralibrary/state/PreviewState.java: -------------------------------------------------------------------------------- 1 | package com.cjt2325.cameralibrary.state; 2 | 3 | import android.graphics.Bitmap; 4 | import android.view.Surface; 5 | import android.view.SurfaceHolder; 6 | 7 | import com.cjt2325.cameralibrary.CameraInterface; 8 | import com.cjt2325.cameralibrary.JCameraView; 9 | import com.cjt2325.cameralibrary.util.LogUtil; 10 | 11 | /** 12 | * ===================================== 13 | * 作 者: 陈嘉桐 14 | * 版 本:1.1.4 15 | * 创建日期:2017/9/8 16 | * 描 述:空闲状态 17 | * ===================================== 18 | */ 19 | class PreviewState implements State { 20 | public static final String TAG = "PreviewState"; 21 | 22 | private CameraMachine machine; 23 | 24 | PreviewState(CameraMachine machine) { 25 | this.machine = machine; 26 | } 27 | 28 | @Override 29 | public void start(SurfaceHolder holder, float screenProp) { 30 | CameraInterface.getInstance().doStartPreview(holder, screenProp); 31 | } 32 | 33 | @Override 34 | public void stop() { 35 | CameraInterface.getInstance().doStopPreview(); 36 | } 37 | 38 | 39 | @Override 40 | public void foucs(float x, float y, CameraInterface.FocusCallback callback) { 41 | LogUtil.i("preview state foucs"); 42 | if (machine.getView().handlerFoucs(x, y)) { 43 | CameraInterface.getInstance().handleFocus(machine.getContext(), x, y, callback); 44 | } 45 | } 46 | 47 | @Override 48 | public void swtich(SurfaceHolder holder, float screenProp) { 49 | CameraInterface.getInstance().switchCamera(holder, screenProp); 50 | } 51 | 52 | @Override 53 | public void restart() { 54 | 55 | } 56 | 57 | @Override 58 | public void capture() { 59 | CameraInterface.getInstance().takePicture(new CameraInterface.TakePictureCallback() { 60 | @Override 61 | public void captureResult(Bitmap bitmap, boolean isVertical) { 62 | machine.getView().showPicture(bitmap, isVertical); 63 | machine.setState(machine.getBorrowPictureState()); 64 | LogUtil.i("capture"); 65 | } 66 | }); 67 | } 68 | 69 | @Override 70 | public void record(Surface surface, float screenProp) { 71 | CameraInterface.getInstance().startRecord(surface, screenProp, null); 72 | } 73 | 74 | @Override 75 | public void stopRecord(final boolean isShort, long time) { 76 | CameraInterface.getInstance().stopRecord(isShort, new CameraInterface.StopRecordCallback() { 77 | @Override 78 | public void recordResult(String url, Bitmap firstFrame) { 79 | if (isShort) { 80 | machine.getView().resetState(JCameraView.TYPE_SHORT); 81 | } else { 82 | machine.getView().playVideo(firstFrame, url); 83 | machine.setState(machine.getBorrowVideoState()); 84 | } 85 | } 86 | }); 87 | } 88 | 89 | @Override 90 | public void cancle(SurfaceHolder holder, float screenProp) { 91 | LogUtil.i("浏览状态下,没有 cancle 事件"); 92 | } 93 | 94 | @Override 95 | public void confirm() { 96 | LogUtil.i("浏览状态下,没有 confirm 事件"); 97 | } 98 | 99 | @Override 100 | public void zoom(float zoom, int type) { 101 | LogUtil.i(TAG, "zoom"); 102 | CameraInterface.getInstance().setZoom(zoom, type); 103 | } 104 | 105 | @Override 106 | public void flash(String mode) { 107 | CameraInterface.getInstance().setFlashMode(mode); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /camera/src/main/java/com/cjt2325/cameralibrary/state/State.java: -------------------------------------------------------------------------------- 1 | package com.cjt2325.cameralibrary.state; 2 | 3 | import android.view.Surface; 4 | import android.view.SurfaceHolder; 5 | 6 | import com.cjt2325.cameralibrary.CameraInterface; 7 | 8 | /** 9 | * ===================================== 10 | * 作 者: 陈嘉桐 11 | * 版 本:1.1.4 12 | * 创建日期:2017/9/8 13 | * 描 述: 14 | * ===================================== 15 | */ 16 | public interface State { 17 | 18 | void start(SurfaceHolder holder, float screenProp); 19 | 20 | void stop(); 21 | 22 | void foucs(float x, float y, CameraInterface.FocusCallback callback); 23 | 24 | void swtich(SurfaceHolder holder, float screenProp); 25 | 26 | void restart(); 27 | 28 | void capture(); 29 | 30 | void record(Surface surface, float screenProp); 31 | 32 | void stopRecord(boolean isShort, long time); 33 | 34 | void cancle(SurfaceHolder holder, float screenProp); 35 | 36 | void confirm(); 37 | 38 | void zoom(float zoom, int type); 39 | 40 | void flash(String mode); 41 | } 42 | -------------------------------------------------------------------------------- /camera/src/main/java/com/cjt2325/cameralibrary/util/AngleUtil.java: -------------------------------------------------------------------------------- 1 | package com.cjt2325.cameralibrary.util; 2 | 3 | /** 4 | * ===================================== 5 | * 作 者: 陈嘉桐 6 | * 版 本:1.1.4 7 | * 创建日期:2017/5/2 8 | * 描 述: 9 | * ===================================== 10 | */ 11 | public class AngleUtil { 12 | public static int getSensorAngle(float x, float y) { 13 | if (Math.abs(x) > Math.abs(y)) { 14 | /** 15 | * 横屏倾斜角度比较大 16 | */ 17 | if (x > 4) { 18 | /** 19 | * 左边倾斜 20 | */ 21 | return 270; 22 | } else if (x < -4) { 23 | /** 24 | * 右边倾斜 25 | */ 26 | return 90; 27 | } else { 28 | /** 29 | * 倾斜角度不够大 30 | */ 31 | return 0; 32 | } 33 | } else { 34 | if (y > 7) { 35 | /** 36 | * 左边倾斜 37 | */ 38 | return 0; 39 | } else if (y < -7) { 40 | /** 41 | * 右边倾斜 42 | */ 43 | return 180; 44 | } else { 45 | /** 46 | * 倾斜角度不够大 47 | */ 48 | return 0; 49 | } 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /camera/src/main/java/com/cjt2325/cameralibrary/util/AudioUtil.java: -------------------------------------------------------------------------------- 1 | package com.cjt2325.cameralibrary.util; 2 | 3 | import android.content.Context; 4 | import android.media.AudioManager; 5 | 6 | /** 7 | * ===================================== 8 | * 作 者: 陈嘉桐 9 | * 版 本:1.1.4 10 | * 创建日期:2017/4/26 11 | * 描 述: 12 | * ===================================== 13 | */ 14 | public class AudioUtil { 15 | public static void setAudioManage(Context context) { 16 | AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); 17 | audioManager.setStreamMute(AudioManager.STREAM_SYSTEM, true); 18 | audioManager.setStreamMute(AudioManager.STREAM_MUSIC, true); 19 | audioManager.setStreamVolume(AudioManager.STREAM_ALARM, 0, 0); 20 | audioManager.setStreamVolume(AudioManager.STREAM_DTMF, 0, 0); 21 | audioManager.setStreamVolume(AudioManager.STREAM_NOTIFICATION, 0, 0); 22 | audioManager.setStreamVolume(AudioManager.STREAM_RING, 0, 0); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /camera/src/main/java/com/cjt2325/cameralibrary/util/CameraParamUtil.java: -------------------------------------------------------------------------------- 1 | package com.cjt2325.cameralibrary.util; 2 | 3 | import android.content.Context; 4 | import android.hardware.Camera; 5 | import android.util.Log; 6 | import android.view.Surface; 7 | import android.view.WindowManager; 8 | 9 | import java.util.Collections; 10 | import java.util.Comparator; 11 | import java.util.List; 12 | 13 | /** 14 | * ===================================== 15 | * 作 者: 陈嘉桐 16 | * 版 本:1.1.4 17 | * 创建日期:2017/4/25 18 | * 描 述: 19 | * ===================================== 20 | */ 21 | public class CameraParamUtil { 22 | private static final String TAG = "JCameraView"; 23 | private CameraSizeComparator sizeComparator = new CameraSizeComparator(); 24 | private static CameraParamUtil cameraParamUtil = null; 25 | 26 | private CameraParamUtil() { 27 | 28 | } 29 | 30 | public static CameraParamUtil getInstance() { 31 | if (cameraParamUtil == null) { 32 | cameraParamUtil = new CameraParamUtil(); 33 | return cameraParamUtil; 34 | } else { 35 | return cameraParamUtil; 36 | } 37 | } 38 | 39 | public Camera.Size getPreviewSize(List list, int th, float rate) { 40 | Collections.sort(list, sizeComparator); 41 | int i = 0; 42 | for (Camera.Size s : list) { 43 | if ((s.width > th) && equalRate(s, rate)) { 44 | Log.i(TAG, "MakeSure Preview :w = " + s.width + " h = " + s.height); 45 | break; 46 | } 47 | i++; 48 | } 49 | if (i == list.size()) { 50 | return getBestSize(list, rate); 51 | } else { 52 | return list.get(i); 53 | } 54 | } 55 | 56 | public Camera.Size getPictureSize(List list, int th, float rate) { 57 | Collections.sort(list, sizeComparator); 58 | int i = 0; 59 | for (Camera.Size s : list) { 60 | if ((s.width > th) && equalRate(s, rate)) { 61 | Log.i(TAG, "MakeSure Picture :w = " + s.width + " h = " + s.height); 62 | break; 63 | } 64 | i++; 65 | } 66 | if (i == list.size()) { 67 | return getBestSize(list, rate); 68 | } else { 69 | return list.get(i); 70 | } 71 | } 72 | 73 | private Camera.Size getBestSize(List list, float rate) { 74 | float previewDisparity = 100; 75 | int index = 0; 76 | for (int i = 0; i < list.size(); i++) { 77 | Camera.Size cur = list.get(i); 78 | float prop = (float) cur.width / (float) cur.height; 79 | if (Math.abs(rate - prop) < previewDisparity) { 80 | previewDisparity = Math.abs(rate - prop); 81 | index = i; 82 | } 83 | } 84 | return list.get(index); 85 | } 86 | 87 | 88 | private boolean equalRate(Camera.Size s, float rate) { 89 | float r = (float) (s.width) / (float) (s.height); 90 | return Math.abs(r - rate) <= 0.2; 91 | } 92 | 93 | public boolean isSupportedFocusMode(List focusList, String focusMode) { 94 | for (int i = 0; i < focusList.size(); i++) { 95 | if (focusMode.equals(focusList.get(i))) { 96 | Log.i(TAG, "FocusMode supported " + focusMode); 97 | return true; 98 | } 99 | } 100 | Log.i(TAG, "FocusMode not supported " + focusMode); 101 | return false; 102 | } 103 | 104 | public boolean isSupportedPictureFormats(List supportedPictureFormats, int jpeg) { 105 | for (int i = 0; i < supportedPictureFormats.size(); i++) { 106 | if (jpeg == supportedPictureFormats.get(i)) { 107 | Log.i(TAG, "Formats supported " + jpeg); 108 | return true; 109 | } 110 | } 111 | Log.i(TAG, "Formats not supported " + jpeg); 112 | return false; 113 | } 114 | 115 | private class CameraSizeComparator implements Comparator { 116 | public int compare(Camera.Size lhs, Camera.Size rhs) { 117 | if (lhs.width == rhs.width) { 118 | return 0; 119 | } else if (lhs.width > rhs.width) { 120 | return 1; 121 | } else { 122 | return -1; 123 | } 124 | } 125 | 126 | } 127 | 128 | public int getCameraDisplayOrientation(Context context, int cameraId) { 129 | android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo(); 130 | android.hardware.Camera.getCameraInfo(cameraId, info); 131 | WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); 132 | int rotation = wm.getDefaultDisplay().getRotation(); 133 | int degrees = 0; 134 | switch (rotation) { 135 | case Surface.ROTATION_0: 136 | degrees = 0; 137 | break; 138 | case Surface.ROTATION_90: 139 | degrees = 90; 140 | break; 141 | case Surface.ROTATION_180: 142 | degrees = 180; 143 | break; 144 | case Surface.ROTATION_270: 145 | degrees = 270; 146 | break; 147 | } 148 | int result; 149 | if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { 150 | result = (info.orientation + degrees) % 360; 151 | result = (360 - result) % 360; // compensate the mirror 152 | } else { 153 | // back-facing 154 | result = (info.orientation - degrees + 360) % 360; 155 | } 156 | return result; 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /camera/src/main/java/com/cjt2325/cameralibrary/util/CheckPermission.java: -------------------------------------------------------------------------------- 1 | package com.cjt2325.cameralibrary.util; 2 | 3 | import android.hardware.Camera; 4 | import android.media.AudioFormat; 5 | import android.media.AudioRecord; 6 | import android.media.MediaRecorder; 7 | import android.util.Log; 8 | 9 | /** 10 | * ===================================== 11 | * 作 者: 陈嘉桐 12 | * 版 本:1.1.4 13 | * 创建日期:2017/6/8 14 | * 描 述: 15 | * ===================================== 16 | */ 17 | public class CheckPermission { 18 | public static final int STATE_RECORDING = -1; 19 | public static final int STATE_NO_PERMISSION = -2; 20 | public static final int STATE_SUCCESS = 1; 21 | 22 | /** 23 | * 用于检测是否具有录音权限 24 | * 25 | * @return 26 | */ 27 | public static int getRecordState() { 28 | int minBuffer = AudioRecord.getMinBufferSize(44100, AudioFormat.CHANNEL_IN_MONO, AudioFormat 29 | .ENCODING_PCM_16BIT); 30 | AudioRecord audioRecord = new AudioRecord(MediaRecorder.AudioSource.DEFAULT, 44100, AudioFormat 31 | .CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, (minBuffer * 100)); 32 | short[] point = new short[minBuffer]; 33 | int readSize = 0; 34 | try { 35 | 36 | audioRecord.startRecording();//检测是否可以进入初始化状态 37 | } catch (Exception e) { 38 | if (audioRecord != null) { 39 | audioRecord.release(); 40 | audioRecord = null; 41 | } 42 | return STATE_NO_PERMISSION; 43 | } 44 | if (audioRecord.getRecordingState() != AudioRecord.RECORDSTATE_RECORDING) { 45 | //6.0以下机型都会返回此状态,故使用时需要判断bulid版本 46 | //检测是否在录音中 47 | if (audioRecord != null) { 48 | audioRecord.stop(); 49 | audioRecord.release(); 50 | audioRecord = null; 51 | Log.d("CheckAudioPermission", "录音机被占用"); 52 | } 53 | return STATE_RECORDING; 54 | } else { 55 | //检测是否可以获取录音结果 56 | 57 | readSize = audioRecord.read(point, 0, point.length); 58 | 59 | 60 | if (readSize <= 0) { 61 | if (audioRecord != null) { 62 | audioRecord.stop(); 63 | audioRecord.release(); 64 | audioRecord = null; 65 | 66 | } 67 | Log.d("CheckAudioPermission", "录音的结果为空"); 68 | return STATE_NO_PERMISSION; 69 | 70 | } else { 71 | if (audioRecord != null) { 72 | audioRecord.stop(); 73 | audioRecord.release(); 74 | audioRecord = null; 75 | 76 | } 77 | 78 | return STATE_SUCCESS; 79 | } 80 | } 81 | } 82 | 83 | public synchronized static boolean isCameraUseable(int cameraID) { 84 | boolean canUse = true; 85 | Camera mCamera = null; 86 | try { 87 | mCamera = Camera.open(cameraID); 88 | // setParameters 是针对魅族MX5。MX5通过Camera.open()拿到的Camera对象不为null 89 | Camera.Parameters mParameters = mCamera.getParameters(); 90 | mCamera.setParameters(mParameters); 91 | } catch (Exception e) { 92 | e.printStackTrace(); 93 | canUse = false; 94 | } finally { 95 | if (mCamera != null) { 96 | mCamera.release(); 97 | } else { 98 | canUse = false; 99 | } 100 | mCamera = null; 101 | } 102 | return canUse; 103 | } 104 | } -------------------------------------------------------------------------------- /camera/src/main/java/com/cjt2325/cameralibrary/util/DeviceUtil.java: -------------------------------------------------------------------------------- 1 | package com.cjt2325.cameralibrary.util; 2 | 3 | import android.os.Build; 4 | 5 | /** 6 | * ===================================== 7 | * 作 者: 陈嘉桐 8 | * 版 本:1.1.4 9 | * 创建日期:2017/6/9 10 | * 描 述: 11 | * ===================================== 12 | */ 13 | public class DeviceUtil { 14 | 15 | private static String[] huaweiRongyao = { 16 | "hwH60", //荣耀6 17 | "hwPE", //荣耀6 plus 18 | "hwH30", //3c 19 | "hwHol", //3c畅玩版 20 | "hwG750", //3x 21 | "hw7D", //x1 22 | "hwChe2", //x1 23 | }; 24 | 25 | public static String getDeviceInfo() { 26 | String handSetInfo = 27 | "手机型号:" + Build.DEVICE + 28 | "\n系统版本:" + Build.VERSION.RELEASE + 29 | "\nSDK版本:" + Build.VERSION.SDK_INT; 30 | return handSetInfo; 31 | } 32 | 33 | public static String getDeviceModel() { 34 | return Build.DEVICE; 35 | } 36 | 37 | public static boolean isHuaWeiRongyao() { 38 | int length = huaweiRongyao.length; 39 | for (int i = 0; i < length; i++) { 40 | if (huaweiRongyao[i].equals(getDeviceModel())) { 41 | return true; 42 | } 43 | } 44 | return false; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /camera/src/main/java/com/cjt2325/cameralibrary/util/FileUtil.java: -------------------------------------------------------------------------------- 1 | package com.cjt2325.cameralibrary.util; 2 | 3 | import android.graphics.Bitmap; 4 | import android.os.Environment; 5 | 6 | import java.io.BufferedOutputStream; 7 | import java.io.File; 8 | import java.io.FileOutputStream; 9 | import java.io.IOException; 10 | 11 | /** 12 | * ===================================== 13 | * 作 者: 陈嘉桐 14 | * 版 本:1.1.4 15 | * 创建日期:2017/4/25 16 | * 描 述: 17 | * ===================================== 18 | */ 19 | public class FileUtil { 20 | private static final String TAG = "CJT"; 21 | private static final File parentPath = Environment.getExternalStorageDirectory(); 22 | private static String storagePath = ""; 23 | private static String DST_FOLDER_NAME = "JCamera"; 24 | 25 | private static String initPath() { 26 | if (storagePath.equals("")) { 27 | storagePath = parentPath.getAbsolutePath() + File.separator + DST_FOLDER_NAME; 28 | File f = new File(storagePath); 29 | if (!f.exists()) { 30 | f.mkdir(); 31 | } 32 | } 33 | return storagePath; 34 | } 35 | 36 | public static String saveBitmap(String dir, Bitmap b) { 37 | DST_FOLDER_NAME = dir; 38 | String path = initPath(); 39 | long dataTake = System.currentTimeMillis(); 40 | String jpegName = path + File.separator + "picture_" + dataTake + ".jpg"; 41 | try { 42 | FileOutputStream fout = new FileOutputStream(jpegName); 43 | BufferedOutputStream bos = new BufferedOutputStream(fout); 44 | b.compress(Bitmap.CompressFormat.JPEG, 100, bos); 45 | bos.flush(); 46 | bos.close(); 47 | return jpegName; 48 | } catch (IOException e) { 49 | e.printStackTrace(); 50 | return ""; 51 | } 52 | } 53 | 54 | public static boolean deleteFile(String url) { 55 | boolean result = false; 56 | File file = new File(url); 57 | if (file.exists()) { 58 | result = file.delete(); 59 | } 60 | return result; 61 | } 62 | 63 | public static boolean isExternalStorageWritable() { 64 | String state = Environment.getExternalStorageState(); 65 | if (Environment.MEDIA_MOUNTED.equals(state)) { 66 | return true; 67 | } 68 | return false; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /camera/src/main/java/com/cjt2325/cameralibrary/util/LogUtil.java: -------------------------------------------------------------------------------- 1 | package com.cjt2325.cameralibrary.util; 2 | 3 | import android.util.Log; 4 | 5 | import static com.cjt2325.cameralibrary.BuildConfig.DEBUG; 6 | 7 | /** 8 | * ===================================== 9 | * 作 者: 陈嘉桐 10 | * 版 本:1.1.4 11 | * 创建日期:2017/9/7 12 | * 描 述: 13 | * ===================================== 14 | */ 15 | public class LogUtil { 16 | 17 | private static final String DEFAULT_TAG = "CJT"; 18 | 19 | public static void i(String tag, String msg) { 20 | // if (DEBUG) 21 | Log.i(tag, msg); 22 | } 23 | 24 | public static void v(String tag, String msg) { 25 | if (DEBUG) 26 | Log.v(tag, msg); 27 | } 28 | 29 | public static void d(String tag, String msg) { 30 | if (DEBUG) 31 | Log.d(tag, msg); 32 | } 33 | 34 | public static void e(String tag, String msg) { 35 | if (DEBUG) 36 | Log.e(tag, msg); 37 | } 38 | 39 | public static void i(String msg) { 40 | i(DEFAULT_TAG, msg); 41 | } 42 | 43 | public static void v(String msg) { 44 | v(DEFAULT_TAG, msg); 45 | } 46 | 47 | public static void d(String msg) { 48 | d(DEFAULT_TAG, msg); 49 | } 50 | 51 | public static void e(String msg) { 52 | e(DEFAULT_TAG, msg); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /camera/src/main/java/com/cjt2325/cameralibrary/util/ScreenUtils.java: -------------------------------------------------------------------------------- 1 | package com.cjt2325.cameralibrary.util; 2 | 3 | import android.content.Context; 4 | import android.util.DisplayMetrics; 5 | import android.view.WindowManager; 6 | 7 | /** 8 | * ===================================== 9 | * 作 者: 陈嘉桐 10 | * 版 本:1.1.4 11 | * 创建日期:2017/5/25 12 | * 描 述: 13 | * ===================================== 14 | */ 15 | public class ScreenUtils { 16 | public static int getScreenHeight(Context context) { 17 | DisplayMetrics metric = new DisplayMetrics(); 18 | WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); 19 | wm.getDefaultDisplay().getMetrics(metric); 20 | return metric.heightPixels; 21 | } 22 | 23 | public static int getScreenWidth(Context context) { 24 | DisplayMetrics metric = new DisplayMetrics(); 25 | WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); 26 | wm.getDefaultDisplay().getMetrics(metric); 27 | return metric.widthPixels; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /camera/src/main/java/com/cjt2325/cameralibrary/view/CameraView.java: -------------------------------------------------------------------------------- 1 | package com.cjt2325.cameralibrary.view; 2 | 3 | import android.graphics.Bitmap; 4 | 5 | /** 6 | * ===================================== 7 | * 作 者: 陈嘉桐 8 | * 版 本:1.1.4 9 | * 创建日期:2017/9/8 10 | * 描 述: 11 | * ===================================== 12 | */ 13 | public interface CameraView { 14 | void resetState(int type); 15 | 16 | void confirmState(int type); 17 | 18 | void showPicture(Bitmap bitmap, boolean isVertical); 19 | 20 | void playVideo(Bitmap firstFrame, String url); 21 | 22 | void stopVideo(); 23 | 24 | void setTip(String tip); 25 | 26 | void startPreviewCallback(); 27 | 28 | boolean handlerFoucs(float x, float y); 29 | } 30 | -------------------------------------------------------------------------------- /camera/src/main/res/drawable/ic_camera.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /camera/src/main/res/drawable/ic_flash_auto.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /camera/src/main/res/drawable/ic_flash_off.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /camera/src/main/res/drawable/ic_flash_on.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /camera/src/main/res/drawable/ic_photo.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /camera/src/main/res/layout/camera_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 11 | 12 | 16 | 17 | 23 | 24 | 25 | 26 | 31 | 32 | 38 | 39 | 45 | 46 | 47 | 48 | 49 | 54 | 55 | 61 | -------------------------------------------------------------------------------- /camera/src/main/res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /camera/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | CameraLibrary 3 | 4 | -------------------------------------------------------------------------------- /camera/src/test/java/com/cjt2325/cameralibrary/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.cjt2325.cameralibrary; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * To work on unit tests, switch the Test Artifact in the Build Variants view. 9 | */ 10 | public class ExampleUnitTest { 11 | @Test 12 | public void addition_isCorrect() throws Exception { 13 | assertEquals(4, 2 + 2); 14 | } 15 | } -------------------------------------------------------------------------------- /cameraapplication/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /cameraapplication/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 25 5 | buildToolsVersion "25.0.1" 6 | 7 | defaultConfig { 8 | applicationId "com.zxing.cameraapplication" 9 | minSdkVersion 14 10 | targetSdkVersion 25 11 | versionCode 1 12 | versionName "1.0" 13 | 14 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 15 | 16 | } 17 | buildTypes { 18 | release { 19 | minifyEnabled false 20 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 21 | } 22 | } 23 | } 24 | 25 | repositories { 26 | flatDir { 27 | dirs 'libs' 28 | } 29 | } 30 | dependencies { 31 | compile fileTree(include: ['*.jar'], dir: 'libs') 32 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 33 | exclude group: 'com.android.support', module: 'support-annotations' 34 | }) 35 | compile 'com.android.support:appcompat-v7:25.3.1' 36 | testCompile 'junit:junit:4.12' 37 | compile project(':camera') 38 | 39 | debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5.1' 40 | releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.1' 41 | testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.1' 42 | } 43 | -------------------------------------------------------------------------------- /cameraapplication/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in D:\Users\Administrator\AppData\Local\Android\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /cameraapplication/src/androidTest/java/com/zxing/cameraapplication/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.zxing.cameraapplication; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumentation test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.zxing.cameraapplication", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /cameraapplication/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /cameraapplication/src/main/java/com/zxing/cameraapplication/CameraActivity.java: -------------------------------------------------------------------------------- 1 | package com.zxing.cameraapplication; 2 | 3 | import android.content.Intent; 4 | import android.content.pm.ActivityInfo; 5 | import android.graphics.Bitmap; 6 | import android.os.Build; 7 | import android.os.Bundle; 8 | import android.os.Environment; 9 | import android.support.v7.app.AppCompatActivity; 10 | import android.util.Log; 11 | import android.view.View; 12 | import android.view.WindowManager; 13 | import android.widget.Toast; 14 | 15 | import com.cjt2325.cameralibrary.JCameraView; 16 | import com.cjt2325.cameralibrary.listener.ClickListener; 17 | import com.cjt2325.cameralibrary.listener.ErrorListener; 18 | import com.cjt2325.cameralibrary.listener.JCameraListener; 19 | import com.cjt2325.cameralibrary.util.DeviceUtil; 20 | import com.cjt2325.cameralibrary.util.FileUtil; 21 | 22 | import java.io.File; 23 | 24 | public class CameraActivity extends AppCompatActivity { 25 | private JCameraView jCameraView; 26 | 27 | @Override 28 | protected void onCreate(Bundle savedInstanceState) { 29 | super.onCreate(savedInstanceState); 30 | getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); 31 | setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); 32 | setContentView(R.layout.activity_camera); 33 | jCameraView = (JCameraView) findViewById(R.id.jcameraview); 34 | //设置视频保存路径 35 | jCameraView.setSaveVideoPath(Environment.getExternalStorageDirectory().getPath() + File.separator + "JCamera"); 36 | jCameraView.setFeatures(JCameraView.BUTTON_STATE_BOTH); 37 | jCameraView.setTip("JCameraView Tip"); 38 | jCameraView.setMediaQuality(JCameraView.MEDIA_QUALITY_MIDDLE); 39 | jCameraView.setErrorLisenter(new ErrorListener() { 40 | @Override 41 | public void onError() { 42 | //错误监听 43 | Log.i("CJT", "camera error"); 44 | Intent intent = new Intent(); 45 | setResult(103, intent); 46 | finish(); 47 | } 48 | 49 | @Override 50 | public void AudioPermissionError() { 51 | Toast.makeText(CameraActivity.this, "给点录音权限可以?", Toast.LENGTH_SHORT).show(); 52 | } 53 | }); 54 | //JCameraView监听 55 | jCameraView.setJCameraLisenter(new JCameraListener() { 56 | @Override 57 | public void captureSuccess(Bitmap bitmap) { 58 | //获取图片bitmap 59 | // Log.i("JCameraView", "bitmap = " + bitmap.getWidth()); 60 | String path = FileUtil.saveBitmap("JCamera", bitmap); 61 | Intent intent = new Intent(); 62 | intent.putExtra("path", path); 63 | setResult(101, intent); 64 | finish(); 65 | } 66 | 67 | @Override 68 | public void recordSuccess(String url, Bitmap firstFrame) { 69 | //获取视频路径 70 | String path = FileUtil.saveBitmap("JCamera", firstFrame); 71 | Log.i("CJT", "url = " + url + ", Bitmap = " + path); 72 | Intent intent = new Intent(); 73 | intent.putExtra("path", path); 74 | setResult(101, intent); 75 | finish(); 76 | } 77 | }); 78 | 79 | jCameraView.setLeftClickListener(new ClickListener() { 80 | @Override 81 | public void onClick() { 82 | CameraActivity.this.finish(); 83 | } 84 | }); 85 | jCameraView.setRightClickListener(new ClickListener() { 86 | @Override 87 | public void onClick() { 88 | Toast.makeText(CameraActivity.this,"Right",Toast.LENGTH_SHORT).show(); 89 | } 90 | }); 91 | 92 | Log.i("CJT", DeviceUtil.getDeviceModel()); 93 | } 94 | 95 | @Override 96 | protected void onStart() { 97 | super.onStart(); 98 | //全屏显示 99 | if (Build.VERSION.SDK_INT >= 19) { 100 | View decorView = getWindow().getDecorView(); 101 | decorView.setSystemUiVisibility( 102 | View.SYSTEM_UI_FLAG_LAYOUT_STABLE 103 | | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 104 | | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN 105 | | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION 106 | | View.SYSTEM_UI_FLAG_FULLSCREEN 107 | | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); 108 | } else { 109 | View decorView = getWindow().getDecorView(); 110 | int option = View.SYSTEM_UI_FLAG_FULLSCREEN; 111 | decorView.setSystemUiVisibility(option); 112 | } 113 | } 114 | 115 | @Override 116 | protected void onResume() { 117 | super.onResume(); 118 | jCameraView.onResume(); 119 | } 120 | 121 | @Override 122 | protected void onPause() { 123 | super.onPause(); 124 | jCameraView.onPause(); 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /cameraapplication/src/main/java/com/zxing/cameraapplication/CameraApplication.java: -------------------------------------------------------------------------------- 1 | package com.zxing.cameraapplication; 2 | 3 | import android.app.Application; 4 | import android.content.Context; 5 | 6 | import com.squareup.leakcanary.LeakCanary; 7 | import com.squareup.leakcanary.RefWatcher; 8 | 9 | /** 10 | * ===================================== 11 | * 作 者: 陈嘉桐 12 | * 版 本:1.1.4 13 | * 创建日期:2017/5/8 14 | * 描 述: 15 | * ===================================== 16 | */ 17 | public class CameraApplication extends Application { 18 | @Override 19 | public void onCreate() { 20 | super.onCreate(); 21 | if (LeakCanary.isInAnalyzerProcess(this)) { 22 | // This process is dedicated to LeakCanary for heap analysis. 23 | // You should not init your app in this process. 24 | return; 25 | } 26 | LeakCanary.install(this); 27 | // Normal app init code... 28 | } 29 | 30 | public static RefWatcher getRefWatcher(Context context) { 31 | CameraApplication application = (CameraApplication) context.getApplicationContext(); 32 | return application.refWatcher; 33 | } 34 | 35 | private RefWatcher refWatcher; 36 | } 37 | -------------------------------------------------------------------------------- /cameraapplication/src/main/java/com/zxing/cameraapplication/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.zxing.cameraapplication; 2 | 3 | import android.Manifest; 4 | import android.annotation.TargetApi; 5 | import android.content.Intent; 6 | import android.content.pm.PackageManager; 7 | import android.graphics.BitmapFactory; 8 | import android.os.Build; 9 | import android.os.Bundle; 10 | import android.support.v4.app.ActivityCompat; 11 | import android.support.v4.content.ContextCompat; 12 | import android.support.v7.app.AppCompatActivity; 13 | import android.util.Log; 14 | import android.view.View; 15 | import android.widget.ImageView; 16 | import android.widget.TextView; 17 | import android.widget.Toast; 18 | 19 | import com.cjt2325.cameralibrary.util.DeviceUtil; 20 | 21 | public class MainActivity extends AppCompatActivity { 22 | private final int GET_PERMISSION_REQUEST = 100; //权限申请自定义码 23 | private ImageView photo; 24 | private TextView device; 25 | 26 | @Override 27 | protected void onCreate(Bundle savedInstanceState) { 28 | super.onCreate(savedInstanceState); 29 | setContentView(R.layout.activity_main); 30 | findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() { 31 | @Override 32 | public void onClick(View v) { 33 | getPermissions(); 34 | } 35 | }); 36 | photo = (ImageView) findViewById(R.id.image_photo); 37 | device = (TextView) findViewById(R.id.device); 38 | device.setText(DeviceUtil.getDeviceInfo()); 39 | } 40 | 41 | /** 42 | * 获取权限 43 | */ 44 | private void getPermissions() { 45 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 46 | if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager 47 | .PERMISSION_GRANTED && 48 | ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) == PackageManager 49 | .PERMISSION_GRANTED && 50 | ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager 51 | .PERMISSION_GRANTED) { 52 | startActivityForResult(new Intent(MainActivity.this, CameraActivity.class), 100); 53 | } else { 54 | //不具有获取权限,需要进行权限申请 55 | ActivityCompat.requestPermissions(MainActivity.this, new String[]{ 56 | Manifest.permission.WRITE_EXTERNAL_STORAGE, 57 | Manifest.permission.RECORD_AUDIO, 58 | Manifest.permission.CAMERA}, GET_PERMISSION_REQUEST); 59 | } 60 | } else { 61 | startActivityForResult(new Intent(MainActivity.this, CameraActivity.class), 100); 62 | } 63 | } 64 | 65 | @Override 66 | protected void onActivityResult(int requestCode, int resultCode, Intent data) { 67 | super.onActivityResult(requestCode, resultCode, data); 68 | if (resultCode == 101) { 69 | Log.i("CJT", "picture"); 70 | String path = data.getStringExtra("path"); 71 | photo.setImageBitmap(BitmapFactory.decodeFile(path)); 72 | } 73 | if (resultCode == 102) { 74 | Log.i("CJT", "video"); 75 | String path = data.getStringExtra("path"); 76 | } 77 | if (resultCode == 103) { 78 | Toast.makeText(this, "请检查相机权限~", Toast.LENGTH_SHORT).show(); 79 | } 80 | } 81 | 82 | @TargetApi(23) 83 | @Override 84 | public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { 85 | super.onRequestPermissionsResult(requestCode, permissions, grantResults); 86 | if (requestCode == GET_PERMISSION_REQUEST) { 87 | int size = 0; 88 | if (grantResults.length >= 1) { 89 | int writeResult = grantResults[0]; 90 | //读写内存权限 91 | boolean writeGranted = writeResult == PackageManager.PERMISSION_GRANTED;//读写内存权限 92 | if (!writeGranted) { 93 | size++; 94 | } 95 | //录音权限 96 | int recordPermissionResult = grantResults[1]; 97 | boolean recordPermissionGranted = recordPermissionResult == PackageManager.PERMISSION_GRANTED; 98 | if (!recordPermissionGranted) { 99 | size++; 100 | } 101 | //相机权限 102 | int cameraPermissionResult = grantResults[2]; 103 | boolean cameraPermissionGranted = cameraPermissionResult == PackageManager.PERMISSION_GRANTED; 104 | if (!cameraPermissionGranted) { 105 | size++; 106 | } 107 | if (size == 0) { 108 | startActivityForResult(new Intent(MainActivity.this, CameraActivity.class), 100); 109 | } else { 110 | Toast.makeText(this, "请到设置-权限管理中开启", Toast.LENGTH_SHORT).show(); 111 | } 112 | } 113 | } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /cameraapplication/src/main/res/drawable/ic_back.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /cameraapplication/src/main/res/drawable/ic_camera_enhance_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /cameraapplication/src/main/res/drawable/ic_capture.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /cameraapplication/src/main/res/drawable/ic_photo.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /cameraapplication/src/main/res/layout/activity_camera.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 20 | 21 | -------------------------------------------------------------------------------- /cameraapplication/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 19 | 20 | 29 | 30 | 36 | 37 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /cameraapplication/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CJT2325/CameraView/c9d291102a2e1a883d8dd4f657977bd94dd750b2/cameraapplication/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /cameraapplication/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CJT2325/CameraView/c9d291102a2e1a883d8dd4f657977bd94dd750b2/cameraapplication/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /cameraapplication/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CJT2325/CameraView/c9d291102a2e1a883d8dd4f657977bd94dd750b2/cameraapplication/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /cameraapplication/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CJT2325/CameraView/c9d291102a2e1a883d8dd4f657977bd94dd750b2/cameraapplication/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /cameraapplication/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CJT2325/CameraView/c9d291102a2e1a883d8dd4f657977bd94dd750b2/cameraapplication/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /cameraapplication/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /cameraapplication/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | -------------------------------------------------------------------------------- /cameraapplication/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 6 | -------------------------------------------------------------------------------- /cameraapplication/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | CameraApplication 3 | 4 | -------------------------------------------------------------------------------- /cameraapplication/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /cameraapplication/src/test/java/com/zxing/cameraapplication/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.zxing.cameraapplication; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() throws Exception { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CJT2325/CameraView/c9d291102a2e1a883d8dd4f657977bd94dd750b2/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Mar 01 20:51:02 CST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | #distributionUrl=file:///D:/gradle_offline/gradle-2.14.1-all.zip 7 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip 8 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /kotlin-jcameraview/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /kotlin-jcameraview/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'kotlin-android' 3 | 4 | android { 5 | compileSdkVersion 25 6 | buildToolsVersion "25.0.1" 7 | 8 | defaultConfig { 9 | minSdkVersion 14 10 | targetSdkVersion 25 11 | versionCode 1 12 | versionName "1.0" 13 | 14 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 15 | 16 | } 17 | buildTypes { 18 | release { 19 | minifyEnabled false 20 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 21 | } 22 | } 23 | } 24 | 25 | dependencies { 26 | compile fileTree(dir: 'libs', include: ['*.jar']) 27 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 28 | exclude group: 'com.android.support', module: 'support-annotations' 29 | }) 30 | compile 'com.android.support:appcompat-v7:25.3.1' 31 | testCompile 'junit:junit:4.12' 32 | compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version" 33 | } 34 | repositories { 35 | mavenCentral() 36 | } 37 | -------------------------------------------------------------------------------- /kotlin-jcameraview/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in D:\Users\Administrator\AppData\Local\Android\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /kotlin-jcameraview/src/androidTest/java/com/cjt2325/kotlin_jcameraview/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.cjt2325.kotlin_jcameraview; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumentation test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.cjt2325.kotlin_jcameraview.test", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /kotlin-jcameraview/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /kotlin-jcameraview/src/main/java/com/cjt2325/kotlin_jcameraview/AutoFitTextureView.kt: -------------------------------------------------------------------------------- 1 | package com.cjt2325.kotlin_jcameraview 2 | 3 | import android.content.Context 4 | import android.util.AttributeSet 5 | import android.view.TextureView 6 | 7 | 8 | /** 9 | * ===================================== 10 | * 作 者: 陈嘉桐 11 | * 版 本:1.1.4 12 | * 创建日期:2017/8/11 13 | * 描 述: 14 | * ===================================== 15 | */ 16 | class AutoFitTextureView constructor(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0) : TextureView(context, attrs, defStyle) { 17 | 18 | private var mRatioWidth = 0 19 | private var mRatioHeight = 0 20 | 21 | fun setAspectRatio(width: Int, height: Int) { 22 | if (width < 0 || height < 0) { 23 | throw IllegalArgumentException("Size cannot be negative.") 24 | } 25 | mRatioWidth = width 26 | mRatioHeight = height 27 | requestLayout() 28 | } 29 | 30 | override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { 31 | super.onMeasure(widthMeasureSpec, heightMeasureSpec) 32 | val width = MeasureSpec.getSize(widthMeasureSpec) 33 | val height = MeasureSpec.getSize(heightMeasureSpec) 34 | if (0 == mRatioWidth || 0 == mRatioHeight) { 35 | setMeasuredDimension(width, height) 36 | } else { 37 | if (width < height * mRatioWidth / mRatioHeight) { 38 | setMeasuredDimension(width, width * mRatioHeight / mRatioWidth) 39 | } else { 40 | setMeasuredDimension(height * mRatioWidth / mRatioHeight, height) 41 | } 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /kotlin-jcameraview/src/main/java/com/cjt2325/kotlin_jcameraview/CaptureButton.kt: -------------------------------------------------------------------------------- 1 | package com.cjt2325.kotlin_jcameraview 2 | 3 | import android.animation.Animator 4 | import android.animation.AnimatorListenerAdapter 5 | import android.animation.AnimatorSet 6 | import android.animation.ValueAnimator 7 | import android.content.Context 8 | import android.graphics.Canvas 9 | import android.graphics.Paint 10 | import android.graphics.RectF 11 | import android.os.CountDownTimer 12 | import android.view.MotionEvent 13 | import android.view.View 14 | import com.cjt2325.kotlin_jcameraview.listener.CaptureListener 15 | 16 | /** 17 | * ===================================== 18 | * 作 者: 陈嘉桐 19 | * 版 本:Kotlin 20 | * 创建日期:2017/8/9 21 | * 描 述:拍照按钮 22 | * ===================================== 23 | */ 24 | class CaptureButton(context: Context, size: Float) : View(context) { 25 | 26 | private var state: Int; 27 | private val STATE_IDLE = 0x001//空闲状态 28 | private val STATE_PRESS = 0x002//按下状态 29 | private val STATE_LONG_PRESS = 0x003//进入长按状态 30 | private val STATE_RECORDERING = 0x004//录制状态 31 | 32 | private var mPaint: Paint = Paint() 33 | 34 | private var button_size: Float //控件大小 35 | private val strokeWidth: Float //进度条宽度 36 | 37 | private var button_outside_radius: Float //外圆半径 38 | private var button_inside_radius: Float //内圆半径 39 | 40 | private val outside_add_size: Float //长按外圆半径变大的Size 41 | private val inside_reduce_size: Float //长安内圆缩小的Size 42 | 43 | private var center_X: Float //X轴中心 44 | private var center_Y: Float //Y轴中心 45 | 46 | private var touch_Y: Float = 0f//Touch_Event_Down时候记录的Y值 47 | 48 | var max_duration: Long = 5000//录制最长时间,默认为10s 49 | var recorder_time: Long = 0 //保存录制了多长时间 50 | var progress_color: Int = 0xEE16AE16.toInt()//进度条颜色 51 | var outside_color: Int = 0xEECCCCCC.toInt()//外圆背景色 52 | var inside_color: Int = 0xFFFFFFFF.toInt()//内圆背景色 53 | 54 | 55 | private var progress: Float = 0f//录制视频的进度 56 | private val rectF: RectF 57 | 58 | private var recorderTimer: RecorderTimer 59 | 60 | var mCaptureListener: CaptureListener? = null 61 | 62 | 63 | /** 64 | * 主构造函数初始化代码块 65 | */ 66 | init { 67 | state = STATE_IDLE 68 | 69 | button_size = size 70 | button_outside_radius = size / 2 71 | button_inside_radius = size / 2 * 0.75f 72 | 73 | strokeWidth = size / 15 //精度条宽度 74 | outside_add_size = size / 5 //长按外圆增加的半径 75 | inside_reduce_size = size / 8 //长按内圆减少的半径 76 | //控件中心 77 | center_X = (button_size + outside_add_size * 2) / 2 78 | center_Y = (button_size + outside_add_size * 2) / 2 79 | //精度条矩形范围 80 | rectF = RectF( 81 | center_X - (size / 2 + outside_add_size - strokeWidth / 2), 82 | center_Y - (size / 2 + outside_add_size - strokeWidth / 2), 83 | center_X + (size / 2 + outside_add_size - strokeWidth / 2), 84 | center_Y + (size / 2 + outside_add_size - strokeWidth / 2)) 85 | 86 | mPaint.isAntiAlias = true//抗锯齿 87 | 88 | recorderTimer = RecorderTimer(max_duration, max_duration / 360) 89 | } 90 | 91 | override fun onDraw(canvas: Canvas) { 92 | super.onDraw(canvas) 93 | mPaint.style = Paint.Style.FILL 94 | mPaint.color = outside_color//外圆(默认半透明灰色) 95 | canvas.drawCircle(center_X, center_Y, button_outside_radius, mPaint) 96 | mPaint.color = inside_color//内圆(默认白色) 97 | canvas.drawCircle(center_X, center_Y, button_inside_radius, mPaint) 98 | 99 | //如果状态为按钮长按按下的状态,则绘制录制进度条 100 | if (state == STATE_RECORDERING) { 101 | mPaint.color = progress_color 102 | mPaint.style = Paint.Style.STROKE 103 | mPaint.strokeWidth = strokeWidth 104 | canvas.drawArc(rectF, -90f, progress, false, mPaint) 105 | } 106 | } 107 | 108 | //长按线程 109 | private val longPressRunnable = Runnable { 110 | state = STATE_LONG_PRESS //状态为长按状态 111 | startAnimation( 112 | button_outside_radius, 113 | button_outside_radius + outside_add_size, 114 | button_inside_radius, 115 | button_inside_radius - inside_reduce_size 116 | ) 117 | } 118 | 119 | override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { 120 | super.onMeasure(widthMeasureSpec, heightMeasureSpec) 121 | setMeasuredDimension( 122 | (button_size + outside_add_size * 2).toInt(), 123 | (button_size + outside_add_size * 2).toInt()) 124 | } 125 | 126 | 127 | override fun onTouchEvent(event: MotionEvent): Boolean { 128 | when (event.action) { 129 | MotionEvent.ACTION_DOWN -> { 130 | touch_Y = event.y //记录Y值 131 | state = STATE_PRESS //状态为按下状态 132 | postDelayed(longPressRunnable, 500) 133 | } 134 | MotionEvent.ACTION_MOVE -> { 135 | 136 | } 137 | MotionEvent.ACTION_UP -> { 138 | handlerUnpressByState() 139 | } 140 | } 141 | return true 142 | } 143 | 144 | /** 145 | * 录制视频按钮动画 146 | * @param outside_start 外圆起始半径 147 | * @param outside_end 外圆结束半径 148 | * @param inside_start 内圆起始半径 149 | * @param inside_end 内圆结束半径 150 | */ 151 | private fun startAnimation(outside_start: Float, outside_end: Float, inside_start: Float, inside_end: Float) { 152 | val outside_anim = ValueAnimator.ofFloat(outside_start, outside_end) 153 | val inside_anim = ValueAnimator.ofFloat(inside_start, inside_end) 154 | //外圆 155 | outside_anim.addUpdateListener { animation -> 156 | button_outside_radius = animation.animatedValue as Float 157 | invalidate() 158 | } 159 | //内圆 160 | inside_anim.addUpdateListener { animation -> 161 | button_inside_radius = animation.animatedValue as Float 162 | invalidate() 163 | } 164 | //当动画结束后启动录像Runnable并且回调录像开始接口 165 | var animSet: AnimatorSet = AnimatorSet() 166 | animSet.playTogether(outside_anim, inside_anim) 167 | animSet.addListener(object : AnimatorListenerAdapter() { 168 | override fun onAnimationEnd(animation: Animator?) { 169 | super.onAnimationEnd(animation) 170 | if (state == STATE_LONG_PRESS) { 171 | state = STATE_RECORDERING 172 | if (mCaptureListener != null) 173 | mCaptureListener?.recorderStart() 174 | recorderTimer.start() 175 | } 176 | } 177 | }) 178 | animSet.duration = 100 179 | animSet.start() 180 | } 181 | 182 | /** 183 | * 松开手指处理的逻辑 184 | */ 185 | private fun handlerUnpressByState() { 186 | removeCallbacks(longPressRunnable)//移除长按逻辑的Runnable 187 | when (state) { 188 | STATE_PRESS -> { 189 | captureAnimation() 190 | } 191 | STATE_RECORDERING -> { 192 | recorderTimer.cancel() 193 | recordEnd()//录制结束 194 | } 195 | STATE_LONG_PRESS -> { 196 | resetRecordAnim() 197 | captureAnimation() 198 | } 199 | } 200 | this.state = STATE_IDLE //制空当前状态 201 | } 202 | 203 | /** 204 | * 拍照时按钮动画 205 | */ 206 | private fun captureAnimation() { 207 | val captureAnim = ValueAnimator.ofFloat(button_inside_radius, button_inside_radius - inside_reduce_size, button_size / 2 * 0.75f) 208 | captureAnim.addUpdateListener { animation -> 209 | button_inside_radius = animation.animatedValue as Float 210 | invalidate() 211 | } 212 | captureAnim.addListener(object : AnimatorListenerAdapter() { 213 | override fun onAnimationEnd(animation: Animator?) { 214 | super.onAnimationEnd(animation) 215 | if (mCaptureListener != null) 216 | mCaptureListener?.caputre() 217 | } 218 | }) 219 | captureAnim.duration = 100 220 | captureAnim.start() 221 | } 222 | 223 | /** 224 | * 录制结束 225 | */ 226 | fun recordEnd() { 227 | if (state != STATE_RECORDERING) 228 | return 229 | if (recorder_time < 1500) { 230 | if (mCaptureListener != null) 231 | mCaptureListener?.recorderShort() 232 | // i("录制时间小于1500") 233 | } else { 234 | if (mCaptureListener != null) 235 | mCaptureListener?.recorderEnd(recorder_time) 236 | } 237 | resetRecordAnim() 238 | } 239 | 240 | /** 241 | * 重置 242 | */ 243 | fun resetRecordAnim() { 244 | progress = 0f 245 | invalidate() 246 | state = STATE_IDLE //录制结束状态为(空闲) 247 | startAnimation( 248 | button_outside_radius, 249 | button_size / 2, 250 | button_inside_radius, 251 | button_size / 2 * 0.75f 252 | ) 253 | } 254 | 255 | fun updateProgress(millisUntilFinished: Long) { 256 | recorder_time = max_duration - millisUntilFinished 257 | this.progress = 360f - millisUntilFinished / max_duration.toFloat() * 360 258 | invalidate() 259 | } 260 | 261 | inner class RecorderTimer(millisInFuture: Long, countDownInterval: Long) : CountDownTimer(millisInFuture, countDownInterval) { 262 | override fun onFinish() { 263 | updateProgress(0) 264 | recordEnd() 265 | } 266 | 267 | override fun onTick(millisUntilFinished: Long) { 268 | updateProgress(millisUntilFinished) 269 | } 270 | } 271 | 272 | /** 273 | * 回调 274 | */ 275 | 276 | } -------------------------------------------------------------------------------- /kotlin-jcameraview/src/main/java/com/cjt2325/kotlin_jcameraview/CaptureLayout.kt: -------------------------------------------------------------------------------- 1 | package com.cjt2325.kotlin_jcameraview 2 | 3 | import android.animation.Animator 4 | import android.animation.AnimatorListenerAdapter 5 | import android.animation.ObjectAnimator 6 | import android.content.Context 7 | import android.view.Gravity 8 | import android.view.View 9 | import android.widget.FrameLayout 10 | import android.widget.TextView 11 | import com.cjt2325.kotlin_jcameraview.listener.CaptureListener 12 | import com.cjt2325.kotlin_jcameraview.listener.QuitListener 13 | import com.cjt2325.kotlin_jcameraview.listener.TypeListener 14 | import com.cjt2325.kotlin_jcameraview.util.getScreenWidth 15 | 16 | /** 17 | * ===================================== 18 | * 作 者: 陈嘉桐 19 | * 版 本:Kotlin 20 | * 创建日期:2017/8/10 21 | * 描 述: 22 | * ===================================== 23 | */ 24 | class CaptureLayout(context: Context) : FrameLayout(context) { 25 | 26 | private var layout_width: Int 27 | private var layout_height: Int 28 | private var button_size: Float 29 | 30 | private var captureButton: CaptureButton 31 | private var cancleButton: TypeButton 32 | private var confirmButton: TypeButton 33 | private var quitButton: QuitButton 34 | private var textView_tip: TextView 35 | 36 | var mCaptureListener: CaptureListener? = null 37 | var mQuitListener: QuitListener? = null 38 | var mTypeListener: TypeListener? = null 39 | 40 | init { 41 | layout_width = getScreenWidth(context) //CaptureLayout宽度 42 | button_size = layout_width / 4.5f //按钮大小 43 | layout_height = (button_size + (button_size / 5) * 2 + 100).toInt() //CaptureLayout高度 44 | 45 | //拍照按钮(CaptureButton) 46 | captureButton = CaptureButton(context, button_size) 47 | val capture_param = FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT) 48 | capture_param.gravity = Gravity.CENTER 49 | captureButton.layoutParams = capture_param 50 | 51 | //取消按钮(TypeButton) 52 | cancleButton = TypeButton(context, TypeButton.Companion.TYPE_CANCEL, button_size) 53 | val cancle_param = FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT) 54 | cancle_param.gravity = Gravity.CENTER_VERTICAL 55 | cancle_param.setMargins(layout_width / 6, 0, 0, 0) 56 | cancleButton.layoutParams = cancle_param 57 | // 58 | //确定按钮(TypeButton) 59 | confirmButton = TypeButton(context, TypeButton.Companion.TYPE_CONFIRM, button_size) 60 | val confirm_param = FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT) 61 | confirm_param.gravity = Gravity.CENTER_VERTICAL or Gravity.RIGHT 62 | confirm_param.setMargins(0, 0, layout_width / 6, 0) 63 | confirmButton.layoutParams = confirm_param 64 | 65 | //取消按钮(TypeButton) 66 | quitButton = QuitButton(context, (button_size * 0.4).toInt()) 67 | val quit_param = FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT) 68 | quit_param.gravity = Gravity.CENTER_VERTICAL 69 | quit_param.setMargins(layout_width / 6, 0, 0, 0) 70 | quitButton.layoutParams = quit_param 71 | 72 | 73 | //内容提示 74 | textView_tip = TextView(context) 75 | textView_tip.setTextColor(0xFFFFFFFF.toInt()) 76 | textView_tip.text = "Kotlin JCamera" 77 | val tip_param = FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.MATCH_PARENT) 78 | tip_param.gravity = Gravity.CENTER_HORIZONTAL 79 | textView_tip.layoutParams = tip_param 80 | 81 | this.addView(captureButton) 82 | this.addView(quitButton) 83 | this.addView(cancleButton) 84 | this.addView(confirmButton) 85 | this.addView(textView_tip) 86 | 87 | cancleButton.visibility = View.INVISIBLE 88 | confirmButton.visibility = View.INVISIBLE 89 | 90 | initListener() 91 | } 92 | 93 | private fun initListener() { 94 | cancleButton.setOnClickListener { 95 | resetLayout() 96 | if (mTypeListener != null) 97 | mTypeListener?.cancle() 98 | } 99 | confirmButton.setOnClickListener { 100 | resetLayout() 101 | if (mTypeListener != null) 102 | mTypeListener?.confirm() 103 | } 104 | 105 | quitButton.setOnClickListener { 106 | if (mQuitListener != null) 107 | mQuitListener?.quit() 108 | } 109 | 110 | captureButton.mCaptureListener = object : CaptureListener { 111 | override fun error(error: String) { 112 | } 113 | 114 | override fun recorderZoom() { 115 | } 116 | 117 | 118 | override fun recorderEnd(time: Long) { 119 | startButtonAnimation() 120 | if (mCaptureListener != null) 121 | mCaptureListener?.recorderEnd(time) 122 | } 123 | 124 | override fun recorderShort() { 125 | if (mCaptureListener != null) 126 | mCaptureListener?.recorderShort() 127 | } 128 | 129 | override fun caputre() { 130 | startButtonAnimation() 131 | if (mCaptureListener != null) 132 | mCaptureListener?.caputre() 133 | } 134 | 135 | override fun recorderStart() { 136 | if (mCaptureListener != null) 137 | mCaptureListener?.recorderStart() 138 | } 139 | } 140 | } 141 | 142 | fun startButtonAnimation() { 143 | cancleButton.visibility = View.VISIBLE 144 | confirmButton.visibility = View.VISIBLE 145 | captureButton.visibility = View.INVISIBLE 146 | quitButton.visibility = View.INVISIBLE 147 | //拍照录制结果后的动画 148 | cancleButton.isClickable = false 149 | confirmButton.isClickable = false 150 | val animator_cancel = ObjectAnimator.ofFloat(cancleButton, "translationX", layout_width / 4f, 0f) 151 | animator_cancel.duration = 200 152 | animator_cancel.start() 153 | val animator_confirm = ObjectAnimator.ofFloat(confirmButton, "translationX", -layout_width / 4f, 0f) 154 | animator_confirm.duration = 200 155 | animator_confirm.start() 156 | animator_confirm.addListener(object : AnimatorListenerAdapter() { 157 | override fun onAnimationEnd(animation: Animator) { 158 | super.onAnimationEnd(animation) 159 | cancleButton.isClickable = true 160 | cancleButton.isClickable = true 161 | } 162 | }) 163 | } 164 | 165 | fun resetLayout() { 166 | cancleButton.visibility = View.INVISIBLE 167 | confirmButton.visibility = View.INVISIBLE 168 | captureButton.visibility = View.VISIBLE 169 | quitButton.visibility = View.VISIBLE 170 | } 171 | 172 | override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { 173 | super.onMeasure(widthMeasureSpec, heightMeasureSpec) 174 | setMeasuredDimension(layout_width, layout_height) 175 | } 176 | } -------------------------------------------------------------------------------- /kotlin-jcameraview/src/main/java/com/cjt2325/kotlin_jcameraview/JCameraView.kt: -------------------------------------------------------------------------------- 1 | package com.cjt2325.kotlin_jcameraview 2 | 3 | import android.content.Context 4 | import android.graphics.SurfaceTexture 5 | import android.os.Build 6 | import android.support.annotation.RequiresApi 7 | import android.util.AttributeSet 8 | import android.view.Gravity 9 | import android.view.TextureView 10 | import android.widget.FrameLayout 11 | import android.widget.ImageView 12 | import com.cjt2325.kotlin_jcameraview.listener.CaptureListener 13 | import com.cjt2325.kotlin_jcameraview.listener.QuitListener 14 | import com.cjt2325.kotlin_jcameraview.listener.TypeListener 15 | import com.cjt2325.kotlin_jcameraview.util.getScreenHeight 16 | import com.cjt2325.kotlin_jcameraview.util.getScreenWidth 17 | import com.cjt2325.kotlin_jcameraview.util.i 18 | 19 | /** 20 | * ===================================== 21 | * 作 者: 陈嘉桐 22 | * 版 本:Kotlin 23 | * 创建日期:2017/8/10 24 | * 描 述: 25 | * ===================================== 26 | */ 27 | class JCameraView : FrameLayout, TextureView.SurfaceTextureListener { 28 | 29 | var textureView: AutoFitTextureView 30 | var captureLayout: CaptureLayout 31 | var switchCamera: ImageView 32 | var switchFlash: ImageView 33 | 34 | init { 35 | textureView = AutoFitTextureView(context) 36 | captureLayout = CaptureLayout(context) 37 | switchCamera = ImageView(context) 38 | switchFlash = ImageView(context) 39 | } 40 | 41 | constructor(context: Context?) : this(context, null) 42 | constructor(context: Context?, attrs: AttributeSet?) : this(context, attrs, 0) 43 | constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { 44 | initAttr(attrs) 45 | initView() 46 | initListener() 47 | } 48 | 49 | constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) { 50 | initAttr(attrs) 51 | initView() 52 | initListener() 53 | } 54 | 55 | fun initAttr(attrs: AttributeSet?) { 56 | 57 | } 58 | 59 | fun initView() { 60 | //CaptureLayout 61 | val captureLayout_param = FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT) 62 | captureLayout_param.gravity = Gravity.BOTTOM 63 | captureLayout.layoutParams = captureLayout_param 64 | 65 | //TextureView 66 | val textureView_param = FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT) 67 | textureView.layoutParams = textureView_param 68 | textureView.surfaceTextureListener = this 69 | 70 | val switchcamera_param = FrameLayout.LayoutParams(60, 60) 71 | switchcamera_param.gravity = Gravity.RIGHT 72 | switchcamera_param.setMargins(16, 16, 16, 16) 73 | switchCamera.layoutParams = switchcamera_param 74 | switchCamera.setImageResource(R.drawable.ic_camera) 75 | 76 | val switchflash_param = FrameLayout.LayoutParams(60, 60) 77 | switchflash_param.gravity = Gravity.RIGHT 78 | switchflash_param.setMargins(16, 16, 48 + 60, 16) 79 | switchFlash.layoutParams = switchflash_param 80 | switchFlash.setImageResource(R.drawable.ic_brightness) 81 | 82 | this.addView(textureView) 83 | this.addView(captureLayout) 84 | this.addView(switchCamera) 85 | this.addView(switchFlash) 86 | 87 | } 88 | 89 | fun initListener() { 90 | captureLayout.mQuitListener = object : QuitListener { 91 | override fun quit() { 92 | i("JCameraView : quit") 93 | } 94 | } 95 | captureLayout.mTypeListener = object : TypeListener { 96 | override fun confirm() { 97 | i("JCameraView : confirm") 98 | } 99 | 100 | override fun cancle() { 101 | i("JCameraView : cancle") 102 | } 103 | } 104 | captureLayout.mCaptureListener = object : CaptureListener { 105 | override fun error(error: String) { 106 | } 107 | 108 | override fun recorderZoom() { 109 | 110 | } 111 | 112 | override fun caputre() { 113 | CameraNewInterface.getInstance().takePicture() 114 | i("JCameraView : caputre") 115 | } 116 | 117 | override fun recorderEnd(time: Long) { 118 | i("JCameraView : recorderEnd") 119 | } 120 | 121 | override fun recorderShort() { 122 | i("JCameraView : recorderShort") 123 | } 124 | 125 | override fun recorderStart() { 126 | i("JCameraView : recorderStart") 127 | } 128 | 129 | } 130 | } 131 | 132 | fun onResume() { 133 | i("JCameraView onResume") 134 | } 135 | 136 | fun onPause() { 137 | i("JCameraView onPause") 138 | } 139 | 140 | 141 | //TextureView监听 142 | @RequiresApi(Build.VERSION_CODES.LOLLIPOP) 143 | override fun onSurfaceTextureAvailable(surface: SurfaceTexture?, width: Int, height: Int) { 144 | //锁屏再解锁不会回调onSurfaceTextureAvailable 145 | //打开Camera并启动浏览 146 | i("width = " + getScreenWidth(context) + " height = " + getScreenHeight(context)); 147 | i("Texturewidth = " + width + " Textureheight = " + height); 148 | CameraNewInterface.Companion.getInstance().openCamera(context, textureView, width, height); 149 | } 150 | 151 | @RequiresApi(Build.VERSION_CODES.LOLLIPOP) 152 | override fun onSurfaceTextureDestroyed(surface: SurfaceTexture?): Boolean { 153 | //锁屏会回调销毁(onSurfaceTextureDestroyed) 154 | i("onSurfaceTextureDestroyed") 155 | CameraNewInterface.Companion.getInstance().stopCamera() 156 | return true 157 | } 158 | 159 | override fun onSurfaceTextureSizeChanged(surface: SurfaceTexture?, width: Int, height: Int) { 160 | i("onSurfaceTextureSizeChanged") 161 | } 162 | 163 | override fun onSurfaceTextureUpdated(surface: SurfaceTexture?) { 164 | // i("onSurfaceTextureUpdated") 165 | } 166 | 167 | } -------------------------------------------------------------------------------- /kotlin-jcameraview/src/main/java/com/cjt2325/kotlin_jcameraview/QuitButton.kt: -------------------------------------------------------------------------------- 1 | package com.cjt2325.kotlin_jcameraview 2 | 3 | import android.content.Context 4 | import android.graphics.Canvas 5 | import android.graphics.Color 6 | import android.graphics.Paint 7 | import android.graphics.Path 8 | import android.view.View 9 | 10 | /** 11 | * ===================================== 12 | * 作 者: 陈嘉桐 13 | * 版 本:1.1.4 14 | * 创建日期:2017/8/16 15 | * 描 述: 16 | * ===================================== 17 | */ 18 | class QuitButton(context: Context, size: Int) : View(context) { 19 | 20 | private val size: Int 21 | private var center_X: Int 22 | private var center_Y: Int 23 | private var strokeWidth: Float 24 | private var paint: Paint 25 | internal var path: Path 26 | 27 | init { 28 | this.size = size 29 | center_X = size / 2 30 | center_Y = size / 2 31 | 32 | strokeWidth = size / 15f 33 | 34 | paint = Paint() 35 | paint.isAntiAlias = true 36 | paint.color = Color.WHITE 37 | paint.style = Paint.Style.STROKE 38 | paint.strokeWidth = strokeWidth 39 | 40 | path = Path() 41 | } 42 | 43 | override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { 44 | setMeasuredDimension(size, size / 2) 45 | } 46 | 47 | override fun onDraw(canvas: Canvas) { 48 | super.onDraw(canvas) 49 | path.moveTo(strokeWidth, strokeWidth / 2) 50 | path.lineTo(center_X.toFloat(), center_Y - strokeWidth / 2) 51 | path.lineTo(size - strokeWidth, strokeWidth / 2) 52 | canvas.drawPath(path, paint) 53 | } 54 | } -------------------------------------------------------------------------------- /kotlin-jcameraview/src/main/java/com/cjt2325/kotlin_jcameraview/TypeButton.kt: -------------------------------------------------------------------------------- 1 | package com.cjt2325.kotlin_jcameraview 2 | 3 | import android.content.Context 4 | import android.graphics.* 5 | import android.view.View 6 | 7 | /** 8 | * ===================================== 9 | * 作 者: 陈嘉桐 10 | * 版 本:Kotlin 11 | * 创建日期:2017/8/10 12 | * 描 述:拍照后处理的按钮 13 | * ===================================== 14 | */ 15 | class TypeButton(context: Context, type: Int, size: Float) : View(context) { 16 | 17 | private val button_size: Int = size.toInt() //按钮大小 18 | private val button_type: Int = type //按钮类型 19 | 20 | private val center_X: Float //按钮X轴中心 21 | private val center_Y: Float //按钮Y轴中心 22 | private val button_radius: Float //按钮半径 23 | 24 | private val mPaint: Paint 25 | private val path: Path 26 | private val strokeWidth: Float 27 | 28 | private val index: Float 29 | private val rectF: RectF 30 | 31 | init { 32 | button_radius = button_size / 2.0f 33 | center_X = size / 2.0f 34 | center_Y = size / 2.0f 35 | 36 | mPaint = Paint() 37 | path = Path() 38 | strokeWidth = size / 50f 39 | index = button_size / 12f 40 | rectF = RectF(center_X, center_Y - index, center_X + index * 2, center_Y + index) 41 | } 42 | 43 | 44 | override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { 45 | super.onMeasure(widthMeasureSpec, heightMeasureSpec) 46 | setMeasuredDimension(button_size, button_size) 47 | } 48 | 49 | override fun onDraw(canvas: Canvas) { 50 | super.onDraw(canvas) 51 | //如果类型为取消,则绘制内部为返回箭头 52 | if (button_type == TYPE_CANCEL) { 53 | mPaint.isAntiAlias = true 54 | mPaint.color = 0xEECCCCCC.toInt() 55 | mPaint.style = Paint.Style.FILL 56 | canvas.drawCircle(center_X, center_Y, button_radius, mPaint) 57 | 58 | mPaint.color = Color.BLACK 59 | mPaint.style = Paint.Style.STROKE 60 | mPaint.strokeWidth = strokeWidth 61 | 62 | path.moveTo(center_X - index / 7, center_Y + index) 63 | path.lineTo(center_X + index, center_Y + index) 64 | 65 | path.arcTo(rectF, 90f, -180f) 66 | path.lineTo(center_X - index, center_Y - index) 67 | canvas.drawPath(path, mPaint) 68 | mPaint.style = Paint.Style.FILL 69 | path.reset() 70 | path.moveTo(center_X - index, (center_Y - index * 1.5).toFloat()) 71 | path.lineTo(center_X - index, (center_Y - index / 2.3).toFloat()) 72 | path.lineTo((center_X - index * 1.6).toFloat(), center_Y - index) 73 | path.close() 74 | canvas.drawPath(path, mPaint) 75 | 76 | } 77 | //如果类型为确认,则绘制绿色勾 78 | if (button_type == TYPE_CONFIRM) { 79 | mPaint.isAntiAlias = true 80 | mPaint.color = 0xFFFFFFFF.toInt() 81 | mPaint.style = Paint.Style.FILL 82 | canvas.drawCircle(center_X, center_Y, button_radius, mPaint) 83 | mPaint.isAntiAlias = true 84 | mPaint.style = Paint.Style.STROKE 85 | mPaint.color = 0xEE16AE16.toInt() 86 | mPaint.strokeWidth = strokeWidth 87 | 88 | path.moveTo(center_X - button_size / 6f, center_Y) 89 | path.lineTo(center_X - button_size / 21.2f, center_Y + button_size / 7.7f) 90 | path.lineTo(center_X + button_size / 4.0f, center_Y - button_size / 8.5f) 91 | path.lineTo(center_X - button_size / 21.2f, center_Y + button_size / 9.4f) 92 | path.close() 93 | canvas.drawPath(path, mPaint) 94 | } 95 | } 96 | 97 | companion object { 98 | val TYPE_CANCEL = 0x001 99 | val TYPE_CONFIRM = 0x002 100 | } 101 | } -------------------------------------------------------------------------------- /kotlin-jcameraview/src/main/java/com/cjt2325/kotlin_jcameraview/listener/CaptureListener.kt: -------------------------------------------------------------------------------- 1 | package com.cjt2325.kotlin_jcameraview.listener 2 | 3 | /** 4 | * ===================================== 5 | * 作 者: 陈嘉桐 6 | * 版 本:1.1.4 7 | * 创建日期:2017/8/16 8 | * 描 述: 9 | * ===================================== 10 | */ 11 | interface CaptureListener { 12 | fun caputre() 13 | fun recorderShort() 14 | fun recorderStart() 15 | fun recorderEnd(time: Long) 16 | fun recorderZoom() 17 | fun error(error: String) 18 | } -------------------------------------------------------------------------------- /kotlin-jcameraview/src/main/java/com/cjt2325/kotlin_jcameraview/listener/JCameraListener.kt: -------------------------------------------------------------------------------- 1 | package com.cjt2325.kotlin_jcameraview.listener 2 | 3 | /** 4 | * ===================================== 5 | * 作 者: 陈嘉桐 6 | * 版 本:1.1.4 7 | * 创建日期:2017/8/16 8 | * 描 述: 9 | * ===================================== 10 | */ 11 | interface JCameraListener { 12 | fun caputre() 13 | fun recorderShort() 14 | fun recorderStart() 15 | fun recorderEnd(time: Long) 16 | fun cancle() 17 | fun confirm() 18 | fun quit() 19 | } -------------------------------------------------------------------------------- /kotlin-jcameraview/src/main/java/com/cjt2325/kotlin_jcameraview/listener/QuitListener.kt: -------------------------------------------------------------------------------- 1 | package com.cjt2325.kotlin_jcameraview.listener 2 | 3 | /** 4 | * ===================================== 5 | * 作 者: 陈嘉桐 6 | * 版 本:1.1.4 7 | * 创建日期:2017/8/16 8 | * 描 述: 9 | * ===================================== 10 | */ 11 | interface QuitListener { 12 | fun quit() 13 | } -------------------------------------------------------------------------------- /kotlin-jcameraview/src/main/java/com/cjt2325/kotlin_jcameraview/listener/TypeListener.kt: -------------------------------------------------------------------------------- 1 | package com.cjt2325.kotlin_jcameraview.listener 2 | 3 | /** 4 | * ===================================== 5 | * 作 者: 陈嘉桐 6 | * 版 本:1.1.4 7 | * 创建日期:2017/8/16 8 | * 描 述: 9 | * ===================================== 10 | */ 11 | interface TypeListener { 12 | fun cancle() 13 | fun confirm() 14 | } -------------------------------------------------------------------------------- /kotlin-jcameraview/src/main/java/com/cjt2325/kotlin_jcameraview/util/CompareSizesByArea.kt: -------------------------------------------------------------------------------- 1 | package com.cjt2325.kotlin_jcameraview.util 2 | 3 | import android.os.Build 4 | import android.support.annotation.RequiresApi 5 | import android.util.Size 6 | import java.util.* 7 | 8 | 9 | /** 10 | * ===================================== 11 | * 作 者: 陈嘉桐 12 | * 版 本:1.1.4 13 | * 创建日期:2017/8/11 14 | * 描 述: 15 | * ===================================== 16 | */ 17 | class CompareSizesByArea : Comparator { 18 | 19 | @RequiresApi(Build.VERSION_CODES.LOLLIPOP) 20 | override fun compare(lhs: Size, rhs: Size): Int { 21 | return java.lang.Long.signum(lhs.width as Long * lhs.height - rhs.width as Long * rhs.height) 22 | } 23 | 24 | 25 | } -------------------------------------------------------------------------------- /kotlin-jcameraview/src/main/java/com/cjt2325/kotlin_jcameraview/util/ImageSaver.kt: -------------------------------------------------------------------------------- 1 | package com.cjt2325.kotlin_jcameraview.util 2 | 3 | import android.media.Image 4 | import android.os.Build 5 | import android.support.annotation.RequiresApi 6 | import java.io.File 7 | import java.io.FileOutputStream 8 | import java.io.IOException 9 | 10 | /** 11 | * ===================================== 12 | * 作 者: 陈嘉桐 13 | * 版 本:1.1.4 14 | * 创建日期:2017/8/11 15 | * 描 述: 16 | * ===================================== 17 | */ 18 | class ImageSaver(private val mImage: Image, private val mFile: File) : Runnable { 19 | @RequiresApi(Build.VERSION_CODES.KITKAT) 20 | override fun run() { 21 | val buffer = mImage.getPlanes()[0].getBuffer() 22 | val bytes = ByteArray(buffer.remaining()) 23 | buffer.get(bytes) 24 | var output: FileOutputStream? = null 25 | try { 26 | output = FileOutputStream(mFile) 27 | output!!.write(bytes) 28 | } catch (e: IOException) { 29 | e.printStackTrace() 30 | } finally { 31 | mImage.close() 32 | if (null != output) { 33 | try { 34 | output!!.close() 35 | } catch (e: IOException) { 36 | e.printStackTrace() 37 | } 38 | 39 | } 40 | } 41 | } 42 | 43 | } -------------------------------------------------------------------------------- /kotlin-jcameraview/src/main/java/com/cjt2325/kotlin_jcameraview/util/JLog.kt: -------------------------------------------------------------------------------- 1 | package com.cjt2325.kotlin_jcameraview.util 2 | 3 | import android.util.Log 4 | 5 | /** 6 | * ===================================== 7 | * 作 者: 陈嘉桐 8 | * 版 本:1.1.4 9 | * 创建日期:2017/8/10 10 | * 描 述: 11 | * ===================================== 12 | */ 13 | fun i(message: String) { 14 | Log.i("CJT", message) 15 | } -------------------------------------------------------------------------------- /kotlin-jcameraview/src/main/java/com/cjt2325/kotlin_jcameraview/util/ScreenUtil.kt: -------------------------------------------------------------------------------- 1 | package com.cjt2325.kotlin_jcameraview.util 2 | 3 | import android.content.Context 4 | import android.util.DisplayMetrics 5 | import android.view.WindowManager 6 | 7 | /** 8 | * ===================================== 9 | * 作 者: 陈嘉桐 10 | * 版 本:1.1.4 11 | * 创建日期:2017/8/10 12 | * 描 述:获取屏幕宽高 13 | * ===================================== 14 | */ 15 | 16 | fun getScreenWidth(context: Context): Int { 17 | val manager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager 18 | val outMetrics = DisplayMetrics() 19 | manager.defaultDisplay.getMetrics(outMetrics) 20 | return outMetrics.widthPixels 21 | } 22 | 23 | fun getScreenHeight(context: Context): Int { 24 | val manager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager 25 | val outMetrics = DisplayMetrics() 26 | manager.defaultDisplay.getMetrics(outMetrics) 27 | return outMetrics.heightPixels 28 | } -------------------------------------------------------------------------------- /kotlin-jcameraview/src/main/res/drawable/ic_brightness.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /kotlin-jcameraview/src/main/res/drawable/ic_camera.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /kotlin-jcameraview/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Kotlin-JCameraView 3 | 4 | -------------------------------------------------------------------------------- /kotlin-jcameraview/src/test/java/com/cjt2325/kotlin_jcameraview/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.cjt2325.kotlin_jcameraview; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() throws Exception { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /lib/src/main/java/com/cameraview/AudioUtil.java: -------------------------------------------------------------------------------- 1 | package com.cameraview; 2 | 3 | import android.content.Context; 4 | import android.media.AudioManager; 5 | 6 | /** 7 | * 作者: 陈嘉桐 on 2017/2/12 8 | * 邮箱: 445263848@qq.com. 9 | */ 10 | public class AudioUtil { 11 | public static void setAudioManage(Context context){ 12 | AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); 13 | audioManager.setStreamMute(AudioManager.STREAM_SYSTEM, true); 14 | audioManager.setStreamMute(AudioManager.STREAM_MUSIC, true); 15 | audioManager.setStreamVolume(AudioManager.STREAM_ALARM, 0, 0); 16 | audioManager.setStreamVolume(AudioManager.STREAM_DTMF, 0, 0); 17 | audioManager.setStreamVolume(AudioManager.STREAM_NOTIFICATION, 0, 0); 18 | audioManager.setStreamVolume(AudioManager.STREAM_RING, 0, 0); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /lib/src/main/java/com/cameraview/FileUtil.java: -------------------------------------------------------------------------------- 1 | package com.cameraview; 2 | 3 | import android.graphics.Bitmap; 4 | import android.os.Environment; 5 | import android.util.Log; 6 | 7 | import java.io.BufferedOutputStream; 8 | import java.io.File; 9 | import java.io.FileOutputStream; 10 | import java.io.IOException; 11 | 12 | /** 13 | * 作者: 陈嘉桐 on 2017/2/12 14 | * 邮箱: 445263848@qq.com. 15 | */ 16 | public class FileUtil { 17 | private static final String TAG = "FileUtil"; 18 | private static final File parentPath = Environment.getExternalStorageDirectory(); 19 | private static String storagePath = ""; 20 | private static final String DST_FOLDER_NAME = "PlayCamera"; 21 | 22 | /**初始化保存路径 23 | * @return 24 | */ 25 | private static String initPath(){ 26 | if(storagePath.equals("")){ 27 | storagePath = parentPath.getAbsolutePath()+"/" + DST_FOLDER_NAME; 28 | File f = new File(storagePath); 29 | if(!f.exists()){ 30 | f.mkdir(); 31 | } 32 | } 33 | return storagePath; 34 | } 35 | 36 | /**保存Bitmap到sdcard 37 | * @param b 38 | */ 39 | public static void saveBitmap(Bitmap b){ 40 | 41 | String path = initPath(); 42 | long dataTake = System.currentTimeMillis(); 43 | String jpegName = path + "/" + dataTake +".jpg"; 44 | Log.i(TAG, "saveBitmap:jpegName = " + jpegName); 45 | try { 46 | FileOutputStream fout = new FileOutputStream(jpegName); 47 | BufferedOutputStream bos = new BufferedOutputStream(fout); 48 | b.compress(Bitmap.CompressFormat.JPEG, 100, bos); 49 | bos.flush(); 50 | bos.close(); 51 | Log.i(TAG, "saveBitmap成功"); 52 | } catch (IOException e) { 53 | // TODO Auto-generated catch block 54 | Log.i(TAG, "saveBitmap:失败"); 55 | e.printStackTrace(); 56 | } 57 | 58 | } 59 | 60 | 61 | } 62 | -------------------------------------------------------------------------------- /lib/src/main/java/com/cameraview/ImageUtil.java: -------------------------------------------------------------------------------- 1 | package com.cameraview; 2 | 3 | import android.graphics.Bitmap; 4 | import android.graphics.Matrix; 5 | 6 | /** 7 | * 作者: 陈嘉桐 on 2017/2/12 8 | * 邮箱: 445263848@qq.com. 9 | */ 10 | public class ImageUtil { 11 | /* 12 | 旋转图片 13 | */ 14 | public static Bitmap getRotateBitmap(Bitmap bitmap, float rotateDegree) { 15 | Matrix matrix = new Matrix(); 16 | matrix.setRotate(rotateDegree); 17 | Bitmap rotateBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, false); 18 | return rotateBitmap; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app', ':camera', ':cameraapplication' 2 | --------------------------------------------------------------------------------