├── .gitignore ├── README.md ├── app ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── hai │ │ └── picker │ │ ├── App.java │ │ └── MainActivity.java │ └── res │ ├── mipmap-hdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-mdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── values-zh-rCN │ └── strings.xml │ └── values │ ├── colors.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── cameraview ├── .gitignore ├── build.gradle └── src │ ├── androidTest │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── google │ │ │ └── android │ │ │ └── cameraview │ │ │ ├── AspectRatioInstrumentationTest.java │ │ │ ├── AspectRatioIsCloseTo.java │ │ │ ├── CameraViewActions.java │ │ │ ├── CameraViewActivity.java │ │ │ ├── CameraViewMatchers.java │ │ │ └── CameraViewTest.java │ └── res │ │ └── layout │ │ └── activity_camera_view.xml │ ├── main │ ├── AndroidManifest.xml │ ├── api14 │ │ └── com │ │ │ └── google │ │ │ └── android │ │ │ └── cameraview │ │ │ ├── Camera1.java │ │ │ └── TextureViewPreview.java │ ├── api21 │ │ └── com │ │ │ └── google │ │ │ └── android │ │ │ └── cameraview │ │ │ └── Camera2.java │ ├── api23 │ │ └── com │ │ │ └── google │ │ │ └── android │ │ │ └── cameraview │ │ │ └── Camera2Api23.java │ ├── api9 │ │ └── com │ │ │ └── google │ │ │ └── android │ │ │ └── cameraview │ │ │ └── SurfaceViewPreview.java │ ├── base │ │ └── com │ │ │ └── google │ │ │ └── android │ │ │ └── cameraview │ │ │ ├── AspectRatio.java │ │ │ ├── CameraViewImpl.java │ │ │ ├── Constants.java │ │ │ ├── PreviewImpl.java │ │ │ ├── Size.java │ │ │ └── SizeMap.java │ ├── java │ │ └── com │ │ │ └── google │ │ │ └── android │ │ │ └── cameraview │ │ │ ├── CameraView.java │ │ │ └── DisplayOrientationDetector.java │ └── res │ │ ├── layout-v14 │ │ └── texture_view.xml │ │ ├── layout │ │ └── surface_view.xml │ │ └── values │ │ ├── attrs.xml │ │ ├── public.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── google │ └── android │ └── cameraview │ ├── AspectRatioTest.java │ ├── SizeMapTest.java │ └── SizeTest.java ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── jitpack.xml ├── local.properties ├── settings.gradle ├── shotcuts ├── device-2017-03-20-112104.png ├── device-2017-03-20-112114.png ├── device-2017-03-20-112128.png ├── device-2017-03-20-112139.png ├── device-2017-06-15-141529.png ├── device-2017-06-15-141549.png └── device-2017-06-15-141606.png └── uikit ├── build.gradle ├── proguard-rules.pro └── src └── main ├── AndroidManifest.xml ├── api14 └── com │ └── google │ └── android │ └── cameraview │ ├── Camera1.java │ └── TextureViewPreview.java ├── api21 └── com │ └── google │ └── android │ └── cameraview │ └── Camera2.java ├── api23 └── com │ └── google │ └── android │ └── cameraview │ └── Camera2Api23.java ├── api9 └── com │ └── google │ └── android │ └── cameraview │ └── SurfaceViewPreview.java ├── base └── com │ └── google │ └── android │ └── cameraview │ ├── AspectRatio.java │ ├── CameraViewImpl.java │ ├── Constants.java │ ├── PreviewImpl.java │ ├── Size.java │ └── SizeMap.java ├── java └── com │ ├── google │ └── android │ │ └── cameraview │ │ ├── CameraView.java │ │ └── DisplayOrientationDetector.java │ └── hai │ └── mediapicker │ ├── activity │ ├── AlbumActivity.java │ ├── CaptureActivity.java │ ├── CaptureActivity2.java │ ├── MediaPickerActivity.java │ ├── PreviewActivity.java │ └── VideoPlayer.java │ ├── adapter │ ├── GalleryAdapter.java │ └── PopupDirectoryListAdapter.java │ ├── decoration │ └── SpaceItemDecoration.java │ ├── entity │ ├── Photo.java │ └── PhotoDirectory.java │ ├── save │ ├── BaseSaver.java │ └── ISaver.java │ ├── util │ ├── GalleryFinal.java │ ├── MediaManager.java │ ├── MediaStoreHelper.java │ └── MemoryLeakUtil.java │ ├── view │ ├── PopupWindowMenu.java │ ├── RingProgress.java │ ├── SquareImageView.java │ └── TouchImageView.java │ └── viewholder │ └── GalleryHolder.java └── res ├── anim ├── push_bottom_in.xml └── push_bottom_out.xml ├── drawable ├── btn_dropdown.xml ├── btn_send_bg.xml ├── circle_with_221.xml ├── circle_with_white.xml └── picker_item_bg.xml ├── layout-v14 └── texture_view.xml ├── layout ├── activity_capture.xml ├── activity_capture2.xml ├── activity_media_picker.xml ├── activity_preview.xml ├── activity_video_player.xml ├── empty_media.xml ├── gallery_image_item.xml ├── gallery_video_item.xml ├── pop_directory_item.xml ├── preview_image_item.xml ├── preview_video_item.xml └── surface_view.xml ├── mipmap-xhdpi └── ic_save.png ├── mipmap-xxhdpi ├── ic_cancel.png ├── ic_check_dir.png ├── ic_directory_folder.9.png ├── ic_media_empty.png ├── ic_ok.png ├── ic_switch_camera.png ├── ic_video_flag.png ├── ic_video_play.png ├── selector_indicator_normal.png └── selector_indicator_pressed.png ├── values-zh-rCN └── strings.xml └── values ├── attr.xml ├── dimens.xml ├── ids.xml ├── public.xml ├── strings.xml └── style.xml /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /.idea/workspace.xml 4 | /.idea/libraries 5 | .DS_Store 6 | /build 7 | /captures 8 | .externalNativeBuild 9 | build 10 | build/* 11 | .gradle/* 12 | .idea 13 | .idea/* 14 | */*.iml 15 | */~lock* 16 | *.apk 17 | */*/*.apk 18 | */*# 19 | *.xml~* 20 | out/ 21 | pttsdk.iml 22 | workspace.xml 23 | app/build/* 24 | app/app.iml 25 | app/build/* 26 | app/app.iml 27 | 28 | uikit/build/* 29 | uikit/uikit.iml 30 | *.zip 31 | *.tar.gz 32 | app/libs/ 33 | app/src/main/res/drawable/ 34 | app/src/main/res/layout/ 35 | uikit/libs/ 36 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MediaPicker 2 | [![](https://jitpack.io/v/xushihai/MediaPicker.svg)](https://jitpack.io/#xushihai/MediaPicker) 3 | 4 | # 介绍 5 | 高仿Android版微信的图片和视频选择器。 6 | 7 | # 集成库 8 | Step 1. Add the JitPack repository to your build file 9 | ```sh 10 | allprojects { 11 | repositories { 12 | ... 13 | maven { url 'https://jitpack.io' } 14 | } 15 | } 16 | ``` 17 | Step 2. Add the dependency 18 | ```sh 19 | dependencies { 20 | compile 'com.github.xushihai:MediaPicker:v3.10' 21 | } 22 | 23 | ``` 24 | # 使用教程 25 | 26 | ```sh 27 | GalleryFinal.selectMedias(this, 10, new GalleryFinal.OnSelectMediaListener() { 28 | @Override 29 | public void onSelected(ArrayList photoArrayList) { 30 | 31 | } 32 | }); 33 | ``` 34 | 35 | #新增gif图片标志 36 | 37 | ```sh 38 | 使用EventBus3.0注册,接收选择好的图片和视频列表 39 | @Subscribe(threadMode = ThreadMode.MAIN) 40 | public void sendMedia(ArrayList photoList) { 41 | Log.e("多媒体", photoList.toString()); 42 | } 43 | 44 | GalleryFinal.selectMedias(this, 10); 45 | ``` 46 | 47 | ```sh 48 | GalleryFinal.captureMedia(this, Environment.getExternalStorageDirectory().getAbsolutePath(),10*1000); 49 | ``` 50 | 51 | ```sh 52 | 使用EventBus3.0注册,接收拍摄好的图片或视频 53 | @Subscribe(threadMode = ThreadMode.MAIN) 54 | public void sendMedia(Photo media) { 55 | 56 | } 57 | ``` 58 | 59 | ```sh 60 | GalleryFinal.captureMedia(this, Environment.getExternalStorageDirectory().getAbsolutePath(), new GalleryFinal.OnCaptureListener() { 61 | @Override 62 | public void onSelected(Photo photo) { 63 | Log.e("拍摄","拍摄完成:"+photo); 64 | } 65 | }); 66 | ``` 67 | 使用了v7兼容包,EventBus,Glide,RecyclerView组件。如果项目中包含了这些组件可以使用exclude将这几个组件排除。 68 | ```sh 69 | exclude group: 'com.android.support', module: 'appcompat-v7' 70 | exclude group: 'com.android.support', module: 'recyclerview-v7' 71 | exclude group: 'org.greenrobot', module: 'eventbus' 72 | exclude group: 'com.github.bumptech.glide', module: 'glide' 73 | ``` 74 | 75 | 76 | #混淆: 77 | #-keep class com.google.android.cameraview.CameraView{*;} 78 | 79 | # 截图 80 | [![N|Solid](https://github.com/xushihai/MediaPicker/blob/master/shotcuts/device-2017-03-20-112104.png)] 81 | [![N|Solid](https://github.com/xushihai/MediaPicker/blob/master/shotcuts/device-2017-03-20-112114.png)] 82 | [![N|Solid](https://github.com/xushihai/MediaPicker/blob/master/shotcuts/device-2017-03-20-112128.png)] 83 | [![N|Solid](https://github.com/xushihai/MediaPicker/blob/master/shotcuts/device-2017-03-20-112139.png)] 84 | [![N|Solid](https://github.com/xushihai/MediaPicker/blob/master/shotcuts/device-2017-06-15-141529.png)] 85 | [![N|Solid](https://github.com/xushihai/MediaPicker/blob/master/shotcuts/device-2017-06-15-141549.png)] 86 | [![N|Solid](https://github.com/xushihai/MediaPicker/blob/master/shotcuts/device-2017-06-15-141606.png)] 87 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 29 5 | buildToolsVersion "25.0.0" 6 | defaultConfig { 7 | applicationId "com.hai.picker" 8 | minSdkVersion 29 9 | targetSdkVersion 29 10 | versionCode 1 11 | versionName "1.0" 12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(include: ['*.jar'], dir: 'libs') 24 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 25 | exclude group: 'com.android.support', module: 'support-annotations' 26 | }) 27 | compile project(':uikit') 28 | debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5' 29 | releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5' 30 | 31 | } 32 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in F:\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | # Uncomment this to preserve the line number information for 20 | # debugging stack traces. 21 | #-keepattributes SourceFile,LineNumberTable 22 | 23 | # If you keep the line number information, uncomment this to 24 | # hide the original source file name. 25 | #-renamesourcefileattribute SourceFile 26 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/java/com/hai/picker/App.java: -------------------------------------------------------------------------------- 1 | package com.hai.picker; 2 | 3 | import android.app.Application; 4 | import android.graphics.Color; 5 | import android.graphics.drawable.ColorDrawable; 6 | import android.util.Log; 7 | 8 | import com.nostra13.universalimageloader.core.DisplayImageOptions; 9 | import com.nostra13.universalimageloader.core.ImageLoader; 10 | import com.nostra13.universalimageloader.core.ImageLoaderConfiguration; 11 | import com.nostra13.universalimageloader.core.display.RoundedBitmapDisplayer; 12 | import com.nostra13.universalimageloader.utils.L; 13 | import com.squareup.leakcanary.LeakCanary; 14 | 15 | import static android.os.Environment.DIRECTORY_PICTURES; 16 | 17 | /** 18 | * Created by Administrator on 2017/3/17. 19 | */ 20 | 21 | public class App extends Application { 22 | 23 | 24 | @Override 25 | public void onCreate() { 26 | super.onCreate(); 27 | if (LeakCanary.isInAnalyzerProcess(this)) { 28 | // This process is dedicated to LeakCanary for heap analysis. 29 | // You should not init your app in this process. 30 | return; 31 | } 32 | LeakCanary.install(this); 33 | 34 | 35 | 36 | DisplayImageOptions displayImageOptions = new DisplayImageOptions.Builder() 37 | // .showImageOnLoading(new ColorDrawable(Color.parseColor("#EEEEEE"))) 38 | .cacheOnDisk(true) 39 | .cacheInMemory(true) 40 | .build(); 41 | 42 | ImageLoaderConfiguration imageLoaderConfiguration = new ImageLoaderConfiguration.Builder(this) 43 | .defaultDisplayImageOptions(displayImageOptions) 44 | .build(); 45 | ImageLoader.getInstance().init(imageLoaderConfiguration); 46 | if (BuildConfig.DEBUG) { 47 | L.disableLogging(); 48 | L.writeLogs(false); 49 | L.writeDebugLogs(false); 50 | } 51 | } 52 | 53 | @Override 54 | public void onLowMemory() { 55 | super.onLowMemory(); 56 | Log.e("进程","低内存了,开始释放内存"); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /app/src/main/java/com/hai/picker/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.hai.picker; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.os.Build; 6 | import android.os.Bundle; 7 | import android.os.Environment; 8 | import android.util.Log; 9 | import android.view.View; 10 | import android.widget.Button; 11 | import android.widget.LinearLayout; 12 | 13 | import com.hai.mediapicker.entity.Photo; 14 | import com.hai.mediapicker.save.ISaver; 15 | import com.hai.mediapicker.util.GalleryFinal; 16 | 17 | import org.greenrobot.eventbus.EventBus; 18 | import org.greenrobot.eventbus.Subscribe; 19 | import org.greenrobot.eventbus.ThreadMode; 20 | 21 | import java.io.File; 22 | import java.io.FileInputStream; 23 | import java.io.FileOutputStream; 24 | import java.security.SecureRandom; 25 | import java.util.ArrayList; 26 | 27 | import javax.crypto.Cipher; 28 | import javax.crypto.CipherOutputStream; 29 | import javax.crypto.KeyGenerator; 30 | 31 | public class MainActivity extends Activity { 32 | 33 | 34 | @Override 35 | protected void onCreate(Bundle savedInstanceState) { 36 | super.onCreate(savedInstanceState); 37 | // GalleryFinal.selectMedias(this, 10); 38 | LinearLayout linearLayout = new LinearLayout(this); 39 | linearLayout.setOrientation(LinearLayout.VERTICAL); 40 | Button button = new Button(this); 41 | button.setText("拍照"); 42 | button.setOnClickListener(new View.OnClickListener() { 43 | @Override 44 | public void onClick(View v) { 45 | GalleryFinal.setImageEngine(GalleryFinal.IMAGE_ENGINE_IMAGE_LOADER); 46 | GalleryFinal.setDefaultSelfie(false); 47 | GalleryFinal.initSaver(new EncryptSaver(MainActivity.this)); 48 | String path = Environment.getExternalStorageDirectory().getAbsolutePath(); 49 | if(Build.VERSION.SDK_INT>=29) 50 | path = getExternalFilesDir(Environment.DIRECTORY_PICTURES).getPath(); 51 | Log.e("拍摄",path); 52 | GalleryFinal.captureMedia(MainActivity.this, GalleryFinal.TYPE_ALL, path, new GalleryFinal.OnCaptureListener() { 53 | @Override 54 | public void onSelected(Photo photo) { 55 | Log.e("拍摄", "拍摄完成:" + photo); 56 | } 57 | }); 58 | } 59 | }); 60 | linearLayout.addView(button); 61 | 62 | button = new Button(this); 63 | button.setText("查看图片"); 64 | button.setOnClickListener(new View.OnClickListener() { 65 | @Override 66 | public void onClick(View v) { 67 | 68 | } 69 | }); 70 | linearLayout.addView(button); 71 | button.setOnClickListener(new View.OnClickListener() { 72 | @Override 73 | public void onClick(View v) { 74 | GalleryFinal.setImageEngine(GalleryFinal.IMAGE_ENGINE_GLIDE); 75 | GalleryFinal.selectMedias(MainActivity.this, GalleryFinal.TYPE_ALL, 10, new GalleryFinal.OnSelectMediaListener() { 76 | @Override 77 | public void onSelected(ArrayList photoArrayList) { 78 | 79 | } 80 | }); 81 | } 82 | }); 83 | setContentView(linearLayout); 84 | EventBus.getDefault().register(this); 85 | 86 | 87 | // Cursor cursor = getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 88 | // null, null, null, null); 89 | // ArrayList photoArrayList = new ArrayList<>(); 90 | // while (cursor.moveToNext()) { 91 | // Photo photo = new Photo(); 92 | // photo.setAdddate(cursor.getLong(cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATE_ADDED))); 93 | // photo.setHeight(cursor.getInt(cursor.getColumnIndex(MediaStore.Images.ImageColumns.HEIGHT))); 94 | // photo.setWidth(cursor.getInt(cursor.getColumnIndex(MediaStore.Images.ImageColumns.WIDTH))); 95 | // photo.setId(cursor.getInt(cursor.getColumnIndex(MediaStore.Images.ImageColumns.BUCKET_ID))); 96 | // photo.setSize(cursor.getLong(cursor.getColumnIndex(MediaStore.Images.ImageColumns.SIZE))); 97 | // photo.setPath(cursor.getString(cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA))); 98 | // photo.setMimetype(cursor.getString(cursor.getColumnIndex(MediaStore.Images.ImageColumns.MIME_TYPE))); 99 | // photoArrayList.add(photo); 100 | // } 101 | // cursor.close(); 102 | // GalleryFinal.showMedias(this,photoArrayList); 103 | } 104 | 105 | 106 | @Subscribe(threadMode = ThreadMode.MAIN) 107 | public void sendMedia(Photo photo) { 108 | Log.e("多媒体", photo.toString()); 109 | } 110 | 111 | @Subscribe(threadMode = ThreadMode.MAIN) 112 | public void sendMedia(ArrayList photoList) { 113 | Log.e("多媒体", photoList.toString()); 114 | } 115 | 116 | @Override 117 | protected void onDestroy() { 118 | super.onDestroy(); 119 | EventBus.getDefault().unregister(this); 120 | //MemoryLeakUtil.fixInputMethodManagerLeak(this); 121 | GalleryFinal.mOnSelectMediaListener = null; 122 | System.gc(); 123 | } 124 | 125 | 126 | private static class EncryptSaver implements ISaver { 127 | File dir; 128 | 129 | public EncryptSaver(Context context) { 130 | dir = new File(context.getFilesDir(), "camera"); 131 | dir = context.getExternalFilesDir("camera"); 132 | if (!dir.exists()) 133 | dir.mkdir(); 134 | Log.e("文件", dir.getAbsolutePath()); 135 | } 136 | 137 | @Override 138 | public boolean save(String previousFile) { 139 | try { 140 | File previousFiles = new File(previousFile); 141 | File file = new File(dir, previousFiles.getName()); 142 | Cipher cipher = Cipher.getInstance("DES"); 143 | KeyGenerator keyGenerator = KeyGenerator.getInstance("DES"); 144 | keyGenerator.init(64, new SecureRandom("dnp123fggfhht".getBytes())); 145 | cipher.init(Cipher.ENCRYPT_MODE, keyGenerator.generateKey()); 146 | CipherOutputStream cipherOutputStream = new CipherOutputStream(new FileOutputStream(file), cipher); 147 | int len = -1; 148 | byte[] buffer = new byte[4986]; 149 | FileInputStream fileInputStream = new FileInputStream(previousFiles); 150 | while ((len = fileInputStream.read(buffer)) != -1) { 151 | cipherOutputStream.write(buffer, 0, len); 152 | } 153 | fileInputStream.close(); 154 | cipherOutputStream.flush(); 155 | cipherOutputStream.close(); 156 | previousFiles.delete(); 157 | } catch (Exception e) { 158 | e.printStackTrace(); 159 | } 160 | 161 | return true; 162 | } 163 | 164 | } 165 | 166 | } 167 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xushihai/MediaPicker/f65bbbb8567b4fe8c4cd10b49e7ff5630850d5d3/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xushihai/MediaPicker/f65bbbb8567b4fe8c4cd10b49e7ff5630850d5d3/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xushihai/MediaPicker/f65bbbb8567b4fe8c4cd10b49e7ff5630850d5d3/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xushihai/MediaPicker/f65bbbb8567b4fe8c4cd10b49e7ff5630850d5d3/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xushihai/MediaPicker/f65bbbb8567b4fe8c4cd10b49e7ff5630850d5d3/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xushihai/MediaPicker/f65bbbb8567b4fe8c4cd10b49e7ff5630850d5d3/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xushihai/MediaPicker/f65bbbb8567b4fe8c4cd10b49e7ff5630850d5d3/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xushihai/MediaPicker/f65bbbb8567b4fe8c4cd10b49e7ff5630850d5d3/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xushihai/MediaPicker/f65bbbb8567b4fe8c4cd10b49e7ff5630850d5d3/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xushihai/MediaPicker/f65bbbb8567b4fe8c4cd10b49e7ff5630850d5d3/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/values-zh-rCN/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 已保存到系统相册,hhh 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | MediaPicker 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:2.3.3' 9 | classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5' 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | jcenter() 18 | maven { url 'https://jitpack.io' } 19 | mavenCentral() 20 | } 21 | } 22 | 23 | task clean(type: Delete) { 24 | delete rootProject.buildDir 25 | } -------------------------------------------------------------------------------- /cameraview/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /cameraview/build.gradle: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2016 The Android Open Source Project 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | apply plugin: 'com.android.library' 15 | 16 | android { 17 | compileSdkVersion 29 18 | buildToolsVersion "25.0.0" 19 | 20 | defaultConfig { 21 | minSdkVersion 29 22 | targetSdkVersion 29 23 | testInstrumentationRunner 'android.support.test.runner.AndroidJUnitRunner' 24 | } 25 | buildTypes { 26 | release { 27 | minifyEnabled false 28 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 29 | } 30 | } 31 | sourceSets { 32 | main.java.srcDirs += 'src/main/base' 33 | main.java.srcDirs += 'src/main/api9' 34 | main.java.srcDirs += 'src/main/api14' 35 | main.java.srcDirs += 'src/main/api21' 36 | main.java.srcDirs += 'src/main/api23' 37 | } 38 | } 39 | 40 | dependencies { 41 | compile "com.android.support:support-annotations:+" 42 | compile "com.android.support:support-v4:+" 43 | 44 | // Tests 45 | testCompile 'junit:junit:4.12' 46 | androidTestCompile('com.android.support.test:runner:0.5') { 47 | exclude module: 'support-annotations' 48 | } 49 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2') { 50 | exclude module: 'support-annotations' 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /cameraview/src/androidTest/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 14 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /cameraview/src/androidTest/java/com/google/android/cameraview/AspectRatioInstrumentationTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.android.cameraview; 18 | 19 | import static junit.framework.Assert.assertNotNull; 20 | 21 | import static org.hamcrest.MatcherAssert.assertThat; 22 | import static org.hamcrest.Matchers.sameInstance; 23 | import static org.hamcrest.core.Is.is; 24 | 25 | import android.os.Parcel; 26 | import android.support.test.runner.AndroidJUnit4; 27 | 28 | import org.junit.Test; 29 | import org.junit.runner.RunWith; 30 | 31 | 32 | @RunWith(AndroidJUnit4.class) 33 | public class AspectRatioInstrumentationTest { 34 | 35 | @Test 36 | public void testParcel() { 37 | final AspectRatio original = AspectRatio.of(4, 3); 38 | final Parcel parcel = Parcel.obtain(); 39 | try { 40 | parcel.writeParcelable(original, 0); 41 | parcel.setDataPosition(0); 42 | final AspectRatio restored = parcel.readParcelable(getClass().getClassLoader()); 43 | assertNotNull(restored); 44 | assertThat(restored.getX(), is(4)); 45 | assertThat(restored.getY(), is(3)); 46 | // As the first instance is alive, the parceled result should still be the same instance 47 | assertThat(restored, is(sameInstance(original))); 48 | } finally { 49 | parcel.recycle(); 50 | } 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /cameraview/src/androidTest/java/com/google/android/cameraview/AspectRatioIsCloseTo.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.android.cameraview; 18 | 19 | import static org.hamcrest.CoreMatchers.either; 20 | 21 | import org.hamcrest.Description; 22 | import org.hamcrest.Factory; 23 | import org.hamcrest.Matcher; 24 | import org.hamcrest.TypeSafeMatcher; 25 | 26 | public class AspectRatioIsCloseTo extends TypeSafeMatcher { 27 | 28 | private final AspectRatio mRatio; 29 | private final static float ERROR = 0.01f; 30 | 31 | public AspectRatioIsCloseTo(AspectRatio ratio) { 32 | mRatio = ratio; 33 | } 34 | 35 | @Override 36 | protected boolean matchesSafely(AspectRatio item) { 37 | float other = item.toFloat(); 38 | float self = mRatio.toFloat(); 39 | return self - ERROR < other && other < self + ERROR; 40 | } 41 | 42 | @Override 43 | public void describeTo(Description description) { 44 | description.appendText("an aspect ratio of ").appendValue(mRatio.toString()); 45 | } 46 | 47 | @Factory 48 | public static Matcher closeTo(AspectRatio ratio) { 49 | return new AspectRatioIsCloseTo(ratio); 50 | } 51 | 52 | @Factory 53 | public static Matcher closeToOrInverse(AspectRatio ratio) { 54 | return either(closeTo(ratio)).or(closeTo(ratio.inverse())); 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /cameraview/src/androidTest/java/com/google/android/cameraview/CameraViewActions.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.android.cameraview; 18 | 19 | import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom; 20 | 21 | import android.support.annotation.NonNull; 22 | import android.support.test.espresso.UiController; 23 | import android.support.test.espresso.ViewAction; 24 | import android.view.View; 25 | 26 | import org.hamcrest.Matcher; 27 | 28 | class CameraViewActions { 29 | 30 | static ViewAction setAspectRatio(@NonNull final AspectRatio ratio) { 31 | return new ViewAction() { 32 | 33 | @Override 34 | public Matcher getConstraints() { 35 | return isAssignableFrom(CameraView.class); 36 | } 37 | 38 | @Override 39 | public String getDescription() { 40 | return "Set aspect ratio to " + ratio; 41 | } 42 | 43 | @Override 44 | public void perform(UiController controller, View view) { 45 | ((CameraView) view).setAspectRatio(ratio); 46 | } 47 | }; 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /cameraview/src/androidTest/java/com/google/android/cameraview/CameraViewActivity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.android.cameraview; 18 | 19 | import android.app.Activity; 20 | import android.os.Bundle; 21 | 22 | import com.google.android.cameraview.test.R; 23 | 24 | public class CameraViewActivity extends Activity { 25 | 26 | private CameraView mCameraView; 27 | 28 | @Override 29 | protected void onCreate(Bundle savedInstanceState) { 30 | super.onCreate(savedInstanceState); 31 | setContentView(R.layout.activity_camera_view); 32 | mCameraView = (CameraView) findViewById(R.id.camera); 33 | } 34 | 35 | @Override 36 | protected void onResume() { 37 | super.onResume(); 38 | mCameraView.start(); 39 | } 40 | 41 | @Override 42 | protected void onPause() { 43 | mCameraView.stop(); 44 | super.onPause(); 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /cameraview/src/androidTest/java/com/google/android/cameraview/CameraViewMatchers.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.android.cameraview; 18 | 19 | import android.support.annotation.NonNull; 20 | import android.view.View; 21 | 22 | import org.hamcrest.Description; 23 | import org.hamcrest.Matcher; 24 | import org.hamcrest.TypeSafeMatcher; 25 | 26 | class CameraViewMatchers { 27 | 28 | static Matcher hasAspectRatio(@NonNull final AspectRatio ratio) { 29 | return new TypeSafeMatcher() { 30 | @Override 31 | public void describeTo(Description description) { 32 | description.appendText("has aspect ratio of " + ratio); 33 | } 34 | 35 | @Override 36 | protected boolean matchesSafely(View view) { 37 | return ratio.equals(((CameraView) view).getAspectRatio()); 38 | } 39 | }; 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /cameraview/src/androidTest/res/layout/activity_camera_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 14 | 18 | 19 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /cameraview/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 14 | 16 | 17 | 18 | 19 | 20 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /cameraview/src/main/api14/com/google/android/cameraview/TextureViewPreview.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.android.cameraview; 18 | 19 | import android.annotation.TargetApi; 20 | import android.content.Context; 21 | import android.graphics.Matrix; 22 | import android.graphics.SurfaceTexture; 23 | import android.view.Surface; 24 | import android.view.TextureView; 25 | import android.view.View; 26 | import android.view.ViewGroup; 27 | 28 | @TargetApi(14) 29 | public class TextureViewPreview extends PreviewImpl { 30 | 31 | private final TextureView mTextureView; 32 | 33 | private int mDisplayOrientation; 34 | 35 | TextureViewPreview(Context context, ViewGroup parent) { 36 | final View view = View.inflate(context, R.layout.texture_view, parent); 37 | mTextureView = (TextureView) view.findViewById(R.id.texture_view); 38 | mTextureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() { 39 | 40 | @Override 41 | public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { 42 | setSize(width, height); 43 | configureTransform(); 44 | dispatchSurfaceChanged(); 45 | } 46 | 47 | @Override 48 | public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { 49 | setSize(width, height); 50 | configureTransform(); 51 | dispatchSurfaceChanged(); 52 | } 53 | 54 | @Override 55 | public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { 56 | setSize(0, 0); 57 | return true; 58 | } 59 | 60 | @Override 61 | public void onSurfaceTextureUpdated(SurfaceTexture surface) { 62 | } 63 | }); 64 | } 65 | 66 | // This method is called only from Camera2. 67 | @TargetApi(15) 68 | @Override 69 | void setBufferSize(int width, int height) { 70 | mTextureView.getSurfaceTexture().setDefaultBufferSize(width, height); 71 | } 72 | 73 | @Override 74 | Surface getSurface() { 75 | return new Surface(mTextureView.getSurfaceTexture()); 76 | } 77 | 78 | @Override 79 | SurfaceTexture getSurfaceTexture() { 80 | return mTextureView.getSurfaceTexture(); 81 | } 82 | 83 | @Override 84 | View getView() { 85 | return mTextureView; 86 | } 87 | 88 | @Override 89 | Class getOutputClass() { 90 | return SurfaceTexture.class; 91 | } 92 | 93 | @Override 94 | void setDisplayOrientation(int displayOrientation) { 95 | mDisplayOrientation = displayOrientation; 96 | configureTransform(); 97 | } 98 | 99 | @Override 100 | boolean isReady() { 101 | return mTextureView.getSurfaceTexture() != null; 102 | } 103 | 104 | /** 105 | * Configures the transform matrix for TextureView based on {@link #mDisplayOrientation} and 106 | * the surface size. 107 | */ 108 | void configureTransform() { 109 | Matrix matrix = new Matrix(); 110 | if (mDisplayOrientation % 180 == 90) { 111 | final int width = getWidth(); 112 | final int height = getHeight(); 113 | // Rotate the camera preview when the screen is landscape. 114 | matrix.setPolyToPoly( 115 | new float[]{ 116 | 0.f, 0.f, // top left 117 | width, 0.f, // top right 118 | 0.f, height, // bottom left 119 | width, height, // bottom right 120 | }, 0, 121 | mDisplayOrientation == 90 ? 122 | // Clockwise 123 | new float[]{ 124 | 0.f, height, // top left 125 | 0.f, 0.f, // top right 126 | width, height, // bottom left 127 | width, 0.f, // bottom right 128 | } : // mDisplayOrientation == 270 129 | // Counter-clockwise 130 | new float[]{ 131 | width, 0.f, // top left 132 | width, height, // top right 133 | 0.f, 0.f, // bottom left 134 | 0.f, height, // bottom right 135 | }, 0, 136 | 4); 137 | } else if (mDisplayOrientation == 180) { 138 | matrix.postRotate(180, getWidth() / 2, getHeight() / 2); 139 | } 140 | mTextureView.setTransform(matrix); 141 | } 142 | 143 | } 144 | -------------------------------------------------------------------------------- /cameraview/src/main/api23/com/google/android/cameraview/Camera2Api23.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.android.cameraview; 18 | 19 | import android.annotation.TargetApi; 20 | import android.content.Context; 21 | import android.graphics.ImageFormat; 22 | import android.hardware.camera2.params.StreamConfigurationMap; 23 | 24 | 25 | @TargetApi(23) 26 | class Camera2Api23 extends Camera2 { 27 | 28 | Camera2Api23(Callback callback, PreviewImpl preview, Context context) { 29 | super(callback, preview, context); 30 | } 31 | 32 | @Override 33 | protected void collectPictureSizes(SizeMap sizes, StreamConfigurationMap map) { 34 | // Try to get hi-res output sizes 35 | android.util.Size[] outputSizes = map.getHighResolutionOutputSizes(ImageFormat.JPEG); 36 | if (outputSizes != null) { 37 | for (android.util.Size size : map.getHighResolutionOutputSizes(ImageFormat.JPEG)) { 38 | sizes.add(new Size(size.getWidth(), size.getHeight())); 39 | } 40 | } 41 | if (sizes.isEmpty()) { 42 | super.collectPictureSizes(sizes, map); 43 | } 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /cameraview/src/main/api9/com/google/android/cameraview/SurfaceViewPreview.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.android.cameraview; 18 | 19 | import android.content.Context; 20 | import android.support.v4.view.ViewCompat; 21 | import android.view.Surface; 22 | import android.view.SurfaceHolder; 23 | import android.view.SurfaceView; 24 | import android.view.View; 25 | import android.view.ViewGroup; 26 | 27 | class SurfaceViewPreview extends PreviewImpl { 28 | 29 | final SurfaceView mSurfaceView; 30 | 31 | SurfaceViewPreview(Context context, ViewGroup parent) { 32 | final View view = View.inflate(context, R.layout.surface_view, parent); 33 | mSurfaceView = (SurfaceView) view.findViewById(R.id.surface_view); 34 | final SurfaceHolder holder = mSurfaceView.getHolder(); 35 | //noinspection deprecation 36 | holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); 37 | holder.addCallback(new SurfaceHolder.Callback() { 38 | @Override 39 | public void surfaceCreated(SurfaceHolder h) { 40 | } 41 | 42 | @Override 43 | public void surfaceChanged(SurfaceHolder h, int format, int width, int height) { 44 | setSize(width, height); 45 | if (!ViewCompat.isInLayout(mSurfaceView)) { 46 | dispatchSurfaceChanged(); 47 | } 48 | } 49 | 50 | @Override 51 | public void surfaceDestroyed(SurfaceHolder h) { 52 | setSize(0, 0); 53 | } 54 | }); 55 | } 56 | 57 | @Override 58 | Surface getSurface() { 59 | return getSurfaceHolder().getSurface(); 60 | } 61 | 62 | @Override 63 | SurfaceHolder getSurfaceHolder() { 64 | return mSurfaceView.getHolder(); 65 | } 66 | 67 | @Override 68 | View getView() { 69 | return mSurfaceView; 70 | } 71 | 72 | @Override 73 | Class getOutputClass() { 74 | return SurfaceHolder.class; 75 | } 76 | 77 | @Override 78 | void setDisplayOrientation(int displayOrientation) { 79 | } 80 | 81 | @Override 82 | boolean isReady() { 83 | return getWidth() != 0 && getHeight() != 0; 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /cameraview/src/main/base/com/google/android/cameraview/AspectRatio.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.android.cameraview; 18 | 19 | import android.os.Parcel; 20 | import android.os.Parcelable; 21 | import android.support.annotation.NonNull; 22 | import android.support.v4.util.SparseArrayCompat; 23 | 24 | /** 25 | * Immutable class for describing proportional relationship between width and height. 26 | */ 27 | public class AspectRatio implements Comparable, Parcelable { 28 | 29 | private final static SparseArrayCompat> sCache 30 | = new SparseArrayCompat<>(16); 31 | 32 | private final int mX; 33 | private final int mY; 34 | 35 | /** 36 | * Returns an instance of {@link AspectRatio} specified by {@code x} and {@code y} values. 37 | * The values {@code x} and {@code} will be reduced by their greatest common divider. 38 | * 39 | * @param x The width 40 | * @param y The height 41 | * @return An instance of {@link AspectRatio} 42 | */ 43 | public static AspectRatio of(int x, int y) { 44 | int gcd = gcd(x, y); 45 | x /= gcd; 46 | y /= gcd; 47 | SparseArrayCompat arrayX = sCache.get(x); 48 | if (arrayX == null) { 49 | AspectRatio ratio = new AspectRatio(x, y); 50 | arrayX = new SparseArrayCompat<>(); 51 | arrayX.put(y, ratio); 52 | sCache.put(x, arrayX); 53 | return ratio; 54 | } else { 55 | AspectRatio ratio = arrayX.get(y); 56 | if (ratio == null) { 57 | ratio = new AspectRatio(x, y); 58 | arrayX.put(y, ratio); 59 | } 60 | return ratio; 61 | } 62 | } 63 | 64 | /** 65 | * Parse an {@link AspectRatio} from a {@link String} formatted like "4:3". 66 | * 67 | * @param s The string representation of the aspect ratio 68 | * @return The aspect ratio 69 | * @throws IllegalArgumentException when the format is incorrect. 70 | */ 71 | public static AspectRatio parse(String s) { 72 | int position = s.indexOf(':'); 73 | if (position == -1) { 74 | throw new IllegalArgumentException("Malformed aspect ratio: " + s); 75 | } 76 | try { 77 | int x = Integer.parseInt(s.substring(0, position)); 78 | int y = Integer.parseInt(s.substring(position + 1)); 79 | return AspectRatio.of(x, y); 80 | } catch (NumberFormatException e) { 81 | throw new IllegalArgumentException("Malformed aspect ratio: " + s, e); 82 | } 83 | } 84 | 85 | private AspectRatio(int x, int y) { 86 | mX = x; 87 | mY = y; 88 | } 89 | 90 | public int getX() { 91 | return mX; 92 | } 93 | 94 | public int getY() { 95 | return mY; 96 | } 97 | 98 | public boolean matches(Size size) { 99 | int gcd = gcd(size.getWidth(), size.getHeight()); 100 | int x = size.getWidth() / gcd; 101 | int y = size.getHeight() / gcd; 102 | return mX == x && mY == y; 103 | } 104 | 105 | @Override 106 | public boolean equals(Object o) { 107 | if (o == null) { 108 | return false; 109 | } 110 | if (this == o) { 111 | return true; 112 | } 113 | if (o instanceof AspectRatio) { 114 | AspectRatio ratio = (AspectRatio) o; 115 | return mX == ratio.mX && mY == ratio.mY; 116 | } 117 | return false; 118 | } 119 | 120 | @Override 121 | public String toString() { 122 | return mX + ":" + mY; 123 | } 124 | 125 | public float toFloat() { 126 | return (float) mX / mY; 127 | } 128 | 129 | @Override 130 | public int hashCode() { 131 | // assuming most sizes are <2^16, doing a rotate will give us perfect hashing 132 | return mY ^ ((mX << (Integer.SIZE / 2)) | (mX >>> (Integer.SIZE / 2))); 133 | } 134 | 135 | @Override 136 | public int compareTo(@NonNull AspectRatio another) { 137 | if (equals(another)) { 138 | return 0; 139 | } else if (toFloat() - another.toFloat() > 0) { 140 | return 1; 141 | } 142 | return -1; 143 | } 144 | 145 | /** 146 | * @return The inverse of this {@link AspectRatio}. 147 | */ 148 | public AspectRatio inverse() { 149 | //noinspection SuspiciousNameCombination 150 | return AspectRatio.of(mY, mX); 151 | } 152 | 153 | private static int gcd(int a, int b) { 154 | while (b != 0) { 155 | int c = b; 156 | b = a % b; 157 | a = c; 158 | } 159 | return a; 160 | } 161 | 162 | @Override 163 | public int describeContents() { 164 | return 0; 165 | } 166 | 167 | @Override 168 | public void writeToParcel(Parcel dest, int flags) { 169 | dest.writeInt(mX); 170 | dest.writeInt(mY); 171 | } 172 | 173 | public static final Parcelable.Creator CREATOR 174 | = new Parcelable.Creator() { 175 | 176 | @Override 177 | public AspectRatio createFromParcel(Parcel source) { 178 | int x = source.readInt(); 179 | int y = source.readInt(); 180 | return AspectRatio.of(x, y); 181 | } 182 | 183 | @Override 184 | public AspectRatio[] newArray(int size) { 185 | return new AspectRatio[size]; 186 | } 187 | }; 188 | 189 | } 190 | -------------------------------------------------------------------------------- /cameraview/src/main/base/com/google/android/cameraview/CameraViewImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.android.cameraview; 18 | 19 | import android.view.View; 20 | 21 | import java.util.Set; 22 | 23 | public abstract class CameraViewImpl { 24 | 25 | protected final Callback mCallback; 26 | 27 | protected final PreviewImpl mPreview; 28 | 29 | CameraViewImpl(Callback callback, PreviewImpl preview) { 30 | mCallback = callback; 31 | mPreview = preview; 32 | } 33 | 34 | View getView() { 35 | return mPreview.getView(); 36 | } 37 | 38 | /** 39 | * @return {@code true} if the implementation was able to start the camera session. 40 | */ 41 | abstract boolean start(); 42 | 43 | abstract void stop(); 44 | 45 | abstract boolean isCameraOpened(); 46 | 47 | abstract void setFacing(int facing); 48 | 49 | abstract int getFacing(); 50 | 51 | abstract Set getSupportedAspectRatios(); 52 | 53 | /** 54 | * @return {@code true} if the aspect ratio was changed. 55 | */ 56 | abstract boolean setAspectRatio(AspectRatio ratio); 57 | 58 | abstract AspectRatio getAspectRatio(); 59 | 60 | abstract void setAutoFocus(boolean autoFocus); 61 | 62 | abstract boolean getAutoFocus(); 63 | 64 | abstract void setFlash(int flash); 65 | 66 | abstract int getFlash(); 67 | 68 | abstract void takePicture(); 69 | 70 | abstract void setDisplayOrientation(int displayOrientation); 71 | 72 | interface Callback { 73 | 74 | void onCameraOpened(); 75 | 76 | void onCameraClosed(); 77 | 78 | void onPictureTaken(byte[] data); 79 | 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /cameraview/src/main/base/com/google/android/cameraview/Constants.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.android.cameraview; 18 | 19 | 20 | interface Constants { 21 | 22 | AspectRatio DEFAULT_ASPECT_RATIO = AspectRatio.of(4, 3); 23 | 24 | int FACING_BACK = 0; 25 | int FACING_FRONT = 1; 26 | 27 | int FLASH_OFF = 0; 28 | int FLASH_ON = 1; 29 | int FLASH_TORCH = 2; 30 | int FLASH_AUTO = 3; 31 | int FLASH_RED_EYE = 4; 32 | 33 | int LANDSCAPE_90 = 90; 34 | int LANDSCAPE_270 = 270; 35 | } 36 | -------------------------------------------------------------------------------- /cameraview/src/main/base/com/google/android/cameraview/PreviewImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.android.cameraview; 18 | 19 | import android.view.Surface; 20 | import android.view.SurfaceHolder; 21 | import android.view.View; 22 | 23 | 24 | /** 25 | * Encapsulates all the operations related to camera preview in a backward-compatible manner. 26 | */ 27 | abstract class PreviewImpl { 28 | 29 | interface Callback { 30 | void onSurfaceChanged(); 31 | } 32 | 33 | private Callback mCallback; 34 | 35 | private int mWidth; 36 | 37 | private int mHeight; 38 | 39 | void setCallback(Callback callback) { 40 | mCallback = callback; 41 | } 42 | 43 | abstract Surface getSurface(); 44 | 45 | abstract View getView(); 46 | 47 | abstract Class getOutputClass(); 48 | 49 | abstract void setDisplayOrientation(int displayOrientation); 50 | 51 | abstract boolean isReady(); 52 | 53 | protected void dispatchSurfaceChanged() { 54 | mCallback.onSurfaceChanged(); 55 | } 56 | 57 | SurfaceHolder getSurfaceHolder() { 58 | return null; 59 | } 60 | 61 | Object getSurfaceTexture() { 62 | return null; 63 | } 64 | 65 | void setBufferSize(int width, int height) { 66 | } 67 | 68 | void setSize(int width, int height) { 69 | mWidth = width; 70 | mHeight = height; 71 | } 72 | 73 | int getWidth() { 74 | return mWidth; 75 | } 76 | 77 | int getHeight() { 78 | return mHeight; 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /cameraview/src/main/base/com/google/android/cameraview/Size.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.android.cameraview; 18 | 19 | import android.support.annotation.NonNull; 20 | 21 | /** 22 | * Immutable class for describing width and height dimensions in pixels. 23 | */ 24 | public class Size implements Comparable { 25 | 26 | private final int mWidth; 27 | private final int mHeight; 28 | 29 | /** 30 | * Create a new immutable Size instance. 31 | * 32 | * @param width The width of the size, in pixels 33 | * @param height The height of the size, in pixels 34 | */ 35 | public Size(int width, int height) { 36 | mWidth = width; 37 | mHeight = height; 38 | } 39 | 40 | public int getWidth() { 41 | return mWidth; 42 | } 43 | 44 | public int getHeight() { 45 | return mHeight; 46 | } 47 | 48 | @Override 49 | public boolean equals(Object o) { 50 | if (o == null) { 51 | return false; 52 | } 53 | if (this == o) { 54 | return true; 55 | } 56 | if (o instanceof Size) { 57 | Size size = (Size) o; 58 | return mWidth == size.mWidth && mHeight == size.mHeight; 59 | } 60 | return false; 61 | } 62 | 63 | @Override 64 | public String toString() { 65 | return mWidth + "x" + mHeight; 66 | } 67 | 68 | @Override 69 | public int hashCode() { 70 | // assuming most sizes are <2^16, doing a rotate will give us perfect hashing 71 | return mHeight ^ ((mWidth << (Integer.SIZE / 2)) | (mWidth >>> (Integer.SIZE / 2))); 72 | } 73 | 74 | @Override 75 | public int compareTo(@NonNull Size another) { 76 | return mWidth * mHeight - another.mWidth * another.mHeight; 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /cameraview/src/main/base/com/google/android/cameraview/SizeMap.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.android.cameraview; 18 | 19 | import android.support.v4.util.ArrayMap; 20 | 21 | import java.util.Set; 22 | import java.util.SortedSet; 23 | import java.util.TreeSet; 24 | 25 | /** 26 | * A collection class that automatically groups {@link Size}s by their {@link AspectRatio}s. 27 | */ 28 | class SizeMap { 29 | 30 | private final ArrayMap> mRatios = new ArrayMap<>(); 31 | 32 | /** 33 | * Add a new {@link Size} to this collection. 34 | * 35 | * @param size The size to add. 36 | * @return {@code true} if it is added, {@code false} if it already exists and is not added. 37 | */ 38 | public boolean add(Size size) { 39 | for (AspectRatio ratio : mRatios.keySet()) { 40 | if (ratio.matches(size)) { 41 | final SortedSet sizes = mRatios.get(ratio); 42 | if (sizes.contains(size)) { 43 | return false; 44 | } else { 45 | sizes.add(size); 46 | return true; 47 | } 48 | } 49 | } 50 | // None of the existing ratio matches the provided size; add a new key 51 | SortedSet sizes = new TreeSet<>(); 52 | sizes.add(size); 53 | mRatios.put(AspectRatio.of(size.getWidth(), size.getHeight()), sizes); 54 | return true; 55 | } 56 | 57 | /** 58 | * Removes the specified aspect ratio and all sizes associated with it. 59 | * 60 | * @param ratio The aspect ratio to be removed. 61 | */ 62 | public void remove(AspectRatio ratio) { 63 | mRatios.remove(ratio); 64 | } 65 | 66 | Set ratios() { 67 | return mRatios.keySet(); 68 | } 69 | 70 | SortedSet sizes(AspectRatio ratio) { 71 | return mRatios.get(ratio); 72 | } 73 | 74 | void clear() { 75 | mRatios.clear(); 76 | } 77 | 78 | boolean isEmpty() { 79 | return mRatios.isEmpty(); 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /cameraview/src/main/java/com/google/android/cameraview/DisplayOrientationDetector.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.android.cameraview; 18 | 19 | import android.content.Context; 20 | import android.util.SparseIntArray; 21 | import android.view.Display; 22 | import android.view.OrientationEventListener; 23 | import android.view.Surface; 24 | 25 | 26 | /** 27 | * Monitors the value returned from {@link Display#getRotation()}. 28 | */ 29 | abstract class DisplayOrientationDetector { 30 | 31 | private final OrientationEventListener mOrientationEventListener; 32 | 33 | /** Mapping from Surface.Rotation_n to degrees. */ 34 | static final SparseIntArray DISPLAY_ORIENTATIONS = new SparseIntArray(); 35 | 36 | static { 37 | DISPLAY_ORIENTATIONS.put(Surface.ROTATION_0, 0); 38 | DISPLAY_ORIENTATIONS.put(Surface.ROTATION_90, 90); 39 | DISPLAY_ORIENTATIONS.put(Surface.ROTATION_180, 180); 40 | DISPLAY_ORIENTATIONS.put(Surface.ROTATION_270, 270); 41 | } 42 | 43 | Display mDisplay; 44 | 45 | private int mLastKnownDisplayOrientation = 0; 46 | 47 | public DisplayOrientationDetector(Context context) { 48 | mOrientationEventListener = new OrientationEventListener(context) { 49 | 50 | /** This is either Surface.Rotation_0, _90, _180, _270, or -1 (invalid). */ 51 | private int mLastKnownRotation = -1; 52 | 53 | @Override 54 | public void onOrientationChanged(int orientation) { 55 | if (orientation == OrientationEventListener.ORIENTATION_UNKNOWN || 56 | mDisplay == null) { 57 | return; 58 | } 59 | final int rotation = mDisplay.getRotation(); 60 | if (mLastKnownRotation != rotation) { 61 | mLastKnownRotation = rotation; 62 | dispatchOnDisplayOrientationChanged(DISPLAY_ORIENTATIONS.get(rotation)); 63 | } 64 | } 65 | }; 66 | } 67 | 68 | public void enable(Display display) { 69 | mDisplay = display; 70 | mOrientationEventListener.enable(); 71 | // Immediately dispatch the first callback 72 | dispatchOnDisplayOrientationChanged(DISPLAY_ORIENTATIONS.get(display.getRotation())); 73 | } 74 | 75 | public void disable() { 76 | mOrientationEventListener.disable(); 77 | mDisplay = null; 78 | } 79 | 80 | public int getLastKnownDisplayOrientation() { 81 | return mLastKnownDisplayOrientation; 82 | } 83 | 84 | void dispatchOnDisplayOrientationChanged(int displayOrientation) { 85 | mLastKnownDisplayOrientation = displayOrientation; 86 | onDisplayOrientationChanged(displayOrientation); 87 | } 88 | 89 | /** 90 | * Called when display orientation is changed. 91 | * 92 | * @param displayOrientation One of 0, 90, 180, and 270. 93 | */ 94 | public abstract void onDisplayOrientationChanged(int displayOrientation); 95 | 96 | } 97 | -------------------------------------------------------------------------------- /cameraview/src/main/res/layout-v14/texture_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 14 | 15 | 16 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /cameraview/src/main/res/layout/surface_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 14 | 15 | 16 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /cameraview/src/main/res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 14 | 15 | 16 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 40 | 41 | 45 | 46 | 51 | 52 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /cameraview/src/main/res/values/public.xml: -------------------------------------------------------------------------------- 1 | 2 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /cameraview/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 14 | 15 | 16 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /cameraview/src/test/java/com/google/android/cameraview/AspectRatioTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.android.cameraview; 18 | 19 | import static org.hamcrest.CoreMatchers.is; 20 | import static org.junit.Assert.assertThat; 21 | 22 | import org.junit.Test; 23 | 24 | import java.util.HashSet; 25 | 26 | public class AspectRatioTest { 27 | 28 | @Test 29 | public void testGcd() { 30 | AspectRatio r; 31 | r = AspectRatio.of(1, 2); 32 | assertThat(r.getX(), is(1)); 33 | r = AspectRatio.of(2, 4); 34 | assertThat(r.getX(), is(1)); 35 | assertThat(r.getY(), is(2)); 36 | r = AspectRatio.of(391, 713); 37 | assertThat(r.getX(), is(17)); 38 | assertThat(r.getY(), is(31)); 39 | } 40 | 41 | @Test 42 | public void testMatches() { 43 | AspectRatio ratio = AspectRatio.of(3, 4); 44 | assertThat(ratio.matches(new Size(6, 8)), is(true)); 45 | assertThat(ratio.matches(new Size(1, 2)), is(false)); 46 | } 47 | 48 | @Test 49 | public void testGetters() { 50 | AspectRatio ratio = AspectRatio.of(2, 4); // Reduced to 1:2 51 | assertThat(ratio.getX(), is(1)); 52 | assertThat(ratio.getY(), is(2)); 53 | } 54 | 55 | @Test 56 | public void testToString() { 57 | AspectRatio ratio = AspectRatio.of(1, 2); 58 | assertThat(ratio.toString(), is("1:2")); 59 | } 60 | 61 | @Test 62 | public void testEquals() { 63 | AspectRatio a = AspectRatio.of(1, 2); 64 | AspectRatio b = AspectRatio.of(2, 4); 65 | AspectRatio c = AspectRatio.of(2, 3); 66 | assertThat(a.equals(b), is(true)); 67 | assertThat(a.equals(c), is(false)); 68 | } 69 | 70 | @Test 71 | public void testHashCode() { 72 | int max = 100; 73 | HashSet codes = new HashSet<>(); 74 | for (int x = 1; x <= 100; x++) { 75 | codes.add(AspectRatio.of(x, 1).hashCode()); 76 | } 77 | assertThat(codes.size(), is(max)); 78 | codes.clear(); 79 | for (int y = 1; y <= 100; y++) { 80 | codes.add(AspectRatio.of(1, y).hashCode()); 81 | } 82 | assertThat(codes.size(), is(max)); 83 | } 84 | 85 | @Test 86 | public void testInverse() { 87 | AspectRatio r = AspectRatio.of(4, 3); 88 | assertThat(r.getX(), is(4)); 89 | assertThat(r.getY(), is(3)); 90 | AspectRatio s = r.inverse(); 91 | assertThat(s.getX(), is(3)); 92 | assertThat(s.getY(), is(4)); 93 | } 94 | 95 | @Test 96 | public void testParse() { 97 | AspectRatio r = AspectRatio.parse("23:31"); 98 | assertThat(r.getX(), is(23)); 99 | assertThat(r.getY(), is(31)); 100 | } 101 | 102 | @Test(expected = IllegalArgumentException.class) 103 | public void testParseFailure() { 104 | AspectRatio.parse("MALFORMED"); 105 | } 106 | 107 | } 108 | -------------------------------------------------------------------------------- /cameraview/src/test/java/com/google/android/cameraview/SizeMapTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.android.cameraview; 18 | 19 | import static org.hamcrest.CoreMatchers.is; 20 | import static org.junit.Assert.assertThat; 21 | 22 | import org.junit.Test; 23 | 24 | public class SizeMapTest { 25 | 26 | @Test 27 | public void testAdd_simple() { 28 | SizeMap map = new SizeMap(); 29 | map.add(new Size(3, 4)); 30 | map.add(new Size(9, 16)); 31 | assertThat(map.ratios().size(), is(2)); 32 | } 33 | 34 | @Test 35 | public void testAdd_duplicate() { 36 | SizeMap map = new SizeMap(); 37 | map.add(new Size(3, 4)); 38 | map.add(new Size(6, 8)); 39 | map.add(new Size(9, 12)); 40 | assertThat(map.ratios().size(), is(1)); 41 | AspectRatio ratio = (AspectRatio) map.ratios().toArray()[0]; 42 | assertThat(ratio.toString(), is("3:4")); 43 | assertThat(map.sizes(ratio).size(), is(3)); 44 | } 45 | 46 | @Test 47 | public void testClear() { 48 | SizeMap map = new SizeMap(); 49 | map.add(new Size(12, 34)); 50 | assertThat(map.ratios().size(), is(1)); 51 | map.clear(); 52 | assertThat(map.ratios().size(), is(0)); 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /cameraview/src/test/java/com/google/android/cameraview/SizeTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.android.cameraview; 18 | 19 | import static org.hamcrest.CoreMatchers.is; 20 | import static org.junit.Assert.assertThat; 21 | 22 | import org.junit.Test; 23 | 24 | import java.util.HashSet; 25 | 26 | public class SizeTest { 27 | 28 | @Test 29 | public void testGetters() { 30 | Size size = new Size(1, 2); 31 | assertThat(size.getWidth(), is(1)); 32 | assertThat(size.getHeight(), is(2)); 33 | } 34 | 35 | @Test 36 | public void testToString() { 37 | Size size = new Size(1, 2); 38 | assertThat(size.toString(), is("1x2")); 39 | } 40 | 41 | @Test 42 | public void testEquals() { 43 | Size a = new Size(1, 2); 44 | Size b = new Size(1, 2); 45 | Size c = new Size(3, 4); 46 | assertThat(a.equals(b), is(true)); 47 | assertThat(a.equals(c), is(false)); 48 | } 49 | 50 | @Test 51 | public void testHashCode() { 52 | int max = 100; 53 | HashSet codes = new HashSet<>(); 54 | for (int x = 1; x <= max; x++) { 55 | for (int y = 1; y <= max; y++) { 56 | codes.add(new Size(x, y).hashCode()); 57 | } 58 | } 59 | assertThat(codes.size(), is(max * max)); 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | org.gradle.jvmargs=-Xmx1536m 13 | 14 | # When configured, Gradle will run in incubating parallel mode. 15 | # This option should only be used with decoupled projects. More details, visit 16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 17 | # org.gradle.parallel=true 18 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xushihai/MediaPicker/f65bbbb8567b4fe8c4cd10b49e7ff5630850d5d3/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Mar 13 10:40:44 CST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /jitpack.xml: -------------------------------------------------------------------------------- 1 | jdk: 2 | - oraclejdk8 -------------------------------------------------------------------------------- /local.properties: -------------------------------------------------------------------------------- 1 | ## This file is automatically generated by Android Studio. 2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED! 3 | # 4 | # This file must *NOT* be checked into Version Control Systems, 5 | # as it contains information specific to your local configuration. 6 | # 7 | # Location of the SDK. This is only used by Gradle. 8 | # For customization when using a Version Control System, please read the 9 | # header note. 10 | #Thu Sep 19 11:18:46 CST 2019 11 | sdk.dir=/home/xushihai/Android/Sdk 12 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':uikit', ':app', ':cameraview' 2 | -------------------------------------------------------------------------------- /shotcuts/device-2017-03-20-112104.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xushihai/MediaPicker/f65bbbb8567b4fe8c4cd10b49e7ff5630850d5d3/shotcuts/device-2017-03-20-112104.png -------------------------------------------------------------------------------- /shotcuts/device-2017-03-20-112114.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xushihai/MediaPicker/f65bbbb8567b4fe8c4cd10b49e7ff5630850d5d3/shotcuts/device-2017-03-20-112114.png -------------------------------------------------------------------------------- /shotcuts/device-2017-03-20-112128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xushihai/MediaPicker/f65bbbb8567b4fe8c4cd10b49e7ff5630850d5d3/shotcuts/device-2017-03-20-112128.png -------------------------------------------------------------------------------- /shotcuts/device-2017-03-20-112139.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xushihai/MediaPicker/f65bbbb8567b4fe8c4cd10b49e7ff5630850d5d3/shotcuts/device-2017-03-20-112139.png -------------------------------------------------------------------------------- /shotcuts/device-2017-06-15-141529.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xushihai/MediaPicker/f65bbbb8567b4fe8c4cd10b49e7ff5630850d5d3/shotcuts/device-2017-06-15-141529.png -------------------------------------------------------------------------------- /shotcuts/device-2017-06-15-141549.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xushihai/MediaPicker/f65bbbb8567b4fe8c4cd10b49e7ff5630850d5d3/shotcuts/device-2017-06-15-141549.png -------------------------------------------------------------------------------- /shotcuts/device-2017-06-15-141606.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xushihai/MediaPicker/f65bbbb8567b4fe8c4cd10b49e7ff5630850d5d3/shotcuts/device-2017-06-15-141606.png -------------------------------------------------------------------------------- /uikit/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'com.github.dcendents.android-maven' 3 | group = 'com.github.xushihai' 4 | android { 5 | compileSdkVersion 29 6 | buildToolsVersion "25.0.0" 7 | 8 | defaultConfig { 9 | minSdkVersion 14 10 | targetSdkVersion 29 11 | versionCode 36 12 | versionName "3.12" 13 | } 14 | sourceSets { 15 | main.java.srcDirs += 'src/main/base' 16 | main.java.srcDirs += 'src/main/api9' 17 | main.java.srcDirs += 'src/main/api14' 18 | main.java.srcDirs += 'src/main/api21' 19 | main.java.srcDirs += 'src/main/api23' 20 | } 21 | 22 | } 23 | 24 | repositories { 25 | maven { 26 | url "https://jitpack.io" 27 | } 28 | flatDir { 29 | dirs 'libs' 30 | } 31 | } 32 | 33 | dependencies { 34 | compile fileTree(include: ['*.jar'], dir: 'libs') 35 | compile 'com.android.support:appcompat-v7:+' 36 | compile 'com.android.support:recyclerview-v7:+' 37 | compile 'org.greenrobot:eventbus:3.0.0' 38 | compile 'com.github.bumptech.glide:glide:3.7.0' 39 | compile 'com.nostra13.universalimageloader:universal-image-loader:1.9.5' 40 | //compile project(path: ':cameraview') 41 | compile "com.android.support:support-annotations:25.3.1" 42 | compile "com.android.support:support-v4:+" 43 | } 44 | -------------------------------------------------------------------------------- /uikit/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in F:\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | # Uncomment this to preserve the line number information for 20 | # debugging stack traces. 21 | #-keepattributes SourceFile,LineNumberTable 22 | 23 | # If you keep the line number information, uncomment this to 24 | # hide the original source file name. 25 | #-renamesourcefileattribute SourceFile 26 | -keep class com.google.android.cameraview.CameraView{*;} -------------------------------------------------------------------------------- /uikit/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 16 | 17 | 21 | 22 | 23 | 28 | 29 | 30 | 31 | 32 | 37 | 38 | 43 | 44 | 48 | 52 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /uikit/src/main/api14/com/google/android/cameraview/TextureViewPreview.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.android.cameraview; 18 | 19 | import android.annotation.TargetApi; 20 | import android.content.Context; 21 | import android.graphics.Matrix; 22 | import android.graphics.SurfaceTexture; 23 | import android.view.Surface; 24 | import android.view.TextureView; 25 | import android.view.View; 26 | import android.view.ViewGroup; 27 | 28 | import com.hai.mediapicker.R; 29 | 30 | @TargetApi(14) 31 | public class TextureViewPreview extends PreviewImpl { 32 | 33 | private final TextureView mTextureView; 34 | 35 | private int mDisplayOrientation; 36 | 37 | TextureViewPreview(Context context, ViewGroup parent) { 38 | final View view = View.inflate(context, R.layout.texture_view, parent); 39 | mTextureView = (TextureView) view.findViewById(R.id.texture_view); 40 | mTextureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() { 41 | 42 | @Override 43 | public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { 44 | setSize(width, height); 45 | configureTransform(); 46 | dispatchSurfaceChanged(); 47 | } 48 | 49 | @Override 50 | public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { 51 | setSize(width, height); 52 | configureTransform(); 53 | dispatchSurfaceChanged(); 54 | } 55 | 56 | @Override 57 | public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { 58 | setSize(0, 0); 59 | return true; 60 | } 61 | 62 | @Override 63 | public void onSurfaceTextureUpdated(SurfaceTexture surface) { 64 | } 65 | }); 66 | } 67 | 68 | // This method is called only from Camera2. 69 | @TargetApi(15) 70 | @Override 71 | void setBufferSize(int width, int height) { 72 | mTextureView.getSurfaceTexture().setDefaultBufferSize(width, height); 73 | } 74 | 75 | @Override 76 | Surface getSurface() { 77 | return new Surface(mTextureView.getSurfaceTexture()); 78 | } 79 | 80 | @Override 81 | SurfaceTexture getSurfaceTexture() { 82 | return mTextureView.getSurfaceTexture(); 83 | } 84 | 85 | @Override 86 | View getView() { 87 | return mTextureView; 88 | } 89 | 90 | @Override 91 | Class getOutputClass() { 92 | return SurfaceTexture.class; 93 | } 94 | 95 | @Override 96 | void setDisplayOrientation(int displayOrientation) { 97 | mDisplayOrientation = displayOrientation; 98 | configureTransform(); 99 | } 100 | 101 | @Override 102 | boolean isReady() { 103 | return mTextureView.getSurfaceTexture() != null; 104 | } 105 | 106 | /** 107 | * Configures the transform matrix for TextureView based on {@link #mDisplayOrientation} and 108 | * the surface size. 109 | */ 110 | void configureTransform() { 111 | Matrix matrix = new Matrix(); 112 | if (mDisplayOrientation % 180 == 90) { 113 | final int width = getWidth(); 114 | final int height = getHeight(); 115 | // Rotate the camera preview when the screen is landscape. 116 | matrix.setPolyToPoly( 117 | new float[]{ 118 | 0.f, 0.f, // top left 119 | width, 0.f, // top right 120 | 0.f, height, // bottom left 121 | width, height, // bottom right 122 | }, 0, 123 | mDisplayOrientation == 90 ? 124 | // Clockwise 125 | new float[]{ 126 | 0.f, height, // top left 127 | 0.f, 0.f, // top right 128 | width, height, // bottom left 129 | width, 0.f, // bottom right 130 | } : // mDisplayOrientation == 270 131 | // Counter-clockwise 132 | new float[]{ 133 | width, 0.f, // top left 134 | width, height, // top right 135 | 0.f, 0.f, // bottom left 136 | 0.f, height, // bottom right 137 | }, 0, 138 | 4); 139 | } else if (mDisplayOrientation == 180) { 140 | matrix.postRotate(180, getWidth() / 2, getHeight() / 2); 141 | } 142 | mTextureView.setTransform(matrix); 143 | } 144 | 145 | } 146 | -------------------------------------------------------------------------------- /uikit/src/main/api23/com/google/android/cameraview/Camera2Api23.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.android.cameraview; 18 | 19 | import android.annotation.TargetApi; 20 | import android.content.Context; 21 | import android.graphics.ImageFormat; 22 | import android.hardware.camera2.params.StreamConfigurationMap; 23 | 24 | 25 | @TargetApi(23) 26 | class Camera2Api23 extends Camera2 { 27 | 28 | Camera2Api23(Callback callback, PreviewImpl preview, Context context) { 29 | super(callback, preview, context); 30 | } 31 | 32 | @Override 33 | protected void collectPictureSizes(SizeMap sizes, StreamConfigurationMap map) { 34 | // Try to get hi-res output sizes 35 | android.util.Size[] outputSizes = map.getHighResolutionOutputSizes(ImageFormat.JPEG); 36 | if (outputSizes != null) { 37 | for (android.util.Size size : map.getHighResolutionOutputSizes(ImageFormat.JPEG)) { 38 | sizes.add(new Size(size.getWidth(), size.getHeight())); 39 | } 40 | } 41 | if (sizes.isEmpty()) { 42 | super.collectPictureSizes(sizes, map); 43 | } 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /uikit/src/main/api9/com/google/android/cameraview/SurfaceViewPreview.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.android.cameraview; 18 | 19 | import android.content.Context; 20 | import android.support.v4.view.ViewCompat; 21 | import android.view.Surface; 22 | import android.view.SurfaceHolder; 23 | import android.view.SurfaceView; 24 | import android.view.View; 25 | import android.view.ViewGroup; 26 | 27 | import com.hai.mediapicker.R; 28 | 29 | class SurfaceViewPreview extends PreviewImpl { 30 | 31 | final SurfaceView mSurfaceView; 32 | 33 | SurfaceViewPreview(Context context, ViewGroup parent) { 34 | final View view = View.inflate(context, R.layout.surface_view, parent); 35 | mSurfaceView = (SurfaceView) view.findViewById(R.id.surface_view); 36 | final SurfaceHolder holder = mSurfaceView.getHolder(); 37 | //noinspection deprecation 38 | holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); 39 | holder.addCallback(new SurfaceHolder.Callback() { 40 | @Override 41 | public void surfaceCreated(SurfaceHolder h) { 42 | } 43 | 44 | @Override 45 | public void surfaceChanged(SurfaceHolder h, int format, int width, int height) { 46 | setSize(width, height); 47 | if (!ViewCompat.isInLayout(mSurfaceView)) { 48 | dispatchSurfaceChanged(); 49 | } 50 | } 51 | 52 | @Override 53 | public void surfaceDestroyed(SurfaceHolder h) { 54 | setSize(0, 0); 55 | } 56 | }); 57 | } 58 | 59 | @Override 60 | Surface getSurface() { 61 | return getSurfaceHolder().getSurface(); 62 | } 63 | 64 | @Override 65 | SurfaceHolder getSurfaceHolder() { 66 | return mSurfaceView.getHolder(); 67 | } 68 | 69 | @Override 70 | View getView() { 71 | return mSurfaceView; 72 | } 73 | 74 | @Override 75 | Class getOutputClass() { 76 | return SurfaceHolder.class; 77 | } 78 | 79 | @Override 80 | void setDisplayOrientation(int displayOrientation) { 81 | } 82 | 83 | @Override 84 | boolean isReady() { 85 | return getWidth() != 0 && getHeight() != 0; 86 | } 87 | 88 | } 89 | -------------------------------------------------------------------------------- /uikit/src/main/base/com/google/android/cameraview/AspectRatio.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.android.cameraview; 18 | 19 | import android.os.Parcel; 20 | import android.os.Parcelable; 21 | import android.support.annotation.NonNull; 22 | import android.support.v4.util.SparseArrayCompat; 23 | 24 | /** 25 | * Immutable class for describing proportional relationship between width and height. 26 | */ 27 | public class AspectRatio implements Comparable, Parcelable { 28 | 29 | private final static SparseArrayCompat> sCache 30 | = new SparseArrayCompat<>(16); 31 | 32 | private final int mX; 33 | private final int mY; 34 | 35 | /** 36 | * Returns an instance of {@link AspectRatio} specified by {@code x} and {@code y} values. 37 | * The values {@code x} and {@code} will be reduced by their greatest common divider. 38 | * 39 | * @param x The width 40 | * @param y The height 41 | * @return An instance of {@link AspectRatio} 42 | */ 43 | public static AspectRatio of(int x, int y) { 44 | int gcd = gcd(x, y); 45 | x /= gcd; 46 | y /= gcd; 47 | SparseArrayCompat arrayX = sCache.get(x); 48 | if (arrayX == null) { 49 | AspectRatio ratio = new AspectRatio(x, y); 50 | arrayX = new SparseArrayCompat<>(); 51 | arrayX.put(y, ratio); 52 | sCache.put(x, arrayX); 53 | return ratio; 54 | } else { 55 | AspectRatio ratio = arrayX.get(y); 56 | if (ratio == null) { 57 | ratio = new AspectRatio(x, y); 58 | arrayX.put(y, ratio); 59 | } 60 | return ratio; 61 | } 62 | } 63 | 64 | /** 65 | * Parse an {@link AspectRatio} from a {@link String} formatted like "4:3". 66 | * 67 | * @param s The string representation of the aspect ratio 68 | * @return The aspect ratio 69 | * @throws IllegalArgumentException when the format is incorrect. 70 | */ 71 | public static AspectRatio parse(String s) { 72 | int position = s.indexOf(':'); 73 | if (position == -1) { 74 | throw new IllegalArgumentException("Malformed aspect ratio: " + s); 75 | } 76 | try { 77 | int x = Integer.parseInt(s.substring(0, position)); 78 | int y = Integer.parseInt(s.substring(position + 1)); 79 | return AspectRatio.of(x, y); 80 | } catch (NumberFormatException e) { 81 | throw new IllegalArgumentException("Malformed aspect ratio: " + s, e); 82 | } 83 | } 84 | 85 | private AspectRatio(int x, int y) { 86 | mX = x; 87 | mY = y; 88 | } 89 | 90 | public int getX() { 91 | return mX; 92 | } 93 | 94 | public int getY() { 95 | return mY; 96 | } 97 | 98 | public boolean matches(Size size) { 99 | int gcd = gcd(size.getWidth(), size.getHeight()); 100 | int x = size.getWidth() / gcd; 101 | int y = size.getHeight() / gcd; 102 | return mX == x && mY == y; 103 | } 104 | 105 | @Override 106 | public boolean equals(Object o) { 107 | if (o == null) { 108 | return false; 109 | } 110 | if (this == o) { 111 | return true; 112 | } 113 | if (o instanceof AspectRatio) { 114 | AspectRatio ratio = (AspectRatio) o; 115 | return mX == ratio.mX && mY == ratio.mY; 116 | } 117 | return false; 118 | } 119 | 120 | @Override 121 | public String toString() { 122 | return mX + ":" + mY; 123 | } 124 | 125 | public float toFloat() { 126 | return (float) mX / mY; 127 | } 128 | 129 | @Override 130 | public int hashCode() { 131 | // assuming most sizes are <2^16, doing a rotate will give us perfect hashing 132 | return mY ^ ((mX << (Integer.SIZE / 2)) | (mX >>> (Integer.SIZE / 2))); 133 | } 134 | 135 | @Override 136 | public int compareTo(@NonNull AspectRatio another) { 137 | if (equals(another)) { 138 | return 0; 139 | } else if (toFloat() - another.toFloat() > 0) { 140 | return 1; 141 | } 142 | return -1; 143 | } 144 | 145 | /** 146 | * @return The inverse of this {@link AspectRatio}. 147 | */ 148 | public AspectRatio inverse() { 149 | //noinspection SuspiciousNameCombination 150 | return AspectRatio.of(mY, mX); 151 | } 152 | 153 | private static int gcd(int a, int b) { 154 | while (b != 0) { 155 | int c = b; 156 | b = a % b; 157 | a = c; 158 | } 159 | return a; 160 | } 161 | 162 | @Override 163 | public int describeContents() { 164 | return 0; 165 | } 166 | 167 | @Override 168 | public void writeToParcel(Parcel dest, int flags) { 169 | dest.writeInt(mX); 170 | dest.writeInt(mY); 171 | } 172 | 173 | public static final Parcelable.Creator CREATOR 174 | = new Parcelable.Creator() { 175 | 176 | @Override 177 | public AspectRatio createFromParcel(Parcel source) { 178 | int x = source.readInt(); 179 | int y = source.readInt(); 180 | return AspectRatio.of(x, y); 181 | } 182 | 183 | @Override 184 | public AspectRatio[] newArray(int size) { 185 | return new AspectRatio[size]; 186 | } 187 | }; 188 | 189 | } 190 | -------------------------------------------------------------------------------- /uikit/src/main/base/com/google/android/cameraview/CameraViewImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.android.cameraview; 18 | 19 | import android.view.View; 20 | 21 | import java.util.Set; 22 | 23 | public abstract class CameraViewImpl { 24 | 25 | protected final Callback mCallback; 26 | 27 | protected final PreviewImpl mPreview; 28 | 29 | CameraViewImpl(Callback callback, PreviewImpl preview) { 30 | mCallback = callback; 31 | mPreview = preview; 32 | } 33 | 34 | View getView() { 35 | return mPreview.getView(); 36 | } 37 | 38 | /** 39 | * @return {@code true} if the implementation was able to start the camera session. 40 | */ 41 | abstract boolean start(); 42 | 43 | abstract void stop(); 44 | 45 | abstract boolean isCameraOpened(); 46 | 47 | abstract void setFacing(int facing); 48 | 49 | abstract int getFacing(); 50 | 51 | abstract Set getSupportedAspectRatios(); 52 | 53 | /** 54 | * @return {@code true} if the aspect ratio was changed. 55 | */ 56 | abstract boolean setAspectRatio(AspectRatio ratio); 57 | 58 | abstract AspectRatio getAspectRatio(); 59 | 60 | abstract void setAutoFocus(boolean autoFocus); 61 | 62 | abstract boolean getAutoFocus(); 63 | 64 | abstract void setFlash(int flash); 65 | 66 | abstract int getFlash(); 67 | 68 | abstract void takePicture(); 69 | 70 | abstract void setDisplayOrientation(int displayOrientation); 71 | 72 | interface Callback { 73 | 74 | void onCameraOpened(); 75 | 76 | void onCameraClosed(); 77 | 78 | void onPictureTaken(byte[] data); 79 | 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /uikit/src/main/base/com/google/android/cameraview/Constants.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.android.cameraview; 18 | 19 | 20 | interface Constants { 21 | 22 | AspectRatio DEFAULT_ASPECT_RATIO = AspectRatio.of(4, 3); 23 | 24 | int FACING_BACK = 0; 25 | int FACING_FRONT = 1; 26 | 27 | int FLASH_OFF = 0; 28 | int FLASH_ON = 1; 29 | int FLASH_TORCH = 2; 30 | int FLASH_AUTO = 3; 31 | int FLASH_RED_EYE = 4; 32 | 33 | int LANDSCAPE_90 = 90; 34 | int LANDSCAPE_270 = 270; 35 | } 36 | -------------------------------------------------------------------------------- /uikit/src/main/base/com/google/android/cameraview/PreviewImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.android.cameraview; 18 | 19 | import android.view.Surface; 20 | import android.view.SurfaceHolder; 21 | import android.view.View; 22 | 23 | 24 | /** 25 | * Encapsulates all the operations related to camera preview in a backward-compatible manner. 26 | */ 27 | abstract class PreviewImpl { 28 | 29 | interface Callback { 30 | void onSurfaceChanged(); 31 | } 32 | 33 | private Callback mCallback; 34 | 35 | private int mWidth; 36 | 37 | private int mHeight; 38 | 39 | void setCallback(Callback callback) { 40 | mCallback = callback; 41 | } 42 | 43 | abstract Surface getSurface(); 44 | 45 | abstract View getView(); 46 | 47 | abstract Class getOutputClass(); 48 | 49 | abstract void setDisplayOrientation(int displayOrientation); 50 | 51 | abstract boolean isReady(); 52 | 53 | protected void dispatchSurfaceChanged() { 54 | mCallback.onSurfaceChanged(); 55 | } 56 | 57 | SurfaceHolder getSurfaceHolder() { 58 | return null; 59 | } 60 | 61 | Object getSurfaceTexture() { 62 | return null; 63 | } 64 | 65 | void setBufferSize(int width, int height) { 66 | } 67 | 68 | void setSize(int width, int height) { 69 | mWidth = width; 70 | mHeight = height; 71 | } 72 | 73 | int getWidth() { 74 | return mWidth; 75 | } 76 | 77 | int getHeight() { 78 | return mHeight; 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /uikit/src/main/base/com/google/android/cameraview/Size.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.android.cameraview; 18 | 19 | import android.support.annotation.NonNull; 20 | 21 | /** 22 | * Immutable class for describing width and height dimensions in pixels. 23 | */ 24 | public class Size implements Comparable { 25 | 26 | private final int mWidth; 27 | private final int mHeight; 28 | 29 | /** 30 | * Create a new immutable Size instance. 31 | * 32 | * @param width The width of the size, in pixels 33 | * @param height The height of the size, in pixels 34 | */ 35 | public Size(int width, int height) { 36 | mWidth = width; 37 | mHeight = height; 38 | } 39 | 40 | public int getWidth() { 41 | return mWidth; 42 | } 43 | 44 | public int getHeight() { 45 | return mHeight; 46 | } 47 | 48 | @Override 49 | public boolean equals(Object o) { 50 | if (o == null) { 51 | return false; 52 | } 53 | if (this == o) { 54 | return true; 55 | } 56 | if (o instanceof Size) { 57 | Size size = (Size) o; 58 | return mWidth == size.mWidth && mHeight == size.mHeight; 59 | } 60 | return false; 61 | } 62 | 63 | @Override 64 | public String toString() { 65 | return mWidth + "x" + mHeight; 66 | } 67 | 68 | @Override 69 | public int hashCode() { 70 | // assuming most sizes are <2^16, doing a rotate will give us perfect hashing 71 | return mHeight ^ ((mWidth << (Integer.SIZE / 2)) | (mWidth >>> (Integer.SIZE / 2))); 72 | } 73 | 74 | @Override 75 | public int compareTo(@NonNull Size another) { 76 | return mWidth * mHeight - another.mWidth * another.mHeight; 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /uikit/src/main/base/com/google/android/cameraview/SizeMap.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.android.cameraview; 18 | 19 | import android.support.v4.util.ArrayMap; 20 | 21 | import java.util.Set; 22 | import java.util.SortedSet; 23 | import java.util.TreeSet; 24 | 25 | /** 26 | * A collection class that automatically groups {@link Size}s by their {@link AspectRatio}s. 27 | */ 28 | class SizeMap { 29 | 30 | private final ArrayMap> mRatios = new ArrayMap<>(); 31 | 32 | /** 33 | * Add a new {@link Size} to this collection. 34 | * 35 | * @param size The size to add. 36 | * @return {@code true} if it is added, {@code false} if it already exists and is not added. 37 | */ 38 | public boolean add(Size size) { 39 | for (AspectRatio ratio : mRatios.keySet()) { 40 | if (ratio.matches(size)) { 41 | final SortedSet sizes = mRatios.get(ratio); 42 | if (sizes.contains(size)) { 43 | return false; 44 | } else { 45 | sizes.add(size); 46 | return true; 47 | } 48 | } 49 | } 50 | // None of the existing ratio matches the provided size; add a new key 51 | SortedSet sizes = new TreeSet<>(); 52 | sizes.add(size); 53 | mRatios.put(AspectRatio.of(size.getWidth(), size.getHeight()), sizes); 54 | return true; 55 | } 56 | 57 | /** 58 | * Removes the specified aspect ratio and all sizes associated with it. 59 | * 60 | * @param ratio The aspect ratio to be removed. 61 | */ 62 | public void remove(AspectRatio ratio) { 63 | mRatios.remove(ratio); 64 | } 65 | 66 | Set ratios() { 67 | return mRatios.keySet(); 68 | } 69 | 70 | SortedSet sizes(AspectRatio ratio) { 71 | return mRatios.get(ratio); 72 | } 73 | 74 | void clear() { 75 | mRatios.clear(); 76 | } 77 | 78 | boolean isEmpty() { 79 | return mRatios.isEmpty(); 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /uikit/src/main/java/com/google/android/cameraview/DisplayOrientationDetector.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.android.cameraview; 18 | 19 | import android.content.Context; 20 | import android.util.SparseIntArray; 21 | import android.view.Display; 22 | import android.view.OrientationEventListener; 23 | import android.view.Surface; 24 | 25 | 26 | /** 27 | * Monitors the value returned from {@link Display#getRotation()}. 28 | */ 29 | abstract class DisplayOrientationDetector { 30 | 31 | private final OrientationEventListener mOrientationEventListener; 32 | 33 | /** Mapping from Surface.Rotation_n to degrees. */ 34 | static final SparseIntArray DISPLAY_ORIENTATIONS = new SparseIntArray(); 35 | 36 | static { 37 | DISPLAY_ORIENTATIONS.put(Surface.ROTATION_0, 0); 38 | DISPLAY_ORIENTATIONS.put(Surface.ROTATION_90, 90); 39 | DISPLAY_ORIENTATIONS.put(Surface.ROTATION_180, 180); 40 | DISPLAY_ORIENTATIONS.put(Surface.ROTATION_270, 270); 41 | } 42 | 43 | Display mDisplay; 44 | 45 | private int mLastKnownDisplayOrientation = 0; 46 | 47 | public DisplayOrientationDetector(Context context) { 48 | mOrientationEventListener = new OrientationEventListener(context) { 49 | 50 | /** This is either Surface.Rotation_0, _90, _180, _270, or -1 (invalid). */ 51 | private int mLastKnownRotation = -1; 52 | 53 | @Override 54 | public void onOrientationChanged(int orientation) { 55 | if (orientation == OrientationEventListener.ORIENTATION_UNKNOWN || 56 | mDisplay == null) { 57 | return; 58 | } 59 | final int rotation = mDisplay.getRotation(); 60 | if (mLastKnownRotation != rotation) { 61 | mLastKnownRotation = rotation; 62 | dispatchOnDisplayOrientationChanged(DISPLAY_ORIENTATIONS.get(rotation)); 63 | } 64 | } 65 | }; 66 | } 67 | 68 | public void enable(Display display) { 69 | mDisplay = display; 70 | mOrientationEventListener.enable(); 71 | // Immediately dispatch the first callback 72 | dispatchOnDisplayOrientationChanged(DISPLAY_ORIENTATIONS.get(display.getRotation())); 73 | } 74 | 75 | public void disable() { 76 | mOrientationEventListener.disable(); 77 | mDisplay = null; 78 | } 79 | 80 | public int getLastKnownDisplayOrientation() { 81 | return mLastKnownDisplayOrientation; 82 | } 83 | 84 | void dispatchOnDisplayOrientationChanged(int displayOrientation) { 85 | mLastKnownDisplayOrientation = displayOrientation; 86 | onDisplayOrientationChanged(displayOrientation); 87 | } 88 | 89 | /** 90 | * Called when display orientation is changed. 91 | * 92 | * @param displayOrientation One of 0, 90, 180, and 270. 93 | */ 94 | public abstract void onDisplayOrientationChanged(int displayOrientation); 95 | 96 | } 97 | -------------------------------------------------------------------------------- /uikit/src/main/java/com/hai/mediapicker/activity/AlbumActivity.java: -------------------------------------------------------------------------------- 1 | package com.hai.mediapicker.activity; 2 | 3 | import android.content.Intent; 4 | import android.view.View; 5 | 6 | import com.hai.mediapicker.R; 7 | import com.hai.mediapicker.entity.Photo; 8 | import com.hai.mediapicker.entity.PhotoDirectory; 9 | import com.hai.mediapicker.util.MediaManager; 10 | 11 | import java.util.ArrayList; 12 | 13 | public class AlbumActivity extends MediaPickerActivity implements MediaManager.OnCheckchangeListener { 14 | 15 | public static final String EXTREA_PHOTOS = "photos"; 16 | 17 | 18 | protected void readIntentParams() { 19 | Intent intent = getIntent(); 20 | selectMode = intent.getBooleanExtra(EXTREA_SELECT_MODE, true); 21 | btnSend.setVisibility(selectMode ? View.VISIBLE : View.GONE); 22 | ArrayList photoArrayList = (ArrayList) intent.getSerializableExtra(EXTREA_PHOTOS); 23 | 24 | 25 | ArrayList photoDirectoryArrayList = new ArrayList<>(); 26 | PhotoDirectory photoDirectory = new PhotoDirectory(); 27 | photoDirectory.setPhotos(photoArrayList); 28 | photoDirectory.setSelected(true); 29 | photoDirectoryArrayList.add(photoDirectory); 30 | MediaManager.getInstance().setPhotoDirectorys(photoDirectoryArrayList); 31 | MediaManager.getInstance().setSelectIndex(0); 32 | } 33 | 34 | 35 | @Override 36 | protected void initUi() { 37 | super.initUi(); 38 | findViewById(R.id.bottom).setVisibility(View.GONE); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /uikit/src/main/java/com/hai/mediapicker/activity/VideoPlayer.java: -------------------------------------------------------------------------------- 1 | package com.hai.mediapicker.activity; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.content.pm.ActivityInfo; 6 | import android.media.MediaPlayer; 7 | import android.net.Uri; 8 | import android.os.Bundle; 9 | import android.support.annotation.Nullable; 10 | import android.support.v7.app.AppCompatActivity; 11 | import android.util.Log; 12 | import android.view.SurfaceHolder; 13 | import android.view.SurfaceView; 14 | import android.view.View; 15 | import android.view.WindowManager; 16 | import android.widget.ImageView; 17 | import android.widget.Toast; 18 | 19 | import com.hai.mediapicker.R; 20 | import com.hai.mediapicker.entity.Photo; 21 | import com.hai.mediapicker.util.MemoryLeakUtil; 22 | 23 | import java.io.IOException; 24 | 25 | /** 26 | * Created by Administrator on 2018/5/7. 27 | */ 28 | 29 | public class VideoPlayer extends AppCompatActivity implements SurfaceHolder.Callback { 30 | 31 | public static void playVideo(Context context, Photo video) { 32 | Intent intent = new Intent(context, VideoPlayer.class); 33 | intent.putExtra("video", video); 34 | intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 35 | context.startActivity(intent); 36 | } 37 | 38 | MediaPlayer mediaPlayer; 39 | Photo video; 40 | ImageView ivPlay; 41 | 42 | @Override 43 | protected void onCreate(@Nullable Bundle savedInstanceState) { 44 | WindowManager.LayoutParams winParams = getWindow().getAttributes(); 45 | winParams.flags |= WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION; 46 | winParams.flags |= WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS; 47 | getWindow().setAttributes(winParams); 48 | super.onCreate(savedInstanceState); 49 | setContentView(R.layout.activity_video_player); 50 | 51 | 52 | ivPlay = (ImageView) findViewById(R.id.iv_play); 53 | ivPlay.setOnClickListener(new View.OnClickListener() { 54 | @Override 55 | public void onClick(View v) { 56 | v.setVisibility(View.GONE); 57 | mediaPlayer.start(); 58 | } 59 | }); 60 | video = (Photo) getIntent().getSerializableExtra("video"); 61 | try { 62 | mediaPlayer = new MediaPlayer(); 63 | // mediaPlayer.setDataSource(video.getPath()); 64 | mediaPlayer.setDataSource(getBaseContext(), Uri.parse(video.getMediaUri())); 65 | SurfaceHolder surfaceHolder = ((SurfaceView) findViewById(R.id.surface_video)).getHolder(); 66 | surfaceHolder.addCallback(this); 67 | mediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() { 68 | @Override 69 | public boolean onError(MediaPlayer mp, int what, int extra) { 70 | Toast.makeText(VideoPlayer.this, getString(R.string.total_play_error), Toast.LENGTH_LONG).show(); 71 | return false; 72 | } 73 | }); 74 | mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { 75 | @Override 76 | public void onPrepared(MediaPlayer mp) { 77 | if (mp.getVideoWidth() > mp.getVideoHeight()) { 78 | setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); 79 | } 80 | mp.start(); 81 | } 82 | }); 83 | mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { 84 | @Override 85 | public void onCompletion(MediaPlayer mp) { 86 | ivPlay.setVisibility(View.VISIBLE); 87 | } 88 | }); 89 | mediaPlayer.prepareAsync(); 90 | } catch (IOException e) { 91 | e.printStackTrace(); 92 | } 93 | } 94 | 95 | 96 | 97 | 98 | @Override 99 | public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { 100 | 101 | } 102 | 103 | @Override 104 | public void surfaceCreated(SurfaceHolder holder) { 105 | mediaPlayer.setDisplay(holder); 106 | } 107 | 108 | @Override 109 | public void surfaceDestroyed(SurfaceHolder holder) { 110 | try { 111 | if (mediaPlayer.isPlaying()) 112 | mediaPlayer.stop(); 113 | mediaPlayer.release(); 114 | mediaPlayer = null; 115 | MemoryLeakUtil.fixInputMethodManagerLeak(this); 116 | } catch (Exception e) { 117 | e.printStackTrace(); 118 | } 119 | } 120 | 121 | } 122 | -------------------------------------------------------------------------------- /uikit/src/main/java/com/hai/mediapicker/adapter/PopupDirectoryListAdapter.java: -------------------------------------------------------------------------------- 1 | package com.hai.mediapicker.adapter; 2 | 3 | import android.content.res.ColorStateList; 4 | import android.graphics.Color; 5 | import android.graphics.drawable.Drawable; 6 | import android.support.v4.graphics.drawable.DrawableCompat; 7 | import android.util.Log; 8 | import android.view.LayoutInflater; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | import android.widget.BaseAdapter; 12 | import android.widget.ImageView; 13 | import android.widget.TextView; 14 | 15 | import com.bumptech.glide.Glide; 16 | import com.hai.mediapicker.R; 17 | import com.hai.mediapicker.entity.PhotoDirectory; 18 | 19 | import java.util.ArrayList; 20 | import java.util.List; 21 | 22 | /** 23 | * Created by donglua on 15/6/28. 24 | */ 25 | public class PopupDirectoryListAdapter extends BaseAdapter { 26 | 27 | private List directories = new ArrayList<>(); 28 | 29 | public PopupDirectoryListAdapter(List directories) { 30 | this.directories = directories; 31 | } 32 | 33 | 34 | @Override 35 | public int getCount() { 36 | return directories.size(); 37 | } 38 | 39 | 40 | @Override 41 | public PhotoDirectory getItem(int position) { 42 | return directories.get(position); 43 | } 44 | 45 | 46 | @Override 47 | public long getItemId(int position) { 48 | return directories.get(position).hashCode(); 49 | } 50 | 51 | 52 | @Override 53 | public View getView(int position, View convertView, ViewGroup parent) { 54 | ViewHolder holder; 55 | if (convertView == null) { 56 | LayoutInflater mLayoutInflater = LayoutInflater.from(parent.getContext()); 57 | convertView = mLayoutInflater.inflate(R.layout.pop_directory_item, parent, false); 58 | holder = new ViewHolder(convertView); 59 | convertView.setTag(holder); 60 | } else { 61 | holder = (ViewHolder) convertView.getTag(); 62 | } 63 | 64 | holder.bindData(directories.get(position)); 65 | 66 | return convertView; 67 | } 68 | 69 | private class ViewHolder { 70 | 71 | public ImageView ivCover; 72 | public TextView tvName; 73 | public TextView tvCount; 74 | public ImageView ivSelect; 75 | 76 | public ViewHolder(View rootView) { 77 | ivCover = (ImageView) rootView.findViewById(R.id.iv_dir_cover); 78 | tvName = (TextView) rootView.findViewById(R.id.tv_dir_name); 79 | tvCount = (TextView) rootView.findViewById(R.id.tv_dir_count); 80 | ivSelect = (ImageView) rootView.findViewById(R.id.iv_dir); 81 | } 82 | 83 | public void bindData(PhotoDirectory directory) { 84 | Glide.with(ivCover.getContext()).load(directory.getCoverUri()).into(ivCover); 85 | tvName.setText(directory.getName()); 86 | tvCount.setText(tvCount.getContext().getString(R.string.__picker_image_count, directory.getPhotos().size())); 87 | ivSelect.setVisibility(directory.isSelected() ? View.VISIBLE : View.GONE); 88 | Drawable drawable = tintDrawable(ivCover.getContext().getResources().getDrawable(R.mipmap.ic_check_dir), ColorStateList.valueOf(Color.parseColor("#FF45C01A"))); 89 | drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); 90 | ivSelect.setImageDrawable(drawable); 91 | } 92 | 93 | /** 94 | * 给图片上色 95 | * 96 | * @param drawable 97 | * @param colors 98 | * @return 99 | */ 100 | public Drawable tintDrawable(Drawable drawable, ColorStateList colors) { 101 | final Drawable wrappedDrawable = DrawableCompat.wrap(drawable); 102 | DrawableCompat.setTintList(wrappedDrawable, colors); 103 | return wrappedDrawable; 104 | } 105 | } 106 | 107 | } 108 | -------------------------------------------------------------------------------- /uikit/src/main/java/com/hai/mediapicker/decoration/SpaceItemDecoration.java: -------------------------------------------------------------------------------- 1 | package com.hai.mediapicker.decoration; 2 | 3 | import android.content.Context; 4 | import android.graphics.Rect; 5 | import android.support.v7.widget.GridLayoutManager; 6 | import android.support.v7.widget.LinearLayoutManager; 7 | import android.support.v7.widget.RecyclerView; 8 | import android.view.View; 9 | 10 | /** 11 | * Created by Administrator on 2017/3/14. 12 | */ 13 | 14 | public class SpaceItemDecoration extends RecyclerView.ItemDecoration { 15 | private int space; 16 | 17 | public SpaceItemDecoration(Context context, int space) { 18 | this.space = (int) (space * context.getResources().getDisplayMetrics().density); 19 | } 20 | 21 | @Override 22 | public void getItemOffsets(Rect outRect, View view, 23 | RecyclerView parent, RecyclerView.State state) { 24 | outRect.left = space; 25 | outRect.right = space; 26 | outRect.bottom = space; 27 | 28 | //判断是GridLayoutManager还是LinearLayoutManager 29 | if (parent.getLayoutManager() instanceof GridLayoutManager) { 30 | int spanCount = ((GridLayoutManager) parent.getLayoutManager()).getSpanCount(); 31 | outRect.top = parent.getChildLayoutPosition(view) < spanCount ? space : 0; 32 | } else { 33 | LinearLayoutManager linearLayoutManager = (LinearLayoutManager) parent.getLayoutManager(); 34 | outRect.top = linearLayoutManager.getOrientation() == LinearLayoutManager.HORIZONTAL || 35 | parent.getChildLayoutPosition(view) == 0 ? space : 0; 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /uikit/src/main/java/com/hai/mediapicker/entity/Photo.java: -------------------------------------------------------------------------------- 1 | package com.hai.mediapicker.entity; 2 | 3 | import android.net.Uri; 4 | import android.os.Build; 5 | import android.provider.MediaStore; 6 | 7 | import java.io.Serializable; 8 | 9 | /** 10 | * Created by donglua on 15/6/30. 11 | */ 12 | public class Photo implements Serializable { 13 | 14 | private int id; 15 | private String path; 16 | private String mimetype; 17 | private long duration; 18 | private int width, height; 19 | private long size; 20 | private long adddate; 21 | private boolean fullImage;//是否使用原图,默认图片传送需要进过压缩。 22 | 23 | public Photo(int id, String path, String mimetype, int width, int height, long size) { 24 | this.id = id; 25 | this.path = path; 26 | this.mimetype = mimetype; 27 | this.width = width; 28 | this.height = height; 29 | this.size = size; 30 | } 31 | 32 | 33 | public Photo() { 34 | } 35 | 36 | @Override 37 | public boolean equals(Object o) { 38 | if (this == o) return true; 39 | if (!(o instanceof Photo)) return false; 40 | 41 | Photo photo = (Photo) o; 42 | 43 | return id == photo.id; 44 | } 45 | 46 | public long getAdddate() { 47 | return adddate; 48 | } 49 | 50 | public void setAdddate(long adddate) { 51 | this.adddate = adddate; 52 | } 53 | 54 | public boolean isFullImage() { 55 | return fullImage; 56 | } 57 | 58 | public void setFullImage(boolean fullImage) { 59 | this.fullImage = fullImage; 60 | } 61 | 62 | public String getMimetype() { 63 | return mimetype; 64 | } 65 | 66 | public void setMimetype(String mimetype) { 67 | this.mimetype = mimetype; 68 | } 69 | 70 | @Override 71 | public int hashCode() { 72 | return id; 73 | } 74 | 75 | public String getPath() { 76 | return path; 77 | } 78 | 79 | public void setPath(String path) { 80 | this.path = path; 81 | } 82 | 83 | public int getId() { 84 | return id; 85 | } 86 | 87 | public void setId(int id) { 88 | this.id = id; 89 | } 90 | 91 | public long getDuration() { 92 | return duration; 93 | } 94 | 95 | public void setDuration(long duration) { 96 | this.duration = duration; 97 | } 98 | 99 | public int getWidth() { 100 | return width; 101 | } 102 | 103 | public void setWidth(int width) { 104 | this.width = width; 105 | } 106 | 107 | public int getHeight() { 108 | return height; 109 | } 110 | 111 | public void setHeight(int height) { 112 | this.height = height; 113 | } 114 | 115 | public long getSize() { 116 | return size; 117 | } 118 | 119 | public void setSize(long size) { 120 | this.size = size; 121 | } 122 | 123 | public String getMediaUri() { 124 | if (Build.VERSION.SDK_INT >= 29) { 125 | Uri mediaUri = mimetype.startsWith("image") ? MediaStore.Images.Media.EXTERNAL_CONTENT_URI : MediaStore.Video.Media.EXTERNAL_CONTENT_URI; 126 | return mediaUri.buildUpon().appendPath(String.valueOf(getId())).build().toString(); 127 | } else { 128 | return "file:///" + getPath(); 129 | } 130 | } 131 | 132 | @Override 133 | public String toString() { 134 | return "Photo{" + 135 | "id=" + id + 136 | ", path='" + path + '\'' + 137 | ", mimetype='" + mimetype + '\'' + 138 | ", duration=" + duration + 139 | ", width=" + width + 140 | ", height=" + height + 141 | ", size=" + size + 142 | ", fullImage=" + fullImage + 143 | '}'; 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /uikit/src/main/java/com/hai/mediapicker/entity/PhotoDirectory.java: -------------------------------------------------------------------------------- 1 | package com.hai.mediapicker.entity; 2 | 3 | import android.net.Uri; 4 | import android.os.Build; 5 | import android.provider.MediaStore; 6 | 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | 11 | /** 12 | * Created by donglua on 15/6/28. 13 | */ 14 | public class PhotoDirectory { 15 | 16 | private int id; 17 | private String coverUri; 18 | private String name; 19 | private long dateAdded; 20 | private List photos = new ArrayList<>(); 21 | private boolean selected = false; 22 | 23 | @Override 24 | public boolean equals(Object o) { 25 | if (this == o) return true; 26 | if (!(o instanceof PhotoDirectory)) return false; 27 | 28 | PhotoDirectory directory = (PhotoDirectory) o; 29 | return id == directory.getId(); 30 | } 31 | 32 | public boolean isSelected() { 33 | return selected; 34 | } 35 | 36 | public void setSelected(boolean selected) { 37 | this.selected = selected; 38 | } 39 | 40 | 41 | public int getId() { 42 | return id; 43 | } 44 | 45 | public void setId(int id) { 46 | this.id = id; 47 | } 48 | 49 | public String getCoverUri() { 50 | return coverUri; 51 | } 52 | 53 | public void setCoverUri(Photo coverPath) { 54 | if (Build.VERSION.SDK_INT >= 29) { 55 | Uri mediaUri = coverPath.getMimetype().startsWith("image")?MediaStore.Images.Media.EXTERNAL_CONTENT_URI:MediaStore.Video.Media.EXTERNAL_CONTENT_URI; 56 | int id = coverPath.getId(); 57 | this.coverUri = mediaUri.buildUpon().appendPath(String.valueOf(id)).build().toString(); 58 | } else { 59 | this.coverUri = "file:///" + coverPath; 60 | } 61 | } 62 | 63 | 64 | 65 | public String getName() { 66 | return name; 67 | } 68 | 69 | public void setName(String name) { 70 | this.name = name; 71 | } 72 | 73 | public long getDateAdded() { 74 | return dateAdded; 75 | } 76 | 77 | public void setDateAdded(long dateAdded) { 78 | this.dateAdded = dateAdded; 79 | } 80 | 81 | public List getPhotos() { 82 | return photos; 83 | } 84 | 85 | public void setPhotos(List photos) { 86 | if (photos == null) return; 87 | for (int i = 0, j = 0, num = photos.size(); i < num; i++) { 88 | Photo p = photos.get(j); 89 | if (p == null) { 90 | photos.remove(j); 91 | } else { 92 | j++; 93 | } 94 | } 95 | this.photos = photos; 96 | } 97 | 98 | public List getPhotoPaths() { 99 | List paths = new ArrayList<>(photos.size()); 100 | for (Photo photo : photos) { 101 | paths.add(photo.getPath()); 102 | } 103 | return paths; 104 | } 105 | 106 | public void addPhoto(Photo photo) { 107 | photos.add(photo); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /uikit/src/main/java/com/hai/mediapicker/save/BaseSaver.java: -------------------------------------------------------------------------------- 1 | package com.hai.mediapicker.save; 2 | 3 | import android.os.Environment; 4 | 5 | import java.io.File; 6 | import java.io.FileInputStream; 7 | import java.io.FileOutputStream; 8 | import java.io.IOException; 9 | import java.io.InputStream; 10 | 11 | /** 12 | * Created by Administrator on 2018/5/2. 13 | */ 14 | 15 | public class BaseSaver implements ISaver { 16 | 17 | String destDir; 18 | 19 | public BaseSaver() { 20 | destDir = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "DCIM" + File.separator + "Camera"; 21 | } 22 | 23 | public String getDestDir() { 24 | return destDir; 25 | } 26 | 27 | public void setDestDir(String destFile) { 28 | this.destDir = destFile; 29 | } 30 | 31 | @Override 32 | public boolean save(String previousFile) { 33 | try { 34 | File preFile = new File(previousFile); 35 | File dir = new File(destDir); 36 | if (!dir.exists()) 37 | dir.mkdirs(); 38 | File destFile = new File(dir, preFile.getName()); 39 | if (destFile.exists()) 40 | destFile.delete(); 41 | copyToFile(new FileInputStream(preFile), destFile); 42 | 43 | //preFile.delete(); //取消删除拍摄的照片或视频,避免保存后再发送的时候文件已经不存在了(主要是影响的视频) 44 | } catch (Exception e) { 45 | e.printStackTrace(); 46 | return false; 47 | } 48 | return true; 49 | } 50 | 51 | /** 52 | * Copy data from a source stream to destFile. 53 | * Return true if succeed, return false if failed. 54 | */ 55 | public static boolean copyToFile(InputStream inputStream, File destFile) { 56 | try { 57 | if (destFile.exists()) { 58 | destFile.delete(); 59 | } 60 | FileOutputStream out = new FileOutputStream(destFile); 61 | try { 62 | byte[] buffer = new byte[4096]; 63 | int bytesRead; 64 | while ((bytesRead = inputStream.read(buffer)) >= 0) { 65 | out.write(buffer, 0, bytesRead); 66 | } 67 | } finally { 68 | out.flush(); 69 | try { 70 | out.getFD().sync(); 71 | } catch (IOException e) { 72 | } 73 | out.close(); 74 | } 75 | return true; 76 | } catch (IOException e) { 77 | return false; 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /uikit/src/main/java/com/hai/mediapicker/save/ISaver.java: -------------------------------------------------------------------------------- 1 | package com.hai.mediapicker.save; 2 | 3 | /** 4 | * Created by Administrator on 2018/5/2. 5 | */ 6 | 7 | public interface ISaver { 8 | boolean save(String previousFile); 9 | } 10 | -------------------------------------------------------------------------------- /uikit/src/main/java/com/hai/mediapicker/util/GalleryFinal.java: -------------------------------------------------------------------------------- 1 | package com.hai.mediapicker.util; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | 6 | import com.hai.mediapicker.activity.AlbumActivity; 7 | import com.hai.mediapicker.activity.CaptureActivity; 8 | import com.hai.mediapicker.activity.CaptureActivity2; 9 | import com.hai.mediapicker.activity.MediaPickerActivity; 10 | import com.hai.mediapicker.entity.Photo; 11 | import com.hai.mediapicker.save.BaseSaver; 12 | import com.hai.mediapicker.save.ISaver; 13 | 14 | import java.util.ArrayList; 15 | 16 | /** 17 | * Created by Administrator on 2017/3/16. 18 | */ 19 | 20 | public class GalleryFinal { 21 | public static OnSelectMediaListener mOnSelectMediaListener; 22 | public static OnCaptureListener mOnCaptureListener; 23 | public static final int TYPE_IMAGE = 1;//图片类型 24 | public static final int TYPE_VIDEO = 2;//视频类型 25 | public static final int TYPE_ALL = 3;//所有类型 26 | private static ISaver iSaver = new BaseSaver(); 27 | 28 | private static boolean isSelfie = false;//默认是否进来就是自拍模式 29 | 30 | public static void initSaver(ISaver iSaver) { 31 | GalleryFinal.iSaver = iSaver; 32 | } 33 | 34 | public static ISaver getSaver() { 35 | return iSaver; 36 | } 37 | 38 | public static final int IMAGE_ENGINE_IMAGE_LOADER = 1; 39 | public static final int IMAGE_ENGINE_GLIDE = 2; 40 | private static int imageEngine = IMAGE_ENGINE_IMAGE_LOADER; 41 | 42 | public static void setImageEngine(int imageEngine) { 43 | if (imageEngine == IMAGE_ENGINE_IMAGE_LOADER) { 44 | GalleryFinal.imageEngine = imageEngine; 45 | return; 46 | } 47 | GalleryFinal.imageEngine = IMAGE_ENGINE_GLIDE; 48 | } 49 | 50 | public static int getImageEngine() { 51 | return imageEngine; 52 | } 53 | 54 | public static void selectMedias(Context context, int type, int maxSum, OnSelectMediaListener onSelectMediaListener) { 55 | mOnSelectMediaListener = onSelectMediaListener; 56 | Intent intent = new Intent(context, MediaPickerActivity.class); 57 | intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 58 | intent.putExtra("maxSum", maxSum); 59 | if (type != TYPE_ALL) 60 | intent.putExtra("type", type); 61 | context.startActivity(intent); 62 | } 63 | 64 | public static void selectMedias(Context context, int maxSum, OnSelectMediaListener onSelectMediaListener) { 65 | selectMedias(context, TYPE_ALL, maxSum, onSelectMediaListener); 66 | } 67 | 68 | public static void selectMedias(Context context, int type, int maxSum) { 69 | mOnSelectMediaListener = null; 70 | Intent intent = new Intent(context, MediaPickerActivity.class); 71 | intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 72 | intent.putExtra("maxSum", maxSum); 73 | if (type != TYPE_ALL) 74 | intent.putExtra("type", type); 75 | context.startActivity(intent); 76 | } 77 | 78 | /** 79 | * 自己提供数据供查看 80 | * @param context 81 | * @param maxSum 82 | * @param photoArrayList 83 | */ 84 | public static void selectMedias(Context context, int maxSum, ArrayList photoArrayList) { 85 | mOnSelectMediaListener = null; 86 | Intent intent = new Intent(context, AlbumActivity.class); 87 | intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 88 | intent.putExtra("maxSum", maxSum); 89 | intent.putExtra(AlbumActivity.EXTREA_PHOTOS, photoArrayList); 90 | context.startActivity(intent); 91 | } 92 | 93 | public static void showMedias(Context context, ArrayList photoArrayList) { 94 | mOnSelectMediaListener = null; 95 | Intent intent = new Intent(context, AlbumActivity.class); 96 | intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 97 | intent.putExtra(AlbumActivity.EXTREA_PHOTOS, photoArrayList); 98 | intent.putExtra(AlbumActivity.EXTREA_SELECT_MODE, false); 99 | context.startActivity(intent); 100 | } 101 | 102 | 103 | public static void selectMedias(Context context, int maxSum) { 104 | selectMedias(context, TYPE_ALL, maxSum); 105 | } 106 | 107 | 108 | public static boolean isSelfie() { 109 | return isSelfie; 110 | } 111 | 112 | public static void setDefaultSelfie(boolean isSelfie) { 113 | GalleryFinal.isSelfie = isSelfie; 114 | } 115 | 116 | /** 117 | * @param context 118 | * @param destnationPath 目录路径,非最终的媒体文件的路径 119 | */ 120 | public static void captureMedia(Context context, String destnationPath) { 121 | captureMedia(context, TYPE_ALL, destnationPath, -1); 122 | } 123 | 124 | public static void captureMedia(Context context, int type, String destnationPath) { 125 | captureMedia(context, type, destnationPath, -1); 126 | } 127 | 128 | public static void captureMedia(Context context, int type, String destnationPath, OnCaptureListener onCaptureListener) { 129 | captureMedia(context, type, destnationPath, -1, onCaptureListener); 130 | } 131 | 132 | /** 133 | * @param context 134 | * @param type 135 | * @param destnationPath 136 | * @param maxDuration 137 | */ 138 | public static void captureMedia(Context context, int type, String destnationPath, int maxDuration) { 139 | captureMedia(context, type, destnationPath, maxDuration, null); 140 | } 141 | 142 | /** 143 | * @param context 144 | * @param type:TYPE_IMAGE,TYPE_ALL 只能选择图片或者图片和视频都可以的 145 | * @param destnationPath 146 | * @param maxDuration 147 | * @param onCaptureListener 148 | */ 149 | public static void captureMedia(Context context, int type, String destnationPath, int maxDuration, OnCaptureListener onCaptureListener) { 150 | mOnCaptureListener = onCaptureListener; 151 | Intent intent = new Intent(context, CaptureActivity.class); 152 | intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 153 | if (type != TYPE_IMAGE) 154 | type = TYPE_ALL; 155 | intent.putExtra("type", type); 156 | intent.putExtra("destnationPath", destnationPath); 157 | if (maxDuration > 0) 158 | intent.putExtra("maxDuration", maxDuration); 159 | context.startActivity(intent); 160 | } 161 | 162 | public interface OnSelectMediaListener { 163 | void onSelected(ArrayList photoArrayList); 164 | } 165 | 166 | public interface OnCaptureListener { 167 | void onSelected(Photo photo); 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /uikit/src/main/java/com/hai/mediapicker/util/MediaManager.java: -------------------------------------------------------------------------------- 1 | package com.hai.mediapicker.util; 2 | 3 | import com.hai.mediapicker.entity.Photo; 4 | import com.hai.mediapicker.entity.PhotoDirectory; 5 | 6 | import org.greenrobot.eventbus.EventBus; 7 | 8 | import java.util.ArrayList; 9 | import java.util.HashMap; 10 | import java.util.List; 11 | import java.util.Map; 12 | 13 | /** 14 | * Created by Administrator on 2017/3/14. 15 | */ 16 | 17 | public class MediaManager { 18 | private static final MediaManager ourInstance = new MediaManager(); 19 | 20 | public static MediaManager getInstance() { 21 | return ourInstance; 22 | } 23 | 24 | private MediaManager() { 25 | } 26 | 27 | Map checkStatus; 28 | Map originalImage; 29 | List onCheckchangeListeners; 30 | List photoDirectorys; 31 | private int maxMediaSum; 32 | private int selectIndex; 33 | 34 | public void init() { 35 | checkStatus = new HashMap<>(); 36 | onCheckchangeListeners = new ArrayList<>(); 37 | photoDirectorys = new ArrayList<>(); 38 | originalImage = new HashMap<>(); 39 | maxMediaSum = Integer.MAX_VALUE; 40 | selectIndex = 0; 41 | } 42 | 43 | public void clear() { 44 | checkStatus.clear(); 45 | originalImage.clear(); 46 | photoDirectorys.clear(); 47 | } 48 | 49 | public int getMaxMediaSum() { 50 | return maxMediaSum; 51 | } 52 | 53 | public void setMaxMediaSum(int maxMediaSum) { 54 | this.maxMediaSum = maxMediaSum; 55 | } 56 | 57 | public void addOnCheckchangeListener(OnCheckchangeListener onCheckchangeListener) { 58 | if (onCheckchangeListener != null) { 59 | onCheckchangeListeners.add(onCheckchangeListener); 60 | } 61 | } 62 | 63 | public void removeOnCheckchangeListener(OnCheckchangeListener onCheckchangeListener) { 64 | if (onCheckchangeListener != null) 65 | onCheckchangeListeners.remove(onCheckchangeListener); 66 | } 67 | 68 | /** 69 | * 超过最大允许的数量就不能再添加了 70 | * 71 | * @param id 72 | * @param photo 73 | * @param uiUpdated 74 | * @return 75 | */ 76 | public boolean addMedia(int id, Photo photo, boolean uiUpdated) { 77 | if (checkStatus.size() >= maxMediaSum) { 78 | return false; 79 | } 80 | if (!checkStatus.containsKey(id)) { 81 | checkStatus.put(id, photo); 82 | notifyDataChange(id, uiUpdated); 83 | } 84 | return true; 85 | } 86 | 87 | public boolean addMedia(int id, Photo photo) { 88 | return addMedia(id, photo, false); 89 | } 90 | 91 | public void removeMedia(int id, boolean uiUpdated) { 92 | if (checkStatus.containsKey(id)) { 93 | checkStatus.remove(id); 94 | notifyDataChange(id, uiUpdated); 95 | } 96 | } 97 | 98 | public void removeMedia(int id) { 99 | if (checkStatus.containsKey(id)) { 100 | checkStatus.remove(id); 101 | notifyDataChange(id, false); 102 | } 103 | } 104 | 105 | public int getSelectIndex() { 106 | return selectIndex; 107 | } 108 | 109 | public void setSelectIndex(int selectIndex) { 110 | this.selectIndex = selectIndex; 111 | } 112 | 113 | public boolean exsit(int id) { 114 | return checkStatus.containsKey(id); 115 | } 116 | 117 | public Map getCheckStatus() { 118 | return checkStatus; 119 | } 120 | 121 | public List getPhotoDirectorys() { 122 | return photoDirectorys; 123 | } 124 | 125 | public void setPhotoDirectorys(List photoDirectorys) { 126 | this.photoDirectorys = photoDirectorys; 127 | } 128 | 129 | public PhotoDirectory getSelectDirectory() { 130 | return photoDirectorys.get(selectIndex); 131 | } 132 | 133 | public void setOriginal(int id, boolean original) { 134 | originalImage.put(id, original); 135 | } 136 | 137 | public void removeOriginal(int id) { 138 | if (originalImage.containsKey(id)) 139 | originalImage.remove(id); 140 | } 141 | 142 | public boolean isOriginal(int id) { 143 | return originalImage.containsKey(id); 144 | } 145 | 146 | private void notifyDataChange(int id, boolean uiUpdated) { 147 | for (OnCheckchangeListener listner : 148 | onCheckchangeListeners) { 149 | listner.onCheckedChanged(checkStatus, id, uiUpdated); 150 | } 151 | } 152 | 153 | public interface OnCheckchangeListener { 154 | void onCheckedChanged(Map checkStaus, int changedId, boolean uiUpdated); 155 | } 156 | 157 | public void send() { 158 | ArrayList photoArrayList = new ArrayList<>(checkStatus.size()); 159 | for (Integer integer : checkStatus.keySet()) { 160 | Photo photo = checkStatus.get(integer); 161 | photo.setFullImage(originalImage.containsKey(photo.getId())); 162 | photoArrayList.add(photo); 163 | } 164 | 165 | if (GalleryFinal.mOnSelectMediaListener != null) 166 | GalleryFinal.mOnSelectMediaListener.onSelected(photoArrayList); 167 | EventBus.getDefault().post(photoArrayList); 168 | } 169 | 170 | } 171 | -------------------------------------------------------------------------------- /uikit/src/main/java/com/hai/mediapicker/util/MemoryLeakUtil.java: -------------------------------------------------------------------------------- 1 | package com.hai.mediapicker.util; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.util.Log; 6 | import android.view.View; 7 | import android.view.inputmethod.InputMethodManager; 8 | 9 | import java.lang.reflect.Field; 10 | 11 | /** 12 | * Created by Administrator on 2017/6/12. 13 | */ 14 | 15 | public class MemoryLeakUtil { 16 | 17 | 18 | 19 | /** 20 | * 修复输入法管理器引起的内存泄漏 21 | *

22 | * 有两种情况: 23 | * 1:启动这个activity之前还有activity,这个时候关闭当前activity,InputMethodManager的这三个变量都是之前的activity的,不能将他们置空,否则之前的activity键盘就弹不出来了。 24 | * 2:启动这个activity之前没有activity,这个时候关闭当前activity,InputMethodManager的这三个变量都是当前activity的,需要将他们都置空,否则就会导致当前activity泄漏 25 | * 26 | * @param destContext 27 | */ 28 | public static void fixInputMethodManagerLeak(Context destContext) { 29 | if (destContext == null) { 30 | return; 31 | } 32 | 33 | InputMethodManager imm = (InputMethodManager) destContext.getSystemService(Context.INPUT_METHOD_SERVICE); 34 | if (imm == null) { 35 | return; 36 | } 37 | 38 | String[] arr = new String[]{"mCurRootView", "mServedView", "mNextServedView", "mLastSrvView"}; 39 | Field f = null; 40 | Object obj_get = null; 41 | Activity activity = (Activity) destContext; 42 | for (int i = 0; i < arr.length; i++) { 43 | String param = arr[i]; 44 | try { 45 | f = imm.getClass().getDeclaredField(param); 46 | if (f.isAccessible() == false) { 47 | f.setAccessible(true); 48 | } // author: sodino mail:sodino@qq.com 49 | obj_get = f.get(imm); 50 | 51 | if (obj_get != null && obj_get instanceof View) { 52 | View view = ((View) obj_get); 53 | if (view.getId() == -1) { 54 | Log.e("InputMethodManager", arr[i] + " view.getId()==-1" + view.getContext().getClass().getCanonicalName() + " " + destContext.getClass().getCanonicalName()); 55 | if (destContext == view.getContext()) { 56 | f.set(imm, null); // 置空,破坏掉path to gc节点 57 | Log.e("InputMethodManager", arr[i] + "置空"); 58 | } 59 | continue; 60 | } 61 | View currentView = activity.findViewById(view.getId()); 62 | if (currentView != null && currentView == view) { 63 | f.set(imm, null); // 置空,破坏掉path to gc节点 64 | Log.e("InputMethodManager", arr[i] + "置空"); 65 | } else if (currentView != null) { 66 | Log.e("InputMethodManager", arr[i] + "保留"); 67 | } 68 | 69 | } 70 | } catch (Throwable t) { 71 | 72 | } 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /uikit/src/main/java/com/hai/mediapicker/view/PopupWindowMenu.java: -------------------------------------------------------------------------------- 1 | package com.hai.mediapicker.view; 2 | 3 | import android.app.Activity; 4 | import android.graphics.drawable.ColorDrawable; 5 | import android.os.Handler; 6 | import android.view.View; 7 | import android.view.ViewGroup.LayoutParams; 8 | import android.widget.AdapterView; 9 | import android.widget.BaseAdapter; 10 | import android.widget.ListView; 11 | import android.widget.PopupWindow; 12 | 13 | import com.hai.mediapicker.R; 14 | import com.hai.mediapicker.util.MediaManager; 15 | 16 | 17 | public class PopupWindowMenu extends PopupWindow { 18 | 19 | ListView listView; 20 | BaseAdapter baseAdapter; 21 | 22 | public PopupWindowMenu(Activity context, final AdapterView.OnItemClickListener onItemClickListener) { 23 | super(context); 24 | listView = new ListView(context); 25 | this.setContentView(listView); 26 | this.setWidth(LayoutParams.FILL_PARENT); 27 | this.setHeight(LayoutParams.WRAP_CONTENT); 28 | this.setFocusable(true); 29 | this.setAnimationStyle(R.style.PopupAnimation); 30 | ColorDrawable dw = new ColorDrawable(0xffffffff); 31 | // ColorDrawable dw = new ColorDrawable(0xb0000000); 32 | this.setBackgroundDrawable(dw); 33 | listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { 34 | @Override 35 | public void onItemClick(AdapterView parent, View view, int position, long id) { 36 | MediaManager mediaManager = MediaManager.getInstance(); 37 | if (position == mediaManager.getSelectIndex()) { 38 | dismiss(); 39 | return; 40 | } 41 | 42 | mediaManager.getSelectDirectory().setSelected(false); 43 | mediaManager.getPhotoDirectorys().get(position).setSelected(true); 44 | mediaManager.setSelectIndex(position); 45 | baseAdapter.notifyDataSetChanged(); 46 | if (onItemClickListener != null) 47 | onItemClickListener.onItemClick(parent, view, position, id); 48 | new Handler().postDelayed(new Runnable() { 49 | @Override 50 | public void run() { 51 | dismiss();//直接关闭的话视图不会立刻修改过来,看起来不舒服,等他修改过来后再关闭,体验好些 52 | } 53 | }, 200); 54 | } 55 | }); 56 | } 57 | 58 | public void setAdapter(BaseAdapter baseAdapter) { 59 | listView.setAdapter(baseAdapter); 60 | this.baseAdapter = baseAdapter; 61 | } 62 | 63 | public BaseAdapter getAdapter() { 64 | return baseAdapter; 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /uikit/src/main/java/com/hai/mediapicker/view/RingProgress.java: -------------------------------------------------------------------------------- 1 | package com.hai.mediapicker.view; 2 | 3 | import android.content.Context; 4 | import android.content.res.TypedArray; 5 | import android.graphics.Canvas; 6 | import android.graphics.Color; 7 | import android.graphics.Paint; 8 | import android.graphics.RectF; 9 | import android.support.annotation.Nullable; 10 | import android.util.AttributeSet; 11 | import android.util.Log; 12 | import android.view.View; 13 | 14 | import com.hai.mediapicker.R; 15 | 16 | /** 17 | * Created by Administrator on 2017/6/14. 18 | */ 19 | 20 | public class RingProgress extends View{ 21 | 22 | int max,progress; 23 | int finishColor,backgroundColor; 24 | int stokeWidth; 25 | 26 | public static final int START_FROM_TOP=-90; 27 | public static final int START_FROM_RIGHT=0; 28 | public static final int START_FROM_BOTTOM=90; 29 | public static final int START_FROM_LEFT=180; 30 | int startAngle=START_FROM_TOP; 31 | 32 | Paint paint,bgPaint; 33 | public RingProgress(Context context, @Nullable AttributeSet attrs) { 34 | super(context, attrs); 35 | 36 | TypedArray typedArray = context.obtainStyledAttributes(attrs,R.styleable.RingProgress); 37 | 38 | max = typedArray.getInteger(R.styleable.RingProgress_max,100); 39 | progress=typedArray.getInteger(R.styleable.RingProgress_progress,0); 40 | finishColor= typedArray.getColor(R.styleable.RingProgress_progress_color,Color.GREEN); 41 | backgroundColor=typedArray.getColor(R.styleable.RingProgress_background_color,Color.WHITE); 42 | stokeWidth = typedArray.getDimensionPixelSize(R.styleable.RingProgress_ring_width,10); 43 | startAngle = typedArray.getInteger(R.styleable.RingProgress_start_angle,START_FROM_TOP); 44 | 45 | typedArray.recycle(); 46 | 47 | 48 | paint = new Paint(Paint.ANTI_ALIAS_FLAG); 49 | paint.setColor(finishColor); 50 | paint.setStyle(Paint.Style.FILL); 51 | 52 | bgPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 53 | bgPaint.setColor(backgroundColor); 54 | bgPaint.setStyle(Paint.Style.FILL); 55 | } 56 | 57 | 58 | 59 | @Override 60 | protected void onDraw(Canvas canvas) { 61 | super.onDraw(canvas); 62 | RectF rectF=new RectF(0,0,getWidth(),getHeight()); 63 | 64 | canvas.drawArc(rectF,startAngle,360*progress*1.0f/max,true,paint); 65 | // canvas.drawArc(rectF,startAngle,360*progress*1.0f/max+startAngle,true,paint); 66 | canvas.drawCircle(getWidth()/2,getHeight()/2,getHeight()/2-stokeWidth,bgPaint); 67 | } 68 | 69 | public int getStartAngle() { 70 | return startAngle; 71 | } 72 | 73 | public void setStartAngle(int startAngle) { 74 | this.startAngle = startAngle; 75 | } 76 | 77 | public int getMax() { 78 | return max; 79 | } 80 | 81 | public void setMax(int max) { 82 | this.max = max; 83 | } 84 | 85 | public int getProgress() { 86 | return progress; 87 | } 88 | 89 | public void setProgress(int progress) { 90 | this.progress = progress; 91 | invalidate(); 92 | } 93 | 94 | public int getFinishColor() { 95 | return finishColor; 96 | } 97 | 98 | public void setFinishColor(int finishColor) { 99 | this.finishColor = finishColor; 100 | } 101 | 102 | public int getBackgroundColor() { 103 | return backgroundColor; 104 | } 105 | 106 | @Override 107 | public void setBackgroundColor(int backgroundColor) { 108 | this.backgroundColor = backgroundColor; 109 | } 110 | 111 | public int getStokeWidth() { 112 | return stokeWidth; 113 | } 114 | 115 | public void setStokeWidth(int stokeWidth) { 116 | this.stokeWidth = stokeWidth; 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /uikit/src/main/java/com/hai/mediapicker/view/SquareImageView.java: -------------------------------------------------------------------------------- 1 | package com.hai.mediapicker.view; 2 | 3 | import android.content.Context; 4 | import android.graphics.Canvas; 5 | import android.graphics.drawable.Drawable; 6 | import android.support.v7.widget.AppCompatImageView; 7 | import android.util.AttributeSet; 8 | 9 | /** 10 | * 作者:徐仕海 11 | * 公司:德宁普科技有限公司 12 | * Created on 2016/9/1 0001. 13 | */ 14 | public class SquareImageView extends AppCompatImageView { 15 | Drawable shade; 16 | boolean showShade = false; 17 | 18 | public SquareImageView(Context context) { 19 | super(context); 20 | } 21 | 22 | public SquareImageView(Context context, AttributeSet attrs) { 23 | super(context, attrs); 24 | } 25 | 26 | public SquareImageView(Context context, AttributeSet attrs, int defStyleAttr) { 27 | super(context, attrs, defStyleAttr); 28 | } 29 | 30 | @Override 31 | protected void onDraw(Canvas canvas) { 32 | super.onDraw(canvas); 33 | if (showShade && shade != null) { 34 | shade.setBounds(0, 0, getWidth(), getHeight()); 35 | shade.draw(canvas); 36 | } 37 | } 38 | 39 | public boolean isShowShade() { 40 | return showShade; 41 | } 42 | 43 | public Drawable getShade() { 44 | return shade; 45 | } 46 | 47 | public void setShade(Drawable shade) { 48 | this.shade = shade; 49 | } 50 | 51 | public void setShowShade(boolean showShade) { 52 | this.showShade = showShade; 53 | invalidate(); 54 | } 55 | 56 | public void justSetShowShade(boolean showShade) { 57 | this.showShade = showShade; 58 | } 59 | 60 | @Override 61 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 62 | super.onMeasure(widthMeasureSpec, widthMeasureSpec); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /uikit/src/main/java/com/hai/mediapicker/viewholder/GalleryHolder.java: -------------------------------------------------------------------------------- 1 | package com.hai.mediapicker.viewholder; 2 | 3 | import android.graphics.Color; 4 | import android.graphics.drawable.ColorDrawable; 5 | import android.support.v7.widget.AppCompatCheckBox; 6 | import android.support.v7.widget.RecyclerView; 7 | import android.view.View; 8 | import android.widget.ImageView; 9 | import android.widget.TextView; 10 | 11 | import com.hai.mediapicker.R; 12 | import com.hai.mediapicker.view.SquareImageView; 13 | 14 | /** 15 | * Created by Administrator on 2017/3/14. 16 | */ 17 | 18 | public class GalleryHolder extends RecyclerView.ViewHolder { 19 | public SquareImageView thumbIv; 20 | public AppCompatCheckBox appCompatCheckBox; 21 | public TextView tvVideoDuration,tvGifFlag; 22 | public ImageView ivVideoFlag; 23 | 24 | public GalleryHolder(View itemView) { 25 | super(itemView); 26 | itemView.setClickable(true); 27 | thumbIv = (SquareImageView) itemView.findViewById(R.id.iv_thumb); 28 | thumbIv.setScaleType(ImageView.ScaleType.CENTER_CROP); 29 | appCompatCheckBox = (AppCompatCheckBox) itemView.findViewById(R.id.cb_media); 30 | tvVideoDuration = (TextView) itemView.findViewById(R.id.tv_video_duration); 31 | tvGifFlag = (TextView) itemView.findViewById(R.id.tv_gif_flag); 32 | ivVideoFlag = (ImageView) itemView.findViewById(R.id.iv_video_flag); 33 | thumbIv.setShade(new ColorDrawable(Color.parseColor("#92000000"))); 34 | } 35 | } -------------------------------------------------------------------------------- /uikit/src/main/res/anim/push_bottom_in.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /uikit/src/main/res/anim/push_bottom_out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /uikit/src/main/res/drawable/btn_dropdown.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /uikit/src/main/res/drawable/btn_send_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /uikit/src/main/res/drawable/circle_with_221.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /uikit/src/main/res/drawable/circle_with_white.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /uikit/src/main/res/drawable/picker_item_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /uikit/src/main/res/layout-v14/texture_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 14 | 15 | 16 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /uikit/src/main/res/layout/activity_capture.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 13 | 14 | 15 | 16 | 21 | 22 | 31 | 32 | 41 | 42 | 50 | 51 | 52 | 58 | 59 | 68 | 69 | 75 | 76 | 77 | 78 | 88 | 89 | 98 | 107 | 108 | 109 | -------------------------------------------------------------------------------- /uikit/src/main/res/layout/activity_capture2.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 12 | 13 | 14 | 23 | 24 | 33 | 34 | 42 | 43 | 44 | 50 | 51 | 60 | 61 | 67 | 68 | 69 | 70 | 80 | 81 | 90 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /uikit/src/main/res/layout/activity_media_picker.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 16 | 17 | 18 | 24 | 25 | 26 | 27 | 28 | 34 | 35 |