├── .gitignore
├── .idea
├── codeStyleSettings.xml
└── copyright
│ ├── Apache_License_2_0.xml
│ └── profiles_settings.xml
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── build.gradle
├── demo
├── .gitignore
├── build.gradle
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── google
│ │ └── android
│ │ └── cameraview
│ │ └── demo
│ │ ├── AspectRatioFragment.java
│ │ └── MainActivity.java
│ └── res
│ ├── drawable
│ ├── ic_aspect_ratio.xml
│ ├── ic_camera.xml
│ ├── ic_flash_auto.xml
│ ├── ic_flash_off.xml
│ ├── ic_flash_on.xml
│ └── ic_switch_camera.xml
│ ├── layout-land
│ └── activity_main.xml
│ ├── layout
│ └── activity_main.xml
│ ├── menu
│ └── 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
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── library
├── .gitignore
├── build.gradle
└── src
│ ├── androidTest
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── google
│ │ │ └── android
│ │ │ └── cameraview
│ │ │ ├── AspectRatioInstrumentationTest.java
│ │ │ ├── AspectRatioIsCloseTo.java
│ │ │ ├── CameraViewActions.java
│ │ │ ├── CameraViewActivity.java
│ │ │ ├── CameraViewMatchers.java
│ │ │ └── CameraViewTest.java
│ └── res
│ │ └── layout
│ │ └── activity_camera_view.xml
│ ├── main
│ ├── AndroidManifest.xml
│ ├── api14
│ │ └── com
│ │ │ └── google
│ │ │ └── android
│ │ │ └── cameraview
│ │ │ ├── Camera1.java
│ │ │ ├── SurfaceViewPreview.java
│ │ │ └── TextureViewPreview.java
│ ├── api21
│ │ └── com
│ │ │ └── google
│ │ │ └── android
│ │ │ └── cameraview
│ │ │ └── Camera2.java
│ ├── api23
│ │ └── com
│ │ │ └── google
│ │ │ └── android
│ │ │ └── cameraview
│ │ │ └── Camera2Api23.java
│ ├── base
│ │ └── com
│ │ │ └── google
│ │ │ └── android
│ │ │ └── cameraview
│ │ │ ├── AspectRatio.java
│ │ │ ├── CameraViewImpl.java
│ │ │ ├── Constants.java
│ │ │ ├── PreviewImpl.java
│ │ │ ├── Size.java
│ │ │ └── SizeMap.java
│ ├── java
│ │ └── com
│ │ │ └── google
│ │ │ └── android
│ │ │ └── cameraview
│ │ │ ├── CameraView.java
│ │ │ └── DisplayOrientationDetector.java
│ └── res
│ │ ├── layout-v14
│ │ └── texture_view.xml
│ │ ├── layout
│ │ └── surface_view.xml
│ │ └── values
│ │ ├── attrs.xml
│ │ ├── public.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── com
│ └── google
│ └── android
│ └── cameraview
│ ├── AspectRatioTest.java
│ ├── SizeMapTest.java
│ └── SizeTest.java
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | .DS_Store
5 | /build
6 | /captures
7 |
8 | .idea/
9 | !.idea/copyright/*.xml
10 | !.idea/codeStyleSettings.xml
11 |
--------------------------------------------------------------------------------
/.idea/codeStyleSettings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
319 |
320 |
321 |
322 |
--------------------------------------------------------------------------------
/.idea/copyright/Apache_License_2_0.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # How to become a contributor and submit your own code
2 |
3 | ## Contributor License Agreements
4 |
5 | We'd love to accept your sample apps and patches! Before we can take them, we
6 | have to jump a couple of legal hurdles.
7 |
8 | Please fill out either the individual or corporate Contributor License Agreement (CLA).
9 |
10 | * If you are an individual writing original source code and you're sure you
11 | own the intellectual property, then you'll need to sign an [individual CLA]
12 | (https://cla.developers.google.com).
13 | * If you work for a company that wants to allow you to contribute your work,
14 | then you'll need to sign a [corporate CLA]
15 | (https://cla.developers.google.com).
16 |
17 | Follow either of the two links above to access the appropriate CLA and
18 | instructions for how to sign and return it. Once we receive it, we'll be able to
19 | accept your pull requests.
20 |
21 | ## Contributing A Patch
22 |
23 | 1. Submit an issue describing your proposed change to the repo in question.
24 | 1. The repo owner will respond to your issue promptly.
25 | 1. If your proposed change is accepted, and you haven't already done so, sign a
26 | Contributor License Agreement (see details above).
27 | 1. Fork the desired repo, develop and test your code changes.
28 | 1. Ensure that your code adheres to the existing style in the sample to which
29 | you are contributing. Refer to the
30 | [Android Code Style Guide]
31 | (https://source.android.com/source/code-style.html) for the
32 | recommended coding standards for this organization.
33 | 1. Ensure that your code has an appropriate set of unit tests which all pass.
34 | 1. Submit a pull request.
35 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 |
2 | Apache License
3 | Version 2.0, January 2004
4 | http://www.apache.org/licenses/
5 |
6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7 |
8 | 1. Definitions.
9 |
10 | "License" shall mean the terms and conditions for use, reproduction,
11 | and distribution as defined by Sections 1 through 9 of this document.
12 |
13 | "Licensor" shall mean the copyright owner or entity authorized by
14 | the copyright owner that is granting the License.
15 |
16 | "Legal Entity" shall mean the union of the acting entity and all
17 | other entities that control, are controlled by, or are under common
18 | control with that entity. For the purposes of this definition,
19 | "control" means (i) the power, direct or indirect, to cause the
20 | direction or management of such entity, whether by contract or
21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
22 | outstanding shares, or (iii) beneficial ownership of such entity.
23 |
24 | "You" (or "Your") shall mean an individual or Legal Entity
25 | exercising permissions granted by this License.
26 |
27 | "Source" form shall mean the preferred form for making modifications,
28 | including but not limited to software source code, documentation
29 | source, and configuration files.
30 |
31 | "Object" form shall mean any form resulting from mechanical
32 | transformation or translation of a Source form, including but
33 | not limited to compiled object code, generated documentation,
34 | and conversions to other media types.
35 |
36 | "Work" shall mean the work of authorship, whether in Source or
37 | Object form, made available under the License, as indicated by a
38 | copyright notice that is included in or attached to the work
39 | (an example is provided in the Appendix below).
40 |
41 | "Derivative Works" shall mean any work, whether in Source or Object
42 | form, that is based on (or derived from) the Work and for which the
43 | editorial revisions, annotations, elaborations, or other modifications
44 | represent, as a whole, an original work of authorship. For the purposes
45 | of this License, Derivative Works shall not include works that remain
46 | separable from, or merely link (or bind by name) to the interfaces of,
47 | the Work and Derivative Works thereof.
48 |
49 | "Contribution" shall mean any work of authorship, including
50 | the original version of the Work and any modifications or additions
51 | to that Work or Derivative Works thereof, that is intentionally
52 | submitted to Licensor for inclusion in the Work by the copyright owner
53 | or by an individual or Legal Entity authorized to submit on behalf of
54 | the copyright owner. For the purposes of this definition, "submitted"
55 | means any form of electronic, verbal, or written communication sent
56 | to the Licensor or its representatives, including but not limited to
57 | communication on electronic mailing lists, source code control systems,
58 | and issue tracking systems that are managed by, or on behalf of, the
59 | Licensor for the purpose of discussing and improving the Work, but
60 | excluding communication that is conspicuously marked or otherwise
61 | designated in writing by the copyright owner as "Not a Contribution."
62 |
63 | "Contributor" shall mean Licensor and any individual or Legal Entity
64 | on behalf of whom a Contribution has been received by Licensor and
65 | subsequently incorporated within the Work.
66 |
67 | 2. Grant of Copyright License. Subject to the terms and conditions of
68 | this License, each Contributor hereby grants to You a perpetual,
69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70 | copyright license to reproduce, prepare Derivative Works of,
71 | publicly display, publicly perform, sublicense, and distribute the
72 | Work and such Derivative Works in Source or Object form.
73 |
74 | 3. Grant of Patent License. Subject to the terms and conditions of
75 | this License, each Contributor hereby grants to You a perpetual,
76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77 | (except as stated in this section) patent license to make, have made,
78 | use, offer to sell, sell, import, and otherwise transfer the Work,
79 | where such license applies only to those patent claims licensable
80 | by such Contributor that are necessarily infringed by their
81 | Contribution(s) alone or by combination of their Contribution(s)
82 | with the Work to which such Contribution(s) was submitted. If You
83 | institute patent litigation against any entity (including a
84 | cross-claim or counterclaim in a lawsuit) alleging that the Work
85 | or a Contribution incorporated within the Work constitutes direct
86 | or contributory patent infringement, then any patent licenses
87 | granted to You under this License for that Work shall terminate
88 | as of the date such litigation is filed.
89 |
90 | 4. Redistribution. You may reproduce and distribute copies of the
91 | Work or Derivative Works thereof in any medium, with or without
92 | modifications, and in Source or Object form, provided that You
93 | meet the following conditions:
94 |
95 | (a) You must give any other recipients of the Work or
96 | Derivative Works a copy of this License; and
97 |
98 | (b) You must cause any modified files to carry prominent notices
99 | stating that You changed the files; and
100 |
101 | (c) You must retain, in the Source form of any Derivative Works
102 | that You distribute, all copyright, patent, trademark, and
103 | attribution notices from the Source form of the Work,
104 | excluding those notices that do not pertain to any part of
105 | the Derivative Works; and
106 |
107 | (d) If the Work includes a "NOTICE" text file as part of its
108 | distribution, then any Derivative Works that You distribute must
109 | include a readable copy of the attribution notices contained
110 | within such NOTICE file, excluding those notices that do not
111 | pertain to any part of the Derivative Works, in at least one
112 | of the following places: within a NOTICE text file distributed
113 | as part of the Derivative Works; within the Source form or
114 | documentation, if provided along with the Derivative Works; or,
115 | within a display generated by the Derivative Works, if and
116 | wherever such third-party notices normally appear. The contents
117 | of the NOTICE file are for informational purposes only and
118 | do not modify the License. You may add Your own attribution
119 | notices within Derivative Works that You distribute, alongside
120 | or as an addendum to the NOTICE text from the Work, provided
121 | that such additional attribution notices cannot be construed
122 | as modifying the License.
123 |
124 | You may add Your own copyright statement to Your modifications and
125 | may provide additional or different license terms and conditions
126 | for use, reproduction, or distribution of Your modifications, or
127 | for any such Derivative Works as a whole, provided Your use,
128 | reproduction, and distribution of the Work otherwise complies with
129 | the conditions stated in this License.
130 |
131 | 5. Submission of Contributions. Unless You explicitly state otherwise,
132 | any Contribution intentionally submitted for inclusion in the Work
133 | by You to the Licensor shall be under the terms and conditions of
134 | this License, without any additional terms or conditions.
135 | Notwithstanding the above, nothing herein shall supersede or modify
136 | the terms of any separate license agreement you may have executed
137 | with Licensor regarding such Contributions.
138 |
139 | 6. Trademarks. This License does not grant permission to use the trade
140 | names, trademarks, service marks, or product names of the Licensor,
141 | except as required for reasonable and customary use in describing the
142 | origin of the Work and reproducing the content of the NOTICE file.
143 |
144 | 7. Disclaimer of Warranty. Unless required by applicable law or
145 | agreed to in writing, Licensor provides the Work (and each
146 | Contributor provides its Contributions) on an "AS IS" BASIS,
147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148 | implied, including, without limitation, any warranties or conditions
149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150 | PARTICULAR PURPOSE. You are solely responsible for determining the
151 | appropriateness of using or redistributing the Work and assume any
152 | risks associated with Your exercise of permissions under this License.
153 |
154 | 8. Limitation of Liability. In no event and under no legal theory,
155 | whether in tort (including negligence), contract, or otherwise,
156 | unless required by applicable law (such as deliberate and grossly
157 | negligent acts) or agreed to in writing, shall any Contributor be
158 | liable to You for damages, including any direct, indirect, special,
159 | incidental, or consequential damages of any character arising as a
160 | result of this License or out of the use or inability to use the
161 | Work (including but not limited to damages for loss of goodwill,
162 | work stoppage, computer failure or malfunction, or any and all
163 | other commercial damages or losses), even if such Contributor
164 | has been advised of the possibility of such damages.
165 |
166 | 9. Accepting Warranty or Additional Liability. While redistributing
167 | the Work or Derivative Works thereof, You may choose to offer,
168 | and charge a fee for, acceptance of support, warranty, indemnity,
169 | or other liability obligations and/or rights consistent with this
170 | License. However, in accepting such obligations, You may act only
171 | on Your own behalf and on Your sole responsibility, not on behalf
172 | of any other Contributor, and only if You agree to indemnify,
173 | defend, and hold each Contributor harmless for any liability
174 | incurred by, or claims asserted against, such Contributor by reason
175 | of your accepting any such warranty or additional liability.
176 |
177 | END OF TERMS AND CONDITIONS
178 |
179 | APPENDIX: How to apply the Apache License to your work.
180 |
181 | To apply the Apache License to your work, attach the following
182 | boilerplate notice, with the fields enclosed by brackets "[]"
183 | replaced with your own identifying information. (Don't include
184 | the brackets!) The text should be enclosed in the appropriate
185 | comment syntax for the file format. We also recommend that a
186 | file or class name and description of purpose be included on the
187 | same "printed page" as the copyright notice for easier
188 | identification within third-party archives.
189 |
190 | Copyright [yyyy] [name of copyright owner]
191 |
192 | Licensed under the Apache License, Version 2.0 (the "License");
193 | you may not use this file except in compliance with the License.
194 | You may obtain a copy of the License at
195 |
196 | http://www.apache.org/licenses/LICENSE-2.0
197 |
198 | Unless required by applicable law or agreed to in writing, software
199 | distributed under the License is distributed on an "AS IS" BASIS,
200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201 | See the License for the specific language governing permissions and
202 | limitations under the License.
203 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Deprecated
2 |
3 | CameraView is deprecated. No more development will be taking place.
4 |
5 | Use [Jetpack CameraX](https://developer.android.com/jetpack/androidx/releases/camerax) instead.
6 |
7 | # CameraView
8 |
9 | This is not an official Google product.
10 |
11 | CameraView aims to help Android developers easily integrate Camera features.
12 |
13 | Requires API Level 9. The library uses Camera 1 API on API Level 9-20 and Camera2 on 21 and above.
14 |
15 | | API Level | Camera API | Preview View |
16 | |:---------:|------------|--------------|
17 | | 9-13 | Camera1 | SurfaceView |
18 | | 14-20 | Camera1 | TextureView |
19 | | 21-23 | Camera2 | TextureView |
20 | | 24 | Camera2 | SurfaceView |
21 |
22 | ## Features
23 |
24 | - Camera preview by placing it in a layout XML (and calling the start method)
25 | - Configuration by attributes
26 | - Aspect ratio (app:aspectRatio)
27 | - Auto-focus (app:autoFocus)
28 | - Flash (app:flash)
29 |
30 | ## Usage
31 |
32 | ```xml
33 |
43 | ```
44 |
45 | ```java
46 | @Override
47 | protected void onResume() {
48 | super.onResume();
49 | mCameraView.start();
50 | }
51 |
52 | @Override
53 | protected void onPause() {
54 | mCameraView.stop();
55 | super.onPause();
56 | }
57 | ```
58 |
59 | You can see a complete usage in the demo app.
60 |
61 | ## Contribution
62 |
63 | See [CONTRIBUTING.md](/CONTRIBUTING.md).
64 |
--------------------------------------------------------------------------------
/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 | google()
7 | }
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:2.3.3'
10 |
11 | // NOTE: Do not place your application dependencies here; they belong
12 | // in the individual module build.gradle files
13 | }
14 | }
15 |
16 | allprojects {
17 | repositories {
18 | jcenter()
19 | google()
20 | }
21 | }
22 |
23 | task clean(type: Delete) {
24 | delete rootProject.buildDir
25 | }
26 |
27 | ext {
28 | buildToolsVersion = '26.0.0'
29 | compileSdkVersion = 26
30 | minSdkVersion = 14
31 | targetSdkVersion = 26
32 | supportLibraryVersion = '26.0.0'
33 | }
34 |
--------------------------------------------------------------------------------
/demo/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/demo/build.gradle:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2016 The Android Open Source Project
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | apply plugin: 'com.android.application'
16 |
17 | android {
18 | compileSdkVersion rootProject.ext.compileSdkVersion
19 |
20 | buildToolsVersion rootProject.ext.buildToolsVersion
21 |
22 | defaultConfig {
23 | applicationId 'com.google.android.cameraview.demo'
24 | minSdkVersion rootProject.ext.minSdkVersion
25 | targetSdkVersion rootProject.ext.targetSdkVersion
26 | versionCode 1
27 | versionName '1.0'
28 | testInstrumentationRunner 'android.support.test.runner.AndroidJUnitRunner'
29 | vectorDrawables.useSupportLibrary = true
30 | }
31 | buildTypes {
32 | release {
33 | minifyEnabled false
34 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
35 | }
36 | }
37 | }
38 |
39 | dependencies {
40 | compile fileTree(dir: 'libs', include: ['*.jar'])
41 | compile "com.android.support:design:$supportLibraryVersion"
42 | compile project(':library')
43 | }
44 |
--------------------------------------------------------------------------------
/demo/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
14 |
16 |
17 |
20 |
21 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/demo/src/main/java/com/google/android/cameraview/demo/AspectRatioFragment.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.google.android.cameraview.demo;
18 |
19 | import android.app.Dialog;
20 | import android.content.Context;
21 | import android.content.DialogInterface;
22 | import android.os.Bundle;
23 | import android.support.annotation.NonNull;
24 | import android.support.v4.app.DialogFragment;
25 | import android.support.v7.app.AlertDialog;
26 | import android.view.LayoutInflater;
27 | import android.view.View;
28 | import android.view.ViewGroup;
29 | import android.widget.BaseAdapter;
30 | import android.widget.TextView;
31 |
32 | import com.google.android.cameraview.AspectRatio;
33 |
34 | import java.util.Arrays;
35 | import java.util.Set;
36 |
37 |
38 | /**
39 | * A simple dialog that allows user to pick an aspect ratio.
40 | */
41 | public class AspectRatioFragment extends DialogFragment {
42 |
43 | private static final String ARG_ASPECT_RATIOS = "aspect_ratios";
44 | private static final String ARG_CURRENT_ASPECT_RATIO = "current_aspect_ratio";
45 |
46 | private Listener mListener;
47 |
48 | public static AspectRatioFragment newInstance(Set ratios,
49 | AspectRatio currentRatio) {
50 | final AspectRatioFragment fragment = new AspectRatioFragment();
51 | final Bundle args = new Bundle();
52 | args.putParcelableArray(ARG_ASPECT_RATIOS,
53 | ratios.toArray(new AspectRatio[ratios.size()]));
54 | args.putParcelable(ARG_CURRENT_ASPECT_RATIO, currentRatio);
55 | fragment.setArguments(args);
56 | return fragment;
57 | }
58 |
59 | @Override
60 | public void onAttach(Context context) {
61 | super.onAttach(context);
62 | mListener = (Listener) context;
63 | }
64 |
65 | @Override
66 | public void onDetach() {
67 | mListener = null;
68 | super.onDetach();
69 | }
70 |
71 | @NonNull
72 | @Override
73 | public Dialog onCreateDialog(Bundle savedInstanceState) {
74 | final Bundle args = getArguments();
75 | final AspectRatio[] ratios = (AspectRatio[]) args.getParcelableArray(ARG_ASPECT_RATIOS);
76 | if (ratios == null) {
77 | throw new RuntimeException("No ratios");
78 | }
79 | Arrays.sort(ratios);
80 | final AspectRatio current = args.getParcelable(ARG_CURRENT_ASPECT_RATIO);
81 | final AspectRatioAdapter adapter = new AspectRatioAdapter(ratios, current);
82 | return new AlertDialog.Builder(getActivity())
83 | .setAdapter(adapter, new DialogInterface.OnClickListener() {
84 | @Override
85 | public void onClick(DialogInterface dialog, int position) {
86 | mListener.onAspectRatioSelected(ratios[position]);
87 | }
88 | })
89 | .create();
90 | }
91 |
92 | private static class AspectRatioAdapter extends BaseAdapter {
93 |
94 | private final AspectRatio[] mRatios;
95 | private final AspectRatio mCurrentRatio;
96 |
97 | AspectRatioAdapter(AspectRatio[] ratios, AspectRatio current) {
98 | mRatios = ratios;
99 | mCurrentRatio = current;
100 | }
101 |
102 | @Override
103 | public int getCount() {
104 | return mRatios.length;
105 | }
106 |
107 | @Override
108 | public AspectRatio getItem(int position) {
109 | return mRatios[position];
110 | }
111 |
112 | @Override
113 | public long getItemId(int position) {
114 | return getItem(position).hashCode();
115 | }
116 |
117 | @Override
118 | public View getView(int position, View view, ViewGroup parent) {
119 | AspectRatioAdapter.ViewHolder holder;
120 | if (view == null) {
121 | view = LayoutInflater.from(parent.getContext())
122 | .inflate(android.R.layout.simple_list_item_1, parent, false);
123 | holder = new AspectRatioAdapter.ViewHolder();
124 | holder.text = view.findViewById(android.R.id.text1);
125 | view.setTag(holder);
126 | } else {
127 | holder = (AspectRatioAdapter.ViewHolder) view.getTag();
128 | }
129 | AspectRatio ratio = getItem(position);
130 | StringBuilder sb = new StringBuilder(ratio.toString());
131 | if (ratio.equals(mCurrentRatio)) {
132 | sb.append(" *");
133 | }
134 | holder.text.setText(sb);
135 | return view;
136 | }
137 |
138 | private static class ViewHolder {
139 | TextView text;
140 | }
141 |
142 | }
143 |
144 | public interface Listener {
145 | void onAspectRatioSelected(@NonNull AspectRatio ratio);
146 | }
147 |
148 | }
149 |
--------------------------------------------------------------------------------
/demo/src/main/java/com/google/android/cameraview/demo/MainActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.google.android.cameraview.demo;
18 |
19 | import android.Manifest;
20 | import android.app.Dialog;
21 | import android.content.DialogInterface;
22 | import android.content.pm.PackageManager;
23 | import android.os.Build;
24 | import android.os.Bundle;
25 | import android.os.Environment;
26 | import android.os.Handler;
27 | import android.os.HandlerThread;
28 | import android.support.annotation.NonNull;
29 | import android.support.annotation.StringRes;
30 | import android.support.design.widget.FloatingActionButton;
31 | import android.support.v4.app.ActivityCompat;
32 | import android.support.v4.app.DialogFragment;
33 | import android.support.v4.app.FragmentManager;
34 | import android.support.v4.content.ContextCompat;
35 | import android.support.v7.app.ActionBar;
36 | import android.support.v7.app.AlertDialog;
37 | import android.support.v7.app.AppCompatActivity;
38 | import android.support.v7.widget.Toolbar;
39 | import android.util.Log;
40 | import android.view.Menu;
41 | import android.view.MenuItem;
42 | import android.view.View;
43 | import android.widget.Toast;
44 |
45 | import com.google.android.cameraview.AspectRatio;
46 | import com.google.android.cameraview.CameraView;
47 |
48 | import java.io.File;
49 | import java.io.FileOutputStream;
50 | import java.io.IOException;
51 | import java.io.OutputStream;
52 | import java.util.Set;
53 |
54 |
55 | /**
56 | * This demo app saves the taken picture to a constant file.
57 | * $ adb pull /sdcard/Android/data/com.google.android.cameraview.demo/files/Pictures/picture.jpg
58 | */
59 | public class MainActivity extends AppCompatActivity implements
60 | ActivityCompat.OnRequestPermissionsResultCallback,
61 | AspectRatioFragment.Listener {
62 |
63 | private static final String TAG = "MainActivity";
64 |
65 | private static final int REQUEST_CAMERA_PERMISSION = 1;
66 |
67 | private static final String FRAGMENT_DIALOG = "dialog";
68 |
69 | private static final int[] FLASH_OPTIONS = {
70 | CameraView.FLASH_AUTO,
71 | CameraView.FLASH_OFF,
72 | CameraView.FLASH_ON,
73 | };
74 |
75 | private static final int[] FLASH_ICONS = {
76 | R.drawable.ic_flash_auto,
77 | R.drawable.ic_flash_off,
78 | R.drawable.ic_flash_on,
79 | };
80 |
81 | private static final int[] FLASH_TITLES = {
82 | R.string.flash_auto,
83 | R.string.flash_off,
84 | R.string.flash_on,
85 | };
86 |
87 | private int mCurrentFlash;
88 |
89 | private CameraView mCameraView;
90 |
91 | private Handler mBackgroundHandler;
92 |
93 | private View.OnClickListener mOnClickListener = new View.OnClickListener() {
94 | @Override
95 | public void onClick(View v) {
96 | switch (v.getId()) {
97 | case R.id.take_picture:
98 | if (mCameraView != null) {
99 | mCameraView.takePicture();
100 | }
101 | break;
102 | }
103 | }
104 | };
105 |
106 | @Override
107 | protected void onCreate(Bundle savedInstanceState) {
108 | super.onCreate(savedInstanceState);
109 | setContentView(R.layout.activity_main);
110 | mCameraView = findViewById(R.id.camera);
111 | if (mCameraView != null) {
112 | mCameraView.addCallback(mCallback);
113 | }
114 | FloatingActionButton fab = findViewById(R.id.take_picture);
115 | if (fab != null) {
116 | fab.setOnClickListener(mOnClickListener);
117 | }
118 | Toolbar toolbar = findViewById(R.id.toolbar);
119 | setSupportActionBar(toolbar);
120 | ActionBar actionBar = getSupportActionBar();
121 | if (actionBar != null) {
122 | actionBar.setDisplayShowTitleEnabled(false);
123 | }
124 | }
125 |
126 | @Override
127 | protected void onResume() {
128 | super.onResume();
129 | if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
130 | == PackageManager.PERMISSION_GRANTED) {
131 | mCameraView.start();
132 | } else if (ActivityCompat.shouldShowRequestPermissionRationale(this,
133 | Manifest.permission.CAMERA)) {
134 | ConfirmationDialogFragment
135 | .newInstance(R.string.camera_permission_confirmation,
136 | new String[]{Manifest.permission.CAMERA},
137 | REQUEST_CAMERA_PERMISSION,
138 | R.string.camera_permission_not_granted)
139 | .show(getSupportFragmentManager(), FRAGMENT_DIALOG);
140 | } else {
141 | ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA},
142 | REQUEST_CAMERA_PERMISSION);
143 | }
144 | }
145 |
146 | @Override
147 | protected void onPause() {
148 | mCameraView.stop();
149 | super.onPause();
150 | }
151 |
152 | @Override
153 | protected void onDestroy() {
154 | super.onDestroy();
155 | if (mBackgroundHandler != null) {
156 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
157 | mBackgroundHandler.getLooper().quitSafely();
158 | } else {
159 | mBackgroundHandler.getLooper().quit();
160 | }
161 | mBackgroundHandler = null;
162 | }
163 | }
164 |
165 | @Override
166 | public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
167 | @NonNull int[] grantResults) {
168 | switch (requestCode) {
169 | case REQUEST_CAMERA_PERMISSION:
170 | if (permissions.length != 1 || grantResults.length != 1) {
171 | throw new RuntimeException("Error on requesting camera permission.");
172 | }
173 | if (grantResults[0] != PackageManager.PERMISSION_GRANTED) {
174 | Toast.makeText(this, R.string.camera_permission_not_granted,
175 | Toast.LENGTH_SHORT).show();
176 | }
177 | // No need to start camera here; it is handled by onResume
178 | break;
179 | }
180 | }
181 |
182 | @Override
183 | public boolean onCreateOptionsMenu(Menu menu) {
184 | getMenuInflater().inflate(R.menu.main, menu);
185 | return true;
186 | }
187 |
188 | @Override
189 | public boolean onOptionsItemSelected(MenuItem item) {
190 | switch (item.getItemId()) {
191 | case R.id.aspect_ratio:
192 | FragmentManager fragmentManager = getSupportFragmentManager();
193 | if (mCameraView != null
194 | && fragmentManager.findFragmentByTag(FRAGMENT_DIALOG) == null) {
195 | final Set ratios = mCameraView.getSupportedAspectRatios();
196 | final AspectRatio currentRatio = mCameraView.getAspectRatio();
197 | AspectRatioFragment.newInstance(ratios, currentRatio)
198 | .show(fragmentManager, FRAGMENT_DIALOG);
199 | }
200 | return true;
201 | case R.id.switch_flash:
202 | if (mCameraView != null) {
203 | mCurrentFlash = (mCurrentFlash + 1) % FLASH_OPTIONS.length;
204 | item.setTitle(FLASH_TITLES[mCurrentFlash]);
205 | item.setIcon(FLASH_ICONS[mCurrentFlash]);
206 | mCameraView.setFlash(FLASH_OPTIONS[mCurrentFlash]);
207 | }
208 | return true;
209 | case R.id.switch_camera:
210 | if (mCameraView != null) {
211 | int facing = mCameraView.getFacing();
212 | mCameraView.setFacing(facing == CameraView.FACING_FRONT ?
213 | CameraView.FACING_BACK : CameraView.FACING_FRONT);
214 | }
215 | return true;
216 | }
217 | return super.onOptionsItemSelected(item);
218 | }
219 |
220 | @Override
221 | public void onAspectRatioSelected(@NonNull AspectRatio ratio) {
222 | if (mCameraView != null) {
223 | Toast.makeText(this, ratio.toString(), Toast.LENGTH_SHORT).show();
224 | mCameraView.setAspectRatio(ratio);
225 | }
226 | }
227 |
228 | private Handler getBackgroundHandler() {
229 | if (mBackgroundHandler == null) {
230 | HandlerThread thread = new HandlerThread("background");
231 | thread.start();
232 | mBackgroundHandler = new Handler(thread.getLooper());
233 | }
234 | return mBackgroundHandler;
235 | }
236 |
237 | private CameraView.Callback mCallback
238 | = new CameraView.Callback() {
239 |
240 | @Override
241 | public void onCameraOpened(CameraView cameraView) {
242 | Log.d(TAG, "onCameraOpened");
243 | }
244 |
245 | @Override
246 | public void onCameraClosed(CameraView cameraView) {
247 | Log.d(TAG, "onCameraClosed");
248 | }
249 |
250 | @Override
251 | public void onPictureTaken(CameraView cameraView, final byte[] data) {
252 | Log.d(TAG, "onPictureTaken " + data.length);
253 | Toast.makeText(cameraView.getContext(), R.string.picture_taken, Toast.LENGTH_SHORT)
254 | .show();
255 | getBackgroundHandler().post(new Runnable() {
256 | @Override
257 | public void run() {
258 | File file = new File(getExternalFilesDir(Environment.DIRECTORY_PICTURES),
259 | "picture.jpg");
260 | OutputStream os = null;
261 | try {
262 | os = new FileOutputStream(file);
263 | os.write(data);
264 | os.close();
265 | } catch (IOException e) {
266 | Log.w(TAG, "Cannot write to " + file, e);
267 | } finally {
268 | if (os != null) {
269 | try {
270 | os.close();
271 | } catch (IOException e) {
272 | // Ignore
273 | }
274 | }
275 | }
276 | }
277 | });
278 | }
279 |
280 | };
281 |
282 | public static class ConfirmationDialogFragment extends DialogFragment {
283 |
284 | private static final String ARG_MESSAGE = "message";
285 | private static final String ARG_PERMISSIONS = "permissions";
286 | private static final String ARG_REQUEST_CODE = "request_code";
287 | private static final String ARG_NOT_GRANTED_MESSAGE = "not_granted_message";
288 |
289 | public static ConfirmationDialogFragment newInstance(@StringRes int message,
290 | String[] permissions, int requestCode, @StringRes int notGrantedMessage) {
291 | ConfirmationDialogFragment fragment = new ConfirmationDialogFragment();
292 | Bundle args = new Bundle();
293 | args.putInt(ARG_MESSAGE, message);
294 | args.putStringArray(ARG_PERMISSIONS, permissions);
295 | args.putInt(ARG_REQUEST_CODE, requestCode);
296 | args.putInt(ARG_NOT_GRANTED_MESSAGE, notGrantedMessage);
297 | fragment.setArguments(args);
298 | return fragment;
299 | }
300 |
301 | @NonNull
302 | @Override
303 | public Dialog onCreateDialog(Bundle savedInstanceState) {
304 | final Bundle args = getArguments();
305 | return new AlertDialog.Builder(getActivity())
306 | .setMessage(args.getInt(ARG_MESSAGE))
307 | .setPositiveButton(android.R.string.ok,
308 | new DialogInterface.OnClickListener() {
309 | @Override
310 | public void onClick(DialogInterface dialog, int which) {
311 | String[] permissions = args.getStringArray(ARG_PERMISSIONS);
312 | if (permissions == null) {
313 | throw new IllegalArgumentException();
314 | }
315 | ActivityCompat.requestPermissions(getActivity(),
316 | permissions, args.getInt(ARG_REQUEST_CODE));
317 | }
318 | })
319 | .setNegativeButton(android.R.string.cancel,
320 | new DialogInterface.OnClickListener() {
321 | @Override
322 | public void onClick(DialogInterface dialog, int which) {
323 | Toast.makeText(getActivity(),
324 | args.getInt(ARG_NOT_GRANTED_MESSAGE),
325 | Toast.LENGTH_SHORT).show();
326 | }
327 | })
328 | .create();
329 | }
330 |
331 | }
332 |
333 | }
334 |
--------------------------------------------------------------------------------
/demo/src/main/res/drawable/ic_aspect_ratio.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
22 |
25 |
26 |
--------------------------------------------------------------------------------
/demo/src/main/res/drawable/ic_camera.xml:
--------------------------------------------------------------------------------
1 |
2 |
14 |
19 |
22 |
25 |
26 |
--------------------------------------------------------------------------------
/demo/src/main/res/drawable/ic_flash_auto.xml:
--------------------------------------------------------------------------------
1 |
2 |
14 |
19 |
22 |
23 |
--------------------------------------------------------------------------------
/demo/src/main/res/drawable/ic_flash_off.xml:
--------------------------------------------------------------------------------
1 |
2 |
14 |
19 |
22 |
23 |
--------------------------------------------------------------------------------
/demo/src/main/res/drawable/ic_flash_on.xml:
--------------------------------------------------------------------------------
1 |
2 |
14 |
19 |
22 |
23 |
--------------------------------------------------------------------------------
/demo/src/main/res/drawable/ic_switch_camera.xml:
--------------------------------------------------------------------------------
1 |
2 |
14 |
19 |
22 |
23 |
--------------------------------------------------------------------------------
/demo/src/main/res/layout-land/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
14 |
23 |
24 |
33 |
34 |
41 |
42 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/demo/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
14 |
23 |
24 |
33 |
34 |
41 |
42 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/demo/src/main/res/menu/main.xml:
--------------------------------------------------------------------------------
1 |
2 |
14 |
37 |
--------------------------------------------------------------------------------
/demo/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/cameraview/68947cc1643e7434250e099f38f346eae9c46339/demo/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/demo/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/cameraview/68947cc1643e7434250e099f38f346eae9c46339/demo/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/demo/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/cameraview/68947cc1643e7434250e099f38f346eae9c46339/demo/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/demo/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/cameraview/68947cc1643e7434250e099f38f346eae9c46339/demo/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/demo/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/cameraview/68947cc1643e7434250e099f38f346eae9c46339/demo/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/demo/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
14 |
15 | 64dp
16 |
17 |
--------------------------------------------------------------------------------
/demo/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
14 |
15 | #3F51B5
16 | #303F9F
17 | #4CAF50
18 | #212121
19 | #727272
20 |
21 |
--------------------------------------------------------------------------------
/demo/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
14 |
15 | 16dp
16 | 16dp
17 |
18 |
--------------------------------------------------------------------------------
/demo/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
14 |
15 | CameraView Demo
16 | This app demonstrates the usage of CameraView. In order to do that, it needs permission to access camera.
17 | Camera app cannot do anything without camera permission.
18 | Picture taken
19 | Aspect ratio
20 | Switch flash
21 | Switch camera
22 | Flash auto
23 | Flash off
24 | Flash on
25 |
26 |
--------------------------------------------------------------------------------
/demo/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
14 |
15 |
16 |
17 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/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/google/cameraview/68947cc1643e7434250e099f38f346eae9c46339/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Tue Sep 06 09:02:59 JST 2016
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.0.2-all.zip
7 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/library/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/library/build.gradle:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2016 The Android Open Source Project
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | apply plugin: 'com.android.library'
16 |
17 | android {
18 | compileSdkVersion rootProject.ext.compileSdkVersion
19 | buildToolsVersion rootProject.ext.buildToolsVersion
20 |
21 | defaultConfig {
22 | minSdkVersion rootProject.ext.minSdkVersion
23 | targetSdkVersion rootProject.ext.targetSdkVersion
24 | testInstrumentationRunner 'android.support.test.runner.AndroidJUnitRunner'
25 | }
26 | buildTypes {
27 | release {
28 | minifyEnabled false
29 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
30 | }
31 | }
32 | sourceSets {
33 | main.java.srcDirs += 'src/main/base'
34 | main.java.srcDirs += 'src/main/api14'
35 | main.java.srcDirs += 'src/main/api21'
36 | main.java.srcDirs += 'src/main/api23'
37 | }
38 | }
39 |
40 | dependencies {
41 | compile "com.android.support:support-annotations:$supportLibraryVersion"
42 | compile "com.android.support:support-v4:$supportLibraryVersion"
43 |
44 | // Tests
45 | testCompile 'junit:junit:4.12'
46 | androidTestCompile('com.android.support.test:runner:1.0.0')
47 | androidTestCompile('com.android.support.test.espresso:espresso-core:3.0.0')
48 | }
49 |
--------------------------------------------------------------------------------
/library/src/androidTest/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
14 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/library/src/androidTest/java/com/google/android/cameraview/AspectRatioInstrumentationTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.google.android.cameraview;
18 |
19 | import static junit.framework.Assert.assertNotNull;
20 |
21 | import static org.hamcrest.MatcherAssert.assertThat;
22 | import static org.hamcrest.Matchers.sameInstance;
23 | import static org.hamcrest.core.Is.is;
24 |
25 | import android.os.Parcel;
26 | import android.support.test.runner.AndroidJUnit4;
27 |
28 | import org.junit.Test;
29 | import org.junit.runner.RunWith;
30 |
31 |
32 | @RunWith(AndroidJUnit4.class)
33 | public class AspectRatioInstrumentationTest {
34 |
35 | @Test
36 | public void testParcel() {
37 | final AspectRatio original = AspectRatio.of(4, 3);
38 | final Parcel parcel = Parcel.obtain();
39 | try {
40 | parcel.writeParcelable(original, 0);
41 | parcel.setDataPosition(0);
42 | final AspectRatio restored = parcel.readParcelable(getClass().getClassLoader());
43 | assertNotNull(restored);
44 | assertThat(restored.getX(), is(4));
45 | assertThat(restored.getY(), is(3));
46 | // As the first instance is alive, the parceled result should still be the same instance
47 | assertThat(restored, is(sameInstance(original)));
48 | } finally {
49 | parcel.recycle();
50 | }
51 | }
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/library/src/androidTest/java/com/google/android/cameraview/AspectRatioIsCloseTo.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.google.android.cameraview;
18 |
19 | import static org.hamcrest.CoreMatchers.either;
20 |
21 | import org.hamcrest.Description;
22 | import org.hamcrest.Factory;
23 | import org.hamcrest.Matcher;
24 | import org.hamcrest.TypeSafeMatcher;
25 |
26 | public class AspectRatioIsCloseTo extends TypeSafeMatcher {
27 |
28 | private final AspectRatio mRatio;
29 | private final static float ERROR = 0.01f;
30 |
31 | public AspectRatioIsCloseTo(AspectRatio ratio) {
32 | mRatio = ratio;
33 | }
34 |
35 | @Override
36 | protected boolean matchesSafely(AspectRatio item) {
37 | float other = item.toFloat();
38 | float self = mRatio.toFloat();
39 | return self - ERROR < other && other < self + ERROR;
40 | }
41 |
42 | @Override
43 | public void describeTo(Description description) {
44 | description.appendText("an aspect ratio of ").appendValue(mRatio.toString());
45 | }
46 |
47 | @Factory
48 | public static Matcher closeTo(AspectRatio ratio) {
49 | return new AspectRatioIsCloseTo(ratio);
50 | }
51 |
52 | @Factory
53 | public static Matcher closeToOrInverse(AspectRatio ratio) {
54 | return either(closeTo(ratio)).or(closeTo(ratio.inverse()));
55 | }
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/library/src/androidTest/java/com/google/android/cameraview/CameraViewActions.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.google.android.cameraview;
18 |
19 | import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom;
20 |
21 | import android.support.annotation.NonNull;
22 | import android.support.test.espresso.UiController;
23 | import android.support.test.espresso.ViewAction;
24 | import android.view.View;
25 |
26 | import org.hamcrest.Matcher;
27 |
28 | class CameraViewActions {
29 |
30 | static ViewAction setAspectRatio(@NonNull final AspectRatio ratio) {
31 | return new ViewAction() {
32 |
33 | @Override
34 | public Matcher getConstraints() {
35 | return isAssignableFrom(CameraView.class);
36 | }
37 |
38 | @Override
39 | public String getDescription() {
40 | return "Set aspect ratio to " + ratio;
41 | }
42 |
43 | @Override
44 | public void perform(UiController controller, View view) {
45 | ((CameraView) view).setAspectRatio(ratio);
46 | }
47 | };
48 | }
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/library/src/androidTest/java/com/google/android/cameraview/CameraViewActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.google.android.cameraview;
18 |
19 | import android.app.Activity;
20 | import android.os.Bundle;
21 |
22 | import com.google.android.cameraview.test.R;
23 |
24 | public class CameraViewActivity extends Activity {
25 |
26 | private CameraView mCameraView;
27 |
28 | @Override
29 | protected void onCreate(Bundle savedInstanceState) {
30 | super.onCreate(savedInstanceState);
31 | setContentView(R.layout.activity_camera_view);
32 | mCameraView = (CameraView) findViewById(R.id.camera);
33 | }
34 |
35 | @Override
36 | protected void onResume() {
37 | super.onResume();
38 | mCameraView.start();
39 | }
40 |
41 | @Override
42 | protected void onPause() {
43 | mCameraView.stop();
44 | super.onPause();
45 | }
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/library/src/androidTest/java/com/google/android/cameraview/CameraViewMatchers.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.google.android.cameraview;
18 |
19 | import android.support.annotation.NonNull;
20 | import android.view.View;
21 |
22 | import org.hamcrest.Description;
23 | import org.hamcrest.Matcher;
24 | import org.hamcrest.TypeSafeMatcher;
25 |
26 | class CameraViewMatchers {
27 |
28 | static Matcher hasAspectRatio(@NonNull final AspectRatio ratio) {
29 | return new TypeSafeMatcher() {
30 | @Override
31 | public void describeTo(Description description) {
32 | description.appendText("has aspect ratio of " + ratio);
33 | }
34 |
35 | @Override
36 | protected boolean matchesSafely(View view) {
37 | return ratio.equals(((CameraView) view).getAspectRatio());
38 | }
39 | };
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/library/src/androidTest/java/com/google/android/cameraview/CameraViewTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.google.android.cameraview;
18 |
19 | import static android.support.test.espresso.Espresso.onView;
20 | import static android.support.test.espresso.assertion.ViewAssertions.matches;
21 | import static android.support.test.espresso.matcher.ViewMatchers.assertThat;
22 | import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
23 | import static android.support.test.espresso.matcher.ViewMatchers.withId;
24 |
25 | import static com.google.android.cameraview.AspectRatioIsCloseTo.closeToOrInverse;
26 | import static com.google.android.cameraview.CameraViewActions.setAspectRatio;
27 | import static com.google.android.cameraview.CameraViewMatchers.hasAspectRatio;
28 |
29 | import static junit.framework.Assert.assertFalse;
30 |
31 | import static org.hamcrest.CoreMatchers.is;
32 |
33 | import android.graphics.Bitmap;
34 | import android.os.SystemClock;
35 | import android.support.test.espresso.IdlingRegistry;
36 | import android.support.test.espresso.IdlingResource;
37 | import android.support.test.espresso.NoMatchingViewException;
38 | import android.support.test.espresso.UiController;
39 | import android.support.test.espresso.ViewAction;
40 | import android.support.test.espresso.ViewAssertion;
41 | import android.support.test.filters.FlakyTest;
42 | import android.support.test.rule.ActivityTestRule;
43 | import android.support.test.runner.AndroidJUnit4;
44 | import android.view.TextureView;
45 | import android.view.View;
46 | import android.view.ViewGroup;
47 |
48 | import com.google.android.cameraview.test.R;
49 |
50 | import org.hamcrest.Matcher;
51 | import org.hamcrest.core.IsAnything;
52 | import org.junit.After;
53 | import org.junit.Before;
54 | import org.junit.Rule;
55 | import org.junit.Test;
56 | import org.junit.runner.RunWith;
57 |
58 | import java.io.Closeable;
59 | import java.io.IOException;
60 | import java.util.Set;
61 |
62 | @RunWith(AndroidJUnit4.class)
63 | public class CameraViewTest {
64 |
65 | @Rule
66 | public final ActivityTestRule rule;
67 |
68 | private CameraViewIdlingResource mCameraViewIdlingResource;
69 |
70 | public CameraViewTest() {
71 | rule = new ActivityTestRule<>(CameraViewActivity.class);
72 | }
73 |
74 | @Before
75 | public void setUpIdlingResource() {
76 | mCameraViewIdlingResource = new CameraViewIdlingResource(
77 | (CameraView) rule.getActivity().findViewById(R.id.camera));
78 | IdlingRegistry.getInstance().register(mCameraViewIdlingResource);
79 | }
80 |
81 | @After
82 | public void tearDownIdlingResource() throws Exception {
83 | IdlingRegistry.getInstance().unregister(mCameraViewIdlingResource);
84 | mCameraViewIdlingResource.close();
85 | }
86 |
87 | @Test
88 | public void testSetup() {
89 | onView(withId(R.id.camera))
90 | .check(matches(isDisplayed()));
91 | try {
92 | onView(withId(R.id.texture_view))
93 | .check(matches(isDisplayed()));
94 | } catch (NoMatchingViewException e) {
95 | onView(withId(R.id.surface_view))
96 | .check(matches(isDisplayed()));
97 | }
98 | }
99 |
100 | @Test
101 | @FlakyTest
102 | public void preview_isShowing() throws Exception {
103 | onView(withId(R.id.camera))
104 | .perform(waitFor(1000))
105 | .check(showingPreview());
106 | }
107 |
108 | @Test
109 | public void testAspectRatio() {
110 | final CameraView cameraView = rule.getActivity().findViewById(R.id.camera);
111 | final Set ratios = cameraView.getSupportedAspectRatios();
112 | for (AspectRatio ratio : ratios) {
113 | onView(withId(R.id.camera))
114 | .perform(setAspectRatio(ratio))
115 | .check(matches(hasAspectRatio(ratio)));
116 | }
117 | }
118 |
119 | @Test
120 | public void testAdjustViewBounds() {
121 | onView(withId(R.id.camera))
122 | .check(new ViewAssertion() {
123 | @Override
124 | public void check(View view, NoMatchingViewException noViewFoundException) {
125 | CameraView cameraView = (CameraView) view;
126 | assertThat(cameraView.getAdjustViewBounds(), is(false));
127 | cameraView.setAdjustViewBounds(true);
128 | assertThat(cameraView.getAdjustViewBounds(), is(true));
129 | }
130 | })
131 | .perform(new AnythingAction("layout") {
132 | @Override
133 | public void perform(UiController uiController, View view) {
134 | ViewGroup.LayoutParams params = view.getLayoutParams();
135 | params.height = ViewGroup.LayoutParams.WRAP_CONTENT;
136 | view.setLayoutParams(params);
137 | }
138 | })
139 | .check(new ViewAssertion() {
140 | @Override
141 | public void check(View view, NoMatchingViewException noViewFoundException) {
142 | CameraView cameraView = (CameraView) view;
143 | AspectRatio cameraRatio = cameraView.getAspectRatio();
144 | AspectRatio viewRatio = AspectRatio.of(view.getWidth(), view.getHeight());
145 | assertThat(cameraRatio, is(closeToOrInverse(viewRatio)));
146 | }
147 | });
148 | }
149 |
150 | @Test
151 | public void testPreviewViewSize() {
152 | onView(withId(R.id.camera))
153 | .check(new ViewAssertion() {
154 | @Override
155 | public void check(View view, NoMatchingViewException noViewFoundException) {
156 | CameraView cameraView = (CameraView) view;
157 | View preview = view.findViewById(R.id.texture_view);
158 | if (preview == null) {
159 | preview = view.findViewById(R.id.surface_view);
160 | }
161 | AspectRatio cameraRatio = cameraView.getAspectRatio();
162 | assert cameraRatio != null;
163 | AspectRatio textureRatio = AspectRatio.of(
164 | preview.getWidth(), preview.getHeight());
165 | assertThat(textureRatio, is(closeToOrInverse(cameraRatio)));
166 | }
167 | });
168 | }
169 |
170 | @Test
171 | public void testAutoFocus() {
172 | onView(withId(R.id.camera))
173 | .check(new ViewAssertion() {
174 | @Override
175 | public void check(View view, NoMatchingViewException noViewFoundException) {
176 | CameraView cameraView = (CameraView) view;
177 | // This can fail on devices without auto-focus support
178 | assertThat(cameraView.getAutoFocus(), is(true));
179 | cameraView.setAutoFocus(false);
180 | assertThat(cameraView.getAutoFocus(), is(false));
181 | cameraView.setAutoFocus(true);
182 | assertThat(cameraView.getAutoFocus(), is(true));
183 | }
184 | });
185 | }
186 |
187 | @Test
188 | public void testFacing() {
189 | onView(withId(R.id.camera))
190 | .check(new ViewAssertion() {
191 | @Override
192 | public void check(View view, NoMatchingViewException noViewFoundException) {
193 | CameraView cameraView = (CameraView) view;
194 | assertThat(cameraView.getFacing(), is(CameraView.FACING_BACK));
195 | cameraView.setFacing(CameraView.FACING_FRONT);
196 | assertThat(cameraView.getFacing(), is(CameraView.FACING_FRONT));
197 | }
198 | })
199 | .perform(waitFor(1000))
200 | .check(showingPreview());
201 | }
202 |
203 | @Test
204 | public void testFlash() {
205 | onView(withId(R.id.camera))
206 | .check(new ViewAssertion() {
207 | @Override
208 | public void check(View view, NoMatchingViewException noViewFoundException) {
209 | CameraView cameraView = (CameraView) view;
210 | assertThat(cameraView.getFlash(), is(CameraView.FLASH_AUTO));
211 | cameraView.setFlash(CameraView.FLASH_TORCH);
212 | assertThat(cameraView.getFlash(), is(CameraView.FLASH_TORCH));
213 | }
214 | });
215 | }
216 |
217 | @Test
218 | public void testTakePicture() throws Exception {
219 | TakePictureIdlingResource resource = new TakePictureIdlingResource(
220 | (CameraView) rule.getActivity().findViewById(R.id.camera));
221 | onView(withId(R.id.camera))
222 | .perform(new AnythingAction("take picture") {
223 | @Override
224 | public void perform(UiController uiController, View view) {
225 | CameraView cameraView = (CameraView) view;
226 | cameraView.takePicture();
227 | }
228 | });
229 | try {
230 | IdlingRegistry.getInstance().register(resource);
231 | onView(withId(R.id.camera))
232 | .perform(waitFor(1000))
233 | .check(showingPreview());
234 | assertThat("Didn't receive valid JPEG data.", resource.receivedValidJpeg(), is(true));
235 | } finally {
236 | IdlingRegistry.getInstance().unregister(resource);
237 | resource.close();
238 | }
239 | }
240 |
241 | private static ViewAction waitFor(final long ms) {
242 | return new AnythingAction("wait") {
243 | @Override
244 | public void perform(UiController uiController, View view) {
245 | SystemClock.sleep(ms);
246 | }
247 | };
248 | }
249 |
250 | private static ViewAssertion showingPreview() {
251 | return new ViewAssertion() {
252 | @Override
253 | public void check(View view, NoMatchingViewException noViewFoundException) {
254 | CameraView cameraView = (CameraView) view;
255 | TextureView textureView = cameraView.findViewById(R.id.texture_view);
256 | Bitmap bitmap = textureView.getBitmap();
257 | int topLeft = bitmap.getPixel(0, 0);
258 | int center = bitmap.getPixel(bitmap.getWidth() / 2, bitmap.getHeight() / 2);
259 | int bottomRight = bitmap.getPixel(
260 | bitmap.getWidth() - 1, bitmap.getHeight() - 1);
261 | assertFalse("Preview possibly blank: " + Integer.toHexString(topLeft),
262 | topLeft == center && center == bottomRight);
263 | }
264 | };
265 | }
266 |
267 | /**
268 | * Wait for a camera to open.
269 | */
270 | private static class CameraViewIdlingResource implements IdlingResource, Closeable {
271 |
272 | private final CameraView.Callback mCallback
273 | = new CameraView.Callback() {
274 |
275 | @Override
276 | public void onCameraOpened(CameraView cameraView) {
277 | if (!mIsIdleNow) {
278 | mIsIdleNow = true;
279 | if (mResourceCallback != null) {
280 | mResourceCallback.onTransitionToIdle();
281 | }
282 | }
283 | }
284 |
285 | @Override
286 | public void onCameraClosed(CameraView cameraView) {
287 | mIsIdleNow = false;
288 | }
289 | };
290 |
291 | private final CameraView mCameraView;
292 |
293 | private ResourceCallback mResourceCallback;
294 |
295 | private boolean mIsIdleNow;
296 |
297 | public CameraViewIdlingResource(CameraView cameraView) {
298 | mCameraView = cameraView;
299 | mCameraView.addCallback(mCallback);
300 | mIsIdleNow = mCameraView.isCameraOpened();
301 | }
302 |
303 | @Override
304 | public void close() throws IOException {
305 | mCameraView.removeCallback(mCallback);
306 | }
307 |
308 | @Override
309 | public String getName() {
310 | return CameraViewIdlingResource.class.getSimpleName();
311 | }
312 |
313 | @Override
314 | public boolean isIdleNow() {
315 | return mIsIdleNow;
316 | }
317 |
318 | @Override
319 | public void registerIdleTransitionCallback(ResourceCallback callback) {
320 | mResourceCallback = callback;
321 | }
322 |
323 | }
324 |
325 | private static class TakePictureIdlingResource implements IdlingResource, Closeable {
326 |
327 | private final CameraView.Callback mCallback
328 | = new CameraView.Callback() {
329 | @Override
330 | public void onPictureTaken(CameraView cameraView, byte[] data) {
331 | if (!mIsIdleNow) {
332 | mIsIdleNow = true;
333 | mValidJpeg = data.length > 2 &&
334 | data[0] == (byte) 0xFF && data[1] == (byte) 0xD8;
335 | if (mResourceCallback != null) {
336 | mResourceCallback.onTransitionToIdle();
337 | }
338 | }
339 | }
340 | };
341 |
342 | private final CameraView mCameraView;
343 |
344 | private ResourceCallback mResourceCallback;
345 |
346 | private boolean mIsIdleNow;
347 |
348 | private boolean mValidJpeg;
349 |
350 | public TakePictureIdlingResource(CameraView cameraView) {
351 | mCameraView = cameraView;
352 | mCameraView.addCallback(mCallback);
353 | }
354 |
355 | @Override
356 | public void close() throws IOException {
357 | mCameraView.removeCallback(mCallback);
358 | }
359 |
360 | @Override
361 | public String getName() {
362 | return TakePictureIdlingResource.class.getSimpleName();
363 | }
364 |
365 | @Override
366 | public boolean isIdleNow() {
367 | return mIsIdleNow;
368 | }
369 |
370 | @Override
371 | public void registerIdleTransitionCallback(ResourceCallback callback) {
372 | mResourceCallback = callback;
373 | }
374 |
375 | public boolean receivedValidJpeg() {
376 | return mValidJpeg;
377 | }
378 |
379 | }
380 |
381 | private static abstract class AnythingAction implements ViewAction {
382 |
383 | private final String mDescription;
384 |
385 | public AnythingAction(String description) {
386 | mDescription = description;
387 | }
388 |
389 | @Override
390 | public Matcher getConstraints() {
391 | return new IsAnything<>();
392 | }
393 |
394 | @Override
395 | public String getDescription() {
396 | return mDescription;
397 | }
398 |
399 | }
400 |
401 | }
402 |
--------------------------------------------------------------------------------
/library/src/androidTest/res/layout/activity_camera_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
14 |
18 |
19 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/library/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
14 |
16 |
17 |
18 |
19 |
20 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/library/src/main/api14/com/google/android/cameraview/Camera1.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.google.android.cameraview;
18 |
19 | import android.annotation.SuppressLint;
20 | import android.graphics.SurfaceTexture;
21 | import android.hardware.Camera;
22 | import android.support.v4.util.SparseArrayCompat;
23 | import android.view.SurfaceHolder;
24 |
25 | import java.io.IOException;
26 | import java.util.List;
27 | import java.util.Set;
28 | import java.util.SortedSet;
29 | import java.util.concurrent.atomic.AtomicBoolean;
30 |
31 |
32 | @SuppressWarnings("deprecation")
33 | class Camera1 extends CameraViewImpl {
34 |
35 | private static final int INVALID_CAMERA_ID = -1;
36 |
37 | private static final SparseArrayCompat FLASH_MODES = new SparseArrayCompat<>();
38 |
39 | static {
40 | FLASH_MODES.put(Constants.FLASH_OFF, Camera.Parameters.FLASH_MODE_OFF);
41 | FLASH_MODES.put(Constants.FLASH_ON, Camera.Parameters.FLASH_MODE_ON);
42 | FLASH_MODES.put(Constants.FLASH_TORCH, Camera.Parameters.FLASH_MODE_TORCH);
43 | FLASH_MODES.put(Constants.FLASH_AUTO, Camera.Parameters.FLASH_MODE_AUTO);
44 | FLASH_MODES.put(Constants.FLASH_RED_EYE, Camera.Parameters.FLASH_MODE_RED_EYE);
45 | }
46 |
47 | private int mCameraId;
48 |
49 | private final AtomicBoolean isPictureCaptureInProgress = new AtomicBoolean(false);
50 |
51 | Camera mCamera;
52 |
53 | private Camera.Parameters mCameraParameters;
54 |
55 | private final Camera.CameraInfo mCameraInfo = new Camera.CameraInfo();
56 |
57 | private final SizeMap mPreviewSizes = new SizeMap();
58 |
59 | private final SizeMap mPictureSizes = new SizeMap();
60 |
61 | private AspectRatio mAspectRatio;
62 |
63 | private boolean mShowingPreview;
64 |
65 | private boolean mAutoFocus;
66 |
67 | private int mFacing;
68 |
69 | private int mFlash;
70 |
71 | private int mDisplayOrientation;
72 |
73 | Camera1(Callback callback, PreviewImpl preview) {
74 | super(callback, preview);
75 | preview.setCallback(new PreviewImpl.Callback() {
76 | @Override
77 | public void onSurfaceChanged() {
78 | if (mCamera != null) {
79 | setUpPreview();
80 | adjustCameraParameters();
81 | }
82 | }
83 | });
84 | }
85 |
86 | @Override
87 | boolean start() {
88 | chooseCamera();
89 | openCamera();
90 | if (mPreview.isReady()) {
91 | setUpPreview();
92 | }
93 | mShowingPreview = true;
94 | mCamera.startPreview();
95 | return true;
96 | }
97 |
98 | @Override
99 | void stop() {
100 | if (mCamera != null) {
101 | mCamera.stopPreview();
102 | }
103 | mShowingPreview = false;
104 | releaseCamera();
105 | }
106 |
107 | // Suppresses Camera#setPreviewTexture
108 | @SuppressLint("NewApi")
109 | void setUpPreview() {
110 | try {
111 | if (mPreview.getOutputClass() == SurfaceHolder.class) {
112 | mCamera.setPreviewDisplay(mPreview.getSurfaceHolder());
113 | } else {
114 | mCamera.setPreviewTexture((SurfaceTexture) mPreview.getSurfaceTexture());
115 | }
116 | } catch (IOException e) {
117 | throw new RuntimeException(e);
118 | }
119 | }
120 |
121 | @Override
122 | boolean isCameraOpened() {
123 | return mCamera != null;
124 | }
125 |
126 | @Override
127 | void setFacing(int facing) {
128 | if (mFacing == facing) {
129 | return;
130 | }
131 | mFacing = facing;
132 | if (isCameraOpened()) {
133 | stop();
134 | start();
135 | }
136 | }
137 |
138 | @Override
139 | int getFacing() {
140 | return mFacing;
141 | }
142 |
143 | @Override
144 | Set getSupportedAspectRatios() {
145 | SizeMap idealAspectRatios = mPreviewSizes;
146 | for (AspectRatio aspectRatio : idealAspectRatios.ratios()) {
147 | if (mPictureSizes.sizes(aspectRatio) == null) {
148 | idealAspectRatios.remove(aspectRatio);
149 | }
150 | }
151 | return idealAspectRatios.ratios();
152 | }
153 |
154 | @Override
155 | boolean setAspectRatio(AspectRatio ratio) {
156 | if (mAspectRatio == null || !isCameraOpened()) {
157 | // Handle this later when camera is opened
158 | mAspectRatio = ratio;
159 | return true;
160 | } else if (!mAspectRatio.equals(ratio)) {
161 | final Set sizes = mPreviewSizes.sizes(ratio);
162 | if (sizes == null) {
163 | throw new UnsupportedOperationException(ratio + " is not supported");
164 | } else {
165 | mAspectRatio = ratio;
166 | adjustCameraParameters();
167 | return true;
168 | }
169 | }
170 | return false;
171 | }
172 |
173 | @Override
174 | AspectRatio getAspectRatio() {
175 | return mAspectRatio;
176 | }
177 |
178 | @Override
179 | void setAutoFocus(boolean autoFocus) {
180 | if (mAutoFocus == autoFocus) {
181 | return;
182 | }
183 | if (setAutoFocusInternal(autoFocus)) {
184 | mCamera.setParameters(mCameraParameters);
185 | }
186 | }
187 |
188 | @Override
189 | boolean getAutoFocus() {
190 | if (!isCameraOpened()) {
191 | return mAutoFocus;
192 | }
193 | String focusMode = mCameraParameters.getFocusMode();
194 | return focusMode != null && focusMode.contains("continuous");
195 | }
196 |
197 | @Override
198 | void setFlash(int flash) {
199 | if (flash == mFlash) {
200 | return;
201 | }
202 | if (setFlashInternal(flash)) {
203 | mCamera.setParameters(mCameraParameters);
204 | }
205 | }
206 |
207 | @Override
208 | int getFlash() {
209 | return mFlash;
210 | }
211 |
212 | @Override
213 | void takePicture() {
214 | if (!isCameraOpened()) {
215 | throw new IllegalStateException(
216 | "Camera is not ready. Call start() before takePicture().");
217 | }
218 | if (getAutoFocus()) {
219 | mCamera.cancelAutoFocus();
220 | mCamera.autoFocus(new Camera.AutoFocusCallback() {
221 | @Override
222 | public void onAutoFocus(boolean success, Camera camera) {
223 | takePictureInternal();
224 | }
225 | });
226 | } else {
227 | takePictureInternal();
228 | }
229 | }
230 |
231 | void takePictureInternal() {
232 | if (!isPictureCaptureInProgress.getAndSet(true)) {
233 | mCamera.takePicture(null, null, null, new Camera.PictureCallback() {
234 | @Override
235 | public void onPictureTaken(byte[] data, Camera camera) {
236 | isPictureCaptureInProgress.set(false);
237 | mCallback.onPictureTaken(data);
238 | camera.cancelAutoFocus();
239 | camera.startPreview();
240 | }
241 | });
242 | }
243 | }
244 |
245 | @Override
246 | void setDisplayOrientation(int displayOrientation) {
247 | if (mDisplayOrientation == displayOrientation) {
248 | return;
249 | }
250 | mDisplayOrientation = displayOrientation;
251 | if (isCameraOpened()) {
252 | mCameraParameters.setRotation(calcCameraRotation(displayOrientation));
253 | mCamera.setParameters(mCameraParameters);
254 | mCamera.setDisplayOrientation(calcDisplayOrientation(displayOrientation));
255 | }
256 | }
257 |
258 | /**
259 | * This rewrites {@link #mCameraId} and {@link #mCameraInfo}.
260 | */
261 | private void chooseCamera() {
262 | for (int i = 0, count = Camera.getNumberOfCameras(); i < count; i++) {
263 | Camera.getCameraInfo(i, mCameraInfo);
264 | if (mCameraInfo.facing == mFacing) {
265 | mCameraId = i;
266 | return;
267 | }
268 | }
269 | mCameraId = INVALID_CAMERA_ID;
270 | }
271 |
272 | private void openCamera() {
273 | if (mCamera != null) {
274 | releaseCamera();
275 | }
276 | mCamera = Camera.open(mCameraId);
277 | mCameraParameters = mCamera.getParameters();
278 | // Supported preview sizes
279 | mPreviewSizes.clear();
280 | for (Camera.Size size : mCameraParameters.getSupportedPreviewSizes()) {
281 | mPreviewSizes.add(new Size(size.width, size.height));
282 | }
283 | // Supported picture sizes;
284 | mPictureSizes.clear();
285 | for (Camera.Size size : mCameraParameters.getSupportedPictureSizes()) {
286 | mPictureSizes.add(new Size(size.width, size.height));
287 | }
288 | // AspectRatio
289 | if (mAspectRatio == null) {
290 | mAspectRatio = Constants.DEFAULT_ASPECT_RATIO;
291 | }
292 | adjustCameraParameters();
293 | mCamera.setDisplayOrientation(calcDisplayOrientation(mDisplayOrientation));
294 | mCallback.onCameraOpened();
295 | }
296 |
297 | private AspectRatio chooseAspectRatio() {
298 | AspectRatio r = null;
299 | for (AspectRatio ratio : mPreviewSizes.ratios()) {
300 | r = ratio;
301 | if (ratio.equals(Constants.DEFAULT_ASPECT_RATIO)) {
302 | return ratio;
303 | }
304 | }
305 | return r;
306 | }
307 |
308 | void adjustCameraParameters() {
309 | SortedSet sizes = mPreviewSizes.sizes(mAspectRatio);
310 | if (sizes == null) { // Not supported
311 | mAspectRatio = chooseAspectRatio();
312 | sizes = mPreviewSizes.sizes(mAspectRatio);
313 | }
314 | Size size = chooseOptimalSize(sizes);
315 |
316 | // Always re-apply camera parameters
317 | // Largest picture size in this ratio
318 | final Size pictureSize = mPictureSizes.sizes(mAspectRatio).last();
319 | if (mShowingPreview) {
320 | mCamera.stopPreview();
321 | }
322 | mCameraParameters.setPreviewSize(size.getWidth(), size.getHeight());
323 | mCameraParameters.setPictureSize(pictureSize.getWidth(), pictureSize.getHeight());
324 | mCameraParameters.setRotation(calcCameraRotation(mDisplayOrientation));
325 | setAutoFocusInternal(mAutoFocus);
326 | setFlashInternal(mFlash);
327 | mCamera.setParameters(mCameraParameters);
328 | if (mShowingPreview) {
329 | mCamera.startPreview();
330 | }
331 | }
332 |
333 | @SuppressWarnings("SuspiciousNameCombination")
334 | private Size chooseOptimalSize(SortedSet sizes) {
335 | if (!mPreview.isReady()) { // Not yet laid out
336 | return sizes.first(); // Return the smallest size
337 | }
338 | int desiredWidth;
339 | int desiredHeight;
340 | final int surfaceWidth = mPreview.getWidth();
341 | final int surfaceHeight = mPreview.getHeight();
342 | if (isLandscape(mDisplayOrientation)) {
343 | desiredWidth = surfaceHeight;
344 | desiredHeight = surfaceWidth;
345 | } else {
346 | desiredWidth = surfaceWidth;
347 | desiredHeight = surfaceHeight;
348 | }
349 | Size result = null;
350 | for (Size size : sizes) { // Iterate from small to large
351 | if (desiredWidth <= size.getWidth() && desiredHeight <= size.getHeight()) {
352 | return size;
353 |
354 | }
355 | result = size;
356 | }
357 | return result;
358 | }
359 |
360 | private void releaseCamera() {
361 | if (mCamera != null) {
362 | mCamera.release();
363 | mCamera = null;
364 | mCallback.onCameraClosed();
365 | }
366 | }
367 |
368 | /**
369 | * Calculate display orientation
370 | * https://developer.android.com/reference/android/hardware/Camera.html#setDisplayOrientation(int)
371 | *
372 | * This calculation is used for orienting the preview
373 | *
374 | * Note: This is not the same calculation as the camera rotation
375 | *
376 | * @param screenOrientationDegrees Screen orientation in degrees
377 | * @return Number of degrees required to rotate preview
378 | */
379 | private int calcDisplayOrientation(int screenOrientationDegrees) {
380 | if (mCameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
381 | return (360 - (mCameraInfo.orientation + screenOrientationDegrees) % 360) % 360;
382 | } else { // back-facing
383 | return (mCameraInfo.orientation - screenOrientationDegrees + 360) % 360;
384 | }
385 | }
386 |
387 | /**
388 | * Calculate camera rotation
389 | *
390 | * This calculation is applied to the output JPEG either via Exif Orientation tag
391 | * or by actually transforming the bitmap. (Determined by vendor camera API implementation)
392 | *
393 | * Note: This is not the same calculation as the display orientation
394 | *
395 | * @param screenOrientationDegrees Screen orientation in degrees
396 | * @return Number of degrees to rotate image in order for it to view correctly.
397 | */
398 | private int calcCameraRotation(int screenOrientationDegrees) {
399 | if (mCameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
400 | return (mCameraInfo.orientation + screenOrientationDegrees) % 360;
401 | } else { // back-facing
402 | final int landscapeFlip = isLandscape(screenOrientationDegrees) ? 180 : 0;
403 | return (mCameraInfo.orientation + screenOrientationDegrees + landscapeFlip) % 360;
404 | }
405 | }
406 |
407 | /**
408 | * Test if the supplied orientation is in landscape.
409 | *
410 | * @param orientationDegrees Orientation in degrees (0,90,180,270)
411 | * @return True if in landscape, false if portrait
412 | */
413 | private boolean isLandscape(int orientationDegrees) {
414 | return (orientationDegrees == Constants.LANDSCAPE_90 ||
415 | orientationDegrees == Constants.LANDSCAPE_270);
416 | }
417 |
418 | /**
419 | * @return {@code true} if {@link #mCameraParameters} was modified.
420 | */
421 | private boolean setAutoFocusInternal(boolean autoFocus) {
422 | mAutoFocus = autoFocus;
423 | if (isCameraOpened()) {
424 | final List modes = mCameraParameters.getSupportedFocusModes();
425 | if (autoFocus && modes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
426 | mCameraParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
427 | } else if (modes.contains(Camera.Parameters.FOCUS_MODE_FIXED)) {
428 | mCameraParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_FIXED);
429 | } else if (modes.contains(Camera.Parameters.FOCUS_MODE_INFINITY)) {
430 | mCameraParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_INFINITY);
431 | } else {
432 | mCameraParameters.setFocusMode(modes.get(0));
433 | }
434 | return true;
435 | } else {
436 | return false;
437 | }
438 | }
439 |
440 | /**
441 | * @return {@code true} if {@link #mCameraParameters} was modified.
442 | */
443 | private boolean setFlashInternal(int flash) {
444 | if (isCameraOpened()) {
445 | List modes = mCameraParameters.getSupportedFlashModes();
446 | String mode = FLASH_MODES.get(flash);
447 | if (modes != null && modes.contains(mode)) {
448 | mCameraParameters.setFlashMode(mode);
449 | mFlash = flash;
450 | return true;
451 | }
452 | String currentMode = FLASH_MODES.get(mFlash);
453 | if (modes == null || !modes.contains(currentMode)) {
454 | mCameraParameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
455 | mFlash = Constants.FLASH_OFF;
456 | return true;
457 | }
458 | return false;
459 | } else {
460 | mFlash = flash;
461 | return false;
462 | }
463 | }
464 |
465 | }
466 |
--------------------------------------------------------------------------------
/library/src/main/api14/com/google/android/cameraview/SurfaceViewPreview.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.google.android.cameraview;
18 |
19 | import android.content.Context;
20 | import android.support.v4.view.ViewCompat;
21 | import android.view.Surface;
22 | import android.view.SurfaceHolder;
23 | import android.view.SurfaceView;
24 | import android.view.View;
25 | import android.view.ViewGroup;
26 |
27 | class SurfaceViewPreview extends PreviewImpl {
28 |
29 | final SurfaceView mSurfaceView;
30 |
31 | SurfaceViewPreview(Context context, ViewGroup parent) {
32 | final View view = View.inflate(context, R.layout.surface_view, parent);
33 | mSurfaceView = view.findViewById(R.id.surface_view);
34 | final SurfaceHolder holder = mSurfaceView.getHolder();
35 | //noinspection deprecation
36 | holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
37 | holder.addCallback(new SurfaceHolder.Callback() {
38 | @Override
39 | public void surfaceCreated(SurfaceHolder h) {
40 | }
41 |
42 | @Override
43 | public void surfaceChanged(SurfaceHolder h, int format, int width, int height) {
44 | setSize(width, height);
45 | if (!ViewCompat.isInLayout(mSurfaceView)) {
46 | dispatchSurfaceChanged();
47 | }
48 | }
49 |
50 | @Override
51 | public void surfaceDestroyed(SurfaceHolder h) {
52 | setSize(0, 0);
53 | }
54 | });
55 | }
56 |
57 | @Override
58 | Surface getSurface() {
59 | return getSurfaceHolder().getSurface();
60 | }
61 |
62 | @Override
63 | SurfaceHolder getSurfaceHolder() {
64 | return mSurfaceView.getHolder();
65 | }
66 |
67 | @Override
68 | View getView() {
69 | return mSurfaceView;
70 | }
71 |
72 | @Override
73 | Class getOutputClass() {
74 | return SurfaceHolder.class;
75 | }
76 |
77 | @Override
78 | void setDisplayOrientation(int displayOrientation) {
79 | }
80 |
81 | @Override
82 | boolean isReady() {
83 | return getWidth() != 0 && getHeight() != 0;
84 | }
85 |
86 | }
87 |
--------------------------------------------------------------------------------
/library/src/main/api14/com/google/android/cameraview/TextureViewPreview.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.google.android.cameraview;
18 |
19 | import android.annotation.TargetApi;
20 | import android.content.Context;
21 | import android.graphics.Matrix;
22 | import android.graphics.SurfaceTexture;
23 | import android.view.Surface;
24 | import android.view.TextureView;
25 | import android.view.View;
26 | import android.view.ViewGroup;
27 |
28 | @TargetApi(14)
29 | class TextureViewPreview extends PreviewImpl {
30 |
31 | private final TextureView mTextureView;
32 |
33 | private int mDisplayOrientation;
34 |
35 | TextureViewPreview(Context context, ViewGroup parent) {
36 | final View view = View.inflate(context, R.layout.texture_view, parent);
37 | mTextureView = view.findViewById(R.id.texture_view);
38 | mTextureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {
39 |
40 | @Override
41 | public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
42 | setSize(width, height);
43 | configureTransform();
44 | dispatchSurfaceChanged();
45 | }
46 |
47 | @Override
48 | public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
49 | setSize(width, height);
50 | configureTransform();
51 | dispatchSurfaceChanged();
52 | }
53 |
54 | @Override
55 | public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
56 | setSize(0, 0);
57 | return true;
58 | }
59 |
60 | @Override
61 | public void onSurfaceTextureUpdated(SurfaceTexture surface) {
62 | }
63 | });
64 | }
65 |
66 | // This method is called only from Camera2.
67 | @TargetApi(15)
68 | @Override
69 | void setBufferSize(int width, int height) {
70 | mTextureView.getSurfaceTexture().setDefaultBufferSize(width, height);
71 | }
72 |
73 | @Override
74 | Surface getSurface() {
75 | return new Surface(mTextureView.getSurfaceTexture());
76 | }
77 |
78 | @Override
79 | SurfaceTexture getSurfaceTexture() {
80 | return mTextureView.getSurfaceTexture();
81 | }
82 |
83 | @Override
84 | View getView() {
85 | return mTextureView;
86 | }
87 |
88 | @Override
89 | Class getOutputClass() {
90 | return SurfaceTexture.class;
91 | }
92 |
93 | @Override
94 | void setDisplayOrientation(int displayOrientation) {
95 | mDisplayOrientation = displayOrientation;
96 | configureTransform();
97 | }
98 |
99 | @Override
100 | boolean isReady() {
101 | return mTextureView.getSurfaceTexture() != null;
102 | }
103 |
104 | /**
105 | * Configures the transform matrix for TextureView based on {@link #mDisplayOrientation} and
106 | * the surface size.
107 | */
108 | void configureTransform() {
109 | Matrix matrix = new Matrix();
110 | if (mDisplayOrientation % 180 == 90) {
111 | final int width = getWidth();
112 | final int height = getHeight();
113 | // Rotate the camera preview when the screen is landscape.
114 | matrix.setPolyToPoly(
115 | new float[]{
116 | 0.f, 0.f, // top left
117 | width, 0.f, // top right
118 | 0.f, height, // bottom left
119 | width, height, // bottom right
120 | }, 0,
121 | mDisplayOrientation == 90 ?
122 | // Clockwise
123 | new float[]{
124 | 0.f, height, // top left
125 | 0.f, 0.f, // top right
126 | width, height, // bottom left
127 | width, 0.f, // bottom right
128 | } : // mDisplayOrientation == 270
129 | // Counter-clockwise
130 | new float[]{
131 | width, 0.f, // top left
132 | width, height, // top right
133 | 0.f, 0.f, // bottom left
134 | 0.f, height, // bottom right
135 | }, 0,
136 | 4);
137 | } else if (mDisplayOrientation == 180) {
138 | matrix.postRotate(180, getWidth() / 2, getHeight() / 2);
139 | }
140 | mTextureView.setTransform(matrix);
141 | }
142 |
143 | }
144 |
--------------------------------------------------------------------------------
/library/src/main/api23/com/google/android/cameraview/Camera2Api23.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.google.android.cameraview;
18 |
19 | import android.annotation.TargetApi;
20 | import android.content.Context;
21 | import android.graphics.ImageFormat;
22 | import android.hardware.camera2.params.StreamConfigurationMap;
23 |
24 |
25 | @TargetApi(23)
26 | class Camera2Api23 extends Camera2 {
27 |
28 | Camera2Api23(Callback callback, PreviewImpl preview, Context context) {
29 | super(callback, preview, context);
30 | }
31 |
32 | @Override
33 | protected void collectPictureSizes(SizeMap sizes, StreamConfigurationMap map) {
34 | // Try to get hi-res output sizes
35 | android.util.Size[] outputSizes = map.getHighResolutionOutputSizes(ImageFormat.JPEG);
36 | if (outputSizes != null) {
37 | for (android.util.Size size : map.getHighResolutionOutputSizes(ImageFormat.JPEG)) {
38 | sizes.add(new Size(size.getWidth(), size.getHeight()));
39 | }
40 | }
41 | if (sizes.isEmpty()) {
42 | super.collectPictureSizes(sizes, map);
43 | }
44 | }
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/library/src/main/base/com/google/android/cameraview/AspectRatio.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.google.android.cameraview;
18 |
19 | import android.os.Parcel;
20 | import android.os.Parcelable;
21 | import android.support.annotation.NonNull;
22 | import android.support.v4.util.SparseArrayCompat;
23 |
24 | /**
25 | * Immutable class for describing proportional relationship between width and height.
26 | */
27 | public class AspectRatio implements Comparable, Parcelable {
28 |
29 | private final static SparseArrayCompat> sCache
30 | = new SparseArrayCompat<>(16);
31 |
32 | private final int mX;
33 | private final int mY;
34 |
35 | /**
36 | * Returns an instance of {@link AspectRatio} specified by {@code x} and {@code y} values.
37 | * The values {@code x} and {@code} will be reduced by their greatest common divider.
38 | *
39 | * @param x The width
40 | * @param y The height
41 | * @return An instance of {@link AspectRatio}
42 | */
43 | public static AspectRatio of(int x, int y) {
44 | int gcd = gcd(x, y);
45 | x /= gcd;
46 | y /= gcd;
47 | SparseArrayCompat arrayX = sCache.get(x);
48 | if (arrayX == null) {
49 | AspectRatio ratio = new AspectRatio(x, y);
50 | arrayX = new SparseArrayCompat<>();
51 | arrayX.put(y, ratio);
52 | sCache.put(x, arrayX);
53 | return ratio;
54 | } else {
55 | AspectRatio ratio = arrayX.get(y);
56 | if (ratio == null) {
57 | ratio = new AspectRatio(x, y);
58 | arrayX.put(y, ratio);
59 | }
60 | return ratio;
61 | }
62 | }
63 |
64 | /**
65 | * Parse an {@link AspectRatio} from a {@link String} formatted like "4:3".
66 | *
67 | * @param s The string representation of the aspect ratio
68 | * @return The aspect ratio
69 | * @throws IllegalArgumentException when the format is incorrect.
70 | */
71 | public static AspectRatio parse(String s) {
72 | int position = s.indexOf(':');
73 | if (position == -1) {
74 | throw new IllegalArgumentException("Malformed aspect ratio: " + s);
75 | }
76 | try {
77 | int x = Integer.parseInt(s.substring(0, position));
78 | int y = Integer.parseInt(s.substring(position + 1));
79 | return AspectRatio.of(x, y);
80 | } catch (NumberFormatException e) {
81 | throw new IllegalArgumentException("Malformed aspect ratio: " + s, e);
82 | }
83 | }
84 |
85 | private AspectRatio(int x, int y) {
86 | mX = x;
87 | mY = y;
88 | }
89 |
90 | public int getX() {
91 | return mX;
92 | }
93 |
94 | public int getY() {
95 | return mY;
96 | }
97 |
98 | public boolean matches(Size size) {
99 | int gcd = gcd(size.getWidth(), size.getHeight());
100 | int x = size.getWidth() / gcd;
101 | int y = size.getHeight() / gcd;
102 | return mX == x && mY == y;
103 | }
104 |
105 | @Override
106 | public boolean equals(Object o) {
107 | if (o == null) {
108 | return false;
109 | }
110 | if (this == o) {
111 | return true;
112 | }
113 | if (o instanceof AspectRatio) {
114 | AspectRatio ratio = (AspectRatio) o;
115 | return mX == ratio.mX && mY == ratio.mY;
116 | }
117 | return false;
118 | }
119 |
120 | @Override
121 | public String toString() {
122 | return mX + ":" + mY;
123 | }
124 |
125 | public float toFloat() {
126 | return (float) mX / mY;
127 | }
128 |
129 | @Override
130 | public int hashCode() {
131 | // assuming most sizes are <2^16, doing a rotate will give us perfect hashing
132 | return mY ^ ((mX << (Integer.SIZE / 2)) | (mX >>> (Integer.SIZE / 2)));
133 | }
134 |
135 | @Override
136 | public int compareTo(@NonNull AspectRatio another) {
137 | if (equals(another)) {
138 | return 0;
139 | } else if (toFloat() - another.toFloat() > 0) {
140 | return 1;
141 | }
142 | return -1;
143 | }
144 |
145 | /**
146 | * @return The inverse of this {@link AspectRatio}.
147 | */
148 | public AspectRatio inverse() {
149 | //noinspection SuspiciousNameCombination
150 | return AspectRatio.of(mY, mX);
151 | }
152 |
153 | private static int gcd(int a, int b) {
154 | while (b != 0) {
155 | int c = b;
156 | b = a % b;
157 | a = c;
158 | }
159 | return a;
160 | }
161 |
162 | @Override
163 | public int describeContents() {
164 | return 0;
165 | }
166 |
167 | @Override
168 | public void writeToParcel(Parcel dest, int flags) {
169 | dest.writeInt(mX);
170 | dest.writeInt(mY);
171 | }
172 |
173 | public static final Parcelable.Creator CREATOR
174 | = new Parcelable.Creator() {
175 |
176 | @Override
177 | public AspectRatio createFromParcel(Parcel source) {
178 | int x = source.readInt();
179 | int y = source.readInt();
180 | return AspectRatio.of(x, y);
181 | }
182 |
183 | @Override
184 | public AspectRatio[] newArray(int size) {
185 | return new AspectRatio[size];
186 | }
187 | };
188 |
189 | }
190 |
--------------------------------------------------------------------------------
/library/src/main/base/com/google/android/cameraview/CameraViewImpl.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.google.android.cameraview;
18 |
19 | import android.view.View;
20 |
21 | import java.util.Set;
22 |
23 | abstract class CameraViewImpl {
24 |
25 | protected final Callback mCallback;
26 |
27 | protected final PreviewImpl mPreview;
28 |
29 | CameraViewImpl(Callback callback, PreviewImpl preview) {
30 | mCallback = callback;
31 | mPreview = preview;
32 | }
33 |
34 | View getView() {
35 | return mPreview.getView();
36 | }
37 |
38 | /**
39 | * @return {@code true} if the implementation was able to start the camera session.
40 | */
41 | abstract boolean start();
42 |
43 | abstract void stop();
44 |
45 | abstract boolean isCameraOpened();
46 |
47 | abstract void setFacing(int facing);
48 |
49 | abstract int getFacing();
50 |
51 | abstract Set getSupportedAspectRatios();
52 |
53 | /**
54 | * @return {@code true} if the aspect ratio was changed.
55 | */
56 | abstract boolean setAspectRatio(AspectRatio ratio);
57 |
58 | abstract AspectRatio getAspectRatio();
59 |
60 | abstract void setAutoFocus(boolean autoFocus);
61 |
62 | abstract boolean getAutoFocus();
63 |
64 | abstract void setFlash(int flash);
65 |
66 | abstract int getFlash();
67 |
68 | abstract void takePicture();
69 |
70 | abstract void setDisplayOrientation(int displayOrientation);
71 |
72 | interface Callback {
73 |
74 | void onCameraOpened();
75 |
76 | void onCameraClosed();
77 |
78 | void onPictureTaken(byte[] data);
79 |
80 | }
81 |
82 | }
83 |
--------------------------------------------------------------------------------
/library/src/main/base/com/google/android/cameraview/Constants.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.google.android.cameraview;
18 |
19 |
20 | interface Constants {
21 |
22 | AspectRatio DEFAULT_ASPECT_RATIO = AspectRatio.of(4, 3);
23 |
24 | int FACING_BACK = 0;
25 | int FACING_FRONT = 1;
26 |
27 | int FLASH_OFF = 0;
28 | int FLASH_ON = 1;
29 | int FLASH_TORCH = 2;
30 | int FLASH_AUTO = 3;
31 | int FLASH_RED_EYE = 4;
32 |
33 | int LANDSCAPE_90 = 90;
34 | int LANDSCAPE_270 = 270;
35 | }
36 |
--------------------------------------------------------------------------------
/library/src/main/base/com/google/android/cameraview/PreviewImpl.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.google.android.cameraview;
18 |
19 | import android.view.Surface;
20 | import android.view.SurfaceHolder;
21 | import android.view.View;
22 |
23 |
24 | /**
25 | * Encapsulates all the operations related to camera preview in a backward-compatible manner.
26 | */
27 | abstract class PreviewImpl {
28 |
29 | interface Callback {
30 | void onSurfaceChanged();
31 | }
32 |
33 | private Callback mCallback;
34 |
35 | private int mWidth;
36 |
37 | private int mHeight;
38 |
39 | void setCallback(Callback callback) {
40 | mCallback = callback;
41 | }
42 |
43 | abstract Surface getSurface();
44 |
45 | abstract View getView();
46 |
47 | abstract Class getOutputClass();
48 |
49 | abstract void setDisplayOrientation(int displayOrientation);
50 |
51 | abstract boolean isReady();
52 |
53 | protected void dispatchSurfaceChanged() {
54 | mCallback.onSurfaceChanged();
55 | }
56 |
57 | SurfaceHolder getSurfaceHolder() {
58 | return null;
59 | }
60 |
61 | Object getSurfaceTexture() {
62 | return null;
63 | }
64 |
65 | void setBufferSize(int width, int height) {
66 | }
67 |
68 | void setSize(int width, int height) {
69 | mWidth = width;
70 | mHeight = height;
71 | }
72 |
73 | int getWidth() {
74 | return mWidth;
75 | }
76 |
77 | int getHeight() {
78 | return mHeight;
79 | }
80 |
81 | }
82 |
--------------------------------------------------------------------------------
/library/src/main/base/com/google/android/cameraview/Size.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.google.android.cameraview;
18 |
19 | import android.support.annotation.NonNull;
20 |
21 | /**
22 | * Immutable class for describing width and height dimensions in pixels.
23 | */
24 | public class Size implements Comparable {
25 |
26 | private final int mWidth;
27 | private final int mHeight;
28 |
29 | /**
30 | * Create a new immutable Size instance.
31 | *
32 | * @param width The width of the size, in pixels
33 | * @param height The height of the size, in pixels
34 | */
35 | public Size(int width, int height) {
36 | mWidth = width;
37 | mHeight = height;
38 | }
39 |
40 | public int getWidth() {
41 | return mWidth;
42 | }
43 |
44 | public int getHeight() {
45 | return mHeight;
46 | }
47 |
48 | @Override
49 | public boolean equals(Object o) {
50 | if (o == null) {
51 | return false;
52 | }
53 | if (this == o) {
54 | return true;
55 | }
56 | if (o instanceof Size) {
57 | Size size = (Size) o;
58 | return mWidth == size.mWidth && mHeight == size.mHeight;
59 | }
60 | return false;
61 | }
62 |
63 | @Override
64 | public String toString() {
65 | return mWidth + "x" + mHeight;
66 | }
67 |
68 | @Override
69 | public int hashCode() {
70 | // assuming most sizes are <2^16, doing a rotate will give us perfect hashing
71 | return mHeight ^ ((mWidth << (Integer.SIZE / 2)) | (mWidth >>> (Integer.SIZE / 2)));
72 | }
73 |
74 | @Override
75 | public int compareTo(@NonNull Size another) {
76 | return mWidth * mHeight - another.mWidth * another.mHeight;
77 | }
78 |
79 | }
80 |
--------------------------------------------------------------------------------
/library/src/main/base/com/google/android/cameraview/SizeMap.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.google.android.cameraview;
18 |
19 | import android.support.v4.util.ArrayMap;
20 |
21 | import java.util.Set;
22 | import java.util.SortedSet;
23 | import java.util.TreeSet;
24 |
25 | /**
26 | * A collection class that automatically groups {@link Size}s by their {@link AspectRatio}s.
27 | */
28 | class SizeMap {
29 |
30 | private final ArrayMap> mRatios = new ArrayMap<>();
31 |
32 | /**
33 | * Add a new {@link Size} to this collection.
34 | *
35 | * @param size The size to add.
36 | * @return {@code true} if it is added, {@code false} if it already exists and is not added.
37 | */
38 | public boolean add(Size size) {
39 | for (AspectRatio ratio : mRatios.keySet()) {
40 | if (ratio.matches(size)) {
41 | final SortedSet sizes = mRatios.get(ratio);
42 | if (sizes.contains(size)) {
43 | return false;
44 | } else {
45 | sizes.add(size);
46 | return true;
47 | }
48 | }
49 | }
50 | // None of the existing ratio matches the provided size; add a new key
51 | SortedSet sizes = new TreeSet<>();
52 | sizes.add(size);
53 | mRatios.put(AspectRatio.of(size.getWidth(), size.getHeight()), sizes);
54 | return true;
55 | }
56 |
57 | /**
58 | * Removes the specified aspect ratio and all sizes associated with it.
59 | *
60 | * @param ratio The aspect ratio to be removed.
61 | */
62 | public void remove(AspectRatio ratio) {
63 | mRatios.remove(ratio);
64 | }
65 |
66 | Set ratios() {
67 | return mRatios.keySet();
68 | }
69 |
70 | SortedSet sizes(AspectRatio ratio) {
71 | return mRatios.get(ratio);
72 | }
73 |
74 | void clear() {
75 | mRatios.clear();
76 | }
77 |
78 | boolean isEmpty() {
79 | return mRatios.isEmpty();
80 | }
81 |
82 | }
83 |
--------------------------------------------------------------------------------
/library/src/main/java/com/google/android/cameraview/CameraView.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.google.android.cameraview;
18 |
19 | import android.app.Activity;
20 | import android.content.Context;
21 | import android.content.res.TypedArray;
22 | import android.os.Build;
23 | import android.os.Parcel;
24 | import android.os.Parcelable;
25 | import android.support.annotation.IntDef;
26 | import android.support.annotation.NonNull;
27 | import android.support.annotation.Nullable;
28 | import android.support.v4.view.ViewCompat;
29 | import android.util.AttributeSet;
30 | import android.widget.FrameLayout;
31 |
32 | import java.lang.annotation.Retention;
33 | import java.lang.annotation.RetentionPolicy;
34 | import java.util.ArrayList;
35 | import java.util.Set;
36 |
37 | public class CameraView extends FrameLayout {
38 |
39 | /** The camera device faces the opposite direction as the device's screen. */
40 | public static final int FACING_BACK = Constants.FACING_BACK;
41 |
42 | /** The camera device faces the same direction as the device's screen. */
43 | public static final int FACING_FRONT = Constants.FACING_FRONT;
44 |
45 | /** Direction the camera faces relative to device screen. */
46 | @IntDef({FACING_BACK, FACING_FRONT})
47 | @Retention(RetentionPolicy.SOURCE)
48 | public @interface Facing {
49 | }
50 |
51 | /** Flash will not be fired. */
52 | public static final int FLASH_OFF = Constants.FLASH_OFF;
53 |
54 | /** Flash will always be fired during snapshot. */
55 | public static final int FLASH_ON = Constants.FLASH_ON;
56 |
57 | /** Constant emission of light during preview, auto-focus and snapshot. */
58 | public static final int FLASH_TORCH = Constants.FLASH_TORCH;
59 |
60 | /** Flash will be fired automatically when required. */
61 | public static final int FLASH_AUTO = Constants.FLASH_AUTO;
62 |
63 | /** Flash will be fired in red-eye reduction mode. */
64 | public static final int FLASH_RED_EYE = Constants.FLASH_RED_EYE;
65 |
66 | /** The mode for for the camera device's flash control */
67 | @IntDef({FLASH_OFF, FLASH_ON, FLASH_TORCH, FLASH_AUTO, FLASH_RED_EYE})
68 | public @interface Flash {
69 | }
70 |
71 | CameraViewImpl mImpl;
72 |
73 | private final CallbackBridge mCallbacks;
74 |
75 | private boolean mAdjustViewBounds;
76 |
77 | private final DisplayOrientationDetector mDisplayOrientationDetector;
78 |
79 | public CameraView(Context context) {
80 | this(context, null);
81 | }
82 |
83 | public CameraView(Context context, AttributeSet attrs) {
84 | this(context, attrs, 0);
85 | }
86 |
87 | @SuppressWarnings("WrongConstant")
88 | public CameraView(Context context, AttributeSet attrs, int defStyleAttr) {
89 | super(context, attrs, defStyleAttr);
90 | if (isInEditMode()) {
91 | mCallbacks = null;
92 | mDisplayOrientationDetector = null;
93 | return;
94 | }
95 | // Internal setup
96 | final PreviewImpl preview = createPreviewImpl(context);
97 | mCallbacks = new CallbackBridge();
98 | if (Build.VERSION.SDK_INT < 21) {
99 | mImpl = new Camera1(mCallbacks, preview);
100 | } else if (Build.VERSION.SDK_INT < 23) {
101 | mImpl = new Camera2(mCallbacks, preview, context);
102 | } else {
103 | mImpl = new Camera2Api23(mCallbacks, preview, context);
104 | }
105 | // Attributes
106 | TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CameraView, defStyleAttr,
107 | R.style.Widget_CameraView);
108 | mAdjustViewBounds = a.getBoolean(R.styleable.CameraView_android_adjustViewBounds, false);
109 | setFacing(a.getInt(R.styleable.CameraView_facing, FACING_BACK));
110 | String aspectRatio = a.getString(R.styleable.CameraView_aspectRatio);
111 | if (aspectRatio != null) {
112 | setAspectRatio(AspectRatio.parse(aspectRatio));
113 | } else {
114 | setAspectRatio(Constants.DEFAULT_ASPECT_RATIO);
115 | }
116 | setAutoFocus(a.getBoolean(R.styleable.CameraView_autoFocus, true));
117 | setFlash(a.getInt(R.styleable.CameraView_flash, Constants.FLASH_AUTO));
118 | a.recycle();
119 | // Display orientation detector
120 | mDisplayOrientationDetector = new DisplayOrientationDetector(context) {
121 | @Override
122 | public void onDisplayOrientationChanged(int displayOrientation) {
123 | mImpl.setDisplayOrientation(displayOrientation);
124 | }
125 | };
126 | }
127 |
128 | @NonNull
129 | private PreviewImpl createPreviewImpl(Context context) {
130 | PreviewImpl preview;
131 | if (Build.VERSION.SDK_INT >= 23) {
132 | preview = new SurfaceViewPreview(context, this);
133 | } else {
134 | preview = new TextureViewPreview(context, this);
135 | }
136 | return preview;
137 | }
138 |
139 | @Override
140 | protected void onAttachedToWindow() {
141 | super.onAttachedToWindow();
142 | if (!isInEditMode()) {
143 | mDisplayOrientationDetector.enable(ViewCompat.getDisplay(this));
144 | }
145 | }
146 |
147 | @Override
148 | protected void onDetachedFromWindow() {
149 | if (!isInEditMode()) {
150 | mDisplayOrientationDetector.disable();
151 | }
152 | super.onDetachedFromWindow();
153 | }
154 |
155 | @Override
156 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
157 | if (isInEditMode()) {
158 | super.onMeasure(widthMeasureSpec, heightMeasureSpec);
159 | return;
160 | }
161 | // Handle android:adjustViewBounds
162 | if (mAdjustViewBounds) {
163 | if (!isCameraOpened()) {
164 | mCallbacks.reserveRequestLayoutOnOpen();
165 | super.onMeasure(widthMeasureSpec, heightMeasureSpec);
166 | return;
167 | }
168 | final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
169 | final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
170 | if (widthMode == MeasureSpec.EXACTLY && heightMode != MeasureSpec.EXACTLY) {
171 | final AspectRatio ratio = getAspectRatio();
172 | assert ratio != null;
173 | int height = (int) (MeasureSpec.getSize(widthMeasureSpec) * ratio.toFloat());
174 | if (heightMode == MeasureSpec.AT_MOST) {
175 | height = Math.min(height, MeasureSpec.getSize(heightMeasureSpec));
176 | }
177 | super.onMeasure(widthMeasureSpec,
178 | MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
179 | } else if (widthMode != MeasureSpec.EXACTLY && heightMode == MeasureSpec.EXACTLY) {
180 | final AspectRatio ratio = getAspectRatio();
181 | assert ratio != null;
182 | int width = (int) (MeasureSpec.getSize(heightMeasureSpec) * ratio.toFloat());
183 | if (widthMode == MeasureSpec.AT_MOST) {
184 | width = Math.min(width, MeasureSpec.getSize(widthMeasureSpec));
185 | }
186 | super.onMeasure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
187 | heightMeasureSpec);
188 | } else {
189 | super.onMeasure(widthMeasureSpec, heightMeasureSpec);
190 | }
191 | } else {
192 | super.onMeasure(widthMeasureSpec, heightMeasureSpec);
193 | }
194 | // Measure the TextureView
195 | int width = getMeasuredWidth();
196 | int height = getMeasuredHeight();
197 | AspectRatio ratio = getAspectRatio();
198 | if (mDisplayOrientationDetector.getLastKnownDisplayOrientation() % 180 == 0) {
199 | ratio = ratio.inverse();
200 | }
201 | assert ratio != null;
202 | if (height < width * ratio.getY() / ratio.getX()) {
203 | mImpl.getView().measure(
204 | MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
205 | MeasureSpec.makeMeasureSpec(width * ratio.getY() / ratio.getX(),
206 | MeasureSpec.EXACTLY));
207 | } else {
208 | mImpl.getView().measure(
209 | MeasureSpec.makeMeasureSpec(height * ratio.getX() / ratio.getY(),
210 | MeasureSpec.EXACTLY),
211 | MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
212 | }
213 | }
214 |
215 | @Override
216 | protected Parcelable onSaveInstanceState() {
217 | SavedState state = new SavedState(super.onSaveInstanceState());
218 | state.facing = getFacing();
219 | state.ratio = getAspectRatio();
220 | state.autoFocus = getAutoFocus();
221 | state.flash = getFlash();
222 | return state;
223 | }
224 |
225 | @Override
226 | protected void onRestoreInstanceState(Parcelable state) {
227 | if (!(state instanceof SavedState)) {
228 | super.onRestoreInstanceState(state);
229 | return;
230 | }
231 | SavedState ss = (SavedState) state;
232 | super.onRestoreInstanceState(ss.getSuperState());
233 | setFacing(ss.facing);
234 | setAspectRatio(ss.ratio);
235 | setAutoFocus(ss.autoFocus);
236 | setFlash(ss.flash);
237 | }
238 |
239 | /**
240 | * Open a camera device and start showing camera preview. This is typically called from
241 | * {@link Activity#onResume()}.
242 | */
243 | public void start() {
244 | if (!mImpl.start()) {
245 | //store the state ,and restore this state after fall back o Camera1
246 | Parcelable state = onSaveInstanceState();
247 | // Camera2 uses legacy hardware layer; fall back to Camera1
248 | mImpl = new Camera1(mCallbacks, createPreviewImpl(getContext()));
249 | onRestoreInstanceState(state);
250 | mImpl.start();
251 | }
252 | }
253 |
254 | /**
255 | * Stop camera preview and close the device. This is typically called from
256 | * {@link Activity#onPause()}.
257 | */
258 | public void stop() {
259 | mImpl.stop();
260 | }
261 |
262 | /**
263 | * @return {@code true} if the camera is opened.
264 | */
265 | public boolean isCameraOpened() {
266 | return mImpl.isCameraOpened();
267 | }
268 |
269 | /**
270 | * Add a new callback.
271 | *
272 | * @param callback The {@link Callback} to add.
273 | * @see #removeCallback(Callback)
274 | */
275 | public void addCallback(@NonNull Callback callback) {
276 | mCallbacks.add(callback);
277 | }
278 |
279 | /**
280 | * Remove a callback.
281 | *
282 | * @param callback The {@link Callback} to remove.
283 | * @see #addCallback(Callback)
284 | */
285 | public void removeCallback(@NonNull Callback callback) {
286 | mCallbacks.remove(callback);
287 | }
288 |
289 | /**
290 | * @param adjustViewBounds {@code true} if you want the CameraView to adjust its bounds to
291 | * preserve the aspect ratio of camera.
292 | * @see #getAdjustViewBounds()
293 | */
294 | public void setAdjustViewBounds(boolean adjustViewBounds) {
295 | if (mAdjustViewBounds != adjustViewBounds) {
296 | mAdjustViewBounds = adjustViewBounds;
297 | requestLayout();
298 | }
299 | }
300 |
301 | /**
302 | * @return True when this CameraView is adjusting its bounds to preserve the aspect ratio of
303 | * camera.
304 | * @see #setAdjustViewBounds(boolean)
305 | */
306 | public boolean getAdjustViewBounds() {
307 | return mAdjustViewBounds;
308 | }
309 |
310 | /**
311 | * Chooses camera by the direction it faces.
312 | *
313 | * @param facing The camera facing. Must be either {@link #FACING_BACK} or
314 | * {@link #FACING_FRONT}.
315 | */
316 | public void setFacing(@Facing int facing) {
317 | mImpl.setFacing(facing);
318 | }
319 |
320 | /**
321 | * Gets the direction that the current camera faces.
322 | *
323 | * @return The camera facing.
324 | */
325 | @Facing
326 | public int getFacing() {
327 | //noinspection WrongConstant
328 | return mImpl.getFacing();
329 | }
330 |
331 | /**
332 | * Gets all the aspect ratios supported by the current camera.
333 | */
334 | public Set getSupportedAspectRatios() {
335 | return mImpl.getSupportedAspectRatios();
336 | }
337 |
338 | /**
339 | * Sets the aspect ratio of camera.
340 | *
341 | * @param ratio The {@link AspectRatio} to be set.
342 | */
343 | public void setAspectRatio(@NonNull AspectRatio ratio) {
344 | if (mImpl.setAspectRatio(ratio)) {
345 | requestLayout();
346 | }
347 | }
348 |
349 | /**
350 | * Gets the current aspect ratio of camera.
351 | *
352 | * @return The current {@link AspectRatio}. Can be {@code null} if no camera is opened yet.
353 | */
354 | @Nullable
355 | public AspectRatio getAspectRatio() {
356 | return mImpl.getAspectRatio();
357 | }
358 |
359 | /**
360 | * Enables or disables the continuous auto-focus mode. When the current camera doesn't support
361 | * auto-focus, calling this method will be ignored.
362 | *
363 | * @param autoFocus {@code true} to enable continuous auto-focus mode. {@code false} to
364 | * disable it.
365 | */
366 | public void setAutoFocus(boolean autoFocus) {
367 | mImpl.setAutoFocus(autoFocus);
368 | }
369 |
370 | /**
371 | * Returns whether the continuous auto-focus mode is enabled.
372 | *
373 | * @return {@code true} if the continuous auto-focus mode is enabled. {@code false} if it is
374 | * disabled, or if it is not supported by the current camera.
375 | */
376 | public boolean getAutoFocus() {
377 | return mImpl.getAutoFocus();
378 | }
379 |
380 | /**
381 | * Sets the flash mode.
382 | *
383 | * @param flash The desired flash mode.
384 | */
385 | public void setFlash(@Flash int flash) {
386 | mImpl.setFlash(flash);
387 | }
388 |
389 | /**
390 | * Gets the current flash mode.
391 | *
392 | * @return The current flash mode.
393 | */
394 | @Flash
395 | public int getFlash() {
396 | //noinspection WrongConstant
397 | return mImpl.getFlash();
398 | }
399 |
400 | /**
401 | * Take a picture. The result will be returned to
402 | * {@link Callback#onPictureTaken(CameraView, byte[])}.
403 | */
404 | public void takePicture() {
405 | mImpl.takePicture();
406 | }
407 |
408 | private class CallbackBridge implements CameraViewImpl.Callback {
409 |
410 | private final ArrayList mCallbacks = new ArrayList<>();
411 |
412 | private boolean mRequestLayoutOnOpen;
413 |
414 | CallbackBridge() {
415 | }
416 |
417 | public void add(Callback callback) {
418 | mCallbacks.add(callback);
419 | }
420 |
421 | public void remove(Callback callback) {
422 | mCallbacks.remove(callback);
423 | }
424 |
425 | @Override
426 | public void onCameraOpened() {
427 | if (mRequestLayoutOnOpen) {
428 | mRequestLayoutOnOpen = false;
429 | requestLayout();
430 | }
431 | for (Callback callback : mCallbacks) {
432 | callback.onCameraOpened(CameraView.this);
433 | }
434 | }
435 |
436 | @Override
437 | public void onCameraClosed() {
438 | for (Callback callback : mCallbacks) {
439 | callback.onCameraClosed(CameraView.this);
440 | }
441 | }
442 |
443 | @Override
444 | public void onPictureTaken(byte[] data) {
445 | for (Callback callback : mCallbacks) {
446 | callback.onPictureTaken(CameraView.this, data);
447 | }
448 | }
449 |
450 | public void reserveRequestLayoutOnOpen() {
451 | mRequestLayoutOnOpen = true;
452 | }
453 | }
454 |
455 | protected static class SavedState extends BaseSavedState {
456 |
457 | @Facing
458 | int facing;
459 |
460 | AspectRatio ratio;
461 |
462 | boolean autoFocus;
463 |
464 | @Flash
465 | int flash;
466 |
467 | @SuppressWarnings("WrongConstant")
468 | public SavedState(Parcel source, ClassLoader loader) {
469 | super(source);
470 | facing = source.readInt();
471 | ratio = source.readParcelable(loader);
472 | autoFocus = source.readByte() != 0;
473 | flash = source.readInt();
474 | }
475 |
476 | public SavedState(Parcelable superState) {
477 | super(superState);
478 | }
479 |
480 | @Override
481 | public void writeToParcel(Parcel out, int flags) {
482 | super.writeToParcel(out, flags);
483 | out.writeInt(facing);
484 | out.writeParcelable(ratio, 0);
485 | out.writeByte((byte) (autoFocus ? 1 : 0));
486 | out.writeInt(flash);
487 | }
488 |
489 | public static final Parcelable.Creator CREATOR
490 | = new Parcelable.ClassLoaderCreator() {
491 |
492 | @Override
493 | public SavedState createFromParcel(Parcel in) {
494 | return createFromParcel(in, null);
495 | }
496 |
497 | @Override
498 | public SavedState createFromParcel(Parcel in, ClassLoader loader) {
499 | return new SavedState(in, loader);
500 | }
501 |
502 | @Override
503 | public SavedState[] newArray(int size) {
504 | return new SavedState[size];
505 | }
506 |
507 | };
508 |
509 | }
510 |
511 | /**
512 | * Callback for monitoring events about {@link CameraView}.
513 | */
514 | @SuppressWarnings("UnusedParameters")
515 | public abstract static class Callback {
516 |
517 | /**
518 | * Called when camera is opened.
519 | *
520 | * @param cameraView The associated {@link CameraView}.
521 | */
522 | public void onCameraOpened(CameraView cameraView) {
523 | }
524 |
525 | /**
526 | * Called when camera is closed.
527 | *
528 | * @param cameraView The associated {@link CameraView}.
529 | */
530 | public void onCameraClosed(CameraView cameraView) {
531 | }
532 |
533 | /**
534 | * Called when a picture is taken.
535 | *
536 | * @param cameraView The associated {@link CameraView}.
537 | * @param data JPEG data.
538 | */
539 | public void onPictureTaken(CameraView cameraView, byte[] data) {
540 | }
541 | }
542 |
543 | }
544 |
--------------------------------------------------------------------------------
/library/src/main/java/com/google/android/cameraview/DisplayOrientationDetector.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.google.android.cameraview;
18 |
19 | import android.content.Context;
20 | import android.util.SparseIntArray;
21 | import android.view.Display;
22 | import android.view.OrientationEventListener;
23 | import android.view.Surface;
24 |
25 |
26 | /**
27 | * Monitors the value returned from {@link Display#getRotation()}.
28 | */
29 | abstract class DisplayOrientationDetector {
30 |
31 | private final OrientationEventListener mOrientationEventListener;
32 |
33 | /** Mapping from Surface.Rotation_n to degrees. */
34 | static final SparseIntArray DISPLAY_ORIENTATIONS = new SparseIntArray();
35 |
36 | static {
37 | DISPLAY_ORIENTATIONS.put(Surface.ROTATION_0, 0);
38 | DISPLAY_ORIENTATIONS.put(Surface.ROTATION_90, 90);
39 | DISPLAY_ORIENTATIONS.put(Surface.ROTATION_180, 180);
40 | DISPLAY_ORIENTATIONS.put(Surface.ROTATION_270, 270);
41 | }
42 |
43 | Display mDisplay;
44 |
45 | private int mLastKnownDisplayOrientation = 0;
46 |
47 | public DisplayOrientationDetector(Context context) {
48 | mOrientationEventListener = new OrientationEventListener(context) {
49 |
50 | /** This is either Surface.Rotation_0, _90, _180, _270, or -1 (invalid). */
51 | private int mLastKnownRotation = -1;
52 |
53 | @Override
54 | public void onOrientationChanged(int orientation) {
55 | if (orientation == OrientationEventListener.ORIENTATION_UNKNOWN ||
56 | mDisplay == null) {
57 | return;
58 | }
59 | final int rotation = mDisplay.getRotation();
60 | if (mLastKnownRotation != rotation) {
61 | mLastKnownRotation = rotation;
62 | dispatchOnDisplayOrientationChanged(DISPLAY_ORIENTATIONS.get(rotation));
63 | }
64 | }
65 | };
66 | }
67 |
68 | public void enable(Display display) {
69 | mDisplay = display;
70 | mOrientationEventListener.enable();
71 | // Immediately dispatch the first callback
72 | dispatchOnDisplayOrientationChanged(DISPLAY_ORIENTATIONS.get(display.getRotation()));
73 | }
74 |
75 | public void disable() {
76 | mOrientationEventListener.disable();
77 | mDisplay = null;
78 | }
79 |
80 | public int getLastKnownDisplayOrientation() {
81 | return mLastKnownDisplayOrientation;
82 | }
83 |
84 | void dispatchOnDisplayOrientationChanged(int displayOrientation) {
85 | mLastKnownDisplayOrientation = displayOrientation;
86 | onDisplayOrientationChanged(displayOrientation);
87 | }
88 |
89 | /**
90 | * Called when display orientation is changed.
91 | *
92 | * @param displayOrientation One of 0, 90, 180, and 270.
93 | */
94 | public abstract void onDisplayOrientationChanged(int displayOrientation);
95 |
96 | }
97 |
--------------------------------------------------------------------------------
/library/src/main/res/layout-v14/texture_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
14 |
15 |
16 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/library/src/main/res/layout/surface_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
14 |
15 |
16 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/library/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
14 |
15 |
16 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
40 |
41 |
45 |
46 |
51 |
52 |
55 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/library/src/main/res/values/public.xml:
--------------------------------------------------------------------------------
1 |
2 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/library/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
14 |
15 |
16 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/library/src/test/java/com/google/android/cameraview/AspectRatioTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.google.android.cameraview;
18 |
19 | import static org.hamcrest.CoreMatchers.is;
20 | import static org.junit.Assert.assertThat;
21 |
22 | import org.junit.Test;
23 |
24 | import java.util.HashSet;
25 |
26 | public class AspectRatioTest {
27 |
28 | @Test
29 | public void testGcd() {
30 | AspectRatio r;
31 | r = AspectRatio.of(1, 2);
32 | assertThat(r.getX(), is(1));
33 | r = AspectRatio.of(2, 4);
34 | assertThat(r.getX(), is(1));
35 | assertThat(r.getY(), is(2));
36 | r = AspectRatio.of(391, 713);
37 | assertThat(r.getX(), is(17));
38 | assertThat(r.getY(), is(31));
39 | }
40 |
41 | @Test
42 | public void testMatches() {
43 | AspectRatio ratio = AspectRatio.of(3, 4);
44 | assertThat(ratio.matches(new Size(6, 8)), is(true));
45 | assertThat(ratio.matches(new Size(1, 2)), is(false));
46 | }
47 |
48 | @Test
49 | public void testGetters() {
50 | AspectRatio ratio = AspectRatio.of(2, 4); // Reduced to 1:2
51 | assertThat(ratio.getX(), is(1));
52 | assertThat(ratio.getY(), is(2));
53 | }
54 |
55 | @Test
56 | public void testToString() {
57 | AspectRatio ratio = AspectRatio.of(1, 2);
58 | assertThat(ratio.toString(), is("1:2"));
59 | }
60 |
61 | @Test
62 | public void testEquals() {
63 | AspectRatio a = AspectRatio.of(1, 2);
64 | AspectRatio b = AspectRatio.of(2, 4);
65 | AspectRatio c = AspectRatio.of(2, 3);
66 | assertThat(a.equals(b), is(true));
67 | assertThat(a.equals(c), is(false));
68 | }
69 |
70 | @Test
71 | public void testHashCode() {
72 | int max = 100;
73 | HashSet codes = new HashSet<>();
74 | for (int x = 1; x <= 100; x++) {
75 | codes.add(AspectRatio.of(x, 1).hashCode());
76 | }
77 | assertThat(codes.size(), is(max));
78 | codes.clear();
79 | for (int y = 1; y <= 100; y++) {
80 | codes.add(AspectRatio.of(1, y).hashCode());
81 | }
82 | assertThat(codes.size(), is(max));
83 | }
84 |
85 | @Test
86 | public void testInverse() {
87 | AspectRatio r = AspectRatio.of(4, 3);
88 | assertThat(r.getX(), is(4));
89 | assertThat(r.getY(), is(3));
90 | AspectRatio s = r.inverse();
91 | assertThat(s.getX(), is(3));
92 | assertThat(s.getY(), is(4));
93 | }
94 |
95 | @Test
96 | public void testParse() {
97 | AspectRatio r = AspectRatio.parse("23:31");
98 | assertThat(r.getX(), is(23));
99 | assertThat(r.getY(), is(31));
100 | }
101 |
102 | @Test(expected = IllegalArgumentException.class)
103 | public void testParseFailure() {
104 | AspectRatio.parse("MALFORMED");
105 | }
106 |
107 | }
108 |
--------------------------------------------------------------------------------
/library/src/test/java/com/google/android/cameraview/SizeMapTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.google.android.cameraview;
18 |
19 | import static org.hamcrest.CoreMatchers.is;
20 | import static org.junit.Assert.assertThat;
21 |
22 | import org.junit.Test;
23 |
24 | public class SizeMapTest {
25 |
26 | @Test
27 | public void testAdd_simple() {
28 | SizeMap map = new SizeMap();
29 | map.add(new Size(3, 4));
30 | map.add(new Size(9, 16));
31 | assertThat(map.ratios().size(), is(2));
32 | }
33 |
34 | @Test
35 | public void testAdd_duplicate() {
36 | SizeMap map = new SizeMap();
37 | map.add(new Size(3, 4));
38 | map.add(new Size(6, 8));
39 | map.add(new Size(9, 12));
40 | assertThat(map.ratios().size(), is(1));
41 | AspectRatio ratio = (AspectRatio) map.ratios().toArray()[0];
42 | assertThat(ratio.toString(), is("3:4"));
43 | assertThat(map.sizes(ratio).size(), is(3));
44 | }
45 |
46 | @Test
47 | public void testClear() {
48 | SizeMap map = new SizeMap();
49 | map.add(new Size(12, 34));
50 | assertThat(map.ratios().size(), is(1));
51 | map.clear();
52 | assertThat(map.ratios().size(), is(0));
53 | }
54 |
55 | }
56 |
--------------------------------------------------------------------------------
/library/src/test/java/com/google/android/cameraview/SizeTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.google.android.cameraview;
18 |
19 | import static org.hamcrest.CoreMatchers.is;
20 | import static org.junit.Assert.assertThat;
21 |
22 | import org.junit.Test;
23 |
24 | import java.util.HashSet;
25 |
26 | public class SizeTest {
27 |
28 | @Test
29 | public void testGetters() {
30 | Size size = new Size(1, 2);
31 | assertThat(size.getWidth(), is(1));
32 | assertThat(size.getHeight(), is(2));
33 | }
34 |
35 | @Test
36 | public void testToString() {
37 | Size size = new Size(1, 2);
38 | assertThat(size.toString(), is("1x2"));
39 | }
40 |
41 | @Test
42 | public void testEquals() {
43 | Size a = new Size(1, 2);
44 | Size b = new Size(1, 2);
45 | Size c = new Size(3, 4);
46 | assertThat(a.equals(b), is(true));
47 | assertThat(a.equals(c), is(false));
48 | }
49 |
50 | @Test
51 | public void testHashCode() {
52 | int max = 100;
53 | HashSet codes = new HashSet<>();
54 | for (int x = 1; x <= max; x++) {
55 | for (int y = 1; y <= max; y++) {
56 | codes.add(new Size(x, y).hashCode());
57 | }
58 | }
59 | assertThat(codes.size(), is(max * max));
60 | }
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2016 The Android Open Source Project
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | include ':demo', ':library'
16 |
--------------------------------------------------------------------------------