From e9a2186b887888748e165111040408385da58dc2 Mon Sep 17 00:00:00 2001 From: kevinkawai Date: Thu, 23 Mar 2017 12:17:43 -0700 Subject: [PATCH 01/42] initial --- build.gradle | 3 ++- library/build.gradle | 31 +++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 0e3b4e3d..2a6442ac 100644 --- a/build.gradle +++ b/build.gradle @@ -9,6 +9,7 @@ buildscript { // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files + classpath 'org.jfrog.buildinfo:build-info-extractor-gradle:4.1.0' } } @@ -23,7 +24,7 @@ task clean(type: Delete) { } ext { - buildToolsVersion = '25.0.2' + buildToolsVersion = '25.0.1' compileSdkVersion = 25 minSdkVersion = 9 targetSdkVersion = 25 diff --git a/library/build.gradle b/library/build.gradle index 30b53bd8..c4aa51d3 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -13,6 +13,8 @@ // limitations under the License. apply plugin: 'com.android.library' +apply plugin: 'com.jfrog.artifactory' +apply plugin: 'maven-publish' android { compileSdkVersion rootProject.ext.compileSdkVersion @@ -38,6 +40,35 @@ android { } } +artifactory { + contextUrl = "${System.env.ARTIFACTORY_URL}" + publish { + repository { + repoKey = 'private-local' + username = "${System.env.ARTIFACTORY_USERNAME}" + password = "${System.env.ARTIFACTORY_PASSWORD}" + maven = true + } + defaults { + publications('aar') + } + } +} + + + +publishing { + publications { + aar(MavenPublication) { + groupId 'premise.android.cameraview' + version '0.0.1' + artifactId 'cameraview' + + artifact("$buildDir/outputs/aar/${project.getName()}-release.aar") + } + } +} + dependencies { compile "com.android.support:support-annotations:$supportLibraryVersion" compile "com.android.support:support-v4:$supportLibraryVersion" From 08ca69616850b7a9d89568d50916d9be2ac8e2e2 Mon Sep 17 00:00:00 2001 From: kevinkawai Date: Fri, 24 Mar 2017 00:11:17 -0700 Subject: [PATCH 02/42] added premise SimpleCameraActivity to library --- .../main/res/layout-land/activity_main.xml | 2 +- library/build.gradle | 2 + .../AspectRatioFragment.java | 146 ++++++ .../SimpleCameraActivity.java | 483 ++++++++++++++++++ .../com/premise.android.camera/Utils.java | 143 ++++++ .../drawable-xxxhdpi/ic_check_white_24dp.png | Bin 0 -> 308 bytes .../src/main/res/drawable/ic_aspect_ratio.xml | 25 + library/src/main/res/drawable/ic_camera.xml | 25 + .../src/main/res/drawable/ic_flash_auto.xml | 22 + .../src/main/res/drawable/ic_flash_off.xml | 22 + library/src/main/res/drawable/ic_flash_on.xml | 22 + .../main/res/drawable/ic_switch_camera.xml | 22 + .../res/layout-land/simple_camera_layout.xml | 43 ++ .../main/res/layout/include_simple_camera.xml | 40 ++ .../main/res/layout/simple_camera_layout.xml | 37 ++ .../src/main/res/menu/simple_camera_menu.xml | 38 ++ library/src/main/res/values-w820dp/dimens.xml | 16 + library/src/main/res/values/colors.xml | 20 + library/src/main/res/values/dimens.xml | 17 + library/src/main/res/values/strings.xml | 27 + library/src/main/res/values/styles.xml | 18 + 21 files changed, 1169 insertions(+), 1 deletion(-) create mode 100644 library/src/main/java/com/premise.android.camera/AspectRatioFragment.java create mode 100644 library/src/main/java/com/premise.android.camera/SimpleCameraActivity.java create mode 100644 library/src/main/java/com/premise.android.camera/Utils.java create mode 100644 library/src/main/res/drawable-xxxhdpi/ic_check_white_24dp.png create mode 100644 library/src/main/res/drawable/ic_aspect_ratio.xml create mode 100644 library/src/main/res/drawable/ic_camera.xml create mode 100644 library/src/main/res/drawable/ic_flash_auto.xml create mode 100644 library/src/main/res/drawable/ic_flash_off.xml create mode 100644 library/src/main/res/drawable/ic_flash_on.xml create mode 100644 library/src/main/res/drawable/ic_switch_camera.xml create mode 100644 library/src/main/res/layout-land/simple_camera_layout.xml create mode 100644 library/src/main/res/layout/include_simple_camera.xml create mode 100644 library/src/main/res/layout/simple_camera_layout.xml create mode 100644 library/src/main/res/menu/simple_camera_menu.xml create mode 100644 library/src/main/res/values-w820dp/dimens.xml create mode 100644 library/src/main/res/values/colors.xml create mode 100644 library/src/main/res/values/dimens.xml create mode 100644 library/src/main/res/values/strings.xml diff --git a/demo/src/main/res/layout-land/activity_main.xml b/demo/src/main/res/layout-land/activity_main.xml index af24ba0a..6b7572a4 100644 --- a/demo/src/main/res/layout-land/activity_main.xml +++ b/demo/src/main/res/layout-land/activity_main.xml @@ -21,7 +21,7 @@ tools:context=".MainActivity"> diff --git a/library/build.gradle b/library/build.gradle index c4aa51d3..0908d82a 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -24,6 +24,7 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion testInstrumentationRunner 'android.support.test.runner.AndroidJUnitRunner' + vectorDrawables.useSupportLibrary = true } buildTypes { release { @@ -72,6 +73,7 @@ publishing { dependencies { compile "com.android.support:support-annotations:$supportLibraryVersion" compile "com.android.support:support-v4:$supportLibraryVersion" + compile "com.android.support:design:$supportLibraryVersion" // Tests testCompile 'junit:junit:4.12' diff --git a/library/src/main/java/com/premise.android.camera/AspectRatioFragment.java b/library/src/main/java/com/premise.android.camera/AspectRatioFragment.java new file mode 100644 index 00000000..15d409b7 --- /dev/null +++ b/library/src/main/java/com/premise.android.camera/AspectRatioFragment.java @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.premise.android.camera; + +import android.app.Dialog; +import android.content.Context; +import android.content.DialogInterface; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.v4.app.DialogFragment; +import android.support.v7.app.AlertDialog; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.TextView; + +import com.google.android.cameraview.AspectRatio; + +import java.util.Set; + + +/** + * A simple dialog that allows user to pick an aspect ratio. + */ +public class AspectRatioFragment extends DialogFragment { + + private static final String ARG_ASPECT_RATIOS = "aspect_ratios"; + private static final String ARG_CURRENT_ASPECT_RATIO = "current_aspect_ratio"; + + private Listener mListener; + + public static AspectRatioFragment newInstance(Set ratios, + AspectRatio currentRatio) { + final AspectRatioFragment fragment = new AspectRatioFragment(); + final Bundle args = new Bundle(); + args.putParcelableArray(ARG_ASPECT_RATIOS, + ratios.toArray(new AspectRatio[ratios.size()])); + args.putParcelable(ARG_CURRENT_ASPECT_RATIO, currentRatio); + fragment.setArguments(args); + return fragment; + } + + @Override + public void onAttach(Context context) { + super.onAttach(context); + mListener = (Listener) context; + } + + @Override + public void onDetach() { + mListener = null; + super.onDetach(); + } + + @NonNull + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + final Bundle args = getArguments(); + final AspectRatio[] ratios = (AspectRatio[]) args.getParcelableArray(ARG_ASPECT_RATIOS); + if (ratios == null) { + throw new RuntimeException("No ratios"); + } + final AspectRatio current = args.getParcelable(ARG_CURRENT_ASPECT_RATIO); + final AspectRatioAdapter adapter = new AspectRatioAdapter(ratios, current); + return new AlertDialog.Builder(getActivity()) + .setAdapter(adapter, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int position) { + mListener.onAspectRatioSelected(ratios[position]); + } + }) + .create(); + } + + private static class AspectRatioAdapter extends BaseAdapter { + + private final AspectRatio[] mRatios; + private final AspectRatio mCurrentRatio; + + AspectRatioAdapter(AspectRatio[] ratios, AspectRatio current) { + mRatios = ratios; + mCurrentRatio = current; + } + + @Override + public int getCount() { + return mRatios.length; + } + + @Override + public AspectRatio getItem(int position) { + return mRatios[position]; + } + + @Override + public long getItemId(int position) { + return getItem(position).hashCode(); + } + + @Override + public View getView(int position, View view, ViewGroup parent) { + AspectRatioAdapter.ViewHolder holder; + if (view == null) { + view = LayoutInflater.from(parent.getContext()) + .inflate(android.R.layout.simple_list_item_1, parent, false); + holder = new AspectRatioAdapter.ViewHolder(); + holder.text = (TextView) view.findViewById(android.R.id.text1); + view.setTag(holder); + } else { + holder = (AspectRatioAdapter.ViewHolder) view.getTag(); + } + AspectRatio ratio = getItem(position); + StringBuilder sb = new StringBuilder(ratio.toString()); + if (ratio.equals(mCurrentRatio)) { + sb.append(" *"); + } + holder.text.setText(sb); + return view; + } + + private static class ViewHolder { + TextView text; + } + + } + + public interface Listener { + void onAspectRatioSelected(@NonNull AspectRatio ratio); + } + +} diff --git a/library/src/main/java/com/premise.android.camera/SimpleCameraActivity.java b/library/src/main/java/com/premise.android.camera/SimpleCameraActivity.java new file mode 100644 index 00000000..f52e1703 --- /dev/null +++ b/library/src/main/java/com/premise.android.camera/SimpleCameraActivity.java @@ -0,0 +1,483 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.premise.android.camera; + +import static android.os.Build.VERSION.SDK_INT; + +import android.Manifest; +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.annotation.TargetApi; +import android.app.Dialog; +import android.content.DialogInterface; +import android.content.pm.ActivityInfo; +import android.content.pm.PackageManager; +import android.content.res.Configuration; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.media.MediaActionSound; +import android.os.Build; +import android.os.Bundle; +import android.os.Environment; +import android.os.Handler; +import android.os.HandlerThread; +import android.support.annotation.NonNull; +import android.support.annotation.StringRes; +import android.support.design.widget.FloatingActionButton; +import android.support.v4.app.ActivityCompat; +import android.support.v4.app.DialogFragment; +import android.support.v4.content.ContextCompat; +import android.support.v7.app.ActionBar; +import android.support.v7.app.AlertDialog; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.Toolbar; +import android.util.Log; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewAnimationUtils; +import android.widget.ImageView; +import android.widget.Toast; + +import com.google.android.cameraview.AspectRatio; +import com.google.android.cameraview.CameraView; +import com.google.android.cameraview.R; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.Set; +import java.util.concurrent.CountDownLatch; + + +/** + * This demo app saves the taken picture to a constant file. + * $ adb pull /sdcard/Android/data/com.google.android.cameraview.demo/files/Pictures/picture.jpg + */ +public class SimpleCameraActivity extends AppCompatActivity implements + ActivityCompat.OnRequestPermissionsResultCallback, + AspectRatioFragment.Listener { + + private static final String TAG = "MainActivity"; + + private static final boolean DO_ANIM = true; + + private static final int REQUEST_CAMERA_PERMISSION = 1; + + private static final String FRAGMENT_DIALOG = "dialog"; + + private static final int[] FLASH_OPTIONS = { + CameraView.FLASH_OFF, + CameraView.FLASH_AUTO, + CameraView.FLASH_ON, + }; + + private static final int[] FLASH_ICONS = { + R.drawable.ic_flash_off, + R.drawable.ic_flash_auto, + R.drawable.ic_flash_on, + }; + + private static final int[] FLASH_TITLES = { + R.string.flash_off, + R.string.flash_auto, + R.string.flash_on, + }; + + private int mCurrentFlash; + + private CameraView mCameraView; + + private ImageView mCapturedImageView; + + private Handler mBackgroundHandler; + + private FloatingActionButton mTakePicButton; + + private CountDownLatch mCountDownLatch = new CountDownLatch(1); + + private MediaActionSound mSound; + + private Bitmap mBitmap; + + private View.OnClickListener mOnClickListener = new View.OnClickListener() { + @Override + public void onClick(View v) { + if (v.getId() == R.id.take_picture) { + takePhoto(); + } + } + }; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.simple_camera_layout); + mCameraView = (CameraView) findViewById(R.id.camera); + mCameraView.setFlash(CameraView.FLASH_OFF); + if (mCameraView != null) { + mCameraView.addCallback(mCallback); + } + mTakePicButton = (FloatingActionButton) findViewById(R.id.take_picture); + mTakePicButton.setOnClickListener(mOnClickListener); + mCapturedImageView = (ImageView)findViewById(R.id.captured_camera_image); + + Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); + setSupportActionBar(toolbar); + ActionBar actionBar = getSupportActionBar(); + if (actionBar != null) { + actionBar.setDisplayShowTitleEnabled(false); + } + initSound(); + } + + private void initSound() { + if (SDK_INT >= 16) { + mSound = new MediaActionSound(); + } + } + + private void playSound() { + if (SDK_INT >= 16) { + if (mSound != null) { + mSound.play(MediaActionSound.SHUTTER_CLICK); + } + } + } + + private void releaseSound() { + if (SDK_INT >= 16) { + if (mSound != null) { + mSound.release(); + } + } + } + + @Override + protected void onResume() { + super.onResume(); + if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) + == PackageManager.PERMISSION_GRANTED) { + mCameraView.start(); + } else if (ActivityCompat.shouldShowRequestPermissionRationale(this, + Manifest.permission.CAMERA)) { + ConfirmationDialogFragment + .newInstance(R.string.camera_permission_confirmation, + new String[]{Manifest.permission.CAMERA}, + REQUEST_CAMERA_PERMISSION, + R.string.camera_permission_not_granted) + .show(getSupportFragmentManager(), FRAGMENT_DIALOG); + } else { + ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, + REQUEST_CAMERA_PERMISSION); + } + } + + @Override + protected void onPause() { + mCameraView.stop(); + super.onPause(); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + if (mBackgroundHandler != null) { + if (SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { + mBackgroundHandler.getLooper().quitSafely(); + } else { + mBackgroundHandler.getLooper().quit(); + } + mBackgroundHandler = null; + } + if (mBitmap != null && !mBitmap.isRecycled()) { + mCapturedImageView.setImageDrawable(null); + mBitmap.recycle(); + } + releaseSound(); + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, + @NonNull int[] grantResults) { + switch (requestCode) { + case REQUEST_CAMERA_PERMISSION: + if (permissions.length != 1 || grantResults.length != 1) { + throw new RuntimeException("Error on requesting camera permission."); + } + if (grantResults[0] != PackageManager.PERMISSION_GRANTED) { + Toast.makeText(this, R.string.camera_permission_not_granted, + Toast.LENGTH_SHORT).show(); + } + // No need to start camera here; it is handled by onResume + break; + } + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.simple_camera_menu, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + + //cannot use resource ID in switch statements in android library projects + if (item.getItemId() == R.id.aspect_ratio) { + if (mCameraView != null) { + final Set ratios = mCameraView.getSupportedAspectRatios(); + final AspectRatio currentRatio = mCameraView.getAspectRatio(); + AspectRatioFragment.newInstance(ratios, currentRatio) + .show(getSupportFragmentManager(), FRAGMENT_DIALOG); + } + } else if (item.getItemId() == R.id.switch_flash) { + if (mCameraView != null) { + mCurrentFlash = (mCurrentFlash + 1) % FLASH_OPTIONS.length; + item.setTitle(FLASH_TITLES[mCurrentFlash]); + item.setIcon(FLASH_ICONS[mCurrentFlash]); + mCameraView.setFlash(FLASH_OPTIONS[mCurrentFlash]); + } + } else if (item.getItemId() == R.id.switch_camera) { + if (mCameraView != null) { + int facing = mCameraView.getFacing(); + mCameraView.setFacing(facing == CameraView.FACING_FRONT ? + CameraView.FACING_BACK : CameraView.FACING_FRONT); + } + } + return false; + } + + @Override + public void onAspectRatioSelected(@NonNull AspectRatio ratio) { + if (mCameraView != null) { + Toast.makeText(this, ratio.toString(), Toast.LENGTH_SHORT).show(); + mCameraView.setAspectRatio(ratio); + } + } + + private Handler getBackgroundHandler() { + if (mBackgroundHandler == null) { + HandlerThread thread = new HandlerThread("background"); + thread.start(); + mBackgroundHandler = new Handler(thread.getLooper()); + } + return mBackgroundHandler; + } + + private CameraView.Callback mCallback + = new CameraView.Callback() { + + @Override + public void onCameraOpened(CameraView cameraView) { + Log.d(TAG, "onCameraOpened"); + } + + @Override + public void onCameraClosed(CameraView cameraView) { + Log.d(TAG, "onCameraClosed"); + } + + @Override + public void onPictureTaken(CameraView cameraView, final byte[] data) { + Log.d(TAG, "onPictureTaken " + data.length); + //Toast.makeText(cameraView.getContext(), R.string.picture_taken, Toast.LENGTH_SHORT) + // .show(); + getBackgroundHandler().post(new Runnable() { + @Override + public void run() { + File file = new File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), + "picture.jpg"); + OutputStream os = null; + try { + os = new FileOutputStream(file); + os.write(data); + os.close(); + mBitmap = BitmapFactory.decodeFile(file.getAbsolutePath()); + if (Utils.bitmapNeedsRotating(SimpleCameraActivity.this,mBitmap)) { + mBitmap = Utils.fixBitmapOrientation(mBitmap, file); + } + mCountDownLatch.await(); + mCountDownLatch = new CountDownLatch(1); + runOnUiThread(new Runnable() { + @Override + public void run() { + revealCapturedImage(mBitmap); + } + }); + } catch (IOException e) { + Log.w(TAG, "Cannot write to " + file, e); + Toast.makeText(SimpleCameraActivity.this, "Failed. Try again",Toast.LENGTH_SHORT).show(); + } catch (InterruptedException e) { + Log.w(TAG, "Interrupted while writing image to disk", e); + } finally { + if (os != null) { + try { + os.close(); + } catch (IOException e) { + // Ignore + } + } + } + } + }); + } + + }; + + public static class ConfirmationDialogFragment extends DialogFragment { + + private static final String ARG_MESSAGE = "message"; + private static final String ARG_PERMISSIONS = "permissions"; + private static final String ARG_REQUEST_CODE = "request_code"; + private static final String ARG_NOT_GRANTED_MESSAGE = "not_granted_message"; + + public static ConfirmationDialogFragment newInstance(@StringRes int message, + String[] permissions, int requestCode, @StringRes int notGrantedMessage) { + ConfirmationDialogFragment fragment = new ConfirmationDialogFragment(); + Bundle args = new Bundle(); + args.putInt(ARG_MESSAGE, message); + args.putStringArray(ARG_PERMISSIONS, permissions); + args.putInt(ARG_REQUEST_CODE, requestCode); + args.putInt(ARG_NOT_GRANTED_MESSAGE, notGrantedMessage); + fragment.setArguments(args); + return fragment; + } + + @NonNull + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + final Bundle args = getArguments(); + return new AlertDialog.Builder(getActivity()) + .setMessage(args.getInt(ARG_MESSAGE)) + .setPositiveButton(android.R.string.ok, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + String[] permissions = args.getStringArray(ARG_PERMISSIONS); + if (permissions == null) { + throw new IllegalArgumentException(); + } + ActivityCompat.requestPermissions(getActivity(), + permissions, args.getInt(ARG_REQUEST_CODE)); + } + }) + .setNegativeButton(android.R.string.cancel, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + Toast.makeText(getActivity(), + args.getInt(ARG_NOT_GRANTED_MESSAGE), + Toast.LENGTH_SHORT).show(); + } + }) + .create(); + } + + } + + + private void setCameraButtonImage(final int imageRes) { + mTakePicButton.setImageResource(imageRes); + mTakePicButton.setEnabled(true); + Utils.expandFromCenter(mTakePicButton); + } + + @TargetApi(21) + private void revealCapturedImage(Bitmap bitmap) { + + Log.d("MainActivity", "revealCapturedImage"); + + setCameraButtonImage(R.drawable.ic_check_white_24dp); + if (SDK_INT < 21 || !DO_ANIM) { + mCapturedImageView.setVisibility(View.VISIBLE); + mCapturedImageView.setImageBitmap(bitmap); + return; + } + // previously invisible view + + int cx = mCapturedImageView.getMeasuredWidth() / 2; + int cy = mCapturedImageView.getMeasuredHeight() / 2; + + // get the final radius for the clipping circle + int finalRadius = Math.max(mCapturedImageView.getWidth(), mCapturedImageView.getHeight()) / 2; + + // create the animator for this view (the start radius is zero) + Animator anim = + ViewAnimationUtils.createCircularReveal(mCapturedImageView, cx, cy, 0, finalRadius); + + // make the view visible and start the animation + anim.start(); + mCapturedImageView.setVisibility(View.VISIBLE); + mCapturedImageView.setImageBitmap(bitmap); + } + + + + @TargetApi(21) + private void takePhoto() { + + playSound(); + mTakePicButton.setEnabled(false); + Utils.shrinkToCenter(mTakePicButton); + lockScreenOrientation(); + mCameraView.takePicture(); + + if (SDK_INT < 21 || !DO_ANIM) { + mCameraView.setVisibility(View.INVISIBLE); + mCountDownLatch.countDown(); + return; + } + + // previously visible view + + // get the center for the clipping circle + int cx = mCameraView.getMeasuredWidth() / 2; + int cy = mCameraView.getMeasuredHeight() / 2; + + // get the initial radius for the clipping circle + int initialRadius = mCameraView.getWidth() / 2; + + // create the animation (the final radius is zero) + Animator anim = + ViewAnimationUtils.createCircularReveal(mCameraView, cx, cy, initialRadius, 0); + + // make the view invisible when the animation is done + anim.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + mCameraView.setVisibility(View.INVISIBLE); + mCountDownLatch.countDown(); + } + }); + + // start the animation + anim.start(); + } + + private void lockScreenOrientation() { + if (getResources().getConfiguration().orientation == Configuration + .ORIENTATION_LANDSCAPE) { + setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); //lock orientation + } else { + setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); + } + } + +} \ No newline at end of file diff --git a/library/src/main/java/com/premise.android.camera/Utils.java b/library/src/main/java/com/premise.android.camera/Utils.java new file mode 100644 index 00000000..73c2f6a4 --- /dev/null +++ b/library/src/main/java/com/premise.android.camera/Utils.java @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.premise.android.camera; + +import static android.os.Build.VERSION.SDK_INT; + +import android.animation.Animator; +import android.annotation.TargetApi; +import android.content.Context; +import android.content.res.Configuration; +import android.graphics.Bitmap; +import android.graphics.Matrix; +import android.view.View; +import android.view.ViewAnimationUtils; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +/** + * Created by kevinkawai on 3/22/17. + */ + +class Utils { + + /** + * Expand the given invisible view from the center of itself until + * it is fully revealed. The view will be set to View.VISIBLE. + * If the platform is less than SDK_INT 21, then just set the + * view visibility to View.VISIBLE without the animation. + * + * @param view + */ + @TargetApi(21) + static void expandFromCenter(View view) { + + if (SDK_INT < 21) { + view.setVisibility(View.VISIBLE); + return; + } + + int cx = view.getMeasuredWidth() / 2; + int cy = view.getMeasuredHeight() / 2; + + // get the final radius for the clipping circle + int finalRadius = Math.max(view.getWidth(), view.getHeight()) / 2; + + // create the animator for this view (the start radius is zero) + Animator anim = + ViewAnimationUtils.createCircularReveal(view, cx, cy, 0, finalRadius); + + // make the view visible and start the animation + view.setVisibility(View.VISIBLE); + anim.start(); + } + + /** + * Shrink the given visible view to the center of itself until + * it is no longer visible. The view will be set to View.INVISIBLE. + * If the platform is less than SDK_INT 21, then just set the + * view visibility to View.INVISIBLE without the animation. + * + * @param view + */ + @TargetApi(21) + static void shrinkToCenter(final View view) { + + if (SDK_INT < 21) { + view.setVisibility(View.INVISIBLE); + return; + } + + // get the center for the clipping circle + int cx = view.getMeasuredWidth() / 2; + int cy = view.getMeasuredHeight() / 2; + + // get the initial radius for the clipping circle + int initialRadius = view.getWidth() / 2; + + // create the animation (the final radius is zero) + Animator anim = + ViewAnimationUtils.createCircularReveal(view, cx, cy, initialRadius, 0); + + + // start the animation + view.setVisibility(View.INVISIBLE); + anim.start(); + + } + + /** + * A fix for Samsung phones that have a hardware bug where all photos taken while + * the device is in portrait orientation are saved in landscape mode to disk. + * + * @param bitmap + * @param target + * @return + * @throws IOException + */ + static Bitmap fixBitmapOrientation(Bitmap bitmap, File target) throws IOException { + Matrix matrix = new Matrix(); + matrix.postRotate(90); + Bitmap rotatedBitmap = Bitmap.createBitmap(bitmap , 0, 0, + bitmap.getWidth(), bitmap.getHeight(), matrix, true); + bitmap.recycle(); + writeBitmapToFile(rotatedBitmap, target); + return rotatedBitmap; + } + + static boolean bitmapNeedsRotating(Context context, Bitmap bitmap) throws IOException { + if (context.getResources().getConfiguration().orientation == Configuration + .ORIENTATION_PORTRAIT) { + return bitmap.getWidth() > bitmap.getHeight(); + } + return false; + } + + static void writeBitmapToFile(final Bitmap inBitmap, final File file) throws + IOException { + + if (!file.exists()) { + file.getParentFile().mkdirs(); + } + final FileOutputStream fos = new FileOutputStream(file); + inBitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos); + fos.close(); + } + +} diff --git a/library/src/main/res/drawable-xxxhdpi/ic_check_white_24dp.png b/library/src/main/res/drawable-xxxhdpi/ic_check_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..d670618c7e96225f7756cb4c2743e7ebbf688cf8 GIT binary patch literal 308 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD0wg^q?%xcgetWt&hE&{od;P3vlYxj!B3Hnh z1714EonD+``t$ZU)3IJ|2aboi6~%ilJM7!-={Kv*@R&q$518Ox)_m^XpXp1^&DOu% zB6r^~@kqJ%j0e`LXFkL-JviL|Ir_(khlktwLa#r83bn@|VwIw^gKjzH(>hUq>tlAsh9~)aj{(R+p z`Qx=v&?j!r?}<)Pb+Jxa|B9Td>MRd7#ru4CATBh=u6rtH + + + + diff --git a/library/src/main/res/drawable/ic_camera.xml b/library/src/main/res/drawable/ic_camera.xml new file mode 100644 index 00000000..14584648 --- /dev/null +++ b/library/src/main/res/drawable/ic_camera.xml @@ -0,0 +1,25 @@ + + + + + + diff --git a/library/src/main/res/drawable/ic_flash_auto.xml b/library/src/main/res/drawable/ic_flash_auto.xml new file mode 100644 index 00000000..b4164042 --- /dev/null +++ b/library/src/main/res/drawable/ic_flash_auto.xml @@ -0,0 +1,22 @@ + + + + + diff --git a/library/src/main/res/drawable/ic_flash_off.xml b/library/src/main/res/drawable/ic_flash_off.xml new file mode 100644 index 00000000..cae6f0ca --- /dev/null +++ b/library/src/main/res/drawable/ic_flash_off.xml @@ -0,0 +1,22 @@ + + + + + diff --git a/library/src/main/res/drawable/ic_flash_on.xml b/library/src/main/res/drawable/ic_flash_on.xml new file mode 100644 index 00000000..3aad5f47 --- /dev/null +++ b/library/src/main/res/drawable/ic_flash_on.xml @@ -0,0 +1,22 @@ + + + + + diff --git a/library/src/main/res/drawable/ic_switch_camera.xml b/library/src/main/res/drawable/ic_switch_camera.xml new file mode 100644 index 00000000..bade6e71 --- /dev/null +++ b/library/src/main/res/drawable/ic_switch_camera.xml @@ -0,0 +1,22 @@ + + + + + diff --git a/library/src/main/res/layout-land/simple_camera_layout.xml b/library/src/main/res/layout-land/simple_camera_layout.xml new file mode 100644 index 00000000..9b598c4c --- /dev/null +++ b/library/src/main/res/layout-land/simple_camera_layout.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + diff --git a/library/src/main/res/layout/include_simple_camera.xml b/library/src/main/res/layout/include_simple_camera.xml new file mode 100644 index 00000000..42232eba --- /dev/null +++ b/library/src/main/res/layout/include_simple_camera.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + diff --git a/library/src/main/res/layout/simple_camera_layout.xml b/library/src/main/res/layout/simple_camera_layout.xml new file mode 100644 index 00000000..3f060ed2 --- /dev/null +++ b/library/src/main/res/layout/simple_camera_layout.xml @@ -0,0 +1,37 @@ + + + + + + + + + diff --git a/library/src/main/res/menu/simple_camera_menu.xml b/library/src/main/res/menu/simple_camera_menu.xml new file mode 100644 index 00000000..8f013d12 --- /dev/null +++ b/library/src/main/res/menu/simple_camera_menu.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + diff --git a/library/src/main/res/values-w820dp/dimens.xml b/library/src/main/res/values-w820dp/dimens.xml new file mode 100644 index 00000000..648f774e --- /dev/null +++ b/library/src/main/res/values-w820dp/dimens.xml @@ -0,0 +1,16 @@ + + + + 64dp + diff --git a/library/src/main/res/values/colors.xml b/library/src/main/res/values/colors.xml new file mode 100644 index 00000000..9bbf0348 --- /dev/null +++ b/library/src/main/res/values/colors.xml @@ -0,0 +1,20 @@ + + + + #3F51B5 + #303F9F + #4CAF50 + #212121 + #727272 + diff --git a/library/src/main/res/values/dimens.xml b/library/src/main/res/values/dimens.xml new file mode 100644 index 00000000..d65da19e --- /dev/null +++ b/library/src/main/res/values/dimens.xml @@ -0,0 +1,17 @@ + + + + 16dp + 16dp + diff --git a/library/src/main/res/values/strings.xml b/library/src/main/res/values/strings.xml new file mode 100644 index 00000000..b6da5997 --- /dev/null +++ b/library/src/main/res/values/strings.xml @@ -0,0 +1,27 @@ + + + + This app demonstrates the usage of CameraView. In order to do that, it needs permission to access camera. + Camera app cannot do anything without camera permission. + Picture taken + Aspect ratio + Switch flash + Switch camera + Flash auto + Flash off + Flash on + diff --git a/library/src/main/res/values/styles.xml b/library/src/main/res/values/styles.xml index 6ded7168..fd5bf230 100644 --- a/library/src/main/res/values/styles.xml +++ b/library/src/main/res/values/styles.xml @@ -13,6 +13,24 @@ --> + + + + + + + From efb88f312a00ddc1159a2a94d817c72c37e7b6ea Mon Sep 17 00:00:00 2001 From: kevinkawai Date: Mon, 27 Mar 2017 15:32:35 -0700 Subject: [PATCH 15/42] touch ups --- .../res/drawable/dark_transparent_circle.xml | 28 ------------------- .../main/res/drawable/semi_transparent_fg.xml | 7 ----- 2 files changed, 35 deletions(-) delete mode 100644 library/src/main/res/drawable/dark_transparent_circle.xml delete mode 100644 library/src/main/res/drawable/semi_transparent_fg.xml diff --git a/library/src/main/res/drawable/dark_transparent_circle.xml b/library/src/main/res/drawable/dark_transparent_circle.xml deleted file mode 100644 index af0312ea..00000000 --- a/library/src/main/res/drawable/dark_transparent_circle.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/library/src/main/res/drawable/semi_transparent_fg.xml b/library/src/main/res/drawable/semi_transparent_fg.xml deleted file mode 100644 index 39d73375..00000000 --- a/library/src/main/res/drawable/semi_transparent_fg.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file From 4cc984a83c5a65ff91d07bdfd8b134ec086c5632 Mon Sep 17 00:00:00 2001 From: kevinkawai Date: Mon, 27 Mar 2017 18:01:15 -0700 Subject: [PATCH 16/42] touch ups --- .../android/cameraview}/AspectRatioFragment.java | 4 +--- .../java/com/premise.android.camera/SimpleCameraActivity.java | 1 + 2 files changed, 2 insertions(+), 3 deletions(-) rename library/src/main/java/com/{premise.android.camera => google/android/cameraview}/AspectRatioFragment.java (98%) diff --git a/library/src/main/java/com/premise.android.camera/AspectRatioFragment.java b/library/src/main/java/com/google/android/cameraview/AspectRatioFragment.java similarity index 98% rename from library/src/main/java/com/premise.android.camera/AspectRatioFragment.java rename to library/src/main/java/com/google/android/cameraview/AspectRatioFragment.java index 15d409b7..2b50206c 100644 --- a/library/src/main/java/com/premise.android.camera/AspectRatioFragment.java +++ b/library/src/main/java/com/google/android/cameraview/AspectRatioFragment.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.premise.android.camera; +package com.google.android.cameraview; import android.app.Dialog; import android.content.Context; @@ -29,8 +29,6 @@ import android.widget.BaseAdapter; import android.widget.TextView; -import com.google.android.cameraview.AspectRatio; - import java.util.Set; diff --git a/library/src/main/java/com/premise.android.camera/SimpleCameraActivity.java b/library/src/main/java/com/premise.android.camera/SimpleCameraActivity.java index bffb0455..c4b90557 100644 --- a/library/src/main/java/com/premise.android.camera/SimpleCameraActivity.java +++ b/library/src/main/java/com/premise.android.camera/SimpleCameraActivity.java @@ -53,6 +53,7 @@ import android.widget.Toast; import com.google.android.cameraview.AspectRatio; +import com.google.android.cameraview.AspectRatioFragment; import com.google.android.cameraview.CameraView; import com.google.android.cameraview.R; From 885a6f8f3b7c016a829cf02c1ae07a98076cf83c Mon Sep 17 00:00:00 2001 From: kevinkawai Date: Wed, 29 Mar 2017 23:57:21 -0700 Subject: [PATCH 17/42] purified back --- .../cameraview/demo/MainActivity2.java | 8 - .../transparent_circle_selector.xml | 0 .../drawable-xxxhdpi/ic_check_white_24dp.png | Bin .../ic_keyboard_backspace_white_24dp.png | Bin .../res/drawable/transparent_circle_25.xml | 0 .../res/drawable/transparent_circle_75.xml | 0 .../drawable/transparent_circle_selector.xml | 0 .../main/res/layout/include_simple_camera.xml | 0 .../main/res/layout/simple_camera_layout.xml | 0 .../src/main/res/menu/simple_camera_menu.xml | 2 +- demo/src/main/res/values/colors.xml | 4 + demo/src/main/res/values/dimens.xml | 1 + demo/src/main/res/values/styles.xml | 23 + library/build.gradle | 2 +- .../cameraview/AspectRatioFragment.java | 144 ----- .../SimpleCameraActivity.java | 532 ------------------ .../com/premise.android.camera/Utils.java | 143 ----- .../src/main/res/drawable/ic_aspect_ratio.xml | 25 - library/src/main/res/drawable/ic_camera.xml | 25 - .../src/main/res/drawable/ic_flash_auto.xml | 22 - .../src/main/res/drawable/ic_flash_off.xml | 22 - library/src/main/res/drawable/ic_flash_on.xml | 22 - .../main/res/drawable/ic_switch_camera.xml | 22 - .../res/layout-land/simple_camera_layout.xml | 34 -- library/src/main/res/values-w820dp/dimens.xml | 16 - library/src/main/res/values/colors.xml | 23 - library/src/main/res/values/dimens.xml | 18 - library/src/main/res/values/public.xml | 1 + library/src/main/res/values/strings.xml | 28 - library/src/main/res/values/styles.xml | 49 +- 30 files changed, 45 insertions(+), 1121 deletions(-) rename {library => demo}/src/main/res/drawable-v21/transparent_circle_selector.xml (100%) rename {library => demo}/src/main/res/drawable-xxxhdpi/ic_check_white_24dp.png (100%) rename {library => demo}/src/main/res/drawable-xxxhdpi/ic_keyboard_backspace_white_24dp.png (100%) rename {library => demo}/src/main/res/drawable/transparent_circle_25.xml (100%) rename {library => demo}/src/main/res/drawable/transparent_circle_75.xml (100%) rename {library => demo}/src/main/res/drawable/transparent_circle_selector.xml (100%) rename {library => demo}/src/main/res/layout/include_simple_camera.xml (100%) rename {library => demo}/src/main/res/layout/simple_camera_layout.xml (100%) rename {library => demo}/src/main/res/menu/simple_camera_menu.xml (97%) delete mode 100644 library/src/main/java/com/google/android/cameraview/AspectRatioFragment.java delete mode 100644 library/src/main/java/com/premise.android.camera/SimpleCameraActivity.java delete mode 100644 library/src/main/java/com/premise.android.camera/Utils.java delete mode 100644 library/src/main/res/drawable/ic_aspect_ratio.xml delete mode 100644 library/src/main/res/drawable/ic_camera.xml delete mode 100644 library/src/main/res/drawable/ic_flash_auto.xml delete mode 100644 library/src/main/res/drawable/ic_flash_off.xml delete mode 100644 library/src/main/res/drawable/ic_flash_on.xml delete mode 100644 library/src/main/res/drawable/ic_switch_camera.xml delete mode 100644 library/src/main/res/layout-land/simple_camera_layout.xml delete mode 100644 library/src/main/res/values-w820dp/dimens.xml delete mode 100644 library/src/main/res/values/colors.xml delete mode 100644 library/src/main/res/values/dimens.xml delete mode 100644 library/src/main/res/values/strings.xml diff --git a/demo/src/main/java/com/google/android/cameraview/demo/MainActivity2.java b/demo/src/main/java/com/google/android/cameraview/demo/MainActivity2.java index 67ce52d9..692c5a3b 100644 --- a/demo/src/main/java/com/google/android/cameraview/demo/MainActivity2.java +++ b/demo/src/main/java/com/google/android/cameraview/demo/MainActivity2.java @@ -16,13 +16,10 @@ package com.google.android.cameraview.demo; -import android.content.Intent; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v7.app.AppCompatActivity; -import com.premise.android.camera.SimpleCameraActivity; - public class MainActivity2 extends AppCompatActivity { @@ -30,10 +27,5 @@ public class MainActivity2 extends AppCompatActivity { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); - Intent intent = new Intent(this, SimpleCameraActivity.class); - String imagePath = getFilesDir().getPath() + "/picture.jpg"; - intent.putExtra(SimpleCameraActivity.KEY_OUTPUT_PATH,imagePath); - startActivityForResult(intent, REQ_CODE); - finish(); } } diff --git a/library/src/main/res/drawable-v21/transparent_circle_selector.xml b/demo/src/main/res/drawable-v21/transparent_circle_selector.xml similarity index 100% rename from library/src/main/res/drawable-v21/transparent_circle_selector.xml rename to demo/src/main/res/drawable-v21/transparent_circle_selector.xml diff --git a/library/src/main/res/drawable-xxxhdpi/ic_check_white_24dp.png b/demo/src/main/res/drawable-xxxhdpi/ic_check_white_24dp.png similarity index 100% rename from library/src/main/res/drawable-xxxhdpi/ic_check_white_24dp.png rename to demo/src/main/res/drawable-xxxhdpi/ic_check_white_24dp.png diff --git a/library/src/main/res/drawable-xxxhdpi/ic_keyboard_backspace_white_24dp.png b/demo/src/main/res/drawable-xxxhdpi/ic_keyboard_backspace_white_24dp.png similarity index 100% rename from library/src/main/res/drawable-xxxhdpi/ic_keyboard_backspace_white_24dp.png rename to demo/src/main/res/drawable-xxxhdpi/ic_keyboard_backspace_white_24dp.png diff --git a/library/src/main/res/drawable/transparent_circle_25.xml b/demo/src/main/res/drawable/transparent_circle_25.xml similarity index 100% rename from library/src/main/res/drawable/transparent_circle_25.xml rename to demo/src/main/res/drawable/transparent_circle_25.xml diff --git a/library/src/main/res/drawable/transparent_circle_75.xml b/demo/src/main/res/drawable/transparent_circle_75.xml similarity index 100% rename from library/src/main/res/drawable/transparent_circle_75.xml rename to demo/src/main/res/drawable/transparent_circle_75.xml diff --git a/library/src/main/res/drawable/transparent_circle_selector.xml b/demo/src/main/res/drawable/transparent_circle_selector.xml similarity index 100% rename from library/src/main/res/drawable/transparent_circle_selector.xml rename to demo/src/main/res/drawable/transparent_circle_selector.xml diff --git a/library/src/main/res/layout/include_simple_camera.xml b/demo/src/main/res/layout/include_simple_camera.xml similarity index 100% rename from library/src/main/res/layout/include_simple_camera.xml rename to demo/src/main/res/layout/include_simple_camera.xml diff --git a/library/src/main/res/layout/simple_camera_layout.xml b/demo/src/main/res/layout/simple_camera_layout.xml similarity index 100% rename from library/src/main/res/layout/simple_camera_layout.xml rename to demo/src/main/res/layout/simple_camera_layout.xml diff --git a/library/src/main/res/menu/simple_camera_menu.xml b/demo/src/main/res/menu/simple_camera_menu.xml similarity index 97% rename from library/src/main/res/menu/simple_camera_menu.xml rename to demo/src/main/res/menu/simple_camera_menu.xml index 8f013d12..3ec120bb 100644 --- a/library/src/main/res/menu/simple_camera_menu.xml +++ b/demo/src/main/res/menu/simple_camera_menu.xml @@ -33,6 +33,6 @@ android:icon="@drawable/ic_switch_camera" android:title="@string/switch_camera" app:showAsAction="ifRoom" - android:visible="false"/> + android:visible="true"/> diff --git a/demo/src/main/res/values/colors.xml b/demo/src/main/res/values/colors.xml index 9bbf0348..666e33a7 100644 --- a/demo/src/main/res/values/colors.xml +++ b/demo/src/main/res/values/colors.xml @@ -17,4 +17,8 @@ #4CAF50 #212121 #727272 + + #40000000 + #BF000000 + diff --git a/demo/src/main/res/values/dimens.xml b/demo/src/main/res/values/dimens.xml index d65da19e..0e5f08d6 100644 --- a/demo/src/main/res/values/dimens.xml +++ b/demo/src/main/res/values/dimens.xml @@ -14,4 +14,5 @@ 16dp 16dp + 48dp diff --git a/demo/src/main/res/values/styles.xml b/demo/src/main/res/values/styles.xml index 3bc78ff2..61806d15 100644 --- a/demo/src/main/res/values/styles.xml +++ b/demo/src/main/res/values/styles.xml @@ -23,4 +23,27 @@ @color/secondaryText + + + + + + diff --git a/library/build.gradle b/library/build.gradle index 06d3b727..d804ec31 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -62,7 +62,7 @@ publishing { publications { aar(MavenPublication) { groupId 'premise.android.cameraview' - version '0.1.5' + version '0.2.0' artifactId 'cameraview' artifact("$buildDir/outputs/aar/${project.getName()}-release.aar") diff --git a/library/src/main/java/com/google/android/cameraview/AspectRatioFragment.java b/library/src/main/java/com/google/android/cameraview/AspectRatioFragment.java deleted file mode 100644 index 2b50206c..00000000 --- a/library/src/main/java/com/google/android/cameraview/AspectRatioFragment.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.cameraview; - -import android.app.Dialog; -import android.content.Context; -import android.content.DialogInterface; -import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v4.app.DialogFragment; -import android.support.v7.app.AlertDialog; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.BaseAdapter; -import android.widget.TextView; - -import java.util.Set; - - -/** - * A simple dialog that allows user to pick an aspect ratio. - */ -public class AspectRatioFragment extends DialogFragment { - - private static final String ARG_ASPECT_RATIOS = "aspect_ratios"; - private static final String ARG_CURRENT_ASPECT_RATIO = "current_aspect_ratio"; - - private Listener mListener; - - public static AspectRatioFragment newInstance(Set ratios, - AspectRatio currentRatio) { - final AspectRatioFragment fragment = new AspectRatioFragment(); - final Bundle args = new Bundle(); - args.putParcelableArray(ARG_ASPECT_RATIOS, - ratios.toArray(new AspectRatio[ratios.size()])); - args.putParcelable(ARG_CURRENT_ASPECT_RATIO, currentRatio); - fragment.setArguments(args); - return fragment; - } - - @Override - public void onAttach(Context context) { - super.onAttach(context); - mListener = (Listener) context; - } - - @Override - public void onDetach() { - mListener = null; - super.onDetach(); - } - - @NonNull - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - final Bundle args = getArguments(); - final AspectRatio[] ratios = (AspectRatio[]) args.getParcelableArray(ARG_ASPECT_RATIOS); - if (ratios == null) { - throw new RuntimeException("No ratios"); - } - final AspectRatio current = args.getParcelable(ARG_CURRENT_ASPECT_RATIO); - final AspectRatioAdapter adapter = new AspectRatioAdapter(ratios, current); - return new AlertDialog.Builder(getActivity()) - .setAdapter(adapter, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int position) { - mListener.onAspectRatioSelected(ratios[position]); - } - }) - .create(); - } - - private static class AspectRatioAdapter extends BaseAdapter { - - private final AspectRatio[] mRatios; - private final AspectRatio mCurrentRatio; - - AspectRatioAdapter(AspectRatio[] ratios, AspectRatio current) { - mRatios = ratios; - mCurrentRatio = current; - } - - @Override - public int getCount() { - return mRatios.length; - } - - @Override - public AspectRatio getItem(int position) { - return mRatios[position]; - } - - @Override - public long getItemId(int position) { - return getItem(position).hashCode(); - } - - @Override - public View getView(int position, View view, ViewGroup parent) { - AspectRatioAdapter.ViewHolder holder; - if (view == null) { - view = LayoutInflater.from(parent.getContext()) - .inflate(android.R.layout.simple_list_item_1, parent, false); - holder = new AspectRatioAdapter.ViewHolder(); - holder.text = (TextView) view.findViewById(android.R.id.text1); - view.setTag(holder); - } else { - holder = (AspectRatioAdapter.ViewHolder) view.getTag(); - } - AspectRatio ratio = getItem(position); - StringBuilder sb = new StringBuilder(ratio.toString()); - if (ratio.equals(mCurrentRatio)) { - sb.append(" *"); - } - holder.text.setText(sb); - return view; - } - - private static class ViewHolder { - TextView text; - } - - } - - public interface Listener { - void onAspectRatioSelected(@NonNull AspectRatio ratio); - } - -} diff --git a/library/src/main/java/com/premise.android.camera/SimpleCameraActivity.java b/library/src/main/java/com/premise.android.camera/SimpleCameraActivity.java deleted file mode 100644 index c4b90557..00000000 --- a/library/src/main/java/com/premise.android.camera/SimpleCameraActivity.java +++ /dev/null @@ -1,532 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.premise.android.camera; - -import static android.os.Build.VERSION.SDK_INT; - -import android.Manifest; -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.annotation.TargetApi; -import android.app.Dialog; -import android.content.DialogInterface; -import android.content.pm.ActivityInfo; -import android.content.pm.PackageManager; -import android.content.res.Configuration; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.media.MediaActionSound; -import android.os.Build; -import android.os.Bundle; -import android.os.Handler; -import android.os.HandlerThread; -import android.support.annotation.NonNull; -import android.support.annotation.StringRes; -import android.support.design.widget.FloatingActionButton; -import android.support.v4.app.ActivityCompat; -import android.support.v4.app.DialogFragment; -import android.support.v4.content.ContextCompat; -import android.support.v7.app.ActionBar; -import android.support.v7.app.AlertDialog; -import android.support.v7.app.AppCompatActivity; -import android.support.v7.widget.Toolbar; -import android.util.Log; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewAnimationUtils; -import android.widget.ImageView; -import android.widget.Toast; - -import com.google.android.cameraview.AspectRatio; -import com.google.android.cameraview.AspectRatioFragment; -import com.google.android.cameraview.CameraView; -import com.google.android.cameraview.R; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.util.Set; -import java.util.concurrent.CountDownLatch; - - -/** - * This demo app saves the taken picture to a constant file. - * $ adb pull /sdcard/Android/data/com.google.android.cameraview.demo/files/Pictures/picture.jpg - */ -public class SimpleCameraActivity extends AppCompatActivity implements - ActivityCompat.OnRequestPermissionsResultCallback, - AspectRatioFragment.Listener { - - private static final String TAG = "SimpleCameraActivity"; - - public static final String KEY_OUTPUT_PATH = "key_output_path"; - - private static final boolean DO_ANIM = true; - - private static final int REQUEST_CAMERA_PERMISSION = 1; - - private static final String FRAGMENT_DIALOG = "dialog"; - - private static final int[] FLASH_OPTIONS = { - CameraView.FLASH_OFF, - CameraView.FLASH_AUTO, - CameraView.FLASH_ON, - }; - - private static final int[] FLASH_ICONS = { - R.drawable.ic_flash_off, - R.drawable.ic_flash_auto, - R.drawable.ic_flash_on, - }; - - private static final int[] FLASH_TITLES = { - R.string.flash_off, - R.string.flash_auto, - R.string.flash_on, - }; - - private int mCurrentFlash; - - private CameraView mCameraView; - - private ImageView mCapturedImageView; - - private Handler mBackgroundHandler; - - private FloatingActionButton mTakePicButton; - - private CountDownLatch mCountDownLatch = new CountDownLatch(1); - - private MediaActionSound mSound; - - private Bitmap mBitmap; - - private String mOutputPath; - - private boolean mIsDestroyed; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.simple_camera_layout); - mCameraView = (CameraView) findViewById(R.id.camera); - if (mCameraView != null) { - mCameraView.addCallback(mCallback); - } - mTakePicButton = (FloatingActionButton) findViewById(R.id.take_picture); - mCapturedImageView = (ImageView)findViewById(R.id.captured_camera_image); - - Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); - setSupportActionBar(toolbar); - ActionBar actionBar = getSupportActionBar(); - if (actionBar != null) { - actionBar.setDisplayShowTitleEnabled(false); - } - initSound(); - if (getIntent() != null && getIntent().hasExtra(KEY_OUTPUT_PATH)) { - mOutputPath = getIntent().getStringExtra(KEY_OUTPUT_PATH); - } else { - throw new IllegalArgumentException("SimpleCameraActivity must be passed SimpleCameraActivity.KEY_OUTPUT_PATH"); - } - } - - private void initSound() { - if (SDK_INT >= 16) { - mSound = new MediaActionSound(); - } - } - - private void playSound() { - if (SDK_INT >= 16) { - if (mSound != null) { - mSound.play(MediaActionSound.SHUTTER_CLICK); - } - } - } - - private void releaseSound() { - if (SDK_INT >= 16) { - if (mSound != null) { - mSound.release(); - } - } - } - - @Override - protected void onResume() { - super.onResume(); - if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) - == PackageManager.PERMISSION_GRANTED) { - mCameraView.start(); - } else if (ActivityCompat.shouldShowRequestPermissionRationale(this, - Manifest.permission.CAMERA)) { - ConfirmationDialogFragment - .newInstance(R.string.camera_permission_confirmation, - new String[]{Manifest.permission.CAMERA}, - REQUEST_CAMERA_PERMISSION, - R.string.camera_permission_not_granted) - .show(getSupportFragmentManager(), FRAGMENT_DIALOG); - } else { - ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, - REQUEST_CAMERA_PERMISSION); - } - } - - @Override - protected void onPause() { - mCameraView.stop(); - super.onPause(); - } - - @Override - protected void onDestroy() { - mIsDestroyed = true; - if (mBackgroundHandler != null) { - if (SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { - mBackgroundHandler.getLooper().quitSafely(); - } else { - mBackgroundHandler.getLooper().quit(); - } - mBackgroundHandler = null; - } - if (mBitmap != null && !mBitmap.isRecycled()) { - mCapturedImageView.setImageDrawable(null); - mBitmap.recycle(); - } - releaseSound(); - mCameraView.removeCallback(mCallback); - super.onDestroy(); - } - - @Override - public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, - @NonNull int[] grantResults) { - switch (requestCode) { - case REQUEST_CAMERA_PERMISSION: - if (permissions.length != 1 || grantResults.length != 1) { - throw new RuntimeException("Error on requesting camera permission."); - } - if (grantResults[0] != PackageManager.PERMISSION_GRANTED) { - Toast.makeText(this, R.string.camera_permission_not_granted, - Toast.LENGTH_SHORT).show(); - } - // No need to start camera here; it is handled by onResume - break; - } - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - getMenuInflater().inflate(R.menu.simple_camera_menu, menu); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - - //cannot use resource ID in switch statements in android library projects - if (item.getItemId() == R.id.aspect_ratio) { - if (mCameraView != null) { - final Set ratios = mCameraView.getSupportedAspectRatios(); - final AspectRatio currentRatio = mCameraView.getAspectRatio(); - AspectRatioFragment.newInstance(ratios, currentRatio) - .show(getSupportFragmentManager(), FRAGMENT_DIALOG); - } - } else if (item.getItemId() == R.id.switch_flash) { - if (mCameraView != null) { - mCurrentFlash = (mCurrentFlash + 1) % FLASH_OPTIONS.length; - item.setTitle(FLASH_TITLES[mCurrentFlash]); - item.setIcon(FLASH_ICONS[mCurrentFlash]); - mCameraView.setFlash(FLASH_OPTIONS[mCurrentFlash]); - } - } else if (item.getItemId() == R.id.switch_camera) { - if (mCameraView != null) { - int facing = mCameraView.getFacing(); - mCameraView.setFacing(facing == CameraView.FACING_FRONT ? - CameraView.FACING_BACK : CameraView.FACING_FRONT); - } - } - return false; - } - - @Override - public void onAspectRatioSelected(@NonNull AspectRatio ratio) { - if (mCameraView != null) { - Toast.makeText(this, ratio.toString(), Toast.LENGTH_SHORT).show(); - mCameraView.setAspectRatio(ratio); - } - } - - private Handler getBackgroundHandler() { - if (mBackgroundHandler == null) { - HandlerThread thread = new HandlerThread("background"); - thread.start(); - mBackgroundHandler = new Handler(thread.getLooper()); - } - return mBackgroundHandler; - } - - private CameraView.Callback mCallback - = new CameraView.Callback() { - - @Override - public void onCameraOpened(CameraView cameraView) { - Log.d(TAG, "onCameraOpened"); - } - - @Override - public void onCameraClosed(CameraView cameraView) { - Log.d(TAG, "onCameraClosed"); - } - - @Override - public void onPictureTaken(CameraView cameraView, final byte[] data) { - Log.d(TAG, "onPictureTaken " + data.length); - //Toast.makeText(cameraView.getContext(), R.string.picture_taken, Toast.LENGTH_SHORT) - // .show(); - getBackgroundHandler().post(new Runnable() { - @Override - public void run() { - - if (isActivityDestroyed()) { //check: android image processing takes time - return; - } - OutputStream os = null; - File file = null; - try { - file = new File(mOutputPath); - os = new FileOutputStream(file); - os.write(data); // - os.close(); - if (isActivityDestroyed()) { //check: writing to disk takes time - return; - } - mBitmap = BitmapFactory.decodeFile(file.getAbsolutePath()); - if (Utils.bitmapNeedsRotating(SimpleCameraActivity.this,mBitmap)) { - mBitmap = Utils.fixBitmapOrientation(mBitmap, file); - } - if (isActivityDestroyed()) { //check: bitmap processing takes time - return; - } - mCountDownLatch.await(); - mCountDownLatch = new CountDownLatch(1); - if (isActivityDestroyed()) { //check: animation can take time - return; - } - runOnUiThread(new Runnable() { - @Override - public void run() { - if (isActivityDestroyed()) { //check: animation can take time - return; - } - revealCapturedImage(mBitmap); - } - }); - } catch (IOException e) { - Log.e(TAG, "(a) Cannot write to " + file, e); - showErrorToast(); - } catch (Exception e) { - Log.e(TAG, "(b) Exception occurred while writing image to disk", e); - showErrorToast(); - } finally { - if (os != null) { - try { - os.close(); - } catch (IOException e) { - // Ignore - } - } - } - } - }); - } - - }; - - private void showErrorToast() { - Toast.makeText(SimpleCameraActivity.this, - R.string.camera_failed_to_capture_image, - Toast.LENGTH_SHORT).show(); - } - - public static class ConfirmationDialogFragment extends DialogFragment { - - private static final String ARG_MESSAGE = "message"; - private static final String ARG_PERMISSIONS = "permissions"; - private static final String ARG_REQUEST_CODE = "request_code"; - private static final String ARG_NOT_GRANTED_MESSAGE = "not_granted_message"; - - public static ConfirmationDialogFragment newInstance(@StringRes int message, - String[] permissions, int requestCode, @StringRes int notGrantedMessage) { - ConfirmationDialogFragment fragment = new ConfirmationDialogFragment(); - Bundle args = new Bundle(); - args.putInt(ARG_MESSAGE, message); - args.putStringArray(ARG_PERMISSIONS, permissions); - args.putInt(ARG_REQUEST_CODE, requestCode); - args.putInt(ARG_NOT_GRANTED_MESSAGE, notGrantedMessage); - fragment.setArguments(args); - return fragment; - } - - @NonNull - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - final Bundle args = getArguments(); - return new AlertDialog.Builder(getActivity()) - .setMessage(args.getInt(ARG_MESSAGE)) - .setPositiveButton(android.R.string.ok, - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - String[] permissions = args.getStringArray(ARG_PERMISSIONS); - if (permissions == null) { - throw new IllegalArgumentException(); - } - ActivityCompat.requestPermissions(getActivity(), - permissions, args.getInt(ARG_REQUEST_CODE)); - } - }) - .setNegativeButton(android.R.string.cancel, - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - Toast.makeText(getActivity(), - args.getInt(ARG_NOT_GRANTED_MESSAGE), - Toast.LENGTH_SHORT).show(); - } - }) - .create(); - } - - } - - - private void setCameraButtonImage(final int imageRes) { - mTakePicButton.setImageResource(imageRes); - mTakePicButton.setEnabled(true); - Utils.expandFromCenter(mTakePicButton); - } - - @TargetApi(21) - private void revealCapturedImage(Bitmap bitmap) { - - Log.d(TAG, "revealCapturedImage"); - - setCameraButtonImage(R.drawable.ic_check_white_24dp); - if (SDK_INT < 21 || !DO_ANIM) { - mCapturedImageView.setVisibility(View.VISIBLE); - mCapturedImageView.setImageBitmap(bitmap); - return; - } - - int cx = mCapturedImageView.getMeasuredWidth() / 2; - int cy = mCapturedImageView.getMeasuredHeight() / 2; - - // get the final radius for the clipping circle - int finalRadius = Math.max(mCapturedImageView.getWidth(), mCapturedImageView.getHeight()) / 2; - - // create the animator for this view (the start radius is zero) - Animator anim = - ViewAnimationUtils.createCircularReveal(mCapturedImageView, cx, cy, 0, finalRadius); - - // make the view visible and start the animation - anim.start(); - mCapturedImageView.setVisibility(View.VISIBLE); - mCapturedImageView.setImageBitmap(bitmap); - } - - - - @TargetApi(21) - private void takePhoto() { - - playSound(); - mTakePicButton.setEnabled(false); - Utils.shrinkToCenter(mTakePicButton); - lockScreenOrientation(); - mCameraView.takePicture(); - - if (SDK_INT < 21 || !DO_ANIM) { - mCameraView.setVisibility(View.INVISIBLE); - mCountDownLatch.countDown(); - return; - } - - // get the center for the clipping circle - int cx = mCameraView.getMeasuredWidth() / 2; - int cy = mCameraView.getMeasuredHeight() / 2; - - // get the initial radius for the clipping circle - int initialRadius = mCameraView.getWidth() / 2; - - // create the animation (the final radius is zero) - final Animator anim = - ViewAnimationUtils.createCircularReveal(mCameraView, cx, cy, initialRadius, 0); - - // make the view invisible when the animation is done - anim.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - super.onAnimationEnd(animation); - mCameraView.setVisibility(View.INVISIBLE); - mCountDownLatch.countDown(); - anim.removeAllListeners(); - } - }); - - // start the animation - anim.start(); - } - - private void lockScreenOrientation() { - if (getResources().getConfiguration().orientation == Configuration - .ORIENTATION_LANDSCAPE) { - setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); //lock orientation - } else { - setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); - } - } - - /** - * Embedded in this layout, just finish activity - * @param view - */ - public void onBackClicked(View view) { - finish(); - } - - public void onCameraButtonClicked(View view) { - if (view.getId() == R.id.take_picture) { - if (mBitmap != null) { - setResult(RESULT_OK); - finish(); - } else { - takePhoto(); - } - } - } - - private boolean isActivityDestroyed() { - if (SDK_INT >= 17) { - return isDestroyed(); - } - return isFinishing() || mIsDestroyed; - } - -} \ No newline at end of file diff --git a/library/src/main/java/com/premise.android.camera/Utils.java b/library/src/main/java/com/premise.android.camera/Utils.java deleted file mode 100644 index 73c2f6a4..00000000 --- a/library/src/main/java/com/premise.android.camera/Utils.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.premise.android.camera; - -import static android.os.Build.VERSION.SDK_INT; - -import android.animation.Animator; -import android.annotation.TargetApi; -import android.content.Context; -import android.content.res.Configuration; -import android.graphics.Bitmap; -import android.graphics.Matrix; -import android.view.View; -import android.view.ViewAnimationUtils; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; - -/** - * Created by kevinkawai on 3/22/17. - */ - -class Utils { - - /** - * Expand the given invisible view from the center of itself until - * it is fully revealed. The view will be set to View.VISIBLE. - * If the platform is less than SDK_INT 21, then just set the - * view visibility to View.VISIBLE without the animation. - * - * @param view - */ - @TargetApi(21) - static void expandFromCenter(View view) { - - if (SDK_INT < 21) { - view.setVisibility(View.VISIBLE); - return; - } - - int cx = view.getMeasuredWidth() / 2; - int cy = view.getMeasuredHeight() / 2; - - // get the final radius for the clipping circle - int finalRadius = Math.max(view.getWidth(), view.getHeight()) / 2; - - // create the animator for this view (the start radius is zero) - Animator anim = - ViewAnimationUtils.createCircularReveal(view, cx, cy, 0, finalRadius); - - // make the view visible and start the animation - view.setVisibility(View.VISIBLE); - anim.start(); - } - - /** - * Shrink the given visible view to the center of itself until - * it is no longer visible. The view will be set to View.INVISIBLE. - * If the platform is less than SDK_INT 21, then just set the - * view visibility to View.INVISIBLE without the animation. - * - * @param view - */ - @TargetApi(21) - static void shrinkToCenter(final View view) { - - if (SDK_INT < 21) { - view.setVisibility(View.INVISIBLE); - return; - } - - // get the center for the clipping circle - int cx = view.getMeasuredWidth() / 2; - int cy = view.getMeasuredHeight() / 2; - - // get the initial radius for the clipping circle - int initialRadius = view.getWidth() / 2; - - // create the animation (the final radius is zero) - Animator anim = - ViewAnimationUtils.createCircularReveal(view, cx, cy, initialRadius, 0); - - - // start the animation - view.setVisibility(View.INVISIBLE); - anim.start(); - - } - - /** - * A fix for Samsung phones that have a hardware bug where all photos taken while - * the device is in portrait orientation are saved in landscape mode to disk. - * - * @param bitmap - * @param target - * @return - * @throws IOException - */ - static Bitmap fixBitmapOrientation(Bitmap bitmap, File target) throws IOException { - Matrix matrix = new Matrix(); - matrix.postRotate(90); - Bitmap rotatedBitmap = Bitmap.createBitmap(bitmap , 0, 0, - bitmap.getWidth(), bitmap.getHeight(), matrix, true); - bitmap.recycle(); - writeBitmapToFile(rotatedBitmap, target); - return rotatedBitmap; - } - - static boolean bitmapNeedsRotating(Context context, Bitmap bitmap) throws IOException { - if (context.getResources().getConfiguration().orientation == Configuration - .ORIENTATION_PORTRAIT) { - return bitmap.getWidth() > bitmap.getHeight(); - } - return false; - } - - static void writeBitmapToFile(final Bitmap inBitmap, final File file) throws - IOException { - - if (!file.exists()) { - file.getParentFile().mkdirs(); - } - final FileOutputStream fos = new FileOutputStream(file); - inBitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos); - fos.close(); - } - -} diff --git a/library/src/main/res/drawable/ic_aspect_ratio.xml b/library/src/main/res/drawable/ic_aspect_ratio.xml deleted file mode 100644 index 2c39cace..00000000 --- a/library/src/main/res/drawable/ic_aspect_ratio.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - diff --git a/library/src/main/res/drawable/ic_camera.xml b/library/src/main/res/drawable/ic_camera.xml deleted file mode 100644 index 14584648..00000000 --- a/library/src/main/res/drawable/ic_camera.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - diff --git a/library/src/main/res/drawable/ic_flash_auto.xml b/library/src/main/res/drawable/ic_flash_auto.xml deleted file mode 100644 index b4164042..00000000 --- a/library/src/main/res/drawable/ic_flash_auto.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - diff --git a/library/src/main/res/drawable/ic_flash_off.xml b/library/src/main/res/drawable/ic_flash_off.xml deleted file mode 100644 index cae6f0ca..00000000 --- a/library/src/main/res/drawable/ic_flash_off.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - diff --git a/library/src/main/res/drawable/ic_flash_on.xml b/library/src/main/res/drawable/ic_flash_on.xml deleted file mode 100644 index 3aad5f47..00000000 --- a/library/src/main/res/drawable/ic_flash_on.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - diff --git a/library/src/main/res/drawable/ic_switch_camera.xml b/library/src/main/res/drawable/ic_switch_camera.xml deleted file mode 100644 index bade6e71..00000000 --- a/library/src/main/res/drawable/ic_switch_camera.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - diff --git a/library/src/main/res/layout-land/simple_camera_layout.xml b/library/src/main/res/layout-land/simple_camera_layout.xml deleted file mode 100644 index 3d371506..00000000 --- a/library/src/main/res/layout-land/simple_camera_layout.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - - - diff --git a/library/src/main/res/values-w820dp/dimens.xml b/library/src/main/res/values-w820dp/dimens.xml deleted file mode 100644 index 648f774e..00000000 --- a/library/src/main/res/values-w820dp/dimens.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - 64dp - diff --git a/library/src/main/res/values/colors.xml b/library/src/main/res/values/colors.xml deleted file mode 100644 index 293aece1..00000000 --- a/library/src/main/res/values/colors.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - #3F51B5 - #303F9F - #4CAF50 - #212121 - #727272 - - #40000000 - #BF000000 - diff --git a/library/src/main/res/values/dimens.xml b/library/src/main/res/values/dimens.xml deleted file mode 100644 index 0e5f08d6..00000000 --- a/library/src/main/res/values/dimens.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - 16dp - 16dp - 48dp - diff --git a/library/src/main/res/values/public.xml b/library/src/main/res/values/public.xml index 84966fa6..ee0278e3 100644 --- a/library/src/main/res/values/public.xml +++ b/library/src/main/res/values/public.xml @@ -18,4 +18,5 @@ + diff --git a/library/src/main/res/values/strings.xml b/library/src/main/res/values/strings.xml deleted file mode 100644 index 0ba9bdad..00000000 --- a/library/src/main/res/values/strings.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - This app demonstrates the usage of CameraView. In order to do that, it needs permission to access camera. - Camera app cannot do anything without camera permission. - Picture taken - Aspect ratio - Switch flash - Switch camera - Flash auto - Flash off - Flash on - Sorry! Failed to capture image. Please try again. - diff --git a/library/src/main/res/values/styles.xml b/library/src/main/res/values/styles.xml index 838bf906..ba2ebd3b 100644 --- a/library/src/main/res/values/styles.xml +++ b/library/src/main/res/values/styles.xml @@ -1,36 +1,21 @@ + ~ Copyright (C) 2016 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> - - - - - - - From c0ccf80a370759bf9c321fd32e7f9119e9a662e2 Mon Sep 17 00:00:00 2001 From: kevinkawai Date: Wed, 5 Apr 2017 13:00:00 -0700 Subject: [PATCH 18/42] 0.2.6 - fixed some memory leaks; fixed demo project --- demo/src/main/AndroidManifest.xml | 7 +--- .../android/cameraview/demo/MainActivity.java | 18 +++++++++ .../cameraview/demo/MainActivity2.java | 31 --------------- library/build.gradle | 2 +- .../google/android/cameraview/CameraView.java | 39 ++++++++++++------- 5 files changed, 46 insertions(+), 51 deletions(-) delete mode 100644 demo/src/main/java/com/google/android/cameraview/demo/MainActivity2.java diff --git a/demo/src/main/AndroidManifest.xml b/demo/src/main/AndroidManifest.xml index 4a63c213..291905d3 100644 --- a/demo/src/main/AndroidManifest.xml +++ b/demo/src/main/AndroidManifest.xml @@ -25,17 +25,14 @@ android:supportsRtl="true" android:theme="@style/Theme.Demo"> - + - - - diff --git a/demo/src/main/java/com/google/android/cameraview/demo/MainActivity.java b/demo/src/main/java/com/google/android/cameraview/demo/MainActivity.java index aae59e04..45696011 100644 --- a/demo/src/main/java/com/google/android/cameraview/demo/MainActivity.java +++ b/demo/src/main/java/com/google/android/cameraview/demo/MainActivity.java @@ -25,6 +25,7 @@ import android.os.Environment; import android.os.Handler; import android.os.HandlerThread; +import android.os.StrictMode; import android.support.annotation.NonNull; import android.support.annotation.StringRes; import android.support.design.widget.FloatingActionButton; @@ -39,6 +40,7 @@ import android.util.Log; import android.view.Menu; import android.view.MenuItem; +import android.view.TextureView; import android.view.View; import android.widget.RelativeLayout; import android.widget.Toast; @@ -112,6 +114,18 @@ public void onClick(View v) { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); + + StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder() + .detectNetwork() + .penaltyLog() + .build()); + StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder() + .detectLeakedSqlLiteObjects() + .detectLeakedClosableObjects() + .detectActivityLeaks() + .penaltyLog() + .build()); + mRootView = findViewById(R.id.root_view); mCameraView = (CameraView) findViewById(R.id.camera); if (mCameraView != null) { @@ -157,6 +171,10 @@ protected void onPause() { @Override protected void onDestroy() { + TextureView textureView = (TextureView)mCameraView.findViewById(R.id.texture_view); + textureView.getSurfaceTexture().setOnFrameAvailableListener(null); + textureView.getSurfaceTexture().release(); + textureView.setSurfaceTextureListener(null); super.onDestroy(); if (mBackgroundHandler != null) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { diff --git a/demo/src/main/java/com/google/android/cameraview/demo/MainActivity2.java b/demo/src/main/java/com/google/android/cameraview/demo/MainActivity2.java deleted file mode 100644 index 692c5a3b..00000000 --- a/demo/src/main/java/com/google/android/cameraview/demo/MainActivity2.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.cameraview.demo; - -import android.os.Bundle; -import android.support.annotation.Nullable; -import android.support.v7.app.AppCompatActivity; - - -public class MainActivity2 extends AppCompatActivity { - - private static final int REQ_CODE = 1; - @Override - protected void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - } -} diff --git a/library/build.gradle b/library/build.gradle index d804ec31..2315d496 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -62,7 +62,7 @@ publishing { publications { aar(MavenPublication) { groupId 'premise.android.cameraview' - version '0.2.0' + version '0.2.6' artifactId 'cameraview' artifact("$buildDir/outputs/aar/${project.getName()}-release.aar") diff --git a/library/src/main/java/com/google/android/cameraview/CameraView.java b/library/src/main/java/com/google/android/cameraview/CameraView.java index 04826d84..81d0c5bb 100644 --- a/library/src/main/java/com/google/android/cameraview/CameraView.java +++ b/library/src/main/java/com/google/android/cameraview/CameraView.java @@ -16,10 +16,11 @@ package com.google.android.cameraview; +import static android.os.Build.VERSION.SDK_INT; + import android.app.Activity; import android.content.Context; import android.content.res.TypedArray; -import android.os.Build; import android.os.Parcel; import android.os.Parcelable; import android.support.annotation.IntDef; @@ -95,14 +96,15 @@ public CameraView(Context context, AttributeSet attrs, int defStyleAttr) { return; } // Internal setup - final PreviewImpl preview = createPreviewImpl(context); - mCallbacks = new CallbackBridge(); - if (Build.VERSION.SDK_INT < 21) { + PreviewImpl preview = createPreviewImpl(context); + mCallbacks = new CallbackBridge(this); + final Context applicationContext = context.getApplicationContext(); + if (SDK_INT < 21) { mImpl = new Camera1(mCallbacks, preview); - } else if (Build.VERSION.SDK_INT < 23) { - mImpl = new Camera2(mCallbacks, preview, context); + } else if (SDK_INT < 23) { + mImpl = new Camera2(mCallbacks, preview, applicationContext); } else { - mImpl = new Camera2Api23(mCallbacks, preview, context); + mImpl = new Camera2Api23(mCallbacks, preview, applicationContext); } // Attributes TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CameraView, defStyleAttr, @@ -130,7 +132,7 @@ public void onDisplayOrientationChanged(int displayOrientation) { @NonNull private PreviewImpl createPreviewImpl(Context context) { PreviewImpl preview; - if (Build.VERSION.SDK_INT < 14) { + if (SDK_INT < 14) { preview = new SurfaceViewPreview(context, this); } else { preview = new TextureViewPreview(context, this); @@ -152,6 +154,7 @@ protected void onDetachedFromWindow() { mDisplayOrientationDetector.disable(); } super.onDetachedFromWindow(); + mCallbacks.cleanup(); } @Override @@ -407,13 +410,15 @@ public void takePicture() { mImpl.takePicture(); } - private class CallbackBridge implements CameraViewImpl.Callback { + private static class CallbackBridge implements CameraViewImpl.Callback { private final ArrayList mCallbacks = new ArrayList<>(); private boolean mRequestLayoutOnOpen; + private CameraView cameraView; - CallbackBridge() { + CallbackBridge(CameraView cameraView) { + this.cameraView = cameraView; } public void add(Callback callback) { @@ -428,30 +433,35 @@ public void remove(Callback callback) { public void onCameraOpened() { if (mRequestLayoutOnOpen) { mRequestLayoutOnOpen = false; - requestLayout(); + cameraView.requestLayout(); } for (Callback callback : mCallbacks) { - callback.onCameraOpened(CameraView.this); + callback.onCameraOpened(cameraView); } } @Override public void onCameraClosed() { for (Callback callback : mCallbacks) { - callback.onCameraClosed(CameraView.this); + callback.onCameraClosed(cameraView); } } @Override public void onPictureTaken(byte[] data) { for (Callback callback : mCallbacks) { - callback.onPictureTaken(CameraView.this, data); + callback.onPictureTaken(cameraView, data); } } public void reserveRequestLayoutOnOpen() { mRequestLayoutOnOpen = true; } + + private void cleanup() { + cameraView = null; + mCallbacks.clear(); + } } protected static class SavedState extends BaseSavedState { @@ -535,6 +545,7 @@ public void onCameraClosed(CameraView cameraView) { */ public void onPictureTaken(CameraView cameraView, byte[] data) { } + } } From 172205e0a93e05243f4eb0d612e1a8762525b73f Mon Sep 17 00:00:00 2001 From: kevinkawai Date: Thu, 23 Mar 2017 12:17:43 -0700 Subject: [PATCH 19/42] initial --- build.gradle | 3 ++- library/build.gradle | 31 +++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 20994bab..4ba5c105 100644 --- a/build.gradle +++ b/build.gradle @@ -9,6 +9,7 @@ buildscript { // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files + classpath 'org.jfrog.buildinfo:build-info-extractor-gradle:4.1.0' } } @@ -23,7 +24,7 @@ task clean(type: Delete) { } ext { - buildToolsVersion = '25.0.2' + buildToolsVersion = '25.0.1' compileSdkVersion = 25 minSdkVersion = 9 targetSdkVersion = 25 diff --git a/library/build.gradle b/library/build.gradle index 30b53bd8..c4aa51d3 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -13,6 +13,8 @@ // limitations under the License. apply plugin: 'com.android.library' +apply plugin: 'com.jfrog.artifactory' +apply plugin: 'maven-publish' android { compileSdkVersion rootProject.ext.compileSdkVersion @@ -38,6 +40,35 @@ android { } } +artifactory { + contextUrl = "${System.env.ARTIFACTORY_URL}" + publish { + repository { + repoKey = 'private-local' + username = "${System.env.ARTIFACTORY_USERNAME}" + password = "${System.env.ARTIFACTORY_PASSWORD}" + maven = true + } + defaults { + publications('aar') + } + } +} + + + +publishing { + publications { + aar(MavenPublication) { + groupId 'premise.android.cameraview' + version '0.0.1' + artifactId 'cameraview' + + artifact("$buildDir/outputs/aar/${project.getName()}-release.aar") + } + } +} + dependencies { compile "com.android.support:support-annotations:$supportLibraryVersion" compile "com.android.support:support-v4:$supportLibraryVersion" From 18e862e669bfc01a8d3a0441f377f1a630b0f0d3 Mon Sep 17 00:00:00 2001 From: kevinkawai Date: Fri, 24 Mar 2017 00:11:17 -0700 Subject: [PATCH 20/42] added premise SimpleCameraActivity to library --- .../main/res/layout-land/activity_main.xml | 2 +- library/build.gradle | 2 + .../AspectRatioFragment.java | 146 ++++++ .../SimpleCameraActivity.java | 483 ++++++++++++++++++ .../com/premise.android.camera/Utils.java | 143 ++++++ .../drawable-xxxhdpi/ic_check_white_24dp.png | Bin 0 -> 308 bytes .../src/main/res/drawable/ic_aspect_ratio.xml | 25 + library/src/main/res/drawable/ic_camera.xml | 25 + .../src/main/res/drawable/ic_flash_auto.xml | 22 + .../src/main/res/drawable/ic_flash_off.xml | 22 + library/src/main/res/drawable/ic_flash_on.xml | 22 + .../main/res/drawable/ic_switch_camera.xml | 22 + .../res/layout-land/simple_camera_layout.xml | 43 ++ .../main/res/layout/include_simple_camera.xml | 40 ++ .../main/res/layout/simple_camera_layout.xml | 37 ++ .../src/main/res/menu/simple_camera_menu.xml | 38 ++ library/src/main/res/values-w820dp/dimens.xml | 16 + library/src/main/res/values/colors.xml | 20 + library/src/main/res/values/dimens.xml | 17 + library/src/main/res/values/strings.xml | 27 + library/src/main/res/values/styles.xml | 18 + 21 files changed, 1169 insertions(+), 1 deletion(-) create mode 100644 library/src/main/java/com/premise.android.camera/AspectRatioFragment.java create mode 100644 library/src/main/java/com/premise.android.camera/SimpleCameraActivity.java create mode 100644 library/src/main/java/com/premise.android.camera/Utils.java create mode 100644 library/src/main/res/drawable-xxxhdpi/ic_check_white_24dp.png create mode 100644 library/src/main/res/drawable/ic_aspect_ratio.xml create mode 100644 library/src/main/res/drawable/ic_camera.xml create mode 100644 library/src/main/res/drawable/ic_flash_auto.xml create mode 100644 library/src/main/res/drawable/ic_flash_off.xml create mode 100644 library/src/main/res/drawable/ic_flash_on.xml create mode 100644 library/src/main/res/drawable/ic_switch_camera.xml create mode 100644 library/src/main/res/layout-land/simple_camera_layout.xml create mode 100644 library/src/main/res/layout/include_simple_camera.xml create mode 100644 library/src/main/res/layout/simple_camera_layout.xml create mode 100644 library/src/main/res/menu/simple_camera_menu.xml create mode 100644 library/src/main/res/values-w820dp/dimens.xml create mode 100644 library/src/main/res/values/colors.xml create mode 100644 library/src/main/res/values/dimens.xml create mode 100644 library/src/main/res/values/strings.xml diff --git a/demo/src/main/res/layout-land/activity_main.xml b/demo/src/main/res/layout-land/activity_main.xml index 08deb02d..b825bc72 100644 --- a/demo/src/main/res/layout-land/activity_main.xml +++ b/demo/src/main/res/layout-land/activity_main.xml @@ -23,7 +23,7 @@ tools:context=".MainActivity"> diff --git a/library/build.gradle b/library/build.gradle index c4aa51d3..0908d82a 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -24,6 +24,7 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion testInstrumentationRunner 'android.support.test.runner.AndroidJUnitRunner' + vectorDrawables.useSupportLibrary = true } buildTypes { release { @@ -72,6 +73,7 @@ publishing { dependencies { compile "com.android.support:support-annotations:$supportLibraryVersion" compile "com.android.support:support-v4:$supportLibraryVersion" + compile "com.android.support:design:$supportLibraryVersion" // Tests testCompile 'junit:junit:4.12' diff --git a/library/src/main/java/com/premise.android.camera/AspectRatioFragment.java b/library/src/main/java/com/premise.android.camera/AspectRatioFragment.java new file mode 100644 index 00000000..15d409b7 --- /dev/null +++ b/library/src/main/java/com/premise.android.camera/AspectRatioFragment.java @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.premise.android.camera; + +import android.app.Dialog; +import android.content.Context; +import android.content.DialogInterface; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.v4.app.DialogFragment; +import android.support.v7.app.AlertDialog; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.TextView; + +import com.google.android.cameraview.AspectRatio; + +import java.util.Set; + + +/** + * A simple dialog that allows user to pick an aspect ratio. + */ +public class AspectRatioFragment extends DialogFragment { + + private static final String ARG_ASPECT_RATIOS = "aspect_ratios"; + private static final String ARG_CURRENT_ASPECT_RATIO = "current_aspect_ratio"; + + private Listener mListener; + + public static AspectRatioFragment newInstance(Set ratios, + AspectRatio currentRatio) { + final AspectRatioFragment fragment = new AspectRatioFragment(); + final Bundle args = new Bundle(); + args.putParcelableArray(ARG_ASPECT_RATIOS, + ratios.toArray(new AspectRatio[ratios.size()])); + args.putParcelable(ARG_CURRENT_ASPECT_RATIO, currentRatio); + fragment.setArguments(args); + return fragment; + } + + @Override + public void onAttach(Context context) { + super.onAttach(context); + mListener = (Listener) context; + } + + @Override + public void onDetach() { + mListener = null; + super.onDetach(); + } + + @NonNull + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + final Bundle args = getArguments(); + final AspectRatio[] ratios = (AspectRatio[]) args.getParcelableArray(ARG_ASPECT_RATIOS); + if (ratios == null) { + throw new RuntimeException("No ratios"); + } + final AspectRatio current = args.getParcelable(ARG_CURRENT_ASPECT_RATIO); + final AspectRatioAdapter adapter = new AspectRatioAdapter(ratios, current); + return new AlertDialog.Builder(getActivity()) + .setAdapter(adapter, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int position) { + mListener.onAspectRatioSelected(ratios[position]); + } + }) + .create(); + } + + private static class AspectRatioAdapter extends BaseAdapter { + + private final AspectRatio[] mRatios; + private final AspectRatio mCurrentRatio; + + AspectRatioAdapter(AspectRatio[] ratios, AspectRatio current) { + mRatios = ratios; + mCurrentRatio = current; + } + + @Override + public int getCount() { + return mRatios.length; + } + + @Override + public AspectRatio getItem(int position) { + return mRatios[position]; + } + + @Override + public long getItemId(int position) { + return getItem(position).hashCode(); + } + + @Override + public View getView(int position, View view, ViewGroup parent) { + AspectRatioAdapter.ViewHolder holder; + if (view == null) { + view = LayoutInflater.from(parent.getContext()) + .inflate(android.R.layout.simple_list_item_1, parent, false); + holder = new AspectRatioAdapter.ViewHolder(); + holder.text = (TextView) view.findViewById(android.R.id.text1); + view.setTag(holder); + } else { + holder = (AspectRatioAdapter.ViewHolder) view.getTag(); + } + AspectRatio ratio = getItem(position); + StringBuilder sb = new StringBuilder(ratio.toString()); + if (ratio.equals(mCurrentRatio)) { + sb.append(" *"); + } + holder.text.setText(sb); + return view; + } + + private static class ViewHolder { + TextView text; + } + + } + + public interface Listener { + void onAspectRatioSelected(@NonNull AspectRatio ratio); + } + +} diff --git a/library/src/main/java/com/premise.android.camera/SimpleCameraActivity.java b/library/src/main/java/com/premise.android.camera/SimpleCameraActivity.java new file mode 100644 index 00000000..f52e1703 --- /dev/null +++ b/library/src/main/java/com/premise.android.camera/SimpleCameraActivity.java @@ -0,0 +1,483 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.premise.android.camera; + +import static android.os.Build.VERSION.SDK_INT; + +import android.Manifest; +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.annotation.TargetApi; +import android.app.Dialog; +import android.content.DialogInterface; +import android.content.pm.ActivityInfo; +import android.content.pm.PackageManager; +import android.content.res.Configuration; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.media.MediaActionSound; +import android.os.Build; +import android.os.Bundle; +import android.os.Environment; +import android.os.Handler; +import android.os.HandlerThread; +import android.support.annotation.NonNull; +import android.support.annotation.StringRes; +import android.support.design.widget.FloatingActionButton; +import android.support.v4.app.ActivityCompat; +import android.support.v4.app.DialogFragment; +import android.support.v4.content.ContextCompat; +import android.support.v7.app.ActionBar; +import android.support.v7.app.AlertDialog; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.Toolbar; +import android.util.Log; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewAnimationUtils; +import android.widget.ImageView; +import android.widget.Toast; + +import com.google.android.cameraview.AspectRatio; +import com.google.android.cameraview.CameraView; +import com.google.android.cameraview.R; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.Set; +import java.util.concurrent.CountDownLatch; + + +/** + * This demo app saves the taken picture to a constant file. + * $ adb pull /sdcard/Android/data/com.google.android.cameraview.demo/files/Pictures/picture.jpg + */ +public class SimpleCameraActivity extends AppCompatActivity implements + ActivityCompat.OnRequestPermissionsResultCallback, + AspectRatioFragment.Listener { + + private static final String TAG = "MainActivity"; + + private static final boolean DO_ANIM = true; + + private static final int REQUEST_CAMERA_PERMISSION = 1; + + private static final String FRAGMENT_DIALOG = "dialog"; + + private static final int[] FLASH_OPTIONS = { + CameraView.FLASH_OFF, + CameraView.FLASH_AUTO, + CameraView.FLASH_ON, + }; + + private static final int[] FLASH_ICONS = { + R.drawable.ic_flash_off, + R.drawable.ic_flash_auto, + R.drawable.ic_flash_on, + }; + + private static final int[] FLASH_TITLES = { + R.string.flash_off, + R.string.flash_auto, + R.string.flash_on, + }; + + private int mCurrentFlash; + + private CameraView mCameraView; + + private ImageView mCapturedImageView; + + private Handler mBackgroundHandler; + + private FloatingActionButton mTakePicButton; + + private CountDownLatch mCountDownLatch = new CountDownLatch(1); + + private MediaActionSound mSound; + + private Bitmap mBitmap; + + private View.OnClickListener mOnClickListener = new View.OnClickListener() { + @Override + public void onClick(View v) { + if (v.getId() == R.id.take_picture) { + takePhoto(); + } + } + }; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.simple_camera_layout); + mCameraView = (CameraView) findViewById(R.id.camera); + mCameraView.setFlash(CameraView.FLASH_OFF); + if (mCameraView != null) { + mCameraView.addCallback(mCallback); + } + mTakePicButton = (FloatingActionButton) findViewById(R.id.take_picture); + mTakePicButton.setOnClickListener(mOnClickListener); + mCapturedImageView = (ImageView)findViewById(R.id.captured_camera_image); + + Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); + setSupportActionBar(toolbar); + ActionBar actionBar = getSupportActionBar(); + if (actionBar != null) { + actionBar.setDisplayShowTitleEnabled(false); + } + initSound(); + } + + private void initSound() { + if (SDK_INT >= 16) { + mSound = new MediaActionSound(); + } + } + + private void playSound() { + if (SDK_INT >= 16) { + if (mSound != null) { + mSound.play(MediaActionSound.SHUTTER_CLICK); + } + } + } + + private void releaseSound() { + if (SDK_INT >= 16) { + if (mSound != null) { + mSound.release(); + } + } + } + + @Override + protected void onResume() { + super.onResume(); + if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) + == PackageManager.PERMISSION_GRANTED) { + mCameraView.start(); + } else if (ActivityCompat.shouldShowRequestPermissionRationale(this, + Manifest.permission.CAMERA)) { + ConfirmationDialogFragment + .newInstance(R.string.camera_permission_confirmation, + new String[]{Manifest.permission.CAMERA}, + REQUEST_CAMERA_PERMISSION, + R.string.camera_permission_not_granted) + .show(getSupportFragmentManager(), FRAGMENT_DIALOG); + } else { + ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, + REQUEST_CAMERA_PERMISSION); + } + } + + @Override + protected void onPause() { + mCameraView.stop(); + super.onPause(); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + if (mBackgroundHandler != null) { + if (SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { + mBackgroundHandler.getLooper().quitSafely(); + } else { + mBackgroundHandler.getLooper().quit(); + } + mBackgroundHandler = null; + } + if (mBitmap != null && !mBitmap.isRecycled()) { + mCapturedImageView.setImageDrawable(null); + mBitmap.recycle(); + } + releaseSound(); + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, + @NonNull int[] grantResults) { + switch (requestCode) { + case REQUEST_CAMERA_PERMISSION: + if (permissions.length != 1 || grantResults.length != 1) { + throw new RuntimeException("Error on requesting camera permission."); + } + if (grantResults[0] != PackageManager.PERMISSION_GRANTED) { + Toast.makeText(this, R.string.camera_permission_not_granted, + Toast.LENGTH_SHORT).show(); + } + // No need to start camera here; it is handled by onResume + break; + } + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.simple_camera_menu, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + + //cannot use resource ID in switch statements in android library projects + if (item.getItemId() == R.id.aspect_ratio) { + if (mCameraView != null) { + final Set ratios = mCameraView.getSupportedAspectRatios(); + final AspectRatio currentRatio = mCameraView.getAspectRatio(); + AspectRatioFragment.newInstance(ratios, currentRatio) + .show(getSupportFragmentManager(), FRAGMENT_DIALOG); + } + } else if (item.getItemId() == R.id.switch_flash) { + if (mCameraView != null) { + mCurrentFlash = (mCurrentFlash + 1) % FLASH_OPTIONS.length; + item.setTitle(FLASH_TITLES[mCurrentFlash]); + item.setIcon(FLASH_ICONS[mCurrentFlash]); + mCameraView.setFlash(FLASH_OPTIONS[mCurrentFlash]); + } + } else if (item.getItemId() == R.id.switch_camera) { + if (mCameraView != null) { + int facing = mCameraView.getFacing(); + mCameraView.setFacing(facing == CameraView.FACING_FRONT ? + CameraView.FACING_BACK : CameraView.FACING_FRONT); + } + } + return false; + } + + @Override + public void onAspectRatioSelected(@NonNull AspectRatio ratio) { + if (mCameraView != null) { + Toast.makeText(this, ratio.toString(), Toast.LENGTH_SHORT).show(); + mCameraView.setAspectRatio(ratio); + } + } + + private Handler getBackgroundHandler() { + if (mBackgroundHandler == null) { + HandlerThread thread = new HandlerThread("background"); + thread.start(); + mBackgroundHandler = new Handler(thread.getLooper()); + } + return mBackgroundHandler; + } + + private CameraView.Callback mCallback + = new CameraView.Callback() { + + @Override + public void onCameraOpened(CameraView cameraView) { + Log.d(TAG, "onCameraOpened"); + } + + @Override + public void onCameraClosed(CameraView cameraView) { + Log.d(TAG, "onCameraClosed"); + } + + @Override + public void onPictureTaken(CameraView cameraView, final byte[] data) { + Log.d(TAG, "onPictureTaken " + data.length); + //Toast.makeText(cameraView.getContext(), R.string.picture_taken, Toast.LENGTH_SHORT) + // .show(); + getBackgroundHandler().post(new Runnable() { + @Override + public void run() { + File file = new File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), + "picture.jpg"); + OutputStream os = null; + try { + os = new FileOutputStream(file); + os.write(data); + os.close(); + mBitmap = BitmapFactory.decodeFile(file.getAbsolutePath()); + if (Utils.bitmapNeedsRotating(SimpleCameraActivity.this,mBitmap)) { + mBitmap = Utils.fixBitmapOrientation(mBitmap, file); + } + mCountDownLatch.await(); + mCountDownLatch = new CountDownLatch(1); + runOnUiThread(new Runnable() { + @Override + public void run() { + revealCapturedImage(mBitmap); + } + }); + } catch (IOException e) { + Log.w(TAG, "Cannot write to " + file, e); + Toast.makeText(SimpleCameraActivity.this, "Failed. Try again",Toast.LENGTH_SHORT).show(); + } catch (InterruptedException e) { + Log.w(TAG, "Interrupted while writing image to disk", e); + } finally { + if (os != null) { + try { + os.close(); + } catch (IOException e) { + // Ignore + } + } + } + } + }); + } + + }; + + public static class ConfirmationDialogFragment extends DialogFragment { + + private static final String ARG_MESSAGE = "message"; + private static final String ARG_PERMISSIONS = "permissions"; + private static final String ARG_REQUEST_CODE = "request_code"; + private static final String ARG_NOT_GRANTED_MESSAGE = "not_granted_message"; + + public static ConfirmationDialogFragment newInstance(@StringRes int message, + String[] permissions, int requestCode, @StringRes int notGrantedMessage) { + ConfirmationDialogFragment fragment = new ConfirmationDialogFragment(); + Bundle args = new Bundle(); + args.putInt(ARG_MESSAGE, message); + args.putStringArray(ARG_PERMISSIONS, permissions); + args.putInt(ARG_REQUEST_CODE, requestCode); + args.putInt(ARG_NOT_GRANTED_MESSAGE, notGrantedMessage); + fragment.setArguments(args); + return fragment; + } + + @NonNull + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + final Bundle args = getArguments(); + return new AlertDialog.Builder(getActivity()) + .setMessage(args.getInt(ARG_MESSAGE)) + .setPositiveButton(android.R.string.ok, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + String[] permissions = args.getStringArray(ARG_PERMISSIONS); + if (permissions == null) { + throw new IllegalArgumentException(); + } + ActivityCompat.requestPermissions(getActivity(), + permissions, args.getInt(ARG_REQUEST_CODE)); + } + }) + .setNegativeButton(android.R.string.cancel, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + Toast.makeText(getActivity(), + args.getInt(ARG_NOT_GRANTED_MESSAGE), + Toast.LENGTH_SHORT).show(); + } + }) + .create(); + } + + } + + + private void setCameraButtonImage(final int imageRes) { + mTakePicButton.setImageResource(imageRes); + mTakePicButton.setEnabled(true); + Utils.expandFromCenter(mTakePicButton); + } + + @TargetApi(21) + private void revealCapturedImage(Bitmap bitmap) { + + Log.d("MainActivity", "revealCapturedImage"); + + setCameraButtonImage(R.drawable.ic_check_white_24dp); + if (SDK_INT < 21 || !DO_ANIM) { + mCapturedImageView.setVisibility(View.VISIBLE); + mCapturedImageView.setImageBitmap(bitmap); + return; + } + // previously invisible view + + int cx = mCapturedImageView.getMeasuredWidth() / 2; + int cy = mCapturedImageView.getMeasuredHeight() / 2; + + // get the final radius for the clipping circle + int finalRadius = Math.max(mCapturedImageView.getWidth(), mCapturedImageView.getHeight()) / 2; + + // create the animator for this view (the start radius is zero) + Animator anim = + ViewAnimationUtils.createCircularReveal(mCapturedImageView, cx, cy, 0, finalRadius); + + // make the view visible and start the animation + anim.start(); + mCapturedImageView.setVisibility(View.VISIBLE); + mCapturedImageView.setImageBitmap(bitmap); + } + + + + @TargetApi(21) + private void takePhoto() { + + playSound(); + mTakePicButton.setEnabled(false); + Utils.shrinkToCenter(mTakePicButton); + lockScreenOrientation(); + mCameraView.takePicture(); + + if (SDK_INT < 21 || !DO_ANIM) { + mCameraView.setVisibility(View.INVISIBLE); + mCountDownLatch.countDown(); + return; + } + + // previously visible view + + // get the center for the clipping circle + int cx = mCameraView.getMeasuredWidth() / 2; + int cy = mCameraView.getMeasuredHeight() / 2; + + // get the initial radius for the clipping circle + int initialRadius = mCameraView.getWidth() / 2; + + // create the animation (the final radius is zero) + Animator anim = + ViewAnimationUtils.createCircularReveal(mCameraView, cx, cy, initialRadius, 0); + + // make the view invisible when the animation is done + anim.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + mCameraView.setVisibility(View.INVISIBLE); + mCountDownLatch.countDown(); + } + }); + + // start the animation + anim.start(); + } + + private void lockScreenOrientation() { + if (getResources().getConfiguration().orientation == Configuration + .ORIENTATION_LANDSCAPE) { + setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); //lock orientation + } else { + setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); + } + } + +} \ No newline at end of file diff --git a/library/src/main/java/com/premise.android.camera/Utils.java b/library/src/main/java/com/premise.android.camera/Utils.java new file mode 100644 index 00000000..73c2f6a4 --- /dev/null +++ b/library/src/main/java/com/premise.android.camera/Utils.java @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.premise.android.camera; + +import static android.os.Build.VERSION.SDK_INT; + +import android.animation.Animator; +import android.annotation.TargetApi; +import android.content.Context; +import android.content.res.Configuration; +import android.graphics.Bitmap; +import android.graphics.Matrix; +import android.view.View; +import android.view.ViewAnimationUtils; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +/** + * Created by kevinkawai on 3/22/17. + */ + +class Utils { + + /** + * Expand the given invisible view from the center of itself until + * it is fully revealed. The view will be set to View.VISIBLE. + * If the platform is less than SDK_INT 21, then just set the + * view visibility to View.VISIBLE without the animation. + * + * @param view + */ + @TargetApi(21) + static void expandFromCenter(View view) { + + if (SDK_INT < 21) { + view.setVisibility(View.VISIBLE); + return; + } + + int cx = view.getMeasuredWidth() / 2; + int cy = view.getMeasuredHeight() / 2; + + // get the final radius for the clipping circle + int finalRadius = Math.max(view.getWidth(), view.getHeight()) / 2; + + // create the animator for this view (the start radius is zero) + Animator anim = + ViewAnimationUtils.createCircularReveal(view, cx, cy, 0, finalRadius); + + // make the view visible and start the animation + view.setVisibility(View.VISIBLE); + anim.start(); + } + + /** + * Shrink the given visible view to the center of itself until + * it is no longer visible. The view will be set to View.INVISIBLE. + * If the platform is less than SDK_INT 21, then just set the + * view visibility to View.INVISIBLE without the animation. + * + * @param view + */ + @TargetApi(21) + static void shrinkToCenter(final View view) { + + if (SDK_INT < 21) { + view.setVisibility(View.INVISIBLE); + return; + } + + // get the center for the clipping circle + int cx = view.getMeasuredWidth() / 2; + int cy = view.getMeasuredHeight() / 2; + + // get the initial radius for the clipping circle + int initialRadius = view.getWidth() / 2; + + // create the animation (the final radius is zero) + Animator anim = + ViewAnimationUtils.createCircularReveal(view, cx, cy, initialRadius, 0); + + + // start the animation + view.setVisibility(View.INVISIBLE); + anim.start(); + + } + + /** + * A fix for Samsung phones that have a hardware bug where all photos taken while + * the device is in portrait orientation are saved in landscape mode to disk. + * + * @param bitmap + * @param target + * @return + * @throws IOException + */ + static Bitmap fixBitmapOrientation(Bitmap bitmap, File target) throws IOException { + Matrix matrix = new Matrix(); + matrix.postRotate(90); + Bitmap rotatedBitmap = Bitmap.createBitmap(bitmap , 0, 0, + bitmap.getWidth(), bitmap.getHeight(), matrix, true); + bitmap.recycle(); + writeBitmapToFile(rotatedBitmap, target); + return rotatedBitmap; + } + + static boolean bitmapNeedsRotating(Context context, Bitmap bitmap) throws IOException { + if (context.getResources().getConfiguration().orientation == Configuration + .ORIENTATION_PORTRAIT) { + return bitmap.getWidth() > bitmap.getHeight(); + } + return false; + } + + static void writeBitmapToFile(final Bitmap inBitmap, final File file) throws + IOException { + + if (!file.exists()) { + file.getParentFile().mkdirs(); + } + final FileOutputStream fos = new FileOutputStream(file); + inBitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos); + fos.close(); + } + +} diff --git a/library/src/main/res/drawable-xxxhdpi/ic_check_white_24dp.png b/library/src/main/res/drawable-xxxhdpi/ic_check_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..d670618c7e96225f7756cb4c2743e7ebbf688cf8 GIT binary patch literal 308 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD0wg^q?%xcgetWt&hE&{od;P3vlYxj!B3Hnh z1714EonD+``t$ZU)3IJ|2aboi6~%ilJM7!-={Kv*@R&q$518Ox)_m^XpXp1^&DOu% zB6r^~@kqJ%j0e`LXFkL-JviL|Ir_(khlktwLa#r83bn@|VwIw^gKjzH(>hUq>tlAsh9~)aj{(R+p z`Qx=v&?j!r?}<)Pb+Jxa|B9Td>MRd7#ru4CATBh=u6rtH + + + + diff --git a/library/src/main/res/drawable/ic_camera.xml b/library/src/main/res/drawable/ic_camera.xml new file mode 100644 index 00000000..14584648 --- /dev/null +++ b/library/src/main/res/drawable/ic_camera.xml @@ -0,0 +1,25 @@ + + + + + + diff --git a/library/src/main/res/drawable/ic_flash_auto.xml b/library/src/main/res/drawable/ic_flash_auto.xml new file mode 100644 index 00000000..b4164042 --- /dev/null +++ b/library/src/main/res/drawable/ic_flash_auto.xml @@ -0,0 +1,22 @@ + + + + + diff --git a/library/src/main/res/drawable/ic_flash_off.xml b/library/src/main/res/drawable/ic_flash_off.xml new file mode 100644 index 00000000..cae6f0ca --- /dev/null +++ b/library/src/main/res/drawable/ic_flash_off.xml @@ -0,0 +1,22 @@ + + + + + diff --git a/library/src/main/res/drawable/ic_flash_on.xml b/library/src/main/res/drawable/ic_flash_on.xml new file mode 100644 index 00000000..3aad5f47 --- /dev/null +++ b/library/src/main/res/drawable/ic_flash_on.xml @@ -0,0 +1,22 @@ + + + + + diff --git a/library/src/main/res/drawable/ic_switch_camera.xml b/library/src/main/res/drawable/ic_switch_camera.xml new file mode 100644 index 00000000..bade6e71 --- /dev/null +++ b/library/src/main/res/drawable/ic_switch_camera.xml @@ -0,0 +1,22 @@ + + + + + diff --git a/library/src/main/res/layout-land/simple_camera_layout.xml b/library/src/main/res/layout-land/simple_camera_layout.xml new file mode 100644 index 00000000..9b598c4c --- /dev/null +++ b/library/src/main/res/layout-land/simple_camera_layout.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + diff --git a/library/src/main/res/layout/include_simple_camera.xml b/library/src/main/res/layout/include_simple_camera.xml new file mode 100644 index 00000000..42232eba --- /dev/null +++ b/library/src/main/res/layout/include_simple_camera.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + diff --git a/library/src/main/res/layout/simple_camera_layout.xml b/library/src/main/res/layout/simple_camera_layout.xml new file mode 100644 index 00000000..3f060ed2 --- /dev/null +++ b/library/src/main/res/layout/simple_camera_layout.xml @@ -0,0 +1,37 @@ + + + + + + + + + diff --git a/library/src/main/res/menu/simple_camera_menu.xml b/library/src/main/res/menu/simple_camera_menu.xml new file mode 100644 index 00000000..8f013d12 --- /dev/null +++ b/library/src/main/res/menu/simple_camera_menu.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + diff --git a/library/src/main/res/values-w820dp/dimens.xml b/library/src/main/res/values-w820dp/dimens.xml new file mode 100644 index 00000000..648f774e --- /dev/null +++ b/library/src/main/res/values-w820dp/dimens.xml @@ -0,0 +1,16 @@ + + + + 64dp + diff --git a/library/src/main/res/values/colors.xml b/library/src/main/res/values/colors.xml new file mode 100644 index 00000000..9bbf0348 --- /dev/null +++ b/library/src/main/res/values/colors.xml @@ -0,0 +1,20 @@ + + + + #3F51B5 + #303F9F + #4CAF50 + #212121 + #727272 + diff --git a/library/src/main/res/values/dimens.xml b/library/src/main/res/values/dimens.xml new file mode 100644 index 00000000..d65da19e --- /dev/null +++ b/library/src/main/res/values/dimens.xml @@ -0,0 +1,17 @@ + + + + 16dp + 16dp + diff --git a/library/src/main/res/values/strings.xml b/library/src/main/res/values/strings.xml new file mode 100644 index 00000000..b6da5997 --- /dev/null +++ b/library/src/main/res/values/strings.xml @@ -0,0 +1,27 @@ + + + + This app demonstrates the usage of CameraView. In order to do that, it needs permission to access camera. + Camera app cannot do anything without camera permission. + Picture taken + Aspect ratio + Switch flash + Switch camera + Flash auto + Flash off + Flash on + diff --git a/library/src/main/res/values/styles.xml b/library/src/main/res/values/styles.xml index 6ded7168..fd5bf230 100644 --- a/library/src/main/res/values/styles.xml +++ b/library/src/main/res/values/styles.xml @@ -13,6 +13,24 @@ --> + + + + + + + From c50efd9975c57763928d5efb225829c7fc08ecde Mon Sep 17 00:00:00 2001 From: kevinkawai Date: Mon, 27 Mar 2017 15:32:35 -0700 Subject: [PATCH 33/42] touch ups --- .../res/drawable/dark_transparent_circle.xml | 28 ------------------- .../main/res/drawable/semi_transparent_fg.xml | 7 ----- 2 files changed, 35 deletions(-) delete mode 100644 library/src/main/res/drawable/dark_transparent_circle.xml delete mode 100644 library/src/main/res/drawable/semi_transparent_fg.xml diff --git a/library/src/main/res/drawable/dark_transparent_circle.xml b/library/src/main/res/drawable/dark_transparent_circle.xml deleted file mode 100644 index af0312ea..00000000 --- a/library/src/main/res/drawable/dark_transparent_circle.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/library/src/main/res/drawable/semi_transparent_fg.xml b/library/src/main/res/drawable/semi_transparent_fg.xml deleted file mode 100644 index 39d73375..00000000 --- a/library/src/main/res/drawable/semi_transparent_fg.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file From e9935e4421312d36e6fcafab57269f185c115822 Mon Sep 17 00:00:00 2001 From: kevinkawai Date: Mon, 27 Mar 2017 18:01:15 -0700 Subject: [PATCH 34/42] touch ups --- .../android/cameraview}/AspectRatioFragment.java | 4 +--- .../java/com/premise.android.camera/SimpleCameraActivity.java | 1 + 2 files changed, 2 insertions(+), 3 deletions(-) rename library/src/main/java/com/{premise.android.camera => google/android/cameraview}/AspectRatioFragment.java (98%) diff --git a/library/src/main/java/com/premise.android.camera/AspectRatioFragment.java b/library/src/main/java/com/google/android/cameraview/AspectRatioFragment.java similarity index 98% rename from library/src/main/java/com/premise.android.camera/AspectRatioFragment.java rename to library/src/main/java/com/google/android/cameraview/AspectRatioFragment.java index 15d409b7..2b50206c 100644 --- a/library/src/main/java/com/premise.android.camera/AspectRatioFragment.java +++ b/library/src/main/java/com/google/android/cameraview/AspectRatioFragment.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.premise.android.camera; +package com.google.android.cameraview; import android.app.Dialog; import android.content.Context; @@ -29,8 +29,6 @@ import android.widget.BaseAdapter; import android.widget.TextView; -import com.google.android.cameraview.AspectRatio; - import java.util.Set; diff --git a/library/src/main/java/com/premise.android.camera/SimpleCameraActivity.java b/library/src/main/java/com/premise.android.camera/SimpleCameraActivity.java index bffb0455..c4b90557 100644 --- a/library/src/main/java/com/premise.android.camera/SimpleCameraActivity.java +++ b/library/src/main/java/com/premise.android.camera/SimpleCameraActivity.java @@ -53,6 +53,7 @@ import android.widget.Toast; import com.google.android.cameraview.AspectRatio; +import com.google.android.cameraview.AspectRatioFragment; import com.google.android.cameraview.CameraView; import com.google.android.cameraview.R; From e56b55eb489e1e5222765adde44dd6f8f577e9ca Mon Sep 17 00:00:00 2001 From: kevinkawai Date: Wed, 29 Mar 2017 23:57:21 -0700 Subject: [PATCH 35/42] purified back --- .../cameraview/demo/MainActivity2.java | 8 - .../transparent_circle_selector.xml | 0 .../drawable-xxxhdpi/ic_check_white_24dp.png | Bin .../ic_keyboard_backspace_white_24dp.png | Bin .../res/drawable/transparent_circle_25.xml | 0 .../res/drawable/transparent_circle_75.xml | 0 .../drawable/transparent_circle_selector.xml | 0 .../main/res/layout/include_simple_camera.xml | 0 .../main/res/layout/simple_camera_layout.xml | 0 .../src/main/res/menu/simple_camera_menu.xml | 2 +- demo/src/main/res/values/colors.xml | 4 + demo/src/main/res/values/dimens.xml | 1 + demo/src/main/res/values/styles.xml | 23 + library/build.gradle | 2 +- .../cameraview/AspectRatioFragment.java | 144 ----- .../SimpleCameraActivity.java | 532 ------------------ .../com/premise.android.camera/Utils.java | 143 ----- .../src/main/res/drawable/ic_aspect_ratio.xml | 25 - library/src/main/res/drawable/ic_camera.xml | 25 - .../src/main/res/drawable/ic_flash_auto.xml | 22 - .../src/main/res/drawable/ic_flash_off.xml | 22 - library/src/main/res/drawable/ic_flash_on.xml | 22 - .../main/res/drawable/ic_switch_camera.xml | 22 - .../res/layout-land/simple_camera_layout.xml | 34 -- library/src/main/res/values-w820dp/dimens.xml | 16 - library/src/main/res/values/colors.xml | 23 - library/src/main/res/values/dimens.xml | 18 - library/src/main/res/values/public.xml | 1 + library/src/main/res/values/strings.xml | 28 - library/src/main/res/values/styles.xml | 49 +- 30 files changed, 45 insertions(+), 1121 deletions(-) rename {library => demo}/src/main/res/drawable-v21/transparent_circle_selector.xml (100%) rename {library => demo}/src/main/res/drawable-xxxhdpi/ic_check_white_24dp.png (100%) rename {library => demo}/src/main/res/drawable-xxxhdpi/ic_keyboard_backspace_white_24dp.png (100%) rename {library => demo}/src/main/res/drawable/transparent_circle_25.xml (100%) rename {library => demo}/src/main/res/drawable/transparent_circle_75.xml (100%) rename {library => demo}/src/main/res/drawable/transparent_circle_selector.xml (100%) rename {library => demo}/src/main/res/layout/include_simple_camera.xml (100%) rename {library => demo}/src/main/res/layout/simple_camera_layout.xml (100%) rename {library => demo}/src/main/res/menu/simple_camera_menu.xml (97%) delete mode 100644 library/src/main/java/com/google/android/cameraview/AspectRatioFragment.java delete mode 100644 library/src/main/java/com/premise.android.camera/SimpleCameraActivity.java delete mode 100644 library/src/main/java/com/premise.android.camera/Utils.java delete mode 100644 library/src/main/res/drawable/ic_aspect_ratio.xml delete mode 100644 library/src/main/res/drawable/ic_camera.xml delete mode 100644 library/src/main/res/drawable/ic_flash_auto.xml delete mode 100644 library/src/main/res/drawable/ic_flash_off.xml delete mode 100644 library/src/main/res/drawable/ic_flash_on.xml delete mode 100644 library/src/main/res/drawable/ic_switch_camera.xml delete mode 100644 library/src/main/res/layout-land/simple_camera_layout.xml delete mode 100644 library/src/main/res/values-w820dp/dimens.xml delete mode 100644 library/src/main/res/values/colors.xml delete mode 100644 library/src/main/res/values/dimens.xml delete mode 100644 library/src/main/res/values/strings.xml diff --git a/demo/src/main/java/com/google/android/cameraview/demo/MainActivity2.java b/demo/src/main/java/com/google/android/cameraview/demo/MainActivity2.java index 67ce52d9..692c5a3b 100644 --- a/demo/src/main/java/com/google/android/cameraview/demo/MainActivity2.java +++ b/demo/src/main/java/com/google/android/cameraview/demo/MainActivity2.java @@ -16,13 +16,10 @@ package com.google.android.cameraview.demo; -import android.content.Intent; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v7.app.AppCompatActivity; -import com.premise.android.camera.SimpleCameraActivity; - public class MainActivity2 extends AppCompatActivity { @@ -30,10 +27,5 @@ public class MainActivity2 extends AppCompatActivity { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); - Intent intent = new Intent(this, SimpleCameraActivity.class); - String imagePath = getFilesDir().getPath() + "/picture.jpg"; - intent.putExtra(SimpleCameraActivity.KEY_OUTPUT_PATH,imagePath); - startActivityForResult(intent, REQ_CODE); - finish(); } } diff --git a/library/src/main/res/drawable-v21/transparent_circle_selector.xml b/demo/src/main/res/drawable-v21/transparent_circle_selector.xml similarity index 100% rename from library/src/main/res/drawable-v21/transparent_circle_selector.xml rename to demo/src/main/res/drawable-v21/transparent_circle_selector.xml diff --git a/library/src/main/res/drawable-xxxhdpi/ic_check_white_24dp.png b/demo/src/main/res/drawable-xxxhdpi/ic_check_white_24dp.png similarity index 100% rename from library/src/main/res/drawable-xxxhdpi/ic_check_white_24dp.png rename to demo/src/main/res/drawable-xxxhdpi/ic_check_white_24dp.png diff --git a/library/src/main/res/drawable-xxxhdpi/ic_keyboard_backspace_white_24dp.png b/demo/src/main/res/drawable-xxxhdpi/ic_keyboard_backspace_white_24dp.png similarity index 100% rename from library/src/main/res/drawable-xxxhdpi/ic_keyboard_backspace_white_24dp.png rename to demo/src/main/res/drawable-xxxhdpi/ic_keyboard_backspace_white_24dp.png diff --git a/library/src/main/res/drawable/transparent_circle_25.xml b/demo/src/main/res/drawable/transparent_circle_25.xml similarity index 100% rename from library/src/main/res/drawable/transparent_circle_25.xml rename to demo/src/main/res/drawable/transparent_circle_25.xml diff --git a/library/src/main/res/drawable/transparent_circle_75.xml b/demo/src/main/res/drawable/transparent_circle_75.xml similarity index 100% rename from library/src/main/res/drawable/transparent_circle_75.xml rename to demo/src/main/res/drawable/transparent_circle_75.xml diff --git a/library/src/main/res/drawable/transparent_circle_selector.xml b/demo/src/main/res/drawable/transparent_circle_selector.xml similarity index 100% rename from library/src/main/res/drawable/transparent_circle_selector.xml rename to demo/src/main/res/drawable/transparent_circle_selector.xml diff --git a/library/src/main/res/layout/include_simple_camera.xml b/demo/src/main/res/layout/include_simple_camera.xml similarity index 100% rename from library/src/main/res/layout/include_simple_camera.xml rename to demo/src/main/res/layout/include_simple_camera.xml diff --git a/library/src/main/res/layout/simple_camera_layout.xml b/demo/src/main/res/layout/simple_camera_layout.xml similarity index 100% rename from library/src/main/res/layout/simple_camera_layout.xml rename to demo/src/main/res/layout/simple_camera_layout.xml diff --git a/library/src/main/res/menu/simple_camera_menu.xml b/demo/src/main/res/menu/simple_camera_menu.xml similarity index 97% rename from library/src/main/res/menu/simple_camera_menu.xml rename to demo/src/main/res/menu/simple_camera_menu.xml index 8f013d12..3ec120bb 100644 --- a/library/src/main/res/menu/simple_camera_menu.xml +++ b/demo/src/main/res/menu/simple_camera_menu.xml @@ -33,6 +33,6 @@ android:icon="@drawable/ic_switch_camera" android:title="@string/switch_camera" app:showAsAction="ifRoom" - android:visible="false"/> + android:visible="true"/> diff --git a/demo/src/main/res/values/colors.xml b/demo/src/main/res/values/colors.xml index 9bbf0348..666e33a7 100644 --- a/demo/src/main/res/values/colors.xml +++ b/demo/src/main/res/values/colors.xml @@ -17,4 +17,8 @@ #4CAF50 #212121 #727272 + + #40000000 + #BF000000 + diff --git a/demo/src/main/res/values/dimens.xml b/demo/src/main/res/values/dimens.xml index d65da19e..0e5f08d6 100644 --- a/demo/src/main/res/values/dimens.xml +++ b/demo/src/main/res/values/dimens.xml @@ -14,4 +14,5 @@ 16dp 16dp + 48dp diff --git a/demo/src/main/res/values/styles.xml b/demo/src/main/res/values/styles.xml index 3bc78ff2..61806d15 100644 --- a/demo/src/main/res/values/styles.xml +++ b/demo/src/main/res/values/styles.xml @@ -23,4 +23,27 @@ @color/secondaryText + + + + + + diff --git a/library/build.gradle b/library/build.gradle index 06d3b727..d804ec31 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -62,7 +62,7 @@ publishing { publications { aar(MavenPublication) { groupId 'premise.android.cameraview' - version '0.1.5' + version '0.2.0' artifactId 'cameraview' artifact("$buildDir/outputs/aar/${project.getName()}-release.aar") diff --git a/library/src/main/java/com/google/android/cameraview/AspectRatioFragment.java b/library/src/main/java/com/google/android/cameraview/AspectRatioFragment.java deleted file mode 100644 index 2b50206c..00000000 --- a/library/src/main/java/com/google/android/cameraview/AspectRatioFragment.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.cameraview; - -import android.app.Dialog; -import android.content.Context; -import android.content.DialogInterface; -import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v4.app.DialogFragment; -import android.support.v7.app.AlertDialog; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.BaseAdapter; -import android.widget.TextView; - -import java.util.Set; - - -/** - * A simple dialog that allows user to pick an aspect ratio. - */ -public class AspectRatioFragment extends DialogFragment { - - private static final String ARG_ASPECT_RATIOS = "aspect_ratios"; - private static final String ARG_CURRENT_ASPECT_RATIO = "current_aspect_ratio"; - - private Listener mListener; - - public static AspectRatioFragment newInstance(Set ratios, - AspectRatio currentRatio) { - final AspectRatioFragment fragment = new AspectRatioFragment(); - final Bundle args = new Bundle(); - args.putParcelableArray(ARG_ASPECT_RATIOS, - ratios.toArray(new AspectRatio[ratios.size()])); - args.putParcelable(ARG_CURRENT_ASPECT_RATIO, currentRatio); - fragment.setArguments(args); - return fragment; - } - - @Override - public void onAttach(Context context) { - super.onAttach(context); - mListener = (Listener) context; - } - - @Override - public void onDetach() { - mListener = null; - super.onDetach(); - } - - @NonNull - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - final Bundle args = getArguments(); - final AspectRatio[] ratios = (AspectRatio[]) args.getParcelableArray(ARG_ASPECT_RATIOS); - if (ratios == null) { - throw new RuntimeException("No ratios"); - } - final AspectRatio current = args.getParcelable(ARG_CURRENT_ASPECT_RATIO); - final AspectRatioAdapter adapter = new AspectRatioAdapter(ratios, current); - return new AlertDialog.Builder(getActivity()) - .setAdapter(adapter, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int position) { - mListener.onAspectRatioSelected(ratios[position]); - } - }) - .create(); - } - - private static class AspectRatioAdapter extends BaseAdapter { - - private final AspectRatio[] mRatios; - private final AspectRatio mCurrentRatio; - - AspectRatioAdapter(AspectRatio[] ratios, AspectRatio current) { - mRatios = ratios; - mCurrentRatio = current; - } - - @Override - public int getCount() { - return mRatios.length; - } - - @Override - public AspectRatio getItem(int position) { - return mRatios[position]; - } - - @Override - public long getItemId(int position) { - return getItem(position).hashCode(); - } - - @Override - public View getView(int position, View view, ViewGroup parent) { - AspectRatioAdapter.ViewHolder holder; - if (view == null) { - view = LayoutInflater.from(parent.getContext()) - .inflate(android.R.layout.simple_list_item_1, parent, false); - holder = new AspectRatioAdapter.ViewHolder(); - holder.text = (TextView) view.findViewById(android.R.id.text1); - view.setTag(holder); - } else { - holder = (AspectRatioAdapter.ViewHolder) view.getTag(); - } - AspectRatio ratio = getItem(position); - StringBuilder sb = new StringBuilder(ratio.toString()); - if (ratio.equals(mCurrentRatio)) { - sb.append(" *"); - } - holder.text.setText(sb); - return view; - } - - private static class ViewHolder { - TextView text; - } - - } - - public interface Listener { - void onAspectRatioSelected(@NonNull AspectRatio ratio); - } - -} diff --git a/library/src/main/java/com/premise.android.camera/SimpleCameraActivity.java b/library/src/main/java/com/premise.android.camera/SimpleCameraActivity.java deleted file mode 100644 index c4b90557..00000000 --- a/library/src/main/java/com/premise.android.camera/SimpleCameraActivity.java +++ /dev/null @@ -1,532 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.premise.android.camera; - -import static android.os.Build.VERSION.SDK_INT; - -import android.Manifest; -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.annotation.TargetApi; -import android.app.Dialog; -import android.content.DialogInterface; -import android.content.pm.ActivityInfo; -import android.content.pm.PackageManager; -import android.content.res.Configuration; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.media.MediaActionSound; -import android.os.Build; -import android.os.Bundle; -import android.os.Handler; -import android.os.HandlerThread; -import android.support.annotation.NonNull; -import android.support.annotation.StringRes; -import android.support.design.widget.FloatingActionButton; -import android.support.v4.app.ActivityCompat; -import android.support.v4.app.DialogFragment; -import android.support.v4.content.ContextCompat; -import android.support.v7.app.ActionBar; -import android.support.v7.app.AlertDialog; -import android.support.v7.app.AppCompatActivity; -import android.support.v7.widget.Toolbar; -import android.util.Log; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewAnimationUtils; -import android.widget.ImageView; -import android.widget.Toast; - -import com.google.android.cameraview.AspectRatio; -import com.google.android.cameraview.AspectRatioFragment; -import com.google.android.cameraview.CameraView; -import com.google.android.cameraview.R; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.util.Set; -import java.util.concurrent.CountDownLatch; - - -/** - * This demo app saves the taken picture to a constant file. - * $ adb pull /sdcard/Android/data/com.google.android.cameraview.demo/files/Pictures/picture.jpg - */ -public class SimpleCameraActivity extends AppCompatActivity implements - ActivityCompat.OnRequestPermissionsResultCallback, - AspectRatioFragment.Listener { - - private static final String TAG = "SimpleCameraActivity"; - - public static final String KEY_OUTPUT_PATH = "key_output_path"; - - private static final boolean DO_ANIM = true; - - private static final int REQUEST_CAMERA_PERMISSION = 1; - - private static final String FRAGMENT_DIALOG = "dialog"; - - private static final int[] FLASH_OPTIONS = { - CameraView.FLASH_OFF, - CameraView.FLASH_AUTO, - CameraView.FLASH_ON, - }; - - private static final int[] FLASH_ICONS = { - R.drawable.ic_flash_off, - R.drawable.ic_flash_auto, - R.drawable.ic_flash_on, - }; - - private static final int[] FLASH_TITLES = { - R.string.flash_off, - R.string.flash_auto, - R.string.flash_on, - }; - - private int mCurrentFlash; - - private CameraView mCameraView; - - private ImageView mCapturedImageView; - - private Handler mBackgroundHandler; - - private FloatingActionButton mTakePicButton; - - private CountDownLatch mCountDownLatch = new CountDownLatch(1); - - private MediaActionSound mSound; - - private Bitmap mBitmap; - - private String mOutputPath; - - private boolean mIsDestroyed; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.simple_camera_layout); - mCameraView = (CameraView) findViewById(R.id.camera); - if (mCameraView != null) { - mCameraView.addCallback(mCallback); - } - mTakePicButton = (FloatingActionButton) findViewById(R.id.take_picture); - mCapturedImageView = (ImageView)findViewById(R.id.captured_camera_image); - - Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); - setSupportActionBar(toolbar); - ActionBar actionBar = getSupportActionBar(); - if (actionBar != null) { - actionBar.setDisplayShowTitleEnabled(false); - } - initSound(); - if (getIntent() != null && getIntent().hasExtra(KEY_OUTPUT_PATH)) { - mOutputPath = getIntent().getStringExtra(KEY_OUTPUT_PATH); - } else { - throw new IllegalArgumentException("SimpleCameraActivity must be passed SimpleCameraActivity.KEY_OUTPUT_PATH"); - } - } - - private void initSound() { - if (SDK_INT >= 16) { - mSound = new MediaActionSound(); - } - } - - private void playSound() { - if (SDK_INT >= 16) { - if (mSound != null) { - mSound.play(MediaActionSound.SHUTTER_CLICK); - } - } - } - - private void releaseSound() { - if (SDK_INT >= 16) { - if (mSound != null) { - mSound.release(); - } - } - } - - @Override - protected void onResume() { - super.onResume(); - if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) - == PackageManager.PERMISSION_GRANTED) { - mCameraView.start(); - } else if (ActivityCompat.shouldShowRequestPermissionRationale(this, - Manifest.permission.CAMERA)) { - ConfirmationDialogFragment - .newInstance(R.string.camera_permission_confirmation, - new String[]{Manifest.permission.CAMERA}, - REQUEST_CAMERA_PERMISSION, - R.string.camera_permission_not_granted) - .show(getSupportFragmentManager(), FRAGMENT_DIALOG); - } else { - ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, - REQUEST_CAMERA_PERMISSION); - } - } - - @Override - protected void onPause() { - mCameraView.stop(); - super.onPause(); - } - - @Override - protected void onDestroy() { - mIsDestroyed = true; - if (mBackgroundHandler != null) { - if (SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { - mBackgroundHandler.getLooper().quitSafely(); - } else { - mBackgroundHandler.getLooper().quit(); - } - mBackgroundHandler = null; - } - if (mBitmap != null && !mBitmap.isRecycled()) { - mCapturedImageView.setImageDrawable(null); - mBitmap.recycle(); - } - releaseSound(); - mCameraView.removeCallback(mCallback); - super.onDestroy(); - } - - @Override - public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, - @NonNull int[] grantResults) { - switch (requestCode) { - case REQUEST_CAMERA_PERMISSION: - if (permissions.length != 1 || grantResults.length != 1) { - throw new RuntimeException("Error on requesting camera permission."); - } - if (grantResults[0] != PackageManager.PERMISSION_GRANTED) { - Toast.makeText(this, R.string.camera_permission_not_granted, - Toast.LENGTH_SHORT).show(); - } - // No need to start camera here; it is handled by onResume - break; - } - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - getMenuInflater().inflate(R.menu.simple_camera_menu, menu); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - - //cannot use resource ID in switch statements in android library projects - if (item.getItemId() == R.id.aspect_ratio) { - if (mCameraView != null) { - final Set ratios = mCameraView.getSupportedAspectRatios(); - final AspectRatio currentRatio = mCameraView.getAspectRatio(); - AspectRatioFragment.newInstance(ratios, currentRatio) - .show(getSupportFragmentManager(), FRAGMENT_DIALOG); - } - } else if (item.getItemId() == R.id.switch_flash) { - if (mCameraView != null) { - mCurrentFlash = (mCurrentFlash + 1) % FLASH_OPTIONS.length; - item.setTitle(FLASH_TITLES[mCurrentFlash]); - item.setIcon(FLASH_ICONS[mCurrentFlash]); - mCameraView.setFlash(FLASH_OPTIONS[mCurrentFlash]); - } - } else if (item.getItemId() == R.id.switch_camera) { - if (mCameraView != null) { - int facing = mCameraView.getFacing(); - mCameraView.setFacing(facing == CameraView.FACING_FRONT ? - CameraView.FACING_BACK : CameraView.FACING_FRONT); - } - } - return false; - } - - @Override - public void onAspectRatioSelected(@NonNull AspectRatio ratio) { - if (mCameraView != null) { - Toast.makeText(this, ratio.toString(), Toast.LENGTH_SHORT).show(); - mCameraView.setAspectRatio(ratio); - } - } - - private Handler getBackgroundHandler() { - if (mBackgroundHandler == null) { - HandlerThread thread = new HandlerThread("background"); - thread.start(); - mBackgroundHandler = new Handler(thread.getLooper()); - } - return mBackgroundHandler; - } - - private CameraView.Callback mCallback - = new CameraView.Callback() { - - @Override - public void onCameraOpened(CameraView cameraView) { - Log.d(TAG, "onCameraOpened"); - } - - @Override - public void onCameraClosed(CameraView cameraView) { - Log.d(TAG, "onCameraClosed"); - } - - @Override - public void onPictureTaken(CameraView cameraView, final byte[] data) { - Log.d(TAG, "onPictureTaken " + data.length); - //Toast.makeText(cameraView.getContext(), R.string.picture_taken, Toast.LENGTH_SHORT) - // .show(); - getBackgroundHandler().post(new Runnable() { - @Override - public void run() { - - if (isActivityDestroyed()) { //check: android image processing takes time - return; - } - OutputStream os = null; - File file = null; - try { - file = new File(mOutputPath); - os = new FileOutputStream(file); - os.write(data); // - os.close(); - if (isActivityDestroyed()) { //check: writing to disk takes time - return; - } - mBitmap = BitmapFactory.decodeFile(file.getAbsolutePath()); - if (Utils.bitmapNeedsRotating(SimpleCameraActivity.this,mBitmap)) { - mBitmap = Utils.fixBitmapOrientation(mBitmap, file); - } - if (isActivityDestroyed()) { //check: bitmap processing takes time - return; - } - mCountDownLatch.await(); - mCountDownLatch = new CountDownLatch(1); - if (isActivityDestroyed()) { //check: animation can take time - return; - } - runOnUiThread(new Runnable() { - @Override - public void run() { - if (isActivityDestroyed()) { //check: animation can take time - return; - } - revealCapturedImage(mBitmap); - } - }); - } catch (IOException e) { - Log.e(TAG, "(a) Cannot write to " + file, e); - showErrorToast(); - } catch (Exception e) { - Log.e(TAG, "(b) Exception occurred while writing image to disk", e); - showErrorToast(); - } finally { - if (os != null) { - try { - os.close(); - } catch (IOException e) { - // Ignore - } - } - } - } - }); - } - - }; - - private void showErrorToast() { - Toast.makeText(SimpleCameraActivity.this, - R.string.camera_failed_to_capture_image, - Toast.LENGTH_SHORT).show(); - } - - public static class ConfirmationDialogFragment extends DialogFragment { - - private static final String ARG_MESSAGE = "message"; - private static final String ARG_PERMISSIONS = "permissions"; - private static final String ARG_REQUEST_CODE = "request_code"; - private static final String ARG_NOT_GRANTED_MESSAGE = "not_granted_message"; - - public static ConfirmationDialogFragment newInstance(@StringRes int message, - String[] permissions, int requestCode, @StringRes int notGrantedMessage) { - ConfirmationDialogFragment fragment = new ConfirmationDialogFragment(); - Bundle args = new Bundle(); - args.putInt(ARG_MESSAGE, message); - args.putStringArray(ARG_PERMISSIONS, permissions); - args.putInt(ARG_REQUEST_CODE, requestCode); - args.putInt(ARG_NOT_GRANTED_MESSAGE, notGrantedMessage); - fragment.setArguments(args); - return fragment; - } - - @NonNull - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - final Bundle args = getArguments(); - return new AlertDialog.Builder(getActivity()) - .setMessage(args.getInt(ARG_MESSAGE)) - .setPositiveButton(android.R.string.ok, - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - String[] permissions = args.getStringArray(ARG_PERMISSIONS); - if (permissions == null) { - throw new IllegalArgumentException(); - } - ActivityCompat.requestPermissions(getActivity(), - permissions, args.getInt(ARG_REQUEST_CODE)); - } - }) - .setNegativeButton(android.R.string.cancel, - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - Toast.makeText(getActivity(), - args.getInt(ARG_NOT_GRANTED_MESSAGE), - Toast.LENGTH_SHORT).show(); - } - }) - .create(); - } - - } - - - private void setCameraButtonImage(final int imageRes) { - mTakePicButton.setImageResource(imageRes); - mTakePicButton.setEnabled(true); - Utils.expandFromCenter(mTakePicButton); - } - - @TargetApi(21) - private void revealCapturedImage(Bitmap bitmap) { - - Log.d(TAG, "revealCapturedImage"); - - setCameraButtonImage(R.drawable.ic_check_white_24dp); - if (SDK_INT < 21 || !DO_ANIM) { - mCapturedImageView.setVisibility(View.VISIBLE); - mCapturedImageView.setImageBitmap(bitmap); - return; - } - - int cx = mCapturedImageView.getMeasuredWidth() / 2; - int cy = mCapturedImageView.getMeasuredHeight() / 2; - - // get the final radius for the clipping circle - int finalRadius = Math.max(mCapturedImageView.getWidth(), mCapturedImageView.getHeight()) / 2; - - // create the animator for this view (the start radius is zero) - Animator anim = - ViewAnimationUtils.createCircularReveal(mCapturedImageView, cx, cy, 0, finalRadius); - - // make the view visible and start the animation - anim.start(); - mCapturedImageView.setVisibility(View.VISIBLE); - mCapturedImageView.setImageBitmap(bitmap); - } - - - - @TargetApi(21) - private void takePhoto() { - - playSound(); - mTakePicButton.setEnabled(false); - Utils.shrinkToCenter(mTakePicButton); - lockScreenOrientation(); - mCameraView.takePicture(); - - if (SDK_INT < 21 || !DO_ANIM) { - mCameraView.setVisibility(View.INVISIBLE); - mCountDownLatch.countDown(); - return; - } - - // get the center for the clipping circle - int cx = mCameraView.getMeasuredWidth() / 2; - int cy = mCameraView.getMeasuredHeight() / 2; - - // get the initial radius for the clipping circle - int initialRadius = mCameraView.getWidth() / 2; - - // create the animation (the final radius is zero) - final Animator anim = - ViewAnimationUtils.createCircularReveal(mCameraView, cx, cy, initialRadius, 0); - - // make the view invisible when the animation is done - anim.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - super.onAnimationEnd(animation); - mCameraView.setVisibility(View.INVISIBLE); - mCountDownLatch.countDown(); - anim.removeAllListeners(); - } - }); - - // start the animation - anim.start(); - } - - private void lockScreenOrientation() { - if (getResources().getConfiguration().orientation == Configuration - .ORIENTATION_LANDSCAPE) { - setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); //lock orientation - } else { - setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); - } - } - - /** - * Embedded in this layout, just finish activity - * @param view - */ - public void onBackClicked(View view) { - finish(); - } - - public void onCameraButtonClicked(View view) { - if (view.getId() == R.id.take_picture) { - if (mBitmap != null) { - setResult(RESULT_OK); - finish(); - } else { - takePhoto(); - } - } - } - - private boolean isActivityDestroyed() { - if (SDK_INT >= 17) { - return isDestroyed(); - } - return isFinishing() || mIsDestroyed; - } - -} \ No newline at end of file diff --git a/library/src/main/java/com/premise.android.camera/Utils.java b/library/src/main/java/com/premise.android.camera/Utils.java deleted file mode 100644 index 73c2f6a4..00000000 --- a/library/src/main/java/com/premise.android.camera/Utils.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.premise.android.camera; - -import static android.os.Build.VERSION.SDK_INT; - -import android.animation.Animator; -import android.annotation.TargetApi; -import android.content.Context; -import android.content.res.Configuration; -import android.graphics.Bitmap; -import android.graphics.Matrix; -import android.view.View; -import android.view.ViewAnimationUtils; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; - -/** - * Created by kevinkawai on 3/22/17. - */ - -class Utils { - - /** - * Expand the given invisible view from the center of itself until - * it is fully revealed. The view will be set to View.VISIBLE. - * If the platform is less than SDK_INT 21, then just set the - * view visibility to View.VISIBLE without the animation. - * - * @param view - */ - @TargetApi(21) - static void expandFromCenter(View view) { - - if (SDK_INT < 21) { - view.setVisibility(View.VISIBLE); - return; - } - - int cx = view.getMeasuredWidth() / 2; - int cy = view.getMeasuredHeight() / 2; - - // get the final radius for the clipping circle - int finalRadius = Math.max(view.getWidth(), view.getHeight()) / 2; - - // create the animator for this view (the start radius is zero) - Animator anim = - ViewAnimationUtils.createCircularReveal(view, cx, cy, 0, finalRadius); - - // make the view visible and start the animation - view.setVisibility(View.VISIBLE); - anim.start(); - } - - /** - * Shrink the given visible view to the center of itself until - * it is no longer visible. The view will be set to View.INVISIBLE. - * If the platform is less than SDK_INT 21, then just set the - * view visibility to View.INVISIBLE without the animation. - * - * @param view - */ - @TargetApi(21) - static void shrinkToCenter(final View view) { - - if (SDK_INT < 21) { - view.setVisibility(View.INVISIBLE); - return; - } - - // get the center for the clipping circle - int cx = view.getMeasuredWidth() / 2; - int cy = view.getMeasuredHeight() / 2; - - // get the initial radius for the clipping circle - int initialRadius = view.getWidth() / 2; - - // create the animation (the final radius is zero) - Animator anim = - ViewAnimationUtils.createCircularReveal(view, cx, cy, initialRadius, 0); - - - // start the animation - view.setVisibility(View.INVISIBLE); - anim.start(); - - } - - /** - * A fix for Samsung phones that have a hardware bug where all photos taken while - * the device is in portrait orientation are saved in landscape mode to disk. - * - * @param bitmap - * @param target - * @return - * @throws IOException - */ - static Bitmap fixBitmapOrientation(Bitmap bitmap, File target) throws IOException { - Matrix matrix = new Matrix(); - matrix.postRotate(90); - Bitmap rotatedBitmap = Bitmap.createBitmap(bitmap , 0, 0, - bitmap.getWidth(), bitmap.getHeight(), matrix, true); - bitmap.recycle(); - writeBitmapToFile(rotatedBitmap, target); - return rotatedBitmap; - } - - static boolean bitmapNeedsRotating(Context context, Bitmap bitmap) throws IOException { - if (context.getResources().getConfiguration().orientation == Configuration - .ORIENTATION_PORTRAIT) { - return bitmap.getWidth() > bitmap.getHeight(); - } - return false; - } - - static void writeBitmapToFile(final Bitmap inBitmap, final File file) throws - IOException { - - if (!file.exists()) { - file.getParentFile().mkdirs(); - } - final FileOutputStream fos = new FileOutputStream(file); - inBitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos); - fos.close(); - } - -} diff --git a/library/src/main/res/drawable/ic_aspect_ratio.xml b/library/src/main/res/drawable/ic_aspect_ratio.xml deleted file mode 100644 index 2c39cace..00000000 --- a/library/src/main/res/drawable/ic_aspect_ratio.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - diff --git a/library/src/main/res/drawable/ic_camera.xml b/library/src/main/res/drawable/ic_camera.xml deleted file mode 100644 index 14584648..00000000 --- a/library/src/main/res/drawable/ic_camera.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - diff --git a/library/src/main/res/drawable/ic_flash_auto.xml b/library/src/main/res/drawable/ic_flash_auto.xml deleted file mode 100644 index b4164042..00000000 --- a/library/src/main/res/drawable/ic_flash_auto.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - diff --git a/library/src/main/res/drawable/ic_flash_off.xml b/library/src/main/res/drawable/ic_flash_off.xml deleted file mode 100644 index cae6f0ca..00000000 --- a/library/src/main/res/drawable/ic_flash_off.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - diff --git a/library/src/main/res/drawable/ic_flash_on.xml b/library/src/main/res/drawable/ic_flash_on.xml deleted file mode 100644 index 3aad5f47..00000000 --- a/library/src/main/res/drawable/ic_flash_on.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - diff --git a/library/src/main/res/drawable/ic_switch_camera.xml b/library/src/main/res/drawable/ic_switch_camera.xml deleted file mode 100644 index bade6e71..00000000 --- a/library/src/main/res/drawable/ic_switch_camera.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - diff --git a/library/src/main/res/layout-land/simple_camera_layout.xml b/library/src/main/res/layout-land/simple_camera_layout.xml deleted file mode 100644 index 3d371506..00000000 --- a/library/src/main/res/layout-land/simple_camera_layout.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - - - diff --git a/library/src/main/res/values-w820dp/dimens.xml b/library/src/main/res/values-w820dp/dimens.xml deleted file mode 100644 index 648f774e..00000000 --- a/library/src/main/res/values-w820dp/dimens.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - 64dp - diff --git a/library/src/main/res/values/colors.xml b/library/src/main/res/values/colors.xml deleted file mode 100644 index 293aece1..00000000 --- a/library/src/main/res/values/colors.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - #3F51B5 - #303F9F - #4CAF50 - #212121 - #727272 - - #40000000 - #BF000000 - diff --git a/library/src/main/res/values/dimens.xml b/library/src/main/res/values/dimens.xml deleted file mode 100644 index 0e5f08d6..00000000 --- a/library/src/main/res/values/dimens.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - 16dp - 16dp - 48dp - diff --git a/library/src/main/res/values/public.xml b/library/src/main/res/values/public.xml index 84966fa6..ee0278e3 100644 --- a/library/src/main/res/values/public.xml +++ b/library/src/main/res/values/public.xml @@ -18,4 +18,5 @@ + diff --git a/library/src/main/res/values/strings.xml b/library/src/main/res/values/strings.xml deleted file mode 100644 index 0ba9bdad..00000000 --- a/library/src/main/res/values/strings.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - This app demonstrates the usage of CameraView. In order to do that, it needs permission to access camera. - Camera app cannot do anything without camera permission. - Picture taken - Aspect ratio - Switch flash - Switch camera - Flash auto - Flash off - Flash on - Sorry! Failed to capture image. Please try again. - diff --git a/library/src/main/res/values/styles.xml b/library/src/main/res/values/styles.xml index 838bf906..ba2ebd3b 100644 --- a/library/src/main/res/values/styles.xml +++ b/library/src/main/res/values/styles.xml @@ -1,36 +1,21 @@ + ~ Copyright (C) 2016 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> - - - - - - - From 74207962a7733aa20d5d780c3bebce2295c50e27 Mon Sep 17 00:00:00 2001 From: kevinkawai Date: Wed, 5 Apr 2017 13:00:00 -0700 Subject: [PATCH 36/42] 0.2.6 - fixed some memory leaks; fixed demo project --- demo/src/main/AndroidManifest.xml | 7 +--- .../android/cameraview/demo/MainActivity.java | 18 +++++++++ .../cameraview/demo/MainActivity2.java | 31 --------------- library/build.gradle | 2 +- .../google/android/cameraview/CameraView.java | 39 ++++++++++++------- 5 files changed, 46 insertions(+), 51 deletions(-) delete mode 100644 demo/src/main/java/com/google/android/cameraview/demo/MainActivity2.java diff --git a/demo/src/main/AndroidManifest.xml b/demo/src/main/AndroidManifest.xml index 4a63c213..291905d3 100644 --- a/demo/src/main/AndroidManifest.xml +++ b/demo/src/main/AndroidManifest.xml @@ -25,17 +25,14 @@ android:supportsRtl="true" android:theme="@style/Theme.Demo"> - + - - - diff --git a/demo/src/main/java/com/google/android/cameraview/demo/MainActivity.java b/demo/src/main/java/com/google/android/cameraview/demo/MainActivity.java index aae59e04..45696011 100644 --- a/demo/src/main/java/com/google/android/cameraview/demo/MainActivity.java +++ b/demo/src/main/java/com/google/android/cameraview/demo/MainActivity.java @@ -25,6 +25,7 @@ import android.os.Environment; import android.os.Handler; import android.os.HandlerThread; +import android.os.StrictMode; import android.support.annotation.NonNull; import android.support.annotation.StringRes; import android.support.design.widget.FloatingActionButton; @@ -39,6 +40,7 @@ import android.util.Log; import android.view.Menu; import android.view.MenuItem; +import android.view.TextureView; import android.view.View; import android.widget.RelativeLayout; import android.widget.Toast; @@ -112,6 +114,18 @@ public void onClick(View v) { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); + + StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder() + .detectNetwork() + .penaltyLog() + .build()); + StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder() + .detectLeakedSqlLiteObjects() + .detectLeakedClosableObjects() + .detectActivityLeaks() + .penaltyLog() + .build()); + mRootView = findViewById(R.id.root_view); mCameraView = (CameraView) findViewById(R.id.camera); if (mCameraView != null) { @@ -157,6 +171,10 @@ protected void onPause() { @Override protected void onDestroy() { + TextureView textureView = (TextureView)mCameraView.findViewById(R.id.texture_view); + textureView.getSurfaceTexture().setOnFrameAvailableListener(null); + textureView.getSurfaceTexture().release(); + textureView.setSurfaceTextureListener(null); super.onDestroy(); if (mBackgroundHandler != null) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { diff --git a/demo/src/main/java/com/google/android/cameraview/demo/MainActivity2.java b/demo/src/main/java/com/google/android/cameraview/demo/MainActivity2.java deleted file mode 100644 index 692c5a3b..00000000 --- a/demo/src/main/java/com/google/android/cameraview/demo/MainActivity2.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.android.cameraview.demo; - -import android.os.Bundle; -import android.support.annotation.Nullable; -import android.support.v7.app.AppCompatActivity; - - -public class MainActivity2 extends AppCompatActivity { - - private static final int REQ_CODE = 1; - @Override - protected void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - } -} diff --git a/library/build.gradle b/library/build.gradle index d804ec31..2315d496 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -62,7 +62,7 @@ publishing { publications { aar(MavenPublication) { groupId 'premise.android.cameraview' - version '0.2.0' + version '0.2.6' artifactId 'cameraview' artifact("$buildDir/outputs/aar/${project.getName()}-release.aar") diff --git a/library/src/main/java/com/google/android/cameraview/CameraView.java b/library/src/main/java/com/google/android/cameraview/CameraView.java index 04826d84..81d0c5bb 100644 --- a/library/src/main/java/com/google/android/cameraview/CameraView.java +++ b/library/src/main/java/com/google/android/cameraview/CameraView.java @@ -16,10 +16,11 @@ package com.google.android.cameraview; +import static android.os.Build.VERSION.SDK_INT; + import android.app.Activity; import android.content.Context; import android.content.res.TypedArray; -import android.os.Build; import android.os.Parcel; import android.os.Parcelable; import android.support.annotation.IntDef; @@ -95,14 +96,15 @@ public CameraView(Context context, AttributeSet attrs, int defStyleAttr) { return; } // Internal setup - final PreviewImpl preview = createPreviewImpl(context); - mCallbacks = new CallbackBridge(); - if (Build.VERSION.SDK_INT < 21) { + PreviewImpl preview = createPreviewImpl(context); + mCallbacks = new CallbackBridge(this); + final Context applicationContext = context.getApplicationContext(); + if (SDK_INT < 21) { mImpl = new Camera1(mCallbacks, preview); - } else if (Build.VERSION.SDK_INT < 23) { - mImpl = new Camera2(mCallbacks, preview, context); + } else if (SDK_INT < 23) { + mImpl = new Camera2(mCallbacks, preview, applicationContext); } else { - mImpl = new Camera2Api23(mCallbacks, preview, context); + mImpl = new Camera2Api23(mCallbacks, preview, applicationContext); } // Attributes TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CameraView, defStyleAttr, @@ -130,7 +132,7 @@ public void onDisplayOrientationChanged(int displayOrientation) { @NonNull private PreviewImpl createPreviewImpl(Context context) { PreviewImpl preview; - if (Build.VERSION.SDK_INT < 14) { + if (SDK_INT < 14) { preview = new SurfaceViewPreview(context, this); } else { preview = new TextureViewPreview(context, this); @@ -152,6 +154,7 @@ protected void onDetachedFromWindow() { mDisplayOrientationDetector.disable(); } super.onDetachedFromWindow(); + mCallbacks.cleanup(); } @Override @@ -407,13 +410,15 @@ public void takePicture() { mImpl.takePicture(); } - private class CallbackBridge implements CameraViewImpl.Callback { + private static class CallbackBridge implements CameraViewImpl.Callback { private final ArrayList mCallbacks = new ArrayList<>(); private boolean mRequestLayoutOnOpen; + private CameraView cameraView; - CallbackBridge() { + CallbackBridge(CameraView cameraView) { + this.cameraView = cameraView; } public void add(Callback callback) { @@ -428,30 +433,35 @@ public void remove(Callback callback) { public void onCameraOpened() { if (mRequestLayoutOnOpen) { mRequestLayoutOnOpen = false; - requestLayout(); + cameraView.requestLayout(); } for (Callback callback : mCallbacks) { - callback.onCameraOpened(CameraView.this); + callback.onCameraOpened(cameraView); } } @Override public void onCameraClosed() { for (Callback callback : mCallbacks) { - callback.onCameraClosed(CameraView.this); + callback.onCameraClosed(cameraView); } } @Override public void onPictureTaken(byte[] data) { for (Callback callback : mCallbacks) { - callback.onPictureTaken(CameraView.this, data); + callback.onPictureTaken(cameraView, data); } } public void reserveRequestLayoutOnOpen() { mRequestLayoutOnOpen = true; } + + private void cleanup() { + cameraView = null; + mCallbacks.clear(); + } } protected static class SavedState extends BaseSavedState { @@ -535,6 +545,7 @@ public void onCameraClosed(CameraView cameraView) { */ public void onPictureTaken(CameraView cameraView, byte[] data) { } + } } From e096d9668d4dcbc05e1dc1a5f236bc514d534b27 Mon Sep 17 00:00:00 2001 From: kevinkawai Date: Wed, 12 Apr 2017 10:58:21 -0700 Subject: [PATCH 37/42] 0.2.7 - pulled in the fix for front-facing camera; added weak reference for CallbackBridge; upgraded version to 0.2.7 --- library/build.gradle | 2 +- .../cameraview/TextureViewPreview.java | 2 ++ .../google/android/cameraview/CameraView.java | 31 ++++++++++++++----- 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/library/build.gradle b/library/build.gradle index 2315d496..cdbf503e 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -62,7 +62,7 @@ publishing { publications { aar(MavenPublication) { groupId 'premise.android.cameraview' - version '0.2.6' + version '0.2.7' artifactId 'cameraview' artifact("$buildDir/outputs/aar/${project.getName()}-release.aar") diff --git a/library/src/main/api14/com/google/android/cameraview/TextureViewPreview.java b/library/src/main/api14/com/google/android/cameraview/TextureViewPreview.java index d2f6dc61..8d3d550c 100644 --- a/library/src/main/api14/com/google/android/cameraview/TextureViewPreview.java +++ b/library/src/main/api14/com/google/android/cameraview/TextureViewPreview.java @@ -134,6 +134,8 @@ void configureTransform() { 0.f, height, // bottom right }, 0, 4); + } else if (mDisplayOrientation == 180) { + matrix.postRotate(180, getWidth() / 2, getHeight() / 2); } mTextureView.setTransform(matrix); } diff --git a/library/src/main/java/com/google/android/cameraview/CameraView.java b/library/src/main/java/com/google/android/cameraview/CameraView.java index 81d0c5bb..79b61781 100644 --- a/library/src/main/java/com/google/android/cameraview/CameraView.java +++ b/library/src/main/java/com/google/android/cameraview/CameraView.java @@ -30,15 +30,19 @@ import android.support.v4.os.ParcelableCompatCreatorCallbacks; import android.support.v4.view.ViewCompat; import android.util.AttributeSet; +import android.util.Log; import android.widget.FrameLayout; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Set; public class CameraView extends FrameLayout { + private static final String TAG = "CameraView"; + /** The camera device faces the opposite direction as the device's screen. */ public static final int FACING_BACK = Constants.FACING_BACK; @@ -415,10 +419,10 @@ private static class CallbackBridge implements CameraViewImpl.Callback { private final ArrayList mCallbacks = new ArrayList<>(); private boolean mRequestLayoutOnOpen; - private CameraView cameraView; + private WeakReference cameraView; CallbackBridge(CameraView cameraView) { - this.cameraView = cameraView; + this.cameraView = new WeakReference<>(cameraView); } public void add(Callback callback) { @@ -433,24 +437,38 @@ public void remove(Callback callback) { public void onCameraOpened() { if (mRequestLayoutOnOpen) { mRequestLayoutOnOpen = false; - cameraView.requestLayout(); + if (cameraView.get() != null) { + cameraView.get().requestLayout(); + } } for (Callback callback : mCallbacks) { - callback.onCameraOpened(cameraView); + try { + callback.onCameraOpened(cameraView.get()); + }catch (Throwable t) { + Log.e(TAG,"onCameraOpened() failed",t); + } } } @Override public void onCameraClosed() { for (Callback callback : mCallbacks) { - callback.onCameraClosed(cameraView); + try { + callback.onCameraClosed(cameraView.get()); + }catch (Throwable t) { + Log.e(TAG,"onCameraClosed() failed",t); + } } } @Override public void onPictureTaken(byte[] data) { for (Callback callback : mCallbacks) { - callback.onPictureTaken(cameraView, data); + try { + callback.onPictureTaken(cameraView.get(), data); + }catch (Throwable t) { + Log.e(TAG,"onPictureTaken() failed",t); + } } } @@ -459,7 +477,6 @@ public void reserveRequestLayoutOnOpen() { } private void cleanup() { - cameraView = null; mCallbacks.clear(); } } From 00e88009cd481ab73436a7d63346db051454158d Mon Sep 17 00:00:00 2001 From: kevinkawai Date: Wed, 12 Apr 2017 11:25:42 -0700 Subject: [PATCH 38/42] 0.2.8 - reverted all the changes to 'demo' project back to original google/cameraview --- demo/src/main/AndroidManifest.xml | 3 +- .../android/cameraview/demo/MainActivity.java | 18 -------- .../transparent_circle_selector.xml | 18 -------- .../drawable-xxxhdpi/ic_check_white_24dp.png | Bin 308 -> 0 bytes .../ic_keyboard_backspace_white_24dp.png | Bin 222 -> 0 bytes .../res/drawable/transparent_circle_25.xml | 6 --- .../res/drawable/transparent_circle_75.xml | 6 --- .../drawable/transparent_circle_selector.xml | 7 --- .../main/res/layout-land/activity_main.xml | 2 +- demo/src/main/res/layout/include_camera.xml | 3 +- .../main/res/layout/include_simple_camera.xml | 40 ------------------ .../main/res/layout/simple_camera_layout.xml | 34 --------------- demo/src/main/res/menu/simple_camera_menu.xml | 38 ----------------- demo/src/main/res/values/colors.xml | 4 -- demo/src/main/res/values/dimens.xml | 1 - demo/src/main/res/values/styles.xml | 23 ---------- 16 files changed, 3 insertions(+), 200 deletions(-) delete mode 100644 demo/src/main/res/drawable-v21/transparent_circle_selector.xml delete mode 100644 demo/src/main/res/drawable-xxxhdpi/ic_check_white_24dp.png delete mode 100644 demo/src/main/res/drawable-xxxhdpi/ic_keyboard_backspace_white_24dp.png delete mode 100644 demo/src/main/res/drawable/transparent_circle_25.xml delete mode 100644 demo/src/main/res/drawable/transparent_circle_75.xml delete mode 100644 demo/src/main/res/drawable/transparent_circle_selector.xml delete mode 100644 demo/src/main/res/layout/include_simple_camera.xml delete mode 100644 demo/src/main/res/layout/simple_camera_layout.xml delete mode 100644 demo/src/main/res/menu/simple_camera_menu.xml diff --git a/demo/src/main/AndroidManifest.xml b/demo/src/main/AndroidManifest.xml index 291905d3..97012d47 100644 --- a/demo/src/main/AndroidManifest.xml +++ b/demo/src/main/AndroidManifest.xml @@ -25,8 +25,7 @@ android:supportsRtl="true" android:theme="@style/Theme.Demo"> - + diff --git a/demo/src/main/java/com/google/android/cameraview/demo/MainActivity.java b/demo/src/main/java/com/google/android/cameraview/demo/MainActivity.java index 45696011..aae59e04 100644 --- a/demo/src/main/java/com/google/android/cameraview/demo/MainActivity.java +++ b/demo/src/main/java/com/google/android/cameraview/demo/MainActivity.java @@ -25,7 +25,6 @@ import android.os.Environment; import android.os.Handler; import android.os.HandlerThread; -import android.os.StrictMode; import android.support.annotation.NonNull; import android.support.annotation.StringRes; import android.support.design.widget.FloatingActionButton; @@ -40,7 +39,6 @@ import android.util.Log; import android.view.Menu; import android.view.MenuItem; -import android.view.TextureView; import android.view.View; import android.widget.RelativeLayout; import android.widget.Toast; @@ -114,18 +112,6 @@ public void onClick(View v) { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); - - StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder() - .detectNetwork() - .penaltyLog() - .build()); - StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder() - .detectLeakedSqlLiteObjects() - .detectLeakedClosableObjects() - .detectActivityLeaks() - .penaltyLog() - .build()); - mRootView = findViewById(R.id.root_view); mCameraView = (CameraView) findViewById(R.id.camera); if (mCameraView != null) { @@ -171,10 +157,6 @@ protected void onPause() { @Override protected void onDestroy() { - TextureView textureView = (TextureView)mCameraView.findViewById(R.id.texture_view); - textureView.getSurfaceTexture().setOnFrameAvailableListener(null); - textureView.getSurfaceTexture().release(); - textureView.setSurfaceTextureListener(null); super.onDestroy(); if (mBackgroundHandler != null) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { diff --git a/demo/src/main/res/drawable-v21/transparent_circle_selector.xml b/demo/src/main/res/drawable-v21/transparent_circle_selector.xml deleted file mode 100644 index 2bace96c..00000000 --- a/demo/src/main/res/drawable-v21/transparent_circle_selector.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/demo/src/main/res/drawable-xxxhdpi/ic_check_white_24dp.png b/demo/src/main/res/drawable-xxxhdpi/ic_check_white_24dp.png deleted file mode 100644 index d670618c7e96225f7756cb4c2743e7ebbf688cf8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 308 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD0wg^q?%xcgetWt&hE&{od;P3vlYxj!B3Hnh z1714EonD+``t$ZU)3IJ|2aboi6~%ilJM7!-={Kv*@R&q$518Ox)_m^XpXp1^&DOu% zB6r^~@kqJ%j0e`LXFkL-JviL|Ir_(khlktwLa#r83bn@|VwIw^gKjzH(>hUq>tlAsh9~)aj{(R+p z`Qx=v&?j!r?}<)Pb+Jxa|B9Td>MRd7#ru4CATBh=u6rtH zmheyi(zeUVX70%fE=B8Ws}kysp9ir5)iO-}8hbzWynM;c&%wg8es*#${+Y?C|BV0J z&CmLOkJWrWYknU}q|f=!{P43nt4`*>mWI@`|BpBPP~Otyy{9R?gjIef3um! - - - \ No newline at end of file diff --git a/demo/src/main/res/drawable/transparent_circle_75.xml b/demo/src/main/res/drawable/transparent_circle_75.xml deleted file mode 100644 index 2cca90df..00000000 --- a/demo/src/main/res/drawable/transparent_circle_75.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - \ No newline at end of file diff --git a/demo/src/main/res/drawable/transparent_circle_selector.xml b/demo/src/main/res/drawable/transparent_circle_selector.xml deleted file mode 100644 index 39d73375..00000000 --- a/demo/src/main/res/drawable/transparent_circle_selector.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/demo/src/main/res/layout-land/activity_main.xml b/demo/src/main/res/layout-land/activity_main.xml index b825bc72..08deb02d 100644 --- a/demo/src/main/res/layout-land/activity_main.xml +++ b/demo/src/main/res/layout-land/activity_main.xml @@ -23,7 +23,7 @@ tools:context=".MainActivity"> diff --git a/demo/src/main/res/layout/include_camera.xml b/demo/src/main/res/layout/include_camera.xml index d83a51aa..499f21a6 100644 --- a/demo/src/main/res/layout/include_camera.xml +++ b/demo/src/main/res/layout/include_camera.xml @@ -26,7 +26,6 @@ - + android:layout_height="?attr/actionBarSize"/> diff --git a/demo/src/main/res/layout/include_simple_camera.xml b/demo/src/main/res/layout/include_simple_camera.xml deleted file mode 100644 index 42232eba..00000000 --- a/demo/src/main/res/layout/include_simple_camera.xml +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - diff --git a/demo/src/main/res/layout/simple_camera_layout.xml b/demo/src/main/res/layout/simple_camera_layout.xml deleted file mode 100644 index b454bd2b..00000000 --- a/demo/src/main/res/layout/simple_camera_layout.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - - - diff --git a/demo/src/main/res/menu/simple_camera_menu.xml b/demo/src/main/res/menu/simple_camera_menu.xml deleted file mode 100644 index 3ec120bb..00000000 --- a/demo/src/main/res/menu/simple_camera_menu.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - diff --git a/demo/src/main/res/values/colors.xml b/demo/src/main/res/values/colors.xml index 666e33a7..9bbf0348 100644 --- a/demo/src/main/res/values/colors.xml +++ b/demo/src/main/res/values/colors.xml @@ -17,8 +17,4 @@ #4CAF50 #212121 #727272 - - #40000000 - #BF000000 - diff --git a/demo/src/main/res/values/dimens.xml b/demo/src/main/res/values/dimens.xml index 0e5f08d6..d65da19e 100644 --- a/demo/src/main/res/values/dimens.xml +++ b/demo/src/main/res/values/dimens.xml @@ -14,5 +14,4 @@ 16dp 16dp - 48dp diff --git a/demo/src/main/res/values/styles.xml b/demo/src/main/res/values/styles.xml index 61806d15..3bc78ff2 100644 --- a/demo/src/main/res/values/styles.xml +++ b/demo/src/main/res/values/styles.xml @@ -23,27 +23,4 @@ @color/secondaryText - - - - - - From 17eb0399fc42e096263aa41aa6f7c99ce66804bf Mon Sep 17 00:00:00 2001 From: kevinkawai Date: Wed, 12 Apr 2017 11:26:37 -0700 Subject: [PATCH 39/42] 0.2.8 - updated library version --- library/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/build.gradle b/library/build.gradle index cdbf503e..7f58364e 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -62,7 +62,7 @@ publishing { publications { aar(MavenPublication) { groupId 'premise.android.cameraview' - version '0.2.7' + version '0.2.8' artifactId 'cameraview' artifact("$buildDir/outputs/aar/${project.getName()}-release.aar") From 16f05e260c4fc2bbacb5b1b612d46ee3e71421da Mon Sep 17 00:00:00 2001 From: kevinkawai Date: Wed, 12 Apr 2017 11:59:43 -0700 Subject: [PATCH 40/42] 0.2.8 - simplified code to be as similar as possible to the original google cameraview so comparisons are easier --- library/build.gradle | 2 - .../google/android/cameraview/CameraView.java | 49 ++++++------------- library/src/main/res/values/public.xml | 1 - library/src/main/res/values/styles.xml | 25 +++++----- 4 files changed, 26 insertions(+), 51 deletions(-) diff --git a/library/build.gradle b/library/build.gradle index 7f58364e..4834f895 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -24,7 +24,6 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion testInstrumentationRunner 'android.support.test.runner.AndroidJUnitRunner' - vectorDrawables.useSupportLibrary = true } buildTypes { release { @@ -73,7 +72,6 @@ publishing { dependencies { compile "com.android.support:support-annotations:$supportLibraryVersion" compile "com.android.support:support-v4:$supportLibraryVersion" - compile "com.android.support:design:$supportLibraryVersion" // Tests testCompile 'junit:junit:4.12' diff --git a/library/src/main/java/com/google/android/cameraview/CameraView.java b/library/src/main/java/com/google/android/cameraview/CameraView.java index 79b61781..a2ef8d37 100644 --- a/library/src/main/java/com/google/android/cameraview/CameraView.java +++ b/library/src/main/java/com/google/android/cameraview/CameraView.java @@ -16,11 +16,10 @@ package com.google.android.cameraview; -import static android.os.Build.VERSION.SDK_INT; - import android.app.Activity; import android.content.Context; import android.content.res.TypedArray; +import android.os.Build; import android.os.Parcel; import android.os.Parcelable; import android.support.annotation.IntDef; @@ -30,7 +29,6 @@ import android.support.v4.os.ParcelableCompatCreatorCallbacks; import android.support.v4.view.ViewCompat; import android.util.AttributeSet; -import android.util.Log; import android.widget.FrameLayout; import java.lang.annotation.Retention; @@ -41,8 +39,6 @@ public class CameraView extends FrameLayout { - private static final String TAG = "CameraView"; - /** The camera device faces the opposite direction as the device's screen. */ public static final int FACING_BACK = Constants.FACING_BACK; @@ -100,15 +96,14 @@ public CameraView(Context context, AttributeSet attrs, int defStyleAttr) { return; } // Internal setup - PreviewImpl preview = createPreviewImpl(context); + final PreviewImpl preview = createPreviewImpl(context); mCallbacks = new CallbackBridge(this); - final Context applicationContext = context.getApplicationContext(); - if (SDK_INT < 21) { + if (Build.VERSION.SDK_INT < 21) { mImpl = new Camera1(mCallbacks, preview); - } else if (SDK_INT < 23) { - mImpl = new Camera2(mCallbacks, preview, applicationContext); + } else if (Build.VERSION.SDK_INT < 23) { + mImpl = new Camera2(mCallbacks, preview, context.getApplicationContext()); } else { - mImpl = new Camera2Api23(mCallbacks, preview, applicationContext); + mImpl = new Camera2Api23(mCallbacks, preview, context.getApplicationContext()); } // Attributes TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CameraView, defStyleAttr, @@ -136,7 +131,7 @@ public void onDisplayOrientationChanged(int displayOrientation) { @NonNull private PreviewImpl createPreviewImpl(Context context) { PreviewImpl preview; - if (SDK_INT < 14) { + if (Build.VERSION.SDK_INT < 14) { preview = new SurfaceViewPreview(context, this); } else { preview = new TextureViewPreview(context, this); @@ -158,7 +153,9 @@ protected void onDetachedFromWindow() { mDisplayOrientationDetector.disable(); } super.onDetachedFromWindow(); - mCallbacks.cleanup(); + if (mCallbacks != null && mCallbacks.mCallbacks != null) { + mCallbacks.mCallbacks.clear(); + } } @Override @@ -419,6 +416,7 @@ private static class CallbackBridge implements CameraViewImpl.Callback { private final ArrayList mCallbacks = new ArrayList<>(); private boolean mRequestLayoutOnOpen; + private WeakReference cameraView; CallbackBridge(CameraView cameraView) { @@ -442,43 +440,27 @@ public void onCameraOpened() { } } for (Callback callback : mCallbacks) { - try { - callback.onCameraOpened(cameraView.get()); - }catch (Throwable t) { - Log.e(TAG,"onCameraOpened() failed",t); - } + callback.onCameraOpened(cameraView.get()); } } @Override public void onCameraClosed() { for (Callback callback : mCallbacks) { - try { - callback.onCameraClosed(cameraView.get()); - }catch (Throwable t) { - Log.e(TAG,"onCameraClosed() failed",t); - } + callback.onCameraClosed(cameraView.get()); } } @Override public void onPictureTaken(byte[] data) { for (Callback callback : mCallbacks) { - try { - callback.onPictureTaken(cameraView.get(), data); - }catch (Throwable t) { - Log.e(TAG,"onPictureTaken() failed",t); - } + callback.onPictureTaken(cameraView.get(), data); } } public void reserveRequestLayoutOnOpen() { mRequestLayoutOnOpen = true; } - - private void cleanup() { - mCallbacks.clear(); - } } protected static class SavedState extends BaseSavedState { @@ -515,7 +497,7 @@ public void writeToParcel(Parcel out, int flags) { out.writeInt(flash); } - public static final Parcelable.Creator CREATOR + public static final Creator CREATOR = ParcelableCompat.newCreator(new ParcelableCompatCreatorCallbacks() { @Override @@ -562,7 +544,6 @@ public void onCameraClosed(CameraView cameraView) { */ public void onPictureTaken(CameraView cameraView, byte[] data) { } - } } diff --git a/library/src/main/res/values/public.xml b/library/src/main/res/values/public.xml index ee0278e3..84966fa6 100644 --- a/library/src/main/res/values/public.xml +++ b/library/src/main/res/values/public.xml @@ -18,5 +18,4 @@ - diff --git a/library/src/main/res/values/styles.xml b/library/src/main/res/values/styles.xml index ba2ebd3b..6ded7168 100644 --- a/library/src/main/res/values/styles.xml +++ b/library/src/main/res/values/styles.xml @@ -1,19 +1,16 @@ + Copyright (C) 2016 The Android Open Source Project + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +-->