├── .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 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
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 | [](https://bintray.com//cjt/maven/cameraView/_latestVersion) [](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 | 
29 | 
30 | 
31 |
32 | ## GIF图
33 |
34 | 
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 | 
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 |
--------------------------------------------------------------------------------