├── .gitignore ├── .idea ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── encodings.xml ├── gradle.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── 1.jpg ├── README.md ├── apk └── CustomCamera.apk ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── example │ │ └── ysq │ │ └── customcamera │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── ysq │ │ │ └── customcamera │ │ │ ├── CameraActivity.java │ │ │ ├── CameraUtil.java │ │ │ ├── DefaultSubscriber.java │ │ │ └── MainActivity.java │ └── res │ │ ├── drawable-xxhdpi │ │ ├── camera_back.png │ │ ├── camera_flash_auto.png │ │ ├── camera_flash_off.png │ │ ├── camera_flash_on.png │ │ ├── camera_flip.png │ │ ├── camera_library.png │ │ └── camera_photo.png │ │ ├── drawable │ │ ├── btn_take_photo.xml │ │ └── cam_focus.xml │ │ ├── layout │ │ ├── activity_main.xml │ │ └── activity_test_camera.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── example │ └── ysq │ └── customcamera │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | Android 39 | 40 | 41 | Android > Lint > Correctness 42 | 43 | 44 | Android > Lint > Internationalization 45 | 46 | 47 | Android > Lint > Security 48 | 49 | 50 | CorrectnessLintAndroid 51 | 52 | 53 | Gradle 54 | 55 | 56 | LintAndroid 57 | 58 | 59 | Probable bugsGradle 60 | 61 | 62 | 63 | 64 | Android 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 86 | 87 | 88 | 89 | 90 | 1.8 91 | 92 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 108 | 109 | 110 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ysq1051838264/CustomCamera/d3bd869bb70f5df0502d1d52edc11110ed1a556c/1.jpg -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CustomCamera 2 | 自定义相机,有聚焦、闪光灯、以及连续拍照、查看等功能 3 | 4 | ![image](https://github.com/ysq1051838264/CustomCamera/blob/master/1.jpg) 5 | 6 | ###Camera控制拍照的过程 7 | 8 | 调用Camera的open()方法打开相机。 9 | 10 | 调用Camera的getParameters()获取拍照参数,该方法返回一个Cmera.Parameters对象。 11 | 12 | 调用Camera.Parameters对象对照相的参数进行设置。 13 | 14 | 调用Camera的setParameters(),并将Camera.Parameters对象作为参数传入,这样就可以对拍照进行参数控制,Android2.3.3以后不用设置。 15 | 16 | 调用Camerade的startPreview()的方法开始预览取景,在之前需要调用Camera的setPreviewDisplay(SurfaceHolder holder)设置使用哪个SurfaceView来显示取得的图片。 17 | 18 | 调用Camera的takePicture()方法进行拍照。 19 | 20 | 程序结束时,要调用Camera的stopPreview()方法停止预览,并且通过Camera.release()来释放资源。 21 | 22 | 23 | **[DownLoad Apk](https://github.com/ysq1051838264/CustomCamera/blob/master/apk/CustomCamera.apk?raw=true)** 24 | -------------------------------------------------------------------------------- /apk/CustomCamera.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ysq1051838264/CustomCamera/d3bd869bb70f5df0502d1d52edc11110ed1a556c/apk/CustomCamera.apk -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 24 5 | buildToolsVersion "24.0.2" 6 | defaultConfig { 7 | applicationId "com.example.ysq.customcamera" 8 | minSdkVersion 18 9 | targetSdkVersion 24 10 | versionCode 1 11 | versionName "1.0" 12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(dir: 'libs', include: ['*.jar']) 24 | 25 | compile ('com.tbruyelle.rxpermissions:rxpermissions:0.7.0@aar') 26 | compile ('com.squareup.retrofit2:adapter-rxjava:2.0.0-beta4') 27 | 28 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 29 | exclude group: 'com.android.support', module: 'support-annotations' 30 | }) 31 | compile 'com.android.support:appcompat-v7:24.2.1' 32 | testCompile 'junit:junit:4.12' 33 | } 34 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Volumes/ms/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/example/ysq/customcamera/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.example.ysq.customcamera; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumentation test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.example.ysq.customcamera", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/ysq/customcamera/CameraActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.ysq.customcamera; 2 | 3 | import android.Manifest; 4 | import android.content.Context; 5 | import android.content.DialogInterface; 6 | import android.content.Intent; 7 | import android.graphics.Bitmap; 8 | import android.graphics.BitmapFactory; 9 | import android.graphics.Matrix; 10 | import android.graphics.Rect; 11 | import android.hardware.Camera; 12 | import android.net.Uri; 13 | import android.os.Build; 14 | import android.os.Bundle; 15 | import android.os.Environment; 16 | import android.os.Handler; 17 | import android.provider.MediaStore; 18 | import android.provider.Settings; 19 | import android.support.annotation.Nullable; 20 | import android.support.v7.app.AlertDialog; 21 | import android.support.v7.app.AppCompatActivity; 22 | import android.util.Log; 23 | import android.view.MotionEvent; 24 | import android.view.SurfaceHolder; 25 | import android.view.SurfaceView; 26 | import android.view.View; 27 | import android.view.animation.ScaleAnimation; 28 | import android.widget.Button; 29 | import android.widget.FrameLayout; 30 | import android.widget.ImageButton; 31 | import android.widget.ImageView; 32 | import android.widget.RelativeLayout; 33 | import android.widget.Toast; 34 | 35 | import com.tbruyelle.rxpermissions.Permission; 36 | import com.tbruyelle.rxpermissions.RxPermissions; 37 | 38 | import java.io.File; 39 | import java.io.FileNotFoundException; 40 | import java.io.FileOutputStream; 41 | import java.io.IOException; 42 | import java.util.ArrayList; 43 | import java.util.List; 44 | 45 | public class CameraActivity extends AppCompatActivity implements SurfaceHolder.Callback, View.OnClickListener { 46 | private Camera mCamera; 47 | private int cameraPosition = 0;//0代表前置摄像头,1代表后置摄像头,默认打开前置摄像头 48 | SurfaceHolder holder; 49 | 50 | SurfaceView mSurfaceView; 51 | ImageButton openLight; 52 | View focusIndex; 53 | View bootomRly; 54 | 55 | private float pointX, pointY; 56 | static final int FOCUS = 1; // 聚焦 57 | static final int ZOOM = 2; // 缩放 58 | private int mode; //0是聚焦 1是放大 59 | //放大缩小 60 | int curZoomValue = 0; 61 | private float dist; 62 | Camera.Parameters parameters; 63 | private Handler handler = new Handler(); 64 | boolean safeToTakePicture = true; 65 | RxPermissions rxPermissions; 66 | 67 | /* 图像数据处理完成后的回调函数 */ 68 | private Camera.PictureCallback mJpeg = new Camera.PictureCallback() { 69 | @Override 70 | public void onPictureTaken(final byte[] data, Camera camera) { 71 | new Thread(new Runnable() { 72 | @Override 73 | public void run() { 74 | try { 75 | //将照片改为竖直方向 76 | Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length); 77 | Matrix matrix = new Matrix(); 78 | switch (cameraPosition) { 79 | case 0://前 80 | matrix.preRotate(90); 81 | break; 82 | case 1: 83 | matrix.preRotate(90); 84 | break; 85 | } 86 | bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); 87 | saveImageToGallery(getBaseContext(), bitmap); 88 | 89 | mCamera.stopPreview(); 90 | mCamera.startPreview(); 91 | 92 | } catch (Exception e) { 93 | e.printStackTrace(); 94 | } 95 | 96 | safeToTakePicture = true; 97 | } 98 | }).start(); 99 | } 100 | }; 101 | 102 | @Override 103 | protected void onCreate(@Nullable Bundle savedInstanceState) { 104 | super.onCreate(savedInstanceState); 105 | setContentView(R.layout.activity_test_camera); 106 | CameraUtil.init(this); 107 | 108 | initView(); 109 | 110 | initData(); 111 | } 112 | 113 | private void initView() { 114 | rxPermissions = RxPermissions.getInstance(this); 115 | 116 | mSurfaceView = (SurfaceView) findViewById(R.id.my_surfaceView); 117 | openLight = (ImageButton) findViewById(R.id.openLight); 118 | focusIndex = findViewById(R.id.focus_index); 119 | bootomRly = findViewById(R.id.bootomRly); 120 | 121 | ImageView image1 = (ImageView) findViewById(R.id.back); 122 | ImageView next = (ImageView) findViewById(R.id.lookPictureIv); 123 | Button button = (Button) findViewById(R.id.takePhoto); 124 | ImageButton imageButton2 = (ImageButton) findViewById(R.id.cameraSwitch); 125 | 126 | image1.setOnClickListener(this); 127 | next.setOnClickListener(this); 128 | button.setOnClickListener(this); 129 | openLight.setOnClickListener(this); 130 | imageButton2.setOnClickListener(this); 131 | } 132 | 133 | protected void initData() { 134 | holder = mSurfaceView.getHolder(); 135 | holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); 136 | holder.addCallback(this); // 回调接口 137 | 138 | bootomRly.setOnClickListener(new View.OnClickListener() { 139 | @Override 140 | public void onClick(View v) { 141 | } 142 | }); 143 | 144 | mSurfaceView.setOnTouchListener(new View.OnTouchListener() { 145 | @Override 146 | public boolean onTouch(View v, MotionEvent event) { 147 | switch (event.getAction() & MotionEvent.ACTION_MASK) { 148 | // 主点按下 149 | case MotionEvent.ACTION_DOWN: 150 | pointX = event.getX(); 151 | pointY = event.getY(); 152 | mode = FOCUS; 153 | break; 154 | // 副点按下 155 | case MotionEvent.ACTION_POINTER_DOWN: 156 | dist = spacing(event); 157 | // 如果连续两点距离大于10,则判定为多点模式 158 | if (spacing(event) > 10f) { 159 | mode = ZOOM; 160 | } 161 | break; 162 | case MotionEvent.ACTION_UP: 163 | case MotionEvent.ACTION_POINTER_UP: 164 | mode = FOCUS; 165 | break; 166 | case MotionEvent.ACTION_MOVE: 167 | if (mode == FOCUS) { 168 | } else if (mode == ZOOM) { 169 | float newDist = spacing(event); 170 | if (newDist > 10f) { 171 | float tScale = (newDist - dist) / dist; 172 | if (tScale < 0) { 173 | tScale = tScale * 10; 174 | } 175 | addZoomIn((int) tScale); 176 | } 177 | } 178 | break; 179 | } 180 | return false; 181 | } 182 | }); 183 | mSurfaceView.setOnClickListener(new View.OnClickListener() { 184 | @Override 185 | public void onClick(View v) { 186 | try { 187 | pointFocus((int) pointX, (int) pointY); 188 | } catch (Exception e) { 189 | e.printStackTrace(); 190 | } 191 | RelativeLayout.LayoutParams layout = new RelativeLayout.LayoutParams(focusIndex.getLayoutParams()); 192 | layout.setMargins((int) pointX - 60, (int) pointY - 60, 0, 0); 193 | focusIndex.setLayoutParams(layout); 194 | focusIndex.setVisibility(View.VISIBLE); 195 | ScaleAnimation sa = new ScaleAnimation(3f, 1f, 3f, 1f, ScaleAnimation.RELATIVE_TO_SELF, 0.5f, ScaleAnimation.RELATIVE_TO_SELF, 0.5f); 196 | sa.setDuration(800); 197 | focusIndex.startAnimation(sa); 198 | 199 | handler.postDelayed(new Runnable() { 200 | @Override 201 | public void run() { 202 | focusIndex.setVisibility(View.INVISIBLE); 203 | } 204 | }, 700); 205 | } 206 | }); 207 | } 208 | 209 | private void addZoomIn(int delta) { 210 | try { 211 | Camera.Parameters params = mCamera.getParameters(); 212 | Log.d("Camera", "Is support Zoom " + params.isZoomSupported()); 213 | if (!params.isZoomSupported()) { 214 | return; 215 | } 216 | curZoomValue += delta; 217 | if (curZoomValue < 0) { 218 | curZoomValue = 0; 219 | } else if (curZoomValue > params.getMaxZoom()) { 220 | curZoomValue = params.getMaxZoom(); 221 | } 222 | 223 | if (!params.isSmoothZoomSupported()) { 224 | params.setZoom(curZoomValue); 225 | mCamera.setParameters(params); 226 | return; 227 | } else { 228 | mCamera.startSmoothZoom(curZoomValue); 229 | } 230 | } catch (Exception e) { 231 | e.printStackTrace(); 232 | } 233 | } 234 | 235 | //定点对焦的代码 236 | private void pointFocus(int x, int y) { 237 | mCamera.cancelAutoFocus(); 238 | parameters = mCamera.getParameters(); 239 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { 240 | showPoint(x, y); 241 | } 242 | mCamera.setParameters(parameters); 243 | autoFocus(); 244 | } 245 | 246 | /** 247 | * 两点的距离 248 | */ 249 | private float spacing(MotionEvent event) { 250 | if (event == null) { 251 | return 0; 252 | } 253 | float x = event.getX(0) - event.getX(1); 254 | float y = event.getY(0) - event.getY(1); 255 | return (float) Math.sqrt(x * x + y * y); 256 | } 257 | 258 | private void showPoint(int x, int y) { 259 | if (parameters.getMaxNumMeteringAreas() > 0) { 260 | List areas = new ArrayList(); 261 | //xy变换了 262 | int rectY = -x * 2000 / CameraUtil.screenWidth + 1000; 263 | int rectX = y * 2000 / CameraUtil.screenHeight - 1000; 264 | 265 | int left = rectX < -900 ? -1000 : rectX - 100; 266 | int top = rectY < -900 ? -1000 : rectY - 100; 267 | int right = rectX > 900 ? 1000 : rectX + 100; 268 | int bottom = rectY > 900 ? 1000 : rectY + 100; 269 | Rect area1 = new Rect(left, top, right, bottom); 270 | areas.add(new Camera.Area(area1, 800)); 271 | parameters.setMeteringAreas(areas); 272 | } 273 | 274 | parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE); 275 | } 276 | 277 | //实现自动对焦 278 | private void autoFocus() { 279 | new Thread() { 280 | @Override 281 | public void run() { 282 | try { 283 | sleep(100); 284 | } catch (InterruptedException e) { 285 | e.printStackTrace(); 286 | } 287 | if (mCamera == null) { 288 | return; 289 | } 290 | mCamera.autoFocus(new Camera.AutoFocusCallback() { 291 | @Override 292 | public void onAutoFocus(boolean success, Camera camera) { 293 | if (success) { 294 | setupCamera(camera);//实现相机的参数初始化 295 | } 296 | } 297 | }); 298 | } 299 | }; 300 | } 301 | 302 | 303 | @Override 304 | public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { 305 | mCamera.stopPreview(); 306 | startPreview(mCamera, holder); 307 | autoFocus(); 308 | } 309 | 310 | @Override 311 | public void surfaceCreated(SurfaceHolder holder) { 312 | startPreview(mCamera, holder); 313 | } 314 | 315 | @Override 316 | public void surfaceDestroyed(SurfaceHolder holder) { 317 | releaseCamera(); 318 | } 319 | 320 | public void onResume() { 321 | super.onResume(); 322 | if (mCamera == null) { 323 | mCamera = getCamera(cameraPosition); 324 | if (holder != null) { 325 | startPreview(mCamera, holder); 326 | } 327 | } 328 | } 329 | 330 | @Override 331 | public void onPause() { 332 | super.onPause(); 333 | releaseCamera(); 334 | } 335 | 336 | /** 337 | * 闪光灯开关 开->关->自动 338 | * 339 | * @param mCamera 340 | */ 341 | private void turnLight(Camera mCamera) { 342 | if (mCamera == null || mCamera.getParameters() == null 343 | || mCamera.getParameters().getSupportedFlashModes() == null) { 344 | return; 345 | } 346 | Camera.Parameters parameters = mCamera.getParameters(); 347 | String flashMode = mCamera.getParameters().getFlashMode(); 348 | List supportedModes = mCamera.getParameters().getSupportedFlashModes(); 349 | if (Camera.Parameters.FLASH_MODE_OFF.equals(flashMode) 350 | && supportedModes.contains(Camera.Parameters.FLASH_MODE_ON)) {//关闭状态 351 | parameters.setFlashMode(Camera.Parameters.FLASH_MODE_ON); 352 | mCamera.setParameters(parameters); 353 | openLight.setImageResource(R.drawable.camera_flash_on); 354 | } else if (Camera.Parameters.FLASH_MODE_ON.equals(flashMode)) {//开启状态 355 | if (supportedModes.contains(Camera.Parameters.FLASH_MODE_AUTO)) { 356 | parameters.setFlashMode(Camera.Parameters.FLASH_MODE_AUTO); 357 | openLight.setImageResource(R.drawable.camera_flash_auto); 358 | mCamera.setParameters(parameters); 359 | } else if (supportedModes.contains(Camera.Parameters.FLASH_MODE_OFF)) { 360 | parameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF); 361 | openLight.setImageResource(R.drawable.camera_flash_off); 362 | mCamera.setParameters(parameters); 363 | } 364 | } else if (Camera.Parameters.FLASH_MODE_AUTO.equals(flashMode) 365 | && supportedModes.contains(Camera.Parameters.FLASH_MODE_OFF)) { 366 | parameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF); 367 | mCamera.setParameters(parameters); 368 | openLight.setImageResource(R.drawable.camera_flash_off); 369 | } 370 | } 371 | 372 | /** 373 | * 获取Camera实例 374 | */ 375 | private Camera getCamera(int id) { 376 | Camera camera = null; 377 | try { 378 | camera = Camera.open(id); 379 | } catch (Exception e) { 380 | 381 | } 382 | return camera; 383 | } 384 | 385 | /** 386 | * 预览相机 387 | */ 388 | private void startPreview(Camera camera, SurfaceHolder holder) { 389 | try { 390 | setupCamera(camera); 391 | camera.setPreviewDisplay(holder); 392 | //亲测的一个方法 基本覆盖所有手机 将预览矫正 393 | CameraUtil.getInstance().setCameraDisplayOrientation(this, cameraPosition, camera); 394 | camera.startPreview(); 395 | } catch (IOException e) { 396 | e.printStackTrace(); 397 | } 398 | } 399 | 400 | /** 401 | * 释放相机资源 402 | */ 403 | private void releaseCamera() { 404 | if (mCamera != null) { 405 | mCamera.setPreviewCallback(null); 406 | mCamera.stopPreview(); 407 | mCamera.release(); 408 | mCamera = null; 409 | } 410 | } 411 | 412 | @Override 413 | protected void onDestroy() { 414 | super.onDestroy(); 415 | } 416 | 417 | /** 418 | * 设置 419 | */ 420 | private void setupCamera(Camera camera) { 421 | Camera.Parameters parameters = camera.getParameters(); 422 | 423 | List focusModes = parameters.getSupportedFocusModes(); 424 | if (focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) { 425 | // Autofocus mode is supported 自动对焦 426 | parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO); 427 | } 428 | 429 | Camera.Size previewSize = CameraUtil.findBestPreviewResolution(camera); 430 | parameters.setPreviewSize(previewSize.width, previewSize.height); 431 | 432 | Camera.Size pictrueSize = CameraUtil.getInstance().getPropPictureSize(parameters.getSupportedPictureSizes(), 1000); 433 | parameters.setPictureSize(pictrueSize.width, pictrueSize.height); 434 | 435 | camera.setParameters(parameters); 436 | 437 | int picHeight = CameraUtil.screenWidth * previewSize.width / previewSize.height; 438 | FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(CameraUtil.screenWidth, picHeight); 439 | mSurfaceView.setLayoutParams(params); 440 | 441 | } 442 | 443 | //将bitmap保存在本地,然后通知图库更新 444 | public void saveImageToGallery(Context context, Bitmap bmp) { 445 | // 首先保存图片 446 | File appDir = new File(Environment.getExternalStorageDirectory(), "轻牛"); 447 | if (!appDir.exists()) { 448 | appDir.mkdir(); 449 | } 450 | String fileName = System.currentTimeMillis() + ".jpg"; 451 | File file = new File(appDir, fileName); 452 | try { 453 | FileOutputStream fos = new FileOutputStream(file); 454 | bmp.compress(Bitmap.CompressFormat.JPEG, 100, fos); 455 | fos.flush(); 456 | fos.close(); 457 | } catch (Exception e) { 458 | e.printStackTrace(); 459 | Toast.makeText(context, "保存图片失败", Toast.LENGTH_SHORT).show(); 460 | } 461 | 462 | // 其次把文件插入到系统图库 463 | try { 464 | MediaStore.Images.Media.insertImage(context.getContentResolver(), file.getAbsolutePath(), fileName, null); 465 | } catch (FileNotFoundException e) { 466 | e.printStackTrace(); 467 | Toast.makeText(context, "保存图片失败", Toast.LENGTH_SHORT).show(); 468 | } 469 | // 最后通知图库更新 470 | context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://" + file))); 471 | } 472 | 473 | @Override 474 | public void onClick(View v) { 475 | switch (v.getId()) { 476 | case R.id.back: 477 | finish(); 478 | break; 479 | 480 | case R.id.lookPictureIv: 481 | //指定照片 482 | // File appDir = new File(Environment.getExternalStorageDirectory(), "轻牛"); 483 | // intent.setDataAndType(Uri.fromFile(appDir), "image/*"); 484 | 485 | Intent intent = new Intent(); 486 | intent.setAction(Intent.ACTION_VIEW); 487 | intent.setType("image/*"); 488 | 489 | startActivity(intent); 490 | break; 491 | 492 | case R.id.takePhoto: 493 | rxPermissions.requestEach(Manifest.permission.WRITE_EXTERNAL_STORAGE).subscribe(new DefaultSubscriber() { 494 | @Override 495 | public void onNext(Permission permission) { 496 | if (permission.granted) { 497 | if (safeToTakePicture) { 498 | safeToTakePicture = false; 499 | mCamera.takePicture(null, null, mJpeg); 500 | } 501 | } else { 502 | AlertDialog.Builder builder = new AlertDialog.Builder(this.context); 503 | builder.setMessage("您未授权读取本地相册权限,将无法打开相册,请在权限管理中开启存储权限") 504 | .setTitle("提示").setPositiveButton("确认", new DialogInterface.OnClickListener() { 505 | @Override 506 | public void onClick(DialogInterface dialog, int which) { 507 | Uri packageURI = Uri.parse("package:" + getPackageName()); 508 | Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, packageURI); 509 | startActivity(intent); 510 | } 511 | }).setNegativeButton("取消", new DialogInterface.OnClickListener() { 512 | @Override 513 | public void onClick(DialogInterface dialog, int which) { 514 | dialog.dismiss(); 515 | } 516 | }); 517 | builder.create().show(); 518 | 519 | } 520 | } 521 | }); 522 | 523 | break; 524 | 525 | case R.id.openLight: 526 | turnLight(mCamera); 527 | break; 528 | 529 | case R.id.cameraSwitch: 530 | releaseCamera(); 531 | cameraPosition = (cameraPosition + 1) % mCamera.getNumberOfCameras(); 532 | mCamera = getCamera(cameraPosition); 533 | if (holder != null) { 534 | startPreview(mCamera, holder); 535 | } 536 | break; 537 | 538 | } 539 | 540 | } 541 | } 542 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/ysq/customcamera/CameraUtil.java: -------------------------------------------------------------------------------- 1 | package com.example.ysq.customcamera; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.graphics.Bitmap; 6 | import android.graphics.Matrix; 7 | import android.hardware.Camera; 8 | import android.hardware.Camera.Size; 9 | import android.util.DisplayMetrics; 10 | import android.util.Log; 11 | import android.view.Surface; 12 | 13 | import java.util.ArrayList; 14 | import java.util.Collections; 15 | import java.util.Comparator; 16 | import java.util.Iterator; 17 | import java.util.List; 18 | 19 | public class CameraUtil { 20 | public static float scale; 21 | 22 | public static int densityDpi; 23 | 24 | public static float fontScale; 25 | 26 | public static int screenWidth; 27 | public static int screenHeight; 28 | 29 | public static void init(Context context) { 30 | DisplayMetrics dm = context.getResources().getDisplayMetrics(); 31 | scale = dm.density; 32 | densityDpi = dm.densityDpi; 33 | fontScale = dm.scaledDensity; 34 | if (dm.widthPixels < dm.heightPixels) { 35 | screenWidth = dm.widthPixels; 36 | screenHeight = dm.heightPixels; 37 | } else { 38 | screenWidth = dm.heightPixels; 39 | screenHeight = dm.widthPixels; 40 | } 41 | Log.e("screen", "屏幕宽度是:" + screenWidth + " 高度是:" + screenHeight + " dp:" + scale + " fontScale:" + fontScale); 42 | } 43 | 44 | //降序 45 | private CameraDropSizeComparator dropSizeComparator = new CameraDropSizeComparator(); 46 | //升序 47 | private CameraAscendSizeComparator ascendSizeComparator = new CameraAscendSizeComparator(); 48 | private static CameraUtil myCamPara = null; 49 | 50 | private CameraUtil() { 51 | 52 | } 53 | 54 | public static CameraUtil getInstance() { 55 | if (myCamPara == null) { 56 | myCamPara = new CameraUtil(); 57 | return myCamPara; 58 | } else { 59 | return myCamPara; 60 | } 61 | } 62 | 63 | /** 64 | * 保证预览方向正确 65 | * 66 | * @param activity 67 | * @param cameraId 68 | * @param camera 69 | */ 70 | public void setCameraDisplayOrientation(Activity activity, 71 | int cameraId, Camera camera) { 72 | Camera.CameraInfo info = 73 | new Camera.CameraInfo(); 74 | Camera.getCameraInfo(cameraId, info); 75 | int rotation = activity.getWindowManager().getDefaultDisplay() 76 | .getRotation(); 77 | int degrees = 0; 78 | switch (rotation) { 79 | case Surface.ROTATION_0: 80 | degrees = 0; 81 | break; 82 | case Surface.ROTATION_90: 83 | degrees = 90; 84 | break; 85 | case Surface.ROTATION_180: 86 | degrees = 180; 87 | break; 88 | case Surface.ROTATION_270: 89 | degrees = 270; 90 | break; 91 | } 92 | 93 | int result; 94 | if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { 95 | result = (info.orientation + degrees) % 360; 96 | result = (360 - result) % 360; // compensate the mirror 97 | } else { // back-facing 98 | result = (info.orientation - degrees + 360) % 360; 99 | } 100 | camera.setDisplayOrientation(result); 101 | } 102 | 103 | 104 | public Bitmap setTakePicktrueOrientation(int id, Bitmap bitmap) { 105 | Camera.CameraInfo info = new Camera.CameraInfo(); 106 | Camera.getCameraInfo(id, info); 107 | bitmap = rotaingImageView(id, info.orientation, bitmap); 108 | return bitmap; 109 | } 110 | 111 | /** 112 | * 把相机拍照返回照片转正 113 | * 114 | * @param angle 旋转角度 115 | * @return bitmap 图片 116 | */ 117 | public Bitmap rotaingImageView(int id, int angle, Bitmap bitmap) { 118 | //旋转图片 动作 119 | Matrix matrix = new Matrix(); 120 | matrix.postRotate(angle); 121 | //加入翻转 把相机拍照返回照片转正 122 | if (id == 1) { 123 | matrix.postScale(-1, 1); 124 | } 125 | // 创建新的图片 126 | Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0, 127 | bitmap.getWidth(), bitmap.getHeight(), matrix, true); 128 | return resizedBitmap; 129 | } 130 | 131 | /** 132 | * 获取所有支持的预览尺寸 133 | */ 134 | public Size getPropPreviewSize(List list, int minWidth) { 135 | Collections.sort(list, ascendSizeComparator); 136 | 137 | int i = 0; 138 | for (Size s : list) { 139 | if ((s.width >= minWidth)) { 140 | break; 141 | } 142 | i++; 143 | } 144 | if (i == list.size()) { 145 | i = 0;//如果没找到,就选最小的size 146 | } 147 | return list.get(i); 148 | } 149 | 150 | /** 151 | * 获取所有支持的返回图片尺寸 152 | */ 153 | public Size getPropPictureSize(List list, int minWidth) { 154 | Collections.sort(list, ascendSizeComparator); 155 | 156 | int i = 0; 157 | for (Size s : list) { 158 | if ((s.width >= minWidth)) { 159 | break; 160 | } 161 | i++; 162 | } 163 | if (i == list.size()) { 164 | i = 0;//如果没找到,就选最小的size 165 | } 166 | return list.get(i); 167 | } 168 | 169 | public boolean equalRate(Size s, float rate) { 170 | float r = (float) (s.width) / (float) (s.height); 171 | if (Math.abs(r - rate) <= 0.03) { 172 | return true; 173 | } else { 174 | return false; 175 | } 176 | } 177 | 178 | //降序 179 | public class CameraDropSizeComparator implements Comparator { 180 | public int compare(Size lhs, Size rhs) { 181 | if (lhs.width == rhs.width) { 182 | return 0; 183 | } else if (lhs.width < rhs.width) { 184 | return 1; 185 | } else { 186 | return -1; 187 | } 188 | } 189 | 190 | } 191 | 192 | //升序 193 | public class CameraAscendSizeComparator implements Comparator { 194 | public int compare(Size lhs, Size rhs) { 195 | if (lhs.width == rhs.width) { 196 | return 0; 197 | } else if (lhs.width > rhs.width) { 198 | return 1; 199 | } else { 200 | return -1; 201 | } 202 | } 203 | 204 | } 205 | 206 | /** 207 | * 打印支持的previewSizes 208 | */ 209 | public void printSupportPreviewSize(Camera.Parameters params) { 210 | List previewSizes = params.getSupportedPreviewSizes(); 211 | for (int i = 0; i < previewSizes.size(); i++) { 212 | Size size = previewSizes.get(i); 213 | } 214 | 215 | } 216 | 217 | /** 218 | * 打印支持的pictureSizes 219 | */ 220 | public void printSupportPictureSize(Camera.Parameters params) { 221 | List pictureSizes = params.getSupportedPictureSizes(); 222 | for (int i = 0; i < pictureSizes.size(); i++) { 223 | Size size = pictureSizes.get(i); 224 | } 225 | } 226 | 227 | /** 228 | * 打印支持的聚焦模式 229 | */ 230 | public void printSupportFocusMode(Camera.Parameters params) { 231 | List focusModes = params.getSupportedFocusModes(); 232 | for (String mode : focusModes) { 233 | } 234 | } 235 | 236 | /** 237 | * 打开闪关灯 238 | */ 239 | public void turnLightOn(Camera mCamera) { 240 | if (mCamera == null) { 241 | return; 242 | } 243 | Camera.Parameters parameters = mCamera.getParameters(); 244 | if (parameters == null) { 245 | return; 246 | } 247 | List flashModes = parameters.getSupportedFlashModes(); 248 | // Check if camera flash exists 249 | if (flashModes == null) { 250 | // Use the screen as a flashlight (next best thing) 251 | return; 252 | } 253 | String flashMode = parameters.getFlashMode(); 254 | if (!Camera.Parameters.FLASH_MODE_ON.equals(flashMode)) { 255 | // Turn on the flash 256 | if (flashModes.contains(Camera.Parameters.FLASH_MODE_TORCH)) { 257 | parameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH); 258 | mCamera.setParameters(parameters); 259 | } else { 260 | } 261 | } 262 | } 263 | 264 | 265 | /** 266 | * 自动模式闪光灯 267 | */ 268 | public void turnLightAuto(Camera mCamera) { 269 | if (mCamera == null) { 270 | return; 271 | } 272 | Camera.Parameters parameters = mCamera.getParameters(); 273 | if (parameters == null) { 274 | return; 275 | } 276 | List flashModes = parameters.getSupportedFlashModes(); 277 | // Check if camera flash exists 278 | if (flashModes == null) { 279 | // Use the screen as a flashlight (next best thing) 280 | return; 281 | } 282 | String flashMode = parameters.getFlashMode(); 283 | if (!Camera.Parameters.FLASH_MODE_AUTO.equals(flashMode)) { 284 | // Turn on the flash 285 | if (flashModes.contains(Camera.Parameters.FLASH_MODE_TORCH)) { 286 | parameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH); 287 | mCamera.setParameters(parameters); 288 | } else { 289 | } 290 | } 291 | } 292 | 293 | 294 | /** 295 | * 最小预览界面的分辨率 296 | */ 297 | private static final int MIN_PREVIEW_PIXELS = 480 * 320; 298 | /** 299 | * 最大宽高比差 300 | */ 301 | private static final double MAX_ASPECT_DISTORTION = 0.15; 302 | 303 | 304 | /** 305 | * 关闭闪光灯 306 | * 307 | * @param mCamera 308 | */ 309 | public void turnLightOff(Camera mCamera) { 310 | if (mCamera == null) { 311 | return; 312 | } 313 | Camera.Parameters parameters = mCamera.getParameters(); 314 | if (parameters == null) { 315 | return; 316 | } 317 | List flashModes = parameters.getSupportedFlashModes(); 318 | String flashMode = parameters.getFlashMode(); 319 | // Check if camera flash exists 320 | if (flashModes == null) { 321 | return; 322 | } 323 | if (!Camera.Parameters.FLASH_MODE_OFF.equals(flashMode)) { 324 | // Turn off the flash 325 | if (flashModes.contains(Camera.Parameters.FLASH_MODE_TORCH)) { 326 | parameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH); 327 | mCamera.setParameters(parameters); 328 | } else { 329 | } 330 | } 331 | } 332 | 333 | public static Size findBestPreviewResolution(Camera mCamera) { 334 | Camera.Parameters cameraParameters = mCamera.getParameters(); 335 | Size defaultPreviewResolution = cameraParameters.getPreviewSize(); 336 | 337 | List rawSupportedSizes = cameraParameters.getSupportedPreviewSizes(); 338 | if (rawSupportedSizes == null) { 339 | return defaultPreviewResolution; 340 | } 341 | 342 | // 按照分辨率从大到小排序 343 | List supportedPreviewResolutions = new ArrayList(rawSupportedSizes); 344 | Collections.sort(supportedPreviewResolutions, new Comparator() { 345 | @Override 346 | public int compare(Size a, Size b) { 347 | int aPixels = a.height * a.width; 348 | int bPixels = b.height * b.width; 349 | if (bPixels < aPixels) { 350 | return -1; 351 | } 352 | if (bPixels > aPixels) { 353 | return 1; 354 | } 355 | return 0; 356 | } 357 | }); 358 | 359 | StringBuilder previewResolutionSb = new StringBuilder(); 360 | for (Size supportedPreviewResolution : supportedPreviewResolutions) { 361 | previewResolutionSb.append(supportedPreviewResolution.width).append('x').append(supportedPreviewResolution.height) 362 | .append(' '); 363 | } 364 | 365 | // 移除不符合条件的分辨率 366 | double screenAspectRatio = (double) (screenWidth / screenHeight); 367 | Iterator it = supportedPreviewResolutions.iterator(); 368 | while (it.hasNext()) { 369 | Size supportedPreviewResolution = it.next(); 370 | int width = supportedPreviewResolution.width; 371 | int height = supportedPreviewResolution.height; 372 | 373 | // 移除低于下限的分辨率,尽可能取高分辨率 374 | if (width * height < MIN_PREVIEW_PIXELS) { 375 | it.remove(); 376 | continue; 377 | } 378 | 379 | // 在camera分辨率与屏幕分辨率宽高比不相等的情况下,找出差距最小的一组分辨率 380 | // 由于camera的分辨率是width>height,我们设置的portrait模式中,width height; 383 | int maybeFlippedWidth = isCandidatePortrait ? height : width; 384 | int maybeFlippedHeight = isCandidatePortrait ? width : height; 385 | double aspectRatio = (double) maybeFlippedWidth / (double) maybeFlippedHeight; 386 | double distortion = Math.abs(aspectRatio - screenAspectRatio); 387 | 388 | // 找到与屏幕分辨率完全匹配的预览界面分辨率直接返回 389 | if (maybeFlippedWidth == screenWidth 390 | && maybeFlippedHeight == screenHeight) { 391 | return supportedPreviewResolution; 392 | } 393 | 394 | if (distortion > MAX_ASPECT_DISTORTION) { 395 | it.remove(); 396 | continue; 397 | } 398 | 399 | } 400 | 401 | // 如果没有找到合适的,并且还有候选的像素,则设置其中最大比例的,对于配置比较低的机器不太合适 402 | if (!supportedPreviewResolutions.isEmpty()) { 403 | Size largestPreview = supportedPreviewResolutions.get(0); 404 | return largestPreview; 405 | } 406 | 407 | // 没有找到合适的,就返回默认的 408 | 409 | return defaultPreviewResolution; 410 | } 411 | } 412 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/ysq/customcamera/DefaultSubscriber.java: -------------------------------------------------------------------------------- 1 | package com.example.ysq.customcamera; 2 | 3 | import android.content.Context; 4 | 5 | import rx.Subscriber; 6 | 7 | /** 8 | * Created by hdr on 15/9/6. 9 | */ 10 | public class DefaultSubscriber extends Subscriber { 11 | Context context; 12 | 13 | public DefaultSubscriber() { 14 | } 15 | 16 | public DefaultSubscriber(Context context) { 17 | this.context = context; 18 | } 19 | 20 | @Override 21 | public void onStart() { 22 | 23 | } 24 | 25 | @Override 26 | public void onCompleted() { 27 | 28 | } 29 | 30 | @Override 31 | public void onError(Throwable e) { 32 | } 33 | 34 | @Override 35 | public void onNext(T t) { 36 | 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/ysq/customcamera/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.ysq.customcamera; 2 | 3 | import android.Manifest; 4 | import android.content.DialogInterface; 5 | import android.content.Intent; 6 | import android.net.Uri; 7 | import android.os.Bundle; 8 | import android.provider.Settings; 9 | import android.support.v7.app.AlertDialog; 10 | import android.support.v7.app.AppCompatActivity; 11 | import android.view.View; 12 | import android.widget.Button; 13 | 14 | import com.tbruyelle.rxpermissions.Permission; 15 | import com.tbruyelle.rxpermissions.RxPermissions; 16 | 17 | public class MainActivity extends AppCompatActivity { 18 | RxPermissions rxPermissions; 19 | 20 | @Override 21 | protected void onCreate(Bundle savedInstanceState) { 22 | super.onCreate(savedInstanceState); 23 | setContentView(R.layout.activity_main); 24 | 25 | rxPermissions = RxPermissions.getInstance(this); 26 | 27 | Button cameraBtn = (Button) findViewById(R.id.cameraBtn); 28 | cameraBtn.setOnClickListener(new View.OnClickListener() { 29 | @Override 30 | public void onClick(View v) { 31 | rxPermissions.requestEach(Manifest.permission.CAMERA).subscribe(new DefaultSubscriber() { 32 | @Override 33 | public void onNext(Permission permission) { 34 | if (permission.granted) { 35 | startActivity(new Intent(MainActivity.this, CameraActivity.class)); 36 | } else { 37 | AlertDialog.Builder builder = new AlertDialog.Builder(this.context); 38 | builder.setMessage("您未授权相机权限,将无法拍照,请在权限管理中开启相机权限") 39 | .setTitle("提示").setPositiveButton("确认", new DialogInterface.OnClickListener() { 40 | @Override 41 | public void onClick(DialogInterface dialog, int which) { 42 | Uri packageURI = Uri.parse("package:" + getPackageName()); 43 | Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, packageURI); 44 | startActivity(intent); 45 | } 46 | }).setNegativeButton("取消", new DialogInterface.OnClickListener() { 47 | @Override 48 | public void onClick(DialogInterface dialog, int which) { 49 | dialog.dismiss(); 50 | } 51 | }); 52 | builder.create().show(); 53 | 54 | } 55 | } 56 | }); 57 | 58 | } 59 | }); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/camera_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ysq1051838264/CustomCamera/d3bd869bb70f5df0502d1d52edc11110ed1a556c/app/src/main/res/drawable-xxhdpi/camera_back.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/camera_flash_auto.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ysq1051838264/CustomCamera/d3bd869bb70f5df0502d1d52edc11110ed1a556c/app/src/main/res/drawable-xxhdpi/camera_flash_auto.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/camera_flash_off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ysq1051838264/CustomCamera/d3bd869bb70f5df0502d1d52edc11110ed1a556c/app/src/main/res/drawable-xxhdpi/camera_flash_off.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/camera_flash_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ysq1051838264/CustomCamera/d3bd869bb70f5df0502d1d52edc11110ed1a556c/app/src/main/res/drawable-xxhdpi/camera_flash_on.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/camera_flip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ysq1051838264/CustomCamera/d3bd869bb70f5df0502d1d52edc11110ed1a556c/app/src/main/res/drawable-xxhdpi/camera_flip.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/camera_library.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ysq1051838264/CustomCamera/d3bd869bb70f5df0502d1d52edc11110ed1a556c/app/src/main/res/drawable-xxhdpi/camera_library.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/camera_photo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ysq1051838264/CustomCamera/d3bd869bb70f5df0502d1d52edc11110ed1a556c/app/src/main/res/drawable-xxhdpi/camera_photo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/btn_take_photo.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/cam_focus.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 |