diff --git a/multipleimageselect/.gitignore b/multipleimageselect/.gitignore new file mode 100644 index 00000000..796b96d1 --- /dev/null +++ b/multipleimageselect/.gitignore @@ -0,0 +1 @@ +/build diff --git a/multipleimageselect/build.gradle b/multipleimageselect/build.gradle new file mode 100644 index 00000000..e1b17a81 --- /dev/null +++ b/multipleimageselect/build.gradle @@ -0,0 +1,28 @@ +apply plugin: 'com.android.library' + +android { + compileSdkVersion 25 + buildToolsVersion "25.0.2" + + defaultConfig { + minSdkVersion 15 + targetSdkVersion 25 + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { + compile fileTree(dir: 'libs', include: ['*.jar']) + compile 'com.android.support:appcompat-v7:25.1.1' + compile 'com.github.bumptech.glide:glide:3.7.0' + compile 'com.android.support:design:25.1.1' +} diff --git a/multipleimageselect/proguard-rules.pro b/multipleimageselect/proguard-rules.pro new file mode 100644 index 00000000..85237996 --- /dev/null +++ b/multipleimageselect/proguard-rules.pro @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in /Users/zhouxiaodong/Library/Android/sdk/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/multipleimageselect/src/main/AndroidManifest.xml b/multipleimageselect/src/main/AndroidManifest.xml new file mode 100644 index 00000000..cdd2930b --- /dev/null +++ b/multipleimageselect/src/main/AndroidManifest.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + diff --git a/multipleimageselect/src/main/java/darsh/multipleimageselect/activities/AlbumSelectActivity.java b/multipleimageselect/src/main/java/darsh/multipleimageselect/activities/AlbumSelectActivity.java new file mode 100644 index 00000000..9037b95f --- /dev/null +++ b/multipleimageselect/src/main/java/darsh/multipleimageselect/activities/AlbumSelectActivity.java @@ -0,0 +1,334 @@ +package darsh.multipleimageselect.activities; + +import android.content.Context; +import android.content.Intent; +import android.content.res.Configuration; +import android.database.ContentObserver; +import android.database.Cursor; +import android.net.Uri; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.os.Process; +import android.provider.MediaStore; +import android.support.v7.app.ActionBar; +import android.support.v7.widget.Toolbar; +import android.util.DisplayMetrics; +import android.view.MenuItem; +import android.view.View; +import android.view.WindowManager; +import android.widget.GridView; +import android.widget.ProgressBar; +import android.widget.TextView; +import darsh.multipleimageselect.R; +import darsh.multipleimageselect.adapters.CustomAlbumSelectAdapter; +import darsh.multipleimageselect.helpers.Constants; +import darsh.multipleimageselect.models.Album; +import java.io.File; +import java.util.ArrayList; +import java.util.HashSet; + +/** + * Created by Darshan on 4/14/2015. + */ +public class AlbumSelectActivity extends HelperActivity + implements CustomAlbumSelectAdapter.OnItemClick { + private ArrayList albums; + + private TextView errorDisplay, txtTitle; + + private ProgressBar progressBar; + private GridView gridView; + private CustomAlbumSelectAdapter adapter; + + private ActionBar actionBar; + + private ContentObserver observer; + private Handler handler; + private Thread thread; + + private final String[] projection = new String[] { + MediaStore.Images.Media.BUCKET_ID, MediaStore.Images.Media.BUCKET_DISPLAY_NAME, + MediaStore.Images.Media.DATA + }; + + @Override protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_album_select); + setView(findViewById(R.id.layout_album_select)); + + Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); + txtTitle = (TextView) findViewById(R.id.txt_title); + setSupportActionBar(toolbar); + //SystemBarHelper.immersiveStatusBar(this); + //SystemBarHelper.setHeightAndPadding(this, toolbar); + actionBar = getSupportActionBar(); + if (actionBar != null) { + actionBar.setDisplayHomeAsUpEnabled(true); + actionBar.setHomeAsUpIndicator(R.drawable.ic_arrow_back); + actionBar.setDisplayShowTitleEnabled(false); + txtTitle.setText(getString(R.string.album_view)); + } + + Intent intent = getIntent(); + if (intent == null) { + finish(); + } + Constants.limit = intent.getIntExtra(Constants.INTENT_EXTRA_LIMIT, Constants.DEFAULT_LIMIT); + Constants.cameraEnable = intent.getBooleanExtra(Constants.EXTRA_CAMERA_ENABLE, false); + + errorDisplay = (TextView) findViewById(R.id.text_view_error); + errorDisplay.setVisibility(View.INVISIBLE); + + progressBar = (ProgressBar) findViewById(R.id.progress_bar_album_select); + gridView = (GridView) findViewById(R.id.grid_view_album_select); + } + + @Override protected void onStart() { + super.onStart(); + + handler = new Handler() { + @Override public void handleMessage(Message msg) { + switch (msg.what) { + case Constants.PERMISSION_GRANTED: { + loadAlbums(); + break; + } + + case Constants.FETCH_STARTED: { + progressBar.setVisibility(View.VISIBLE); + gridView.setVisibility(View.INVISIBLE); + break; + } + + case Constants.FETCH_COMPLETED: { + if (adapter == null) { + adapter = new CustomAlbumSelectAdapter(getApplicationContext(), albums, + Constants.cameraEnable); + gridView.setAdapter(adapter); + adapter.setOnItemClick(AlbumSelectActivity.this); + + progressBar.setVisibility(View.INVISIBLE); + gridView.setVisibility(View.VISIBLE); + orientationBasedUI(getResources().getConfiguration().orientation); + } else { + adapter.notifyDataSetChanged(); + } + break; + } + + case Constants.ERROR: { + progressBar.setVisibility(View.INVISIBLE); + errorDisplay.setVisibility(View.VISIBLE); + break; + } + + default: { + super.handleMessage(msg); + } + } + } + }; + observer = new ContentObserver(handler) { + @Override public void onChange(boolean selfChange, Uri uri) { + loadAlbums(); + } + }; + getContentResolver().registerContentObserver(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, + false, observer); + + checkPermission(); + } + + @Override protected void onStop() { + super.onStop(); + + stopThread(); + + getContentResolver().unregisterContentObserver(observer); + observer = null; + + if (handler != null) { + handler.removeCallbacksAndMessages(null); + handler = null; + } + } + + @Override protected void onDestroy() { + super.onDestroy(); + + if (actionBar != null) { + actionBar.setHomeAsUpIndicator(null); + } + albums = null; + if (adapter != null) { + adapter.setOnItemClick(null); + adapter.releaseResources(); + } + } + + @Override public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + orientationBasedUI(newConfig.orientation); + } + + private void orientationBasedUI(int orientation) { + final WindowManager windowManager = + (WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE); + final DisplayMetrics metrics = new DisplayMetrics(); + windowManager.getDefaultDisplay().getMetrics(metrics); + + if (adapter != null) { + int size = orientation == Configuration.ORIENTATION_PORTRAIT ? metrics.widthPixels / 2 + : metrics.widthPixels / 4; + adapter.setLayoutParams(size); + } + gridView.setNumColumns(orientation == Configuration.ORIENTATION_PORTRAIT ? 2 : 4); + } + + @Override public void onBackPressed() { + super.onBackPressed(); + setResult(RESULT_CANCELED); + finish(); + } + + @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (requestCode == Constants.REQUEST_CODE && resultCode == RESULT_OK && data != null) { + setResult(RESULT_OK, data); + finish(); + } + } + + @Override public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: { + onBackPressed(); + return true; + } + + default: { + return false; + } + } + } + + private void loadAlbums() { + startThread(new AlbumLoaderRunnable()); + } + + /** + * 选择图片 + */ + @Override public void select(int position) { + Intent intent = new Intent(getApplicationContext(), ImageSelectActivity.class); + intent.putExtra(Constants.INTENT_EXTRA_ALBUM, albums.get(position).name); + startActivityForResult(intent, Constants.REQUEST_CODE); + } + + /** + * 拍照 + */ + @Override public void takePhoto() { + Intent intent = new Intent(); + intent.putExtra(Constants.INTENT_EXTRA_START_CAMERA, true); + setResult(RESULT_OK, intent); + finish(); + } + + private class AlbumLoaderRunnable implements Runnable { + @Override public void run() { + Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); + + if (adapter == null) { + sendMessage(Constants.FETCH_STARTED); + } + + Cursor cursor = getApplicationContext().getContentResolver() + .query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, projection, null, null, + MediaStore.Images.Media.DATE_ADDED); + if (cursor == null) { + sendMessage(Constants.ERROR); + return; + } + + ArrayList temp = new ArrayList<>(cursor.getCount()); + HashSet albumSet = new HashSet<>(); + File file; + if (cursor.moveToLast()) { + do { + if (Thread.interrupted()) { + return; + } + + long albumId = cursor.getLong(cursor.getColumnIndex(projection[0])); + String album = cursor.getString(cursor.getColumnIndex(projection[1])); + String image = cursor.getString(cursor.getColumnIndex(projection[2])); + + if (!albumSet.contains(albumId)) { + /* + It may happen that some image file paths are still present in cache, + though image file does not exist. These last as long as media + scanner is not run again. To avoid get such image file paths, check + if image file exists. + */ + file = new File(image); + if (file.exists()) { + temp.add(new Album(album, image)); + albumSet.add(albumId); + } + } + } while (cursor.moveToPrevious()); + } + cursor.close(); + + if (albums == null) { + albums = new ArrayList<>(); + } + albums.clear(); + albums.addAll(temp); + + sendMessage(Constants.FETCH_COMPLETED); + } + } + + private void startThread(Runnable runnable) { + stopThread(); + thread = new Thread(runnable); + thread.start(); + } + + private void stopThread() { + if (thread == null || !thread.isAlive()) { + return; + } + + thread.interrupt(); + try { + thread.join(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + private void sendMessage(int what) { + if (handler == null) { + return; + } + + Message message = handler.obtainMessage(); + message.what = what; + message.sendToTarget(); + } + + @Override protected void permissionGranted() { + Message message = handler.obtainMessage(); + message.what = Constants.PERMISSION_GRANTED; + message.sendToTarget(); + } + + @Override protected void hideViews() { + progressBar.setVisibility(View.INVISIBLE); + gridView.setVisibility(View.INVISIBLE); + } +} diff --git a/multipleimageselect/src/main/java/darsh/multipleimageselect/activities/HelperActivity.java b/multipleimageselect/src/main/java/darsh/multipleimageselect/activities/HelperActivity.java new file mode 100644 index 00000000..c3ec1eaa --- /dev/null +++ b/multipleimageselect/src/main/java/darsh/multipleimageselect/activities/HelperActivity.java @@ -0,0 +1,117 @@ +package darsh.multipleimageselect.activities; + +import android.Manifest; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.net.Uri; +import android.provider.Settings; +import android.support.annotation.NonNull; +import android.support.design.widget.Snackbar; +import android.support.v4.app.ActivityCompat; +import android.support.v4.content.ContextCompat; +import android.support.v7.app.AppCompatActivity; +import android.view.View; +import darsh.multipleimageselect.R; +import darsh.multipleimageselect.helpers.Constants; + +/** + * Created by darshan on 26/9/16. + */ +public class HelperActivity extends AppCompatActivity { + protected View view; + + private final int maxLines = 4; + private final String[] permissions = new String[]{ Manifest.permission.WRITE_EXTERNAL_STORAGE }; + + protected void checkPermission() { + if (ContextCompat.checkSelfPermission(this, + Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) { + permissionGranted(); + + } else { + ActivityCompat.requestPermissions(this, permissions, Constants.PERMISSION_REQUEST_CODE); + } + } + + private void requestPermission() { + if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) { + showRequestPermissionRationale(); + + } else { + showAppPermissionSettings(); + } + } + + private void showRequestPermissionRationale() { + Snackbar snackbar = Snackbar.make( + view, + getString(R.string.permission_info), + Snackbar.LENGTH_INDEFINITE) + .setAction(getString(R.string.permission_ok), new View.OnClickListener() { + @Override + public void onClick(View v) { + ActivityCompat.requestPermissions( + HelperActivity.this, + permissions, + Constants.PERMISSION_REQUEST_CODE); + } + }); + + /*((TextView) snackbar.getView() + .findViewById(android.support.design.R.id.snackbar_text)).setMaxLines(maxLines);*/ + snackbar.show(); + } + + private void showAppPermissionSettings() { + Snackbar snackbar = Snackbar.make( + view, + getString(R.string.permission_force), + Snackbar.LENGTH_INDEFINITE) + .setAction(getString(R.string.permission_settings), new View.OnClickListener() { + @Override + public void onClick(View v) { + Uri uri = Uri.fromParts( + getString(R.string.permission_package), + HelperActivity.this.getPackageName(), + null); + + Intent intent = new Intent(); + intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); + intent.setData(uri); + startActivityForResult(intent, Constants.PERMISSION_REQUEST_CODE); + } + }); + + /*((TextView) snackbar.getView() + .findViewById(android.support.design.R.id.snackbar_text)).setMaxLines(maxLines);*/ + snackbar.show(); + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull + int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + if (requestCode != Constants.PERMISSION_REQUEST_CODE + || grantResults.length == 0 + || grantResults[0] == PackageManager.PERMISSION_DENIED) { + permissionDenied(); + + } else { + permissionGranted(); + } + } + + protected void permissionGranted() {} + + private void permissionDenied() { + hideViews(); + requestPermission(); + } + + protected void hideViews() {} + + protected void setView(View view) { + this.view = view; + } +} diff --git a/multipleimageselect/src/main/java/darsh/multipleimageselect/activities/ImageSelectActivity.java b/multipleimageselect/src/main/java/darsh/multipleimageselect/activities/ImageSelectActivity.java new file mode 100644 index 00000000..22eda201 --- /dev/null +++ b/multipleimageselect/src/main/java/darsh/multipleimageselect/activities/ImageSelectActivity.java @@ -0,0 +1,386 @@ +package darsh.multipleimageselect.activities; + +import android.content.Context; +import android.content.Intent; +import android.content.res.Configuration; +import android.database.ContentObserver; +import android.database.Cursor; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.os.Process; +import android.provider.MediaStore; +import android.support.v7.app.ActionBar; +import android.support.v7.widget.Toolbar; +import android.text.TextUtils; +import android.util.DisplayMetrics; +import android.view.View; +import android.view.WindowManager; +import android.widget.AdapterView; +import android.widget.GridView; +import android.widget.ProgressBar; +import android.widget.TextView; +import android.widget.Toast; +import darsh.multipleimageselect.R; +import darsh.multipleimageselect.adapters.CustomImageSelectAdapter; +import darsh.multipleimageselect.helpers.Constants; +import darsh.multipleimageselect.models.Image; +import java.io.File; +import java.util.ArrayList; +import java.util.HashSet; + +/** + * Created by Darshan on 4/18/2015. + */ +public class ImageSelectActivity extends HelperActivity { + private ArrayList images; + private String album; + + private TextView errorDisplay, txtFinish, txtTitle; + + private ProgressBar progressBar; + private GridView gridView; + private CustomImageSelectAdapter adapter; + + private ActionBar actionBar; + + private int countSelected; + + private ContentObserver observer; + private Handler handler; + private Thread thread; + + private final String[] projection = new String[] { + MediaStore.Images.Media._ID, MediaStore.Images.Media.DISPLAY_NAME, + MediaStore.Images.Media.DATA + }; + + @Override protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_image_select); + setView(findViewById(R.id.layout_image_select)); + Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); + txtFinish = (TextView) findViewById(R.id.txt_finish); + txtTitle = (TextView) findViewById(R.id.txt_title); + setSupportActionBar(toolbar); + //SystemBarHelper.immersiveStatusBar(this); + //SystemBarHelper.setHeightAndPadding(this, toolbar); + actionBar = getSupportActionBar(); + if (actionBar != null) { + actionBar.setDisplayHomeAsUpEnabled(true); + actionBar.setHomeAsUpIndicator(R.drawable.ic_arrow_back); + actionBar.setDisplayShowTitleEnabled(false); + setTitle(getString(R.string.image_view)); + } + toolbar.setNavigationOnClickListener(new View.OnClickListener() { + @Override public void onClick(View view) { + onBackPressed(); + } + }); + txtFinish.setOnClickListener(new View.OnClickListener() { + @Override public void onClick(View v) { + if (countSelected > 0) sendIntent(); + } + }); + Intent intent = getIntent(); + if (intent == null) { + finish(); + } + album = intent.getStringExtra(Constants.INTENT_EXTRA_ALBUM); + + errorDisplay = (TextView) findViewById(R.id.text_view_error); + errorDisplay.setVisibility(View.INVISIBLE); + + progressBar = (ProgressBar) findViewById(R.id.progress_bar_image_select); + gridView = (GridView) findViewById(R.id.grid_view_image_select); + gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override public void onItemClick(AdapterView parent, View view, int position, long id) { + toggleSelection(position); + String selectFormat = getString(R.string.selected); + setTitle(String.format(selectFormat, Constants.limit - countSelected + "张")); + txtFinish.setVisibility(View.VISIBLE); + if (countSelected == 0) { + setTitle(getString(R.string.image_view)); + txtFinish.setVisibility(View.INVISIBLE); + } + } + }); + } + + @Override protected void onStart() { + super.onStart(); + + handler = new Handler() { + @Override public void handleMessage(Message msg) { + switch (msg.what) { + case Constants.PERMISSION_GRANTED: { + loadImages(); + break; + } + + case Constants.FETCH_STARTED: { + progressBar.setVisibility(View.VISIBLE); + gridView.setVisibility(View.INVISIBLE); + break; + } + + case Constants.FETCH_COMPLETED: { + /* + If adapter is null, this implies that the loaded images will be shown + for the first time, hence send FETCH_COMPLETED message. + However, if adapter has been initialised, this thread was run either + due to the activity being restarted or content being changed. + */ + if (adapter == null) { + adapter = new CustomImageSelectAdapter(getApplicationContext(), images); + gridView.setAdapter(adapter); + + progressBar.setVisibility(View.INVISIBLE); + gridView.setVisibility(View.VISIBLE); + orientationBasedUI(getResources().getConfiguration().orientation); + } else { + adapter.notifyDataSetChanged(); + /* + Some selected images may have been deleted + hence update action mode title + */ + //if (actionMode != null) { + // countSelected = msg.arg1; + // actionMode.setTitle(countSelected + " 已选"); + //} + } + break; + } + + case Constants.ERROR: { + progressBar.setVisibility(View.INVISIBLE); + errorDisplay.setVisibility(View.VISIBLE); + break; + } + + default: { + super.handleMessage(msg); + } + } + } + }; + observer = new ContentObserver(handler) { + @Override public void onChange(boolean selfChange) { + loadImages(); + } + }; + getContentResolver().registerContentObserver(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, + false, observer); + + checkPermission(); + } + + @Override protected void onStop() { + super.onStop(); + + stopThread(); + + getContentResolver().unregisterContentObserver(observer); + observer = null; + + if (handler != null) { + handler.removeCallbacksAndMessages(null); + handler = null; + } + } + + @Override protected void onDestroy() { + super.onDestroy(); + + if (actionBar != null) { + actionBar.setHomeAsUpIndicator(null); + } + images = null; + if (adapter != null) { + adapter.releaseResources(); + } + gridView.setOnItemClickListener(null); + } + + @Override public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + orientationBasedUI(newConfig.orientation); + } + + private void orientationBasedUI(int orientation) { + final WindowManager windowManager = + (WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE); + final DisplayMetrics metrics = new DisplayMetrics(); + windowManager.getDefaultDisplay().getMetrics(metrics); + + if (adapter != null) { + int size = orientation == Configuration.ORIENTATION_PORTRAIT ? metrics.widthPixels / 3 + : metrics.widthPixels / 5; + adapter.setLayoutParams(size); + } + gridView.setNumColumns(orientation == Configuration.ORIENTATION_PORTRAIT ? 3 : 5); + } + + private void toggleSelection(int position) { + if (!images.get(position).isSelected && countSelected >= Constants.limit) { + Toast.makeText(getApplicationContext(), "照片已经达到上限", Toast.LENGTH_SHORT).show(); + //Toast.makeText(getApplicationContext(), + // String.format(getString(R.string.limit_exceeded), Constants.limit), Toast.LENGTH_SHORT) + // .show(); + return; + } + + images.get(position).isSelected = !images.get(position).isSelected; + if (images.get(position).isSelected) { + countSelected++; + } else { + countSelected--; + } + adapter.notifyDataSetChanged(); + } + + private ArrayList getSelected() { + ArrayList selectedImages = new ArrayList<>(); + for (int i = 0, l = images.size(); i < l; i++) { + if (images.get(i).isSelected) { + selectedImages.add(images.get(i)); + } + } + return selectedImages; + } + + private void sendIntent() { + Intent intent = new Intent(); + intent.putParcelableArrayListExtra(Constants.INTENT_EXTRA_IMAGES, getSelected()); + intent.putExtra(Constants.INTENT_EXTRA_START_CAMERA, false); + setResult(RESULT_OK, intent); + finish(); + } + + private void loadImages() { + startThread(new ImageLoaderRunnable()); + } + + private class ImageLoaderRunnable implements Runnable { + @Override public void run() { + Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); + /* + If the adapter is null, this is first time this activity's view is + being shown, hence send FETCH_STARTED message to show progress bar + while images are loaded from phone + */ + if (adapter == null) { + sendMessage(Constants.FETCH_STARTED); + } + + File file; + HashSet selectedImages = new HashSet<>(); + if (images != null) { + Image image; + for (int i = 0, l = images.size(); i < l; i++) { + image = images.get(i); + file = new File(image.path); + if (file.exists() && image.isSelected) { + selectedImages.add(image.id); + } + } + } + + Cursor cursor = + getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, projection, + MediaStore.Images.Media.BUCKET_DISPLAY_NAME + " =?", new String[] { album }, + MediaStore.Images.Media.DATE_ADDED); + if (cursor == null) { + sendMessage(Constants.ERROR); + return; + } + + /* + In case this runnable is executed to onChange calling loadImages, + using countSelected variable can result in a race condition. To avoid that, + tempCountSelected keeps track of number of selected images. On handling + FETCH_COMPLETED message, countSelected is assigned value of tempCountSelected. + */ + int tempCountSelected = 0; + ArrayList temp = new ArrayList<>(cursor.getCount()); + if (cursor.moveToLast()) { + do { + if (Thread.interrupted()) { + return; + } + + long id = cursor.getLong(cursor.getColumnIndex(projection[0])); + String name = cursor.getString(cursor.getColumnIndex(projection[1])); + String path = cursor.getString(cursor.getColumnIndex(projection[2])); + boolean isSelected = selectedImages.contains(id); + if (isSelected) { + tempCountSelected++; + } + + file = new File(path); + if (file.exists()) { + temp.add(new Image(id, name, path, isSelected)); + } + } while (cursor.moveToPrevious()); + } + cursor.close(); + + if (images == null) { + images = new ArrayList<>(); + } + images.clear(); + images.addAll(temp); + + sendMessage(Constants.FETCH_COMPLETED, tempCountSelected); + } + } + + private void startThread(Runnable runnable) { + stopThread(); + thread = new Thread(runnable); + thread.start(); + } + + private void stopThread() { + if (thread == null || !thread.isAlive()) { + return; + } + + thread.interrupt(); + try { + thread.join(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + private void sendMessage(int what) { + sendMessage(what, 0); + } + + private void sendMessage(int what, int arg1) { + if (handler == null) { + return; + } + + Message message = handler.obtainMessage(); + message.what = what; + message.arg1 = arg1; + message.sendToTarget(); + } + + @Override protected void permissionGranted() { + sendMessage(Constants.PERMISSION_GRANTED); + } + + @Override protected void hideViews() { + progressBar.setVisibility(View.INVISIBLE); + gridView.setVisibility(View.INVISIBLE); + } + + private void setTitle(String title) { + if (!TextUtils.isEmpty(title)) { + txtTitle.setText(title); + } + } +} diff --git a/multipleimageselect/src/main/java/darsh/multipleimageselect/adapters/CustomAlbumSelectAdapter.java b/multipleimageselect/src/main/java/darsh/multipleimageselect/adapters/CustomAlbumSelectAdapter.java new file mode 100644 index 00000000..5e35acaf --- /dev/null +++ b/multipleimageselect/src/main/java/darsh/multipleimageselect/adapters/CustomAlbumSelectAdapter.java @@ -0,0 +1,113 @@ +package darsh.multipleimageselect.adapters; + +import android.content.Context; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.TextView; +import com.bumptech.glide.Glide; +import darsh.multipleimageselect.R; +import darsh.multipleimageselect.models.Album; +import java.util.ArrayList; + +/** + * Created by Darshan on 4/14/2015. + */ +public class CustomAlbumSelectAdapter extends CustomGenericAdapter { + private boolean enableCamera; + private OnItemClick onItemClick; + + public CustomAlbumSelectAdapter(Context context, ArrayList albums, boolean enableCamera) { + super(context, albums); + this.enableCamera = enableCamera; + } + + public void setOnItemClick(OnItemClick onItemClick) { + this.onItemClick = onItemClick; + } + + @Override public int getCount() { + if (enableCamera) { + return super.getCount() + 1; + } + return super.getCount(); + } + + @Override public View getView(final int position, View convertView, ViewGroup parent) { + ViewHolder viewHolder; + + if (convertView == null) { + convertView = layoutInflater.inflate(R.layout.grid_view_item_album_select, null); + + viewHolder = new ViewHolder(); + viewHolder.imageView = (ImageView) convertView.findViewById(R.id.image_view_album_image); + viewHolder.textView = (TextView) convertView.findViewById(R.id.text_view_album_name); + viewHolder.frameLayout = (FrameLayout) convertView.findViewById(R.id.frame_album_item); + + convertView.setTag(viewHolder); + } else { + viewHolder = (ViewHolder) convertView.getTag(); + } + + viewHolder.imageView.getLayoutParams().width = size; + viewHolder.imageView.getLayoutParams().height = size; + //启用拍照 + if (enableCamera) { + if (0 == position) { + if (null != onItemClick) { + viewHolder.frameLayout.setOnClickListener(new View.OnClickListener() { + @Override public void onClick(View v) { + onItemClick.takePhoto(); + } + }); + } + viewHolder.textView.setText("拍照"); + Glide.with(context).load(R.drawable.ic_camera).centerCrop().into(viewHolder.imageView); + } else { + if (null != onItemClick) { + viewHolder.frameLayout.setOnClickListener(new View.OnClickListener() { + @Override public void onClick(View v) { + onItemClick.select(position-1); + } + }); + } + viewHolder.textView.setText(arrayList.get(position - 1).name); + Glide.with(context) + .load(arrayList.get(position - 1).cover) + .placeholder(R.drawable.image_placeholder) + .centerCrop() + .into(viewHolder.imageView); + } + } else { + //不启用拍照 + if (null != onItemClick) { + viewHolder.frameLayout.setOnClickListener(new View.OnClickListener() { + @Override public void onClick(View v) { + onItemClick.select(position); + } + }); + } + viewHolder.textView.setText(arrayList.get(position).name); + Glide.with(context) + .load(arrayList.get(position).cover) + .placeholder(R.drawable.image_placeholder) + .centerCrop() + .into(viewHolder.imageView); + } + + return convertView; + } + + private static class ViewHolder { + public FrameLayout frameLayout; + public ImageView imageView; + public TextView textView; + } + + public interface OnItemClick { + void select(int pos); + + void takePhoto(); + } +} diff --git a/multipleimageselect/src/main/java/darsh/multipleimageselect/adapters/CustomGenericAdapter.java b/multipleimageselect/src/main/java/darsh/multipleimageselect/adapters/CustomGenericAdapter.java new file mode 100644 index 00000000..768eecda --- /dev/null +++ b/multipleimageselect/src/main/java/darsh/multipleimageselect/adapters/CustomGenericAdapter.java @@ -0,0 +1,46 @@ +package darsh.multipleimageselect.adapters; + +import android.content.Context; +import android.view.LayoutInflater; +import android.widget.BaseAdapter; +import java.util.ArrayList; + +/** + * Created by Darshan on 4/24/2015. + */ +public abstract class CustomGenericAdapter extends BaseAdapter { + protected ArrayList arrayList; + protected Context context; + protected LayoutInflater layoutInflater; + + protected int size; + + public CustomGenericAdapter(Context context, ArrayList arrayList) { + this.arrayList = arrayList; + this.context = context; + this.layoutInflater = LayoutInflater.from(this.context); + } + + @Override + public int getCount() { + return arrayList.size(); + } + + public T getItem(int position) { + return arrayList.get(position); + } + + @Override + public long getItemId(int position) { + return position; + } + + public void setLayoutParams(int size) { + this.size = size; + } + + public void releaseResources() { + arrayList = null; + context = null; + } +} diff --git a/multipleimageselect/src/main/java/darsh/multipleimageselect/adapters/CustomImageSelectAdapter.java b/multipleimageselect/src/main/java/darsh/multipleimageselect/adapters/CustomImageSelectAdapter.java new file mode 100644 index 00000000..a19cb910 --- /dev/null +++ b/multipleimageselect/src/main/java/darsh/multipleimageselect/adapters/CustomImageSelectAdapter.java @@ -0,0 +1,65 @@ +package darsh.multipleimageselect.adapters; + +import android.content.Context; +import android.support.v4.content.ContextCompat; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.ImageView; +import com.bumptech.glide.Glide; +import darsh.multipleimageselect.R; +import darsh.multipleimageselect.models.Image; +import java.util.ArrayList; + +/** + * Created by Darshan on 4/18/2015. + */ +public class CustomImageSelectAdapter extends CustomGenericAdapter { + public CustomImageSelectAdapter(Context context, ArrayList images) { + super(context, images); + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + ViewHolder viewHolder; + + if (convertView == null) { + convertView = layoutInflater.inflate(R.layout.grid_view_item_image_select, null); + + viewHolder = new ViewHolder(); + viewHolder.imageView = (ImageView) convertView.findViewById(R.id.image_view_image_select); + viewHolder.view = convertView.findViewById(R.id.view_alpha); + + convertView.setTag(viewHolder); + + } else { + viewHolder = (ViewHolder) convertView.getTag(); + } + + viewHolder.imageView.getLayoutParams().width = size; + viewHolder.imageView.getLayoutParams().height = size; + + viewHolder.view.getLayoutParams().width = size; + viewHolder.view.getLayoutParams().height = size; + + if (arrayList.get(position).isSelected) { + viewHolder.view.setAlpha(0.5f); + ((FrameLayout) convertView).setForeground(ContextCompat.getDrawable(context,R.drawable.ic_done_white)); + + } else { + viewHolder.view.setAlpha(0.0f); + ((FrameLayout) convertView).setForeground(null); + } + + Glide.with(context) + .load(arrayList.get(position).path) + .placeholder(R.drawable.image_placeholder).into(viewHolder.imageView); + + return convertView; + } + + private static class ViewHolder { + public ImageView imageView; + public View view; + } +} diff --git a/multipleimageselect/src/main/java/darsh/multipleimageselect/helpers/Constants.java b/multipleimageselect/src/main/java/darsh/multipleimageselect/helpers/Constants.java new file mode 100644 index 00000000..add4b650 --- /dev/null +++ b/multipleimageselect/src/main/java/darsh/multipleimageselect/helpers/Constants.java @@ -0,0 +1,33 @@ +package darsh.multipleimageselect.helpers; + +/** + * Created by Darshan on 5/26/2015. + */ +public class Constants { + public static final int PERMISSION_REQUEST_CODE = 1000; + public static final int PERMISSION_GRANTED = 1001; + public static final int PERMISSION_DENIED = 1002; + + public static final int REQUEST_CODE = 2000; + + public static final int FETCH_STARTED = 2001; + public static final int FETCH_COMPLETED = 2002; + public static final int ERROR = 2005; + + /** + * Request code for permission has to be < (1 << 8) + * Otherwise throws java.lang.IllegalArgumentException: Can only use lower 8 bits for requestCode + */ + public static final int PERMISSION_REQUEST_READ_EXTERNAL_STORAGE = 23; + + public static final String INTENT_EXTRA_ALBUM = "album"; + public static final String INTENT_EXTRA_IMAGES = "images"; + public static final String INTENT_EXTRA_LIMIT = "limit"; + public static final String INTENT_EXTRA_START_CAMERA = "start_camera"; + public static final String EXTRA_CAMERA_ENABLE = "camera_enable"; + public static final int DEFAULT_LIMIT = 10; + + //Maximum number of images that can be selected at a time + public static int limit; + public static boolean cameraEnable; +} diff --git a/multipleimageselect/src/main/java/darsh/multipleimageselect/models/Album.java b/multipleimageselect/src/main/java/darsh/multipleimageselect/models/Album.java new file mode 100644 index 00000000..76e75804 --- /dev/null +++ b/multipleimageselect/src/main/java/darsh/multipleimageselect/models/Album.java @@ -0,0 +1,14 @@ +package darsh.multipleimageselect.models; + +/** + * Created by Darshan on 4/14/2015. + */ +public class Album { + public String name; + public String cover; + + public Album(String name, String cover) { + this.name = name; + this.cover = cover; + } +} diff --git a/multipleimageselect/src/main/java/darsh/multipleimageselect/models/Image.java b/multipleimageselect/src/main/java/darsh/multipleimageselect/models/Image.java new file mode 100644 index 00000000..d99217c8 --- /dev/null +++ b/multipleimageselect/src/main/java/darsh/multipleimageselect/models/Image.java @@ -0,0 +1,51 @@ +package darsh.multipleimageselect.models; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * Created by Darshan on 4/18/2015. + */ +public class Image implements Parcelable { + public long id; + public String name; + public String path; + public boolean isSelected; + + public Image(long id, String name, String path, boolean isSelected) { + this.id = id; + this.name = name; + this.path = path; + this.isSelected = isSelected; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeLong(id); + dest.writeString(name); + dest.writeString(path); + } + + public static final Creator CREATOR = new Creator() { + @Override + public Image createFromParcel(Parcel source) { + return new Image(source); + } + + @Override + public Image[] newArray(int size) { + return new Image[size]; + } + }; + + private Image(Parcel in) { + id = in.readLong(); + name = in.readString(); + path = in.readString(); + } +} diff --git a/multipleimageselect/src/main/res/drawable-xhdpi/ic_arrow_back.png b/multipleimageselect/src/main/res/drawable-xhdpi/ic_arrow_back.png new file mode 100644 index 00000000..ce5b878b Binary files /dev/null and b/multipleimageselect/src/main/res/drawable-xhdpi/ic_arrow_back.png differ diff --git a/multipleimageselect/src/main/res/drawable-xhdpi/ic_camera.png b/multipleimageselect/src/main/res/drawable-xhdpi/ic_camera.png new file mode 100644 index 00000000..17aa3be0 Binary files /dev/null and b/multipleimageselect/src/main/res/drawable-xhdpi/ic_camera.png differ diff --git a/multipleimageselect/src/main/res/drawable-xhdpi/ic_done_white.png b/multipleimageselect/src/main/res/drawable-xhdpi/ic_done_white.png new file mode 100644 index 00000000..0ebb5555 Binary files /dev/null and b/multipleimageselect/src/main/res/drawable-xhdpi/ic_done_white.png differ diff --git a/multipleimageselect/src/main/res/drawable-xxhdpi/ic_arrow_back.png b/multipleimageselect/src/main/res/drawable-xxhdpi/ic_arrow_back.png new file mode 100644 index 00000000..746d7757 Binary files /dev/null and b/multipleimageselect/src/main/res/drawable-xxhdpi/ic_arrow_back.png differ diff --git a/multipleimageselect/src/main/res/drawable-xxhdpi/ic_camera.png b/multipleimageselect/src/main/res/drawable-xxhdpi/ic_camera.png new file mode 100644 index 00000000..8d9c05e3 Binary files /dev/null and b/multipleimageselect/src/main/res/drawable-xxhdpi/ic_camera.png differ diff --git a/multipleimageselect/src/main/res/drawable-xxhdpi/ic_done_white.png b/multipleimageselect/src/main/res/drawable-xxhdpi/ic_done_white.png new file mode 100644 index 00000000..200dc733 Binary files /dev/null and b/multipleimageselect/src/main/res/drawable-xxhdpi/ic_done_white.png differ diff --git a/multipleimageselect/src/main/res/drawable/image_placeholder.xml b/multipleimageselect/src/main/res/drawable/image_placeholder.xml new file mode 100644 index 00000000..43ad7823 --- /dev/null +++ b/multipleimageselect/src/main/res/drawable/image_placeholder.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/multipleimageselect/src/main/res/layout/activity_album_select.xml b/multipleimageselect/src/main/res/layout/activity_album_select.xml new file mode 100644 index 00000000..16c8e360 --- /dev/null +++ b/multipleimageselect/src/main/res/layout/activity_album_select.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/multipleimageselect/src/main/res/layout/activity_image_select.xml b/multipleimageselect/src/main/res/layout/activity_image_select.xml new file mode 100644 index 00000000..9903c168 --- /dev/null +++ b/multipleimageselect/src/main/res/layout/activity_image_select.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/multipleimageselect/src/main/res/layout/grid_view_item_album_select.xml b/multipleimageselect/src/main/res/layout/grid_view_item_album_select.xml new file mode 100644 index 00000000..3b1a49ea --- /dev/null +++ b/multipleimageselect/src/main/res/layout/grid_view_item_album_select.xml @@ -0,0 +1,27 @@ + + + + + + + + \ No newline at end of file diff --git a/multipleimageselect/src/main/res/layout/grid_view_item_image_select.xml b/multipleimageselect/src/main/res/layout/grid_view_item_image_select.xml new file mode 100644 index 00000000..19a32a91 --- /dev/null +++ b/multipleimageselect/src/main/res/layout/grid_view_item_image_select.xml @@ -0,0 +1,21 @@ + + + + + + + \ No newline at end of file diff --git a/multipleimageselect/src/main/res/layout/toolbar.xml b/multipleimageselect/src/main/res/layout/toolbar.xml new file mode 100644 index 00000000..a2cce928 --- /dev/null +++ b/multipleimageselect/src/main/res/layout/toolbar.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/multipleimageselect/src/main/res/values/colors.xml b/multipleimageselect/src/main/res/values/colors.xml new file mode 100644 index 00000000..30605ab4 --- /dev/null +++ b/multipleimageselect/src/main/res/values/colors.xml @@ -0,0 +1,17 @@ + + + #FFFFFF + + #2E7D32 + #1B5E20 + #C8E6C9 + #4CAF50 + + #212121 + #727272 + #B6B6B6 + #FFFFFF + + #99FFFFFF + #000000 + \ No newline at end of file diff --git a/multipleimageselect/src/main/res/values/strings.xml b/multipleimageselect/src/main/res/values/strings.xml new file mode 100644 index 00000000..6934db08 --- /dev/null +++ b/multipleimageselect/src/main/res/values/strings.xml @@ -0,0 +1,18 @@ + + MultipleImageSelect + + OK + Settings + package + App requires permission to Storage to view images. + App requires permission to Storage to view images. Tap Settings + and go to Permissions to grant permission. + + Oops, something went wrong! + 选择图片 + 单击选择 + + 确定 + 还能选%1$s + 最多能选 %d 张 + diff --git a/multipleimageselect/src/main/res/values/style.xml b/multipleimageselect/src/main/res/values/style.xml new file mode 100644 index 00000000..d5241770 --- /dev/null +++ b/multipleimageselect/src/main/res/values/style.xml @@ -0,0 +1,16 @@ + + + + + + + \ No newline at end of file diff --git a/simple/build.gradle b/simple/build.gradle index 09ff929b..84a64c2b 100644 --- a/simple/build.gradle +++ b/simple/build.gradle @@ -22,4 +22,7 @@ android { dependencies { compile fileTree(include: ['*.jar'], dir: 'libs') compile project(':takephoto_library') + compile 'com.android.support:support-v4:25.3.0' + compile 'com.android.support:appcompat-v7:25.3.0' + compile 'com.android.support:design:25.3.0' } diff --git a/simple/src/main/AndroidManifest.xml b/simple/src/main/AndroidManifest.xml index 8908ec7c..8f1f2d93 100644 --- a/simple/src/main/AndroidManifest.xml +++ b/simple/src/main/AndroidManifest.xml @@ -5,7 +5,7 @@ android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" - android:theme="@style/AppTheme" > + android:theme="@style/Theme.AppCompat.NoActionBar" > 1){ - if(rgCrop.getCheckedRadioButtonId()==R.id.rbCropYes){ - takePhoto.onPickMultipleWithCrop(limit,getCropOptions()); - }else { - takePhoto.onPickMultiple(limit); - } - return; - } - if(rgFrom.getCheckedRadioButtonId()==R.id.rbFile){ - if(rgCrop.getCheckedRadioButtonId()==R.id.rbCropYes){ - takePhoto.onPickFromDocumentsWithCrop(imageUri,getCropOptions()); - }else { - takePhoto.onPickFromDocuments(); - } - return; - }else { - if(rgCrop.getCheckedRadioButtonId()==R.id.rbCropYes){ - takePhoto.onPickFromGalleryWithCrop(imageUri,getCropOptions()); - }else { - takePhoto.onPickFromGallery(); - } - } - break; - case R.id.btnPickByTake: - if(rgCrop.getCheckedRadioButtonId()==R.id.rbCropYes){ - takePhoto.onPickFromCaptureWithCrop(imageUri,getCropOptions()); - }else { - takePhoto.onPickFromCapture(imageUri); - } - break; - default: - break; + configCompress(takePhoto); + configTakePhotoOption(takePhoto); + switch (view.getId()) { + case R.id.btnPickBySelect: + int limit = Integer.parseInt(etLimit.getText().toString()); + if (limit > 1) { + boolean isEnableCamera = rgCameraSet.getCheckedRadioButtonId() == R.id.rbCameraEnable; + if (rgCrop.getCheckedRadioButtonId() == R.id.rbCropYes) { + takePhoto.onPickMultipleWithCrop(isEnableCamera, limit, getCropOptions()); + } else { + takePhoto.onPickMultiple(isEnableCamera, limit); + } + return; } - } - private void configTakePhotoOption(TakePhoto takePhoto){ - TakePhotoOptions.Builder builder=new TakePhotoOptions.Builder(); - if(rgPickTool.getCheckedRadioButtonId()==R.id.rbPickWithOwn){ - builder.setWithOwnGallery(true); + if (rgFrom.getCheckedRadioButtonId() == R.id.rbFile) { + if (rgCrop.getCheckedRadioButtonId() == R.id.rbCropYes) { + takePhoto.onPickFromDocumentsWithCrop(imageUri, getCropOptions()); + } else { + takePhoto.onPickFromDocuments(); + } + return; + } else { + if (rgCrop.getCheckedRadioButtonId() == R.id.rbCropYes) { + takePhoto.onPickFromGalleryWithCrop(imageUri, getCropOptions()); + } else { + takePhoto.onPickFromGallery(); + } } - if(rgCorrectTool.getCheckedRadioButtonId()==R.id.rbCorrectYes){ - builder.setCorrectImage(true); + break; + case R.id.btnPickByTake: + if (rgCrop.getCheckedRadioButtonId() == R.id.rbCropYes) { + takePhoto.onPickFromCaptureWithCrop(imageUri, getCropOptions()); + } else { + takePhoto.onPickFromCapture(imageUri); } - takePhoto.setTakePhotoOptions(builder.create()); - + break; + default: + break; } - private void configCompress(TakePhoto takePhoto){ - if(rgCompress.getCheckedRadioButtonId()!=R.id.rbCompressYes){ - takePhoto.onEnableCompress(null,false); - return ; - } - int maxSize= Integer.parseInt(etSize.getText().toString()); - int width= Integer.parseInt(etCropWidth.getText().toString()); - int height= Integer.parseInt(etHeightPx.getText().toString()); - boolean showProgressBar=rgShowProgressBar.getCheckedRadioButtonId()==R.id.rbShowYes? true:false; - boolean enableRawFile = rgRawFile.getCheckedRadioButtonId() == R.id.rbRawYes ? true : false; - CompressConfig config; - if(rgCompressTool.getCheckedRadioButtonId()==R.id.rbCompressWithOwn){ - config=new CompressConfig.Builder() - .setMaxSize(maxSize) - .setMaxPixel(width>=height? width:height) - .enableReserveRaw(enableRawFile) - .create(); - }else { - LubanOptions option=new LubanOptions.Builder() - .setMaxHeight(height) - .setMaxWidth(width) - .setMaxSize(maxSize) - .create(); - config=CompressConfig.ofLuban(option); - config.enableReserveRaw(enableRawFile); - } - takePhoto.onEnableCompress(config,showProgressBar); + } + private void configTakePhotoOption(TakePhoto takePhoto) { + TakePhotoOptions.Builder builder = new TakePhotoOptions.Builder(); + if (rgPickTool.getCheckedRadioButtonId() == R.id.rbPickWithOwn) { + builder.setWithOwnGallery(true); + } + if (rgCorrectTool.getCheckedRadioButtonId() == R.id.rbCorrectYes) { + builder.setCorrectImage(true); + } + takePhoto.setTakePhotoOptions(builder.create()); + } + private void configCompress(TakePhoto takePhoto) { + if (rgCompress.getCheckedRadioButtonId() != R.id.rbCompressYes) { + takePhoto.onEnableCompress(null, false); + return; + } + int maxSize = Integer.parseInt(etSize.getText().toString()); + int width = Integer.parseInt(etCropWidth.getText().toString()); + int height = Integer.parseInt(etHeightPx.getText().toString()); + boolean showProgressBar = + rgShowProgressBar.getCheckedRadioButtonId() == R.id.rbShowYes ? true : false; + boolean enableRawFile = rgRawFile.getCheckedRadioButtonId() == R.id.rbRawYes ? true : false; + CompressConfig config; + if (rgCompressTool.getCheckedRadioButtonId() == R.id.rbCompressWithOwn) { + config = new CompressConfig.Builder().setMaxSize(maxSize) + .setMaxPixel(width >= height ? width : height) + .enableReserveRaw(enableRawFile) + .create(); + } else { + LubanOptions option = new LubanOptions.Builder().setMaxHeight(height) + .setMaxWidth(width) + .setMaxSize(maxSize) + .create(); + config = CompressConfig.ofLuban(option); + config.enableReserveRaw(enableRawFile); } - private CropOptions getCropOptions(){ - if(rgCrop.getCheckedRadioButtonId()!=R.id.rbCropYes)return null; - int height= Integer.parseInt(etCropHeight.getText().toString()); - int width= Integer.parseInt(etCropWidth.getText().toString()); - boolean withWonCrop=rgCropTool.getCheckedRadioButtonId()==R.id.rbCropOwn? true:false; + takePhoto.onEnableCompress(config, showProgressBar); + } - CropOptions.Builder builder=new CropOptions.Builder(); + private CropOptions getCropOptions() { + if (rgCrop.getCheckedRadioButtonId() != R.id.rbCropYes) return null; + int height = Integer.parseInt(etCropHeight.getText().toString()); + int width = Integer.parseInt(etCropWidth.getText().toString()); + boolean withWonCrop = rgCropTool.getCheckedRadioButtonId() == R.id.rbCropOwn ? true : false; - if(rgCropSize.getCheckedRadioButtonId()==R.id.rbAspect){ - builder.setAspectX(width).setAspectY(height); - }else { - builder.setOutputX(width).setOutputY(height); - } - builder.setWithOwnCrop(withWonCrop); - return builder.create(); - } + CropOptions.Builder builder = new CropOptions.Builder(); + if (rgCropSize.getCheckedRadioButtonId() == R.id.rbAspect) { + builder.setAspectX(width).setAspectY(height); + } else { + builder.setOutputX(width).setOutputY(height); + } + builder.setWithOwnCrop(withWonCrop); + return builder.create(); + } } diff --git a/simple/src/main/java/com/jph/simple/ResultActivity.java b/simple/src/main/java/com/jph/simple/ResultActivity.java index 9d3ad1f9..a8f886cb 100644 --- a/simple/src/main/java/com/jph/simple/ResultActivity.java +++ b/simple/src/main/java/com/jph/simple/ResultActivity.java @@ -49,14 +49,14 @@ private void showImg() { View view = LayoutInflater.from(this).inflate(R.layout.image_show, null); ImageView imageView1 = (ImageView) view.findViewById(R.id.imgShow1); ImageView imageView2 = (ImageView) view.findViewById(R.id.imgShow2); - Glide.with(this).load(new File(images.get(i).getCompressPath())).into(imageView1); - Glide.with(this).load(new File(images.get(i + 1).getCompressPath())).into(imageView2); + Glide.with(this).load(new File(images.get(i).getPath())).into(imageView1); + Glide.with(this).load(new File(images.get(i + 1).getPath())).into(imageView2); linearLayout.addView(view); } if (images.size() % 2 == 1) { View view = LayoutInflater.from(this).inflate(R.layout.image_show, null); ImageView imageView1 = (ImageView) view.findViewById(R.id.imgShow1); - Glide.with(this).load(new File(images.get(images.size() - 1).getCompressPath())).into(imageView1); + Glide.with(this).load(new File(images.get(images.size() - 1).getPath())).into(imageView1); linearLayout.addView(view); } diff --git a/simple/src/main/res/layout/common_layout.xml b/simple/src/main/res/layout/common_layout.xml index 6caa3756..f4ca4bac 100644 --- a/simple/src/main/res/layout/common_layout.xml +++ b/simple/src/main/res/layout/common_layout.xml @@ -452,6 +452,40 @@ android:text="从文件" /> + + + + + + + + + + + + + diff --git a/simple/src/main/res/values/styles.xml b/simple/src/main/res/values/styles.xml index 766ab993..0ac0de1d 100644 --- a/simple/src/main/res/values/styles.xml +++ b/simple/src/main/res/values/styles.xml @@ -1,8 +1,5 @@ - - + diff --git a/takephoto_library/build.gradle b/takephoto_library/build.gradle index 712dafe8..50572b74 100644 --- a/takephoto_library/build.gradle +++ b/takephoto_library/build.gradle @@ -1,28 +1,29 @@ apply plugin: 'com.android.library' android { - compileSdkVersion 25 - buildToolsVersion "25.0.0" + compileSdkVersion 25 + buildToolsVersion "25.0.0" - defaultConfig { - minSdkVersion 14 - targetSdkVersion 25 - versionCode 42 - versionName "4.0.2" - } - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' - } + defaultConfig { + minSdkVersion 14 + targetSdkVersion 25 + versionCode 42 + versionName "4.0.2" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } + } } dependencies { - compile fileTree(include: ['*.jar'], dir: 'libs') - compile 'com.android.support:support-v4:25.0.0' - compile 'com.soundcloud.android.crop:lib_crop:1.0.0' - compile 'com.darsh.multipleimageselect:multipleimageselect:1.0.4' - compile 'me.shaohui.advancedluban:library:1.3.2' -} -//apply from: "bintrayUpload.gradle" \ No newline at end of file + compile fileTree(include: ['*.jar'], dir: 'libs') + compile 'com.android.support:support-v4:25.3.0' + compile 'com.android.support:appcompat-v7:25.3.0' + compile 'com.android.support:design:25.3.0' + compile 'com.soundcloud.android.crop:lib_crop:1.0.0' + compile 'me.shaohui.advancedluban:library:1.3.2' + compile 'com.github.bumptech.glide:glide:3.7.0' +} \ No newline at end of file diff --git a/takephoto_library/src/androidTest/java/com/jph/takephoto/ApplicationTest.java b/takephoto_library/src/androidTest/java/com/jph/takephoto/ApplicationTest.java deleted file mode 100644 index 48550d48..00000000 --- a/takephoto_library/src/androidTest/java/com/jph/takephoto/ApplicationTest.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.jph.takephoto; - -import android.app.Application; -import android.test.ApplicationTestCase; - -/** - * Testing Fundamentals - */ -public class ApplicationTest extends ApplicationTestCase { - public ApplicationTest() { - super(Application.class); - } -} \ No newline at end of file diff --git a/takephoto_library/src/main/AndroidManifest.xml b/takephoto_library/src/main/AndroidManifest.xml index 4697527a..13913459 100644 --- a/takephoto_library/src/main/AndroidManifest.xml +++ b/takephoto_library/src/main/AndroidManifest.xml @@ -15,5 +15,21 @@ android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> + + + + + + + + + + diff --git a/takephoto_library/src/main/java/com/jph/takephoto/app/TakePhoto.java b/takephoto_library/src/main/java/com/jph/takephoto/app/TakePhoto.java index da94ade0..bdb6b108 100644 --- a/takephoto_library/src/main/java/com/jph/takephoto/app/TakePhoto.java +++ b/takephoto_library/src/main/java/com/jph/takephoto/app/TakePhoto.java @@ -37,13 +37,13 @@ public interface TakePhoto { * 图片多选 * @param limit 最多选择图片张数的限制 * */ - void onPickMultiple(int limit); + void onPickMultiple(boolean cameraEnable,int limit); /** * 图片多选,并裁切 * @param limit 最多选择图片张数的限制 * @param options 裁剪配置 * */ - void onPickMultipleWithCrop(int limit, CropOptions options); + void onPickMultipleWithCrop(boolean cameraEnable,int limit, CropOptions options); /** * 从文件中获取图片(不裁剪) */ diff --git a/takephoto_library/src/main/java/com/jph/takephoto/app/TakePhotoActivity.java b/takephoto_library/src/main/java/com/jph/takephoto/app/TakePhotoActivity.java index 782c9923..4e033ca6 100644 --- a/takephoto_library/src/main/java/com/jph/takephoto/app/TakePhotoActivity.java +++ b/takephoto_library/src/main/java/com/jph/takephoto/app/TakePhotoActivity.java @@ -62,7 +62,7 @@ public TakePhoto getTakePhoto(){ } @Override public void takeSuccess(TResult result) { - Log.i(TAG,"takeSuccess:" + result.getImage().getCompressPath()); + //Log.i(TAG,"takeSuccess:" + result.getImage().getCompressPath()); } @Override public void takeFail(TResult result,String msg) { diff --git a/takephoto_library/src/main/java/com/jph/takephoto/app/TakePhotoFragment.java b/takephoto_library/src/main/java/com/jph/takephoto/app/TakePhotoFragment.java index 8d054a62..ea622214 100644 --- a/takephoto_library/src/main/java/com/jph/takephoto/app/TakePhotoFragment.java +++ b/takephoto_library/src/main/java/com/jph/takephoto/app/TakePhotoFragment.java @@ -60,7 +60,7 @@ public TakePhoto getTakePhoto(){ } @Override public void takeSuccess(TResult result) { - Log.i(TAG,"takeSuccess:" + result.getImage().getCompressPath()); + //Log.i(TAG,"takeSuccess:" + result.getImage().getCompressPath()); } @Override public void takeFail(TResult result,String msg) { diff --git a/takephoto_library/src/main/java/com/jph/takephoto/app/TakePhotoFragmentActivity.java b/takephoto_library/src/main/java/com/jph/takephoto/app/TakePhotoFragmentActivity.java index 95756679..9af8d87a 100644 --- a/takephoto_library/src/main/java/com/jph/takephoto/app/TakePhotoFragmentActivity.java +++ b/takephoto_library/src/main/java/com/jph/takephoto/app/TakePhotoFragmentActivity.java @@ -59,7 +59,7 @@ public TakePhoto getTakePhoto(){ } @Override public void takeSuccess(TResult result) { - Log.i(TAG,"takeSuccess:" + result.getImage().getCompressPath()); + //Log.i(TAG,"takeSuccess:" + result.getImage().getCompressPath()); } @Override public void takeFail(TResult result,String msg) { diff --git a/takephoto_library/src/main/java/com/jph/takephoto/app/TakePhotoImpl.java b/takephoto_library/src/main/java/com/jph/takephoto/app/TakePhotoImpl.java index c9f712ab..0dcf3780 100644 --- a/takephoto_library/src/main/java/com/jph/takephoto/app/TakePhotoImpl.java +++ b/takephoto_library/src/main/java/com/jph/takephoto/app/TakePhotoImpl.java @@ -7,11 +7,9 @@ import android.net.Uri; import android.os.Build; import android.os.Bundle; +import android.os.Environment; import android.support.v4.app.Fragment; import android.widget.Toast; - -import com.darsh.multipleimageselect.helpers.Constants; -import com.darsh.multipleimageselect.models.Image; import com.jph.takephoto.R; import com.jph.takephoto.compress.CompressConfig; import com.jph.takephoto.compress.CompressImage; @@ -19,6 +17,7 @@ import com.jph.takephoto.model.CropOptions; import com.jph.takephoto.model.MultipleCrop; import com.jph.takephoto.model.TContextWrap; +import com.jph.takephoto.model.TException; import com.jph.takephoto.model.TExceptionType; import com.jph.takephoto.model.TImage; import com.jph.takephoto.model.TIntentWap; @@ -28,16 +27,14 @@ import com.jph.takephoto.uitl.ImageRotateUtil; import com.jph.takephoto.uitl.IntentUtils; import com.jph.takephoto.uitl.TConstant; -import com.jph.takephoto.model.TException; -import com.jph.takephoto.uitl.TFileUtils; import com.jph.takephoto.uitl.TImageFiles; import com.jph.takephoto.uitl.TUriParse; import com.jph.takephoto.uitl.TUtils; -import com.soundcloud.android.crop.Crop; - import java.io.File; import java.util.ArrayList; import java.util.Map; +import multipleimageselect.helpers.Constants; +import multipleimageselect.models.Image; /** * - 支持通过相机拍照获取图片 @@ -53,7 +50,7 @@ * - 支持智能选取及裁剪异常处理 * - 支持因拍照Activity被回收后的自动恢复 * Date: 2016/9/21 0007 20:10 - * Version:4.0.0 + * Version:3.0.0 * 技术博文:http://www.cboy.me * GitHub:https://github.com/crazycodeboy * Eamil:crazycodeboy@gmail.com @@ -69,7 +66,6 @@ public class TakePhotoImpl implements TakePhoto { private CompressConfig compressConfig; private MultipleCrop multipleCrop; private PermissionManager.TPermissionType permissionType; - private TImage.FromType fromType; //CAMERA图片来源相机,OTHER图片来源其他 /** * 是否显示压缩对话框 */ @@ -86,8 +82,7 @@ public TakePhotoImpl(Fragment fragment, TakeResultListener listener) { this.listener = listener; } - @Override - public void onCreate(Bundle savedInstanceState) { + @Override public void onCreate(Bundle savedInstanceState) { if (savedInstanceState != null) { cropOptions = (CropOptions) savedInstanceState.getSerializable("cropOptions"); takePhotoOptions = (TakePhotoOptions) savedInstanceState.getSerializable("takePhotoOptions"); @@ -98,8 +93,7 @@ public void onCreate(Bundle savedInstanceState) { } } - @Override - public void onSaveInstanceState(Bundle outState) { + @Override public void onSaveInstanceState(Bundle outState) { outState.putSerializable("cropOptions", cropOptions); outState.putSerializable("takePhotoOptions", takePhotoOptions); outState.putBoolean("showCompressDialog", showCompressDialog); @@ -108,15 +102,14 @@ public void onSaveInstanceState(Bundle outState) { outState.putSerializable("compressConfig", compressConfig); } - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { + @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode) { case TConstant.RC_PICK_PICTURE_FROM_GALLERY_CROP: if (resultCode == Activity.RESULT_OK && data != null) {//从相册选择照片并裁剪 try { onCrop(data.getData(), outPutUri, cropOptions); } catch (TException e) { - takeResult(TResult.of(TImage.of(outPutUri, fromType)), e.getDetailMessage()); + takeResult(TResult.of(TImage.of(outPutUri)), e.getDetailMessage()); e.printStackTrace(); } } else { @@ -126,9 +119,10 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) { case TConstant.RC_PICK_PICTURE_FROM_GALLERY_ORIGINAL://从相册选择照片不裁剪 if (resultCode == Activity.RESULT_OK) { try { - takeResult(TResult.of(TImage.of(TUriParse.getFilePathWithUri(data.getData(), contextWrap.getActivity()), fromType))); + takeResult(TResult.of(TImage.of( + TUriParse.getFilePathWithUri(data.getData(), contextWrap.getActivity())))); } catch (TException e) { - takeResult(TResult.of(TImage.of(data.getData(), fromType)), e.getDetailMessage()); + takeResult(TResult.of(TImage.of(data.getData())), e.getDetailMessage()); e.printStackTrace(); } } else { @@ -138,9 +132,10 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) { case TConstant.RC_PICK_PICTURE_FROM_DOCUMENTS_ORIGINAL://从文件选择照片不裁剪 if (resultCode == Activity.RESULT_OK) { try { - takeResult(TResult.of(TImage.of(TUriParse.getFilePathWithDocumentsUri(data.getData(), contextWrap.getActivity()), fromType))); + takeResult(TResult.of(TImage.of( + TUriParse.getFilePathWithDocumentsUri(data.getData(), contextWrap.getActivity())))); } catch (TException e) { - takeResult(TResult.of(TImage.of(outPutUri, fromType)), e.getDetailMessage()); + takeResult(TResult.of(TImage.of(outPutUri)), e.getDetailMessage()); e.printStackTrace(); } } else { @@ -152,7 +147,7 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) { try { onCrop(data.getData(), outPutUri, cropOptions); } catch (TException e) { - takeResult(TResult.of(TImage.of(outPutUri, fromType)), e.getDetailMessage()); + takeResult(TResult.of(TImage.of(outPutUri)), e.getDetailMessage()); e.printStackTrace(); } } else { @@ -161,24 +156,28 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) { break; case TConstant.RC_PICK_PICTURE_FROM_CAPTURE_CROP://拍取照片,并裁剪 if (resultCode == Activity.RESULT_OK) { - if(takePhotoOptions!=null&&takePhotoOptions.isCorrectImage())ImageRotateUtil.of().correctImage(contextWrap.getActivity(), tempUri); - try { - onCrop(tempUri, Uri.fromFile(new File(TUriParse.parseOwnUri(contextWrap.getActivity(), outPutUri))), cropOptions); - } catch (TException e) { - takeResult(TResult.of(TImage.of(outPutUri, fromType)), e.getDetailMessage()); - e.printStackTrace(); - } + ImageRotateUtil.of().correctImage(contextWrap.getActivity(), tempUri); + takeResult(TResult.of(TImage.of(outPutUri))); + //try { + // onCrop(tempUri, + // Uri.fromFile(new File(TUriParse.parseOwnUri(contextWrap.getActivity(), outPutUri))), + // cropOptions); + //} catch (TException e) { + // takeResult(TResult.of(TImage.of(outPutUri)), e.getDetailMessage()); + // e.printStackTrace(); + //} } else { listener.takeCancel(); } break; case TConstant.RC_PICK_PICTURE_FROM_CAPTURE://拍取照片 if (resultCode == Activity.RESULT_OK) { - if(takePhotoOptions!=null&&takePhotoOptions.isCorrectImage())ImageRotateUtil.of().correctImage(contextWrap.getActivity(), outPutUri); + ImageRotateUtil.of().correctImage(contextWrap.getActivity(), outPutUri); try { - takeResult(TResult.of(TImage.of(TUriParse.getFilePathWithUri(outPutUri, contextWrap.getActivity()), fromType))); + takeResult(TResult.of( + TImage.of(TUriParse.getFilePathWithUri(outPutUri, contextWrap.getActivity())))); } catch (TException e) { - takeResult(TResult.of(TImage.of(outPutUri, fromType)), e.getDetailMessage()); + takeResult(TResult.of(TImage.of(outPutUri)), e.getDetailMessage()); e.printStackTrace(); } } else { @@ -186,17 +185,18 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) { } break; case TConstant.RC_CROP://裁剪照片返回结果 - case Crop.REQUEST_CROP://裁剪照片返回结果 + //case Crop.REQUEST_CROP://裁剪照片返回结果 if (resultCode == Activity.RESULT_OK) { if (multipleCrop != null) { cropContinue(true); } else { try { - TImage image = TImage.of(TUriParse.getFilePathWithUri(outPutUri, contextWrap.getActivity()), fromType); + TImage image = + TImage.of(TUriParse.getFilePathWithUri(outPutUri, contextWrap.getActivity())); image.setCropped(true); takeResult(TResult.of(image)); } catch (TException e) { - takeResult(TResult.of(TImage.of(outPutUri.getPath(), fromType)), e.getDetailMessage()); + takeResult(TResult.of(TImage.of(outPutUri.getPath())), e.getDetailMessage()); e.printStackTrace(); } } @@ -214,7 +214,7 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) { Bitmap bitmap = data.getParcelableExtra("data");//获取裁剪的结果数据 TImageFiles.writeToFile(bitmap, outPutUri);//将裁剪的结果写入到文件 - TImage image = TImage.of(outPutUri.getPath(), fromType); + TImage image = TImage.of(outPutUri.getPath()); image.setCropped(true); takeResult(TResult.of(image)); } else { @@ -231,18 +231,29 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) { break; case TConstant.RC_PICK_MULTIPLE://多选图片返回结果 if (resultCode == Activity.RESULT_OK && data != null) { - ArrayList images = data.getParcelableArrayListExtra(Constants.INTENT_EXTRA_IMAGES); - if (cropOptions != null) { - try { - onCrop(MultipleCrop.of(TUtils.convertImageToUri(contextWrap.getActivity(), images), contextWrap.getActivity(), fromType), cropOptions); - } catch (TException e) { - cropContinue(false); - e.printStackTrace(); - } + boolean startCamera = data.getBooleanExtra(Constants.INTENT_EXTRA_START_CAMERA, false); + if (startCamera) { + File file = new File(Environment.getExternalStorageDirectory(), + "/temp/" + System.currentTimeMillis() + ".jpg"); + if (!file.getParentFile().exists()) file.getParentFile().mkdirs(); + Uri imageUri = Uri.fromFile(file); + onPickFromCaptureWithCrop(imageUri, null); } else { - takeResult(TResult.of(TUtils.getTImagesWithImages(images, fromType))); + ArrayList images = + data.getParcelableArrayListExtra(Constants.INTENT_EXTRA_IMAGES); + if (cropOptions != null) { + try { + onCrop(MultipleCrop.of( + TUtils.convertImageToUri(contextWrap.getActivity(), images), + contextWrap.getActivity()), cropOptions); + } catch (TException e) { + cropContinue(false); + e.printStackTrace(); + } + } else { + takeResult(TResult.of(TUtils.getTImagesWithImages(images))); + } } - } else { listener.takeCancel(); } @@ -252,35 +263,36 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) { } } - @Override - public void onPickMultiple(int limit) { + @Override public void onPickMultiple(boolean cameraEnable, int limit) { if (PermissionManager.TPermissionType.WAIT.equals(permissionType)) return; - TUtils.startActivityForResult(contextWrap, new TIntentWap(IntentUtils.getPickMultipleIntent(contextWrap, limit), TConstant.RC_PICK_MULTIPLE)); + TUtils.startActivityForResult(contextWrap, + new TIntentWap(IntentUtils.getPickMultipleIntent(contextWrap, cameraEnable, limit), + TConstant.RC_PICK_MULTIPLE)); } @Override - public void onPickMultipleWithCrop(int limit, CropOptions options) { - this.fromType = TImage.FromType.OTHER; - onPickMultiple(limit); + public void onPickMultipleWithCrop(boolean cameraEnable, int limit, CropOptions options) { + onPickMultiple(cameraEnable, limit); this.cropOptions = options; } /** * -----crop------ **/ - @Override - public void onCrop(Uri imageUri, Uri outPutUri, CropOptions options) throws TException { + @Override public void onCrop(Uri imageUri, Uri outPutUri, CropOptions options) throws TException { if (PermissionManager.TPermissionType.WAIT.equals(permissionType)) return; this.outPutUri = outPutUri; - if (!TImageFiles.checkMimeType(contextWrap.getActivity(), TImageFiles.getMimeType(contextWrap.getActivity(), imageUri))) { - Toast.makeText(contextWrap.getActivity(), contextWrap.getActivity().getResources().getText(R.string.tip_type_not_image), Toast.LENGTH_SHORT).show(); + if (!TImageFiles.checkMimeType(contextWrap.getActivity(), + TImageFiles.getMimeType(contextWrap.getActivity(), imageUri))) { + Toast.makeText(contextWrap.getActivity(), + contextWrap.getActivity().getResources().getText(R.string.tip_type_not_image), + Toast.LENGTH_SHORT).show(); throw new TException(TExceptionType.TYPE_NOT_IMAGE); } cropWithNonException(imageUri, outPutUri, options); } - @Override - public void onCrop(MultipleCrop multipleCrop, CropOptions options) throws TException { + @Override public void onCrop(MultipleCrop multipleCrop, CropOptions options) throws TException { this.multipleCrop = multipleCrop; onCrop(multipleCrop.getUris().get(0), multipleCrop.getOutUris().get(0), options); } @@ -288,7 +300,7 @@ public void onCrop(MultipleCrop multipleCrop, CropOptions options) throws TExcep private void cropWithNonException(Uri imageUri, Uri outPutUri, CropOptions options) { this.outPutUri = outPutUri; if (options.isWithOwnCrop()) { - TUtils.cropWithOwnApp(contextWrap, imageUri, outPutUri, options); + //TUtils.cropWithOwnApp(contextWrap, imageUri, outPutUri, options); } else { TUtils.cropWithOtherAppBySafely(contextWrap, imageUri, outPutUri, options); } @@ -303,76 +315,78 @@ private void cropContinue(boolean preSuccess) { if (preSuccess) { takeResult(TResult.of(multipleCrop.gettImages())); } else { - takeResult(TResult.of(multipleCrop.gettImages()), outPutUri.getPath() + contextWrap.getActivity().getResources().getString(R.string.msg_crop_canceled)); + takeResult(TResult.of(multipleCrop.gettImages()), + outPutUri.getPath() + contextWrap.getActivity() + .getResources() + .getString(R.string.msg_crop_canceled)); } } else { - cropWithNonException(multipleCrop.getUris().get(index + 1), multipleCrop.getOutUris().get(index + 1), cropOptions); + cropWithNonException(multipleCrop.getUris().get(index + 1), + multipleCrop.getOutUris().get(index + 1), cropOptions); } } - @Override - public void onPickFromDocuments() { + @Override public void onPickFromDocuments() { selectPicture(0, false); } - @Override - public void onPickFromGallery() { + @Override public void onPickFromGallery() { selectPicture(1, false); } private void selectPicture(int defaultIndex, boolean isCrop) { - this.fromType = TImage.FromType.OTHER; if (takePhotoOptions != null && takePhotoOptions.isWithOwnGallery()) { - onPickMultiple(1); + onPickMultiple(false, 1); return; } if (PermissionManager.TPermissionType.WAIT.equals(permissionType)) return; ArrayList intentWapList = new ArrayList<>(); - intentWapList.add(new TIntentWap(IntentUtils.getPickIntentWithDocuments(), isCrop ? TConstant.RC_PICK_PICTURE_FROM_DOCUMENTS_CROP : TConstant.RC_PICK_PICTURE_FROM_DOCUMENTS_ORIGINAL)); - intentWapList.add(new TIntentWap(IntentUtils.getPickIntentWithGallery(), isCrop ? TConstant.RC_PICK_PICTURE_FROM_GALLERY_CROP : TConstant.RC_PICK_PICTURE_FROM_GALLERY_ORIGINAL)); + intentWapList.add(new TIntentWap(IntentUtils.getPickIntentWithDocuments(), + isCrop ? TConstant.RC_PICK_PICTURE_FROM_DOCUMENTS_CROP + : TConstant.RC_PICK_PICTURE_FROM_DOCUMENTS_ORIGINAL)); + intentWapList.add(new TIntentWap(IntentUtils.getPickIntentWithGallery(), + isCrop ? TConstant.RC_PICK_PICTURE_FROM_GALLERY_CROP + : TConstant.RC_PICK_PICTURE_FROM_GALLERY_ORIGINAL)); try { TUtils.sendIntentBySafely(contextWrap, intentWapList, defaultIndex, isCrop); } catch (TException e) { - takeResult(TResult.of(TImage.of("", fromType)), e.getDetailMessage()); + takeResult(TResult.of(TImage.of("")), e.getDetailMessage()); e.printStackTrace(); } } - @Override - public void onPickFromGalleryWithCrop(Uri outPutUri, CropOptions options) { + @Override public void onPickFromGalleryWithCrop(Uri outPutUri, CropOptions options) { this.cropOptions = options; this.outPutUri = outPutUri; selectPicture(1, true); } - @Override - public void onPickFromDocumentsWithCrop(Uri outPutUri, CropOptions options) { + @Override public void onPickFromDocumentsWithCrop(Uri outPutUri, CropOptions options) { this.cropOptions = options; this.outPutUri = outPutUri; selectPicture(0, true); } - @Override - public void onPickFromCapture(Uri outPutUri) { - this.fromType = TImage.FromType.CAMERA; + @Override public void onPickFromCapture(Uri outPutUri) { if (PermissionManager.TPermissionType.WAIT.equals(permissionType)) return; if (Build.VERSION.SDK_INT >= 23) { - this.outPutUri = TUriParse.convertFileUriToFileProviderUri(contextWrap.getActivity(), outPutUri); + this.outPutUri = + TUriParse.convertFileUriToFileProviderUri(contextWrap.getActivity(), outPutUri); } else { this.outPutUri = outPutUri; } try { - TUtils.captureBySafely(contextWrap, new TIntentWap(IntentUtils.getCaptureIntent(this.outPutUri), TConstant.RC_PICK_PICTURE_FROM_CAPTURE)); + TUtils.captureBySafely(contextWrap, + new TIntentWap(IntentUtils.getCaptureIntent(this.outPutUri), + TConstant.RC_PICK_PICTURE_FROM_CAPTURE)); } catch (TException e) { - takeResult(TResult.of(TImage.of("", fromType)), e.getDetailMessage()); + takeResult(TResult.of(TImage.of("")), e.getDetailMessage()); e.printStackTrace(); } } - @Override - public void onPickFromCaptureWithCrop(Uri outPutUri, CropOptions options) { - this.fromType = TImage.FromType.CAMERA; + @Override public void onPickFromCaptureWithCrop(Uri outPutUri, CropOptions options) { if (PermissionManager.TPermissionType.WAIT.equals(permissionType)) return; this.cropOptions = options; this.outPutUri = outPutUri; @@ -383,26 +397,24 @@ public void onPickFromCaptureWithCrop(Uri outPutUri, CropOptions options) { } try { - TUtils.captureBySafely(contextWrap, new TIntentWap(IntentUtils.getCaptureIntent(this.tempUri), TConstant.RC_PICK_PICTURE_FROM_CAPTURE_CROP)); + TUtils.captureBySafely(contextWrap, new TIntentWap(IntentUtils.getCaptureIntent(this.tempUri), + TConstant.RC_PICK_PICTURE_FROM_CAPTURE_CROP)); } catch (TException e) { - takeResult(TResult.of(TImage.of("", fromType)), e.getDetailMessage()); + takeResult(TResult.of(TImage.of("")), e.getDetailMessage()); e.printStackTrace(); } } - @Override - public void onEnableCompress(CompressConfig config, boolean showCompressDialog) { + @Override public void onEnableCompress(CompressConfig config, boolean showCompressDialog) { this.compressConfig = config; this.showCompressDialog = showCompressDialog; } - @Override - public void setTakePhotoOptions(TakePhotoOptions options) { + @Override public void setTakePhotoOptions(TakePhotoOptions options) { this.takePhotoOptions = options; } - @Override - public void permissionNotify(PermissionManager.TPermissionType type) { + @Override public void permissionNotify(PermissionManager.TPermissionType type) { this.permissionType = type; } @@ -410,39 +422,29 @@ private void takeResult(final TResult result, final String... message) { if (null == compressConfig) { handleTakeCallBack(result, message); } else { - if (showCompressDialog) - wailLoadDialog = TUtils.showProgressDialog(contextWrap.getActivity(), contextWrap.getActivity().getResources().getString(R.string.tip_compress)); - - CompressImageImpl.of(contextWrap.getActivity(), compressConfig, result.getImages(), new CompressImage.CompressListener() { - @Override - public void onCompressSuccess(ArrayList images) { - if(!compressConfig.isEnableReserveRaw()) { - deleteRawFile(images); - } - handleTakeCallBack(result); - if (wailLoadDialog != null && !contextWrap.getActivity().isFinishing()) - wailLoadDialog.dismiss(); - } + if (showCompressDialog) { + wailLoadDialog = TUtils.showProgressDialog(contextWrap.getActivity(), + contextWrap.getActivity().getResources().getString(R.string.tip_compress)); + } - @Override - public void onCompressFailed(ArrayList images, String msg) { - if(!compressConfig.isEnableReserveRaw()) { - deleteRawFile(images); + CompressImageImpl.of(contextWrap.getActivity(), compressConfig, result.getImages(), + new CompressImage.CompressListener() { + @Override public void onCompressSuccess(ArrayList images) { + handleTakeCallBack(result); + if (wailLoadDialog != null && !contextWrap.getActivity().isFinishing()) { + wailLoadDialog.dismiss(); + } } - handleTakeCallBack(TResult.of(images), String.format(contextWrap.getActivity().getResources().getString(R.string.tip_compress_failed), message.length > 0 ? message[0] : "", msg, result.getImage().getCompressPath())); - if (wailLoadDialog != null && !contextWrap.getActivity().isFinishing()) - wailLoadDialog.dismiss(); - } - }).compress(); - } - } - private void deleteRawFile(ArrayList images) { - for(TImage image : images) { - if(TImage.FromType.CAMERA == fromType) { - TFileUtils.delete(image.getOriginalPath()); - image.setOriginalPath(""); - } + @Override public void onCompressFailed(ArrayList images, String msg) { + handleTakeCallBack(TResult.of(images), String.format( + contextWrap.getActivity().getResources().getString(R.string.tip_compress_failed), + message.length > 0 ? message[0] : "", msg, result.getImage().getPath())); + if (wailLoadDialog != null && !contextWrap.getActivity().isFinishing()) { + wailLoadDialog.dismiss(); + } + } + }).compress(); } } @@ -450,7 +452,8 @@ private void handleTakeCallBack(final TResult result, String... message) { if (message.length > 0) { listener.takeFail(result, message[0]); } else if (multipleCrop != null && multipleCrop.hasFailed) { - listener.takeFail(result, contextWrap.getActivity().getResources().getString(R.string.msg_crop_failed)); + listener.takeFail(result, + contextWrap.getActivity().getResources().getString(R.string.msg_crop_failed)); } else if (compressConfig != null) { boolean hasFailed = false; for (TImage image : result.getImages()) { @@ -460,7 +463,8 @@ private void handleTakeCallBack(final TResult result, String... message) { } } if (hasFailed) { - listener.takeFail(result, contextWrap.getActivity().getString(R.string.msg_compress_failed)); + listener.takeFail(result, + contextWrap.getActivity().getString(R.string.msg_compress_failed)); } else { listener.takeSuccess(result); } diff --git a/takephoto_library/src/main/java/com/jph/takephoto/compress/CompressImageImpl.java b/takephoto_library/src/main/java/com/jph/takephoto/compress/CompressImageImpl.java index 461d31ca..9573702a 100644 --- a/takephoto_library/src/main/java/com/jph/takephoto/compress/CompressImageImpl.java +++ b/takephoto_library/src/main/java/com/jph/takephoto/compress/CompressImageImpl.java @@ -46,21 +46,21 @@ public void compress() { } private void compress(final TImage image) { - if (TextUtils.isEmpty(image.getOriginalPath())){ + if (TextUtils.isEmpty(image.getPath())){ continueCompress(image,false); return; } - File file = new File(image.getOriginalPath()); + File file = new File(image.getPath()); if (file == null || !file.exists() || !file.isFile()){ continueCompress(image,false); return; } - compressImageUtil.compress(image.getOriginalPath(), new CompressImageUtil.CompressListener() { + compressImageUtil.compress(image.getPath(), new CompressImageUtil.CompressListener() { @Override public void onCompressSuccess(String imgPath) { - image.setCompressPath(imgPath); + image.setPath(imgPath); continueCompress(image,true); } @@ -89,7 +89,7 @@ private void handleCompressCallBack(String...message){ for(TImage image:images){ if(!image.isCompressed()){ - listener.onCompressFailed(images,image.getCompressPath()+" is compress failures"); + listener.onCompressFailed(images,image.getPath()+" is compress failures"); return; } } diff --git a/takephoto_library/src/main/java/com/jph/takephoto/compress/CompressWithLuBan.java b/takephoto_library/src/main/java/com/jph/takephoto/compress/CompressWithLuBan.java index 2503fad3..a38ec0e0 100644 --- a/takephoto_library/src/main/java/com/jph/takephoto/compress/CompressWithLuBan.java +++ b/takephoto_library/src/main/java/com/jph/takephoto/compress/CompressWithLuBan.java @@ -46,7 +46,7 @@ public CompressWithLuBan(Context context, CompressConfig config, ArrayList files) { for (int i = 0, j = images.size(); i < j; i++) { TImage image = images.get(i); image.setCompressed(true); - image.setCompressPath(files.get(i).getPath()); + image.setPath(files.get(i).getPath()); } listener.onCompressSuccess(images); } -} +} \ No newline at end of file diff --git a/takephoto_library/src/main/java/com/jph/takephoto/model/MultipleCrop.java b/takephoto_library/src/main/java/com/jph/takephoto/model/MultipleCrop.java index fd94276d..d5c25c03 100644 --- a/takephoto_library/src/main/java/com/jph/takephoto/model/MultipleCrop.java +++ b/takephoto_library/src/main/java/com/jph/takephoto/model/MultipleCrop.java @@ -15,30 +15,31 @@ public class MultipleCrop { private ArrayList uris; private ArrayList outUris; - private ArrayListtImages; - private TImage.FromType fromType; + private ArrayList tImages; public boolean hasFailed;//是否有裁切失败的标识 - public static MultipleCrop of(ArrayList uris,Activity activity, TImage.FromType fromType) throws TException { - return new MultipleCrop(uris,activity, fromType); + + public static MultipleCrop of(ArrayList uris, Activity activity) throws TException { + return new MultipleCrop(uris, activity); } - public static MultipleCrop of(ArrayList uris,ArrayListoutUris, TImage.FromType fromType){ - return new MultipleCrop(uris,outUris, fromType); + + public static MultipleCrop of(ArrayList uris, ArrayList outUris) { + return new MultipleCrop(uris, outUris); } - private MultipleCrop(ArrayList uris,Activity activity, TImage.FromType fromType) throws TException { - this.uris=uris; - ArrayListoutUris=new ArrayList<>(); - for (Uri uri:uris){ - outUris.add(Uri.fromFile(TImageFiles.getTempFile(activity,uri)));//生成临时裁切输出路径 + + private MultipleCrop(ArrayList uris, Activity activity) throws TException { + this.uris = uris; + ArrayList outUris = new ArrayList<>(); + for (Uri uri : uris) { + outUris.add(Uri.fromFile(TImageFiles.getTempFile(activity, uri)));//生成临时裁切输出路径 } - this.outUris=outUris; - this.tImages= TUtils.getTImagesWithUris(outUris, fromType); - this.fromType = fromType; + this.outUris = outUris; + this.tImages = TUtils.getTImagesWithUris(outUris); } - private MultipleCrop(ArrayList uris,ArrayListoutUris, TImage.FromType fromType) { - this.uris=uris; - this.outUris=outUris; - this.tImages= TUtils.getTImagesWithUris(outUris, fromType); - this.fromType = fromType; + + private MultipleCrop(ArrayList uris, ArrayList outUris) { + this.uris = uris; + this.outUris = outUris; + this.tImages = TUtils.getTImagesWithUris(outUris); } public ArrayList getUris() { @@ -67,16 +68,17 @@ public void settImages(ArrayList tImages) { /** * 为被裁切的图片设置已被裁切的标识 + * * @param uri 被裁切的图片 * @return 该图片是否是最后一张 */ - public Map setCropWithUri(Uri uri,boolean cropped){ - if(!cropped)hasFailed=true; - int index=outUris.indexOf(uri); + public Map setCropWithUri(Uri uri, boolean cropped) { + if (!cropped) hasFailed = true; + int index = outUris.indexOf(uri); tImages.get(index).setCropped(cropped); - Map result=new HashMap(); - result.put("index",index); - result.put("isLast",index==outUris.size()-1? true:false); + Map result = new HashMap(); + result.put("index", index); + result.put("isLast", index == outUris.size() - 1 ? true : false); return result; } } diff --git a/takephoto_library/src/main/java/com/jph/takephoto/model/TImage.java b/takephoto_library/src/main/java/com/jph/takephoto/model/TImage.java index af661498..0f7d5c68 100644 --- a/takephoto_library/src/main/java/com/jph/takephoto/model/TImage.java +++ b/takephoto_library/src/main/java/com/jph/takephoto/model/TImage.java @@ -10,49 +10,33 @@ * Author: JPH * Date: 2016/8/11 17:01 */ -public class TImage implements Serializable{ - private String originalPath; - private String compressPath; - private FromType fromType; +public class TImage implements Serializable { + private String path; private boolean cropped; private boolean compressed; - public static TImage of(String path, FromType fromType){ - return new TImage(path, fromType); - } - public static TImage of(Uri uri, FromType fromType){ - return new TImage(uri, fromType); - } - private TImage(String path, FromType fromType) { - this.originalPath = path; - this.fromType = fromType; - } - private TImage(Uri uri, FromType fromType) { - this.originalPath = uri.getPath(); - this.fromType = fromType; - } - public String getOriginalPath() { - return originalPath; + public static TImage of(String path) { + return new TImage(path); } - public void setOriginalPath(String originalPath) { - this.originalPath = originalPath; + public static TImage of(Uri uri) { + return new TImage(uri); } - public String getCompressPath() { - return compressPath; + private TImage(String path) { + this.path = path; } - public void setCompressPath(String compressPath) { - this.compressPath = compressPath; + private TImage(Uri uri) { + this.path = uri.getPath(); } - public FromType getFromType() { - return fromType; + public String getPath() { + return path; } - public void setFromType(FromType fromType) { - this.fromType = fromType; + public void setPath(String path) { + this.path = path; } public boolean isCropped() { @@ -70,8 +54,4 @@ public boolean isCompressed() { public void setCompressed(boolean compressed) { this.compressed = compressed; } - - public enum FromType { - CAMERA, OTHER - } } diff --git a/takephoto_library/src/main/java/com/jph/takephoto/uitl/IntentUtils.java b/takephoto_library/src/main/java/com/jph/takephoto/uitl/IntentUtils.java index 4b54c475..8c2ab18e 100644 --- a/takephoto_library/src/main/java/com/jph/takephoto/uitl/IntentUtils.java +++ b/takephoto_library/src/main/java/com/jph/takephoto/uitl/IntentUtils.java @@ -5,10 +5,10 @@ import android.net.Uri; import android.provider.MediaStore; import android.util.Log; -import com.darsh.multipleimageselect.activities.AlbumSelectActivity; -import com.darsh.multipleimageselect.helpers.Constants; import com.jph.takephoto.model.CropOptions; import com.jph.takephoto.model.TContextWrap; +import multipleimageselect.activities.AlbumSelectActivity; +import multipleimageselect.helpers.Constants; /** * Intent工具类用于生成拍照、 @@ -17,76 +17,79 @@ * Date: 2016/6/7 0007 13:41 */ public class IntentUtils { - private static final String TAG = IntentUtils.class.getName(); + private static final String TAG = IntentUtils.class.getName(); - /** - * 获取图片多选的Intent - * @param limit 最多选择图片张数的限制 - * */ - public static Intent getPickMultipleIntent(TContextWrap contextWrap, int limit){ - Intent intent = new Intent(contextWrap.getActivity(), AlbumSelectActivity.class); - intent.putExtra(Constants.INTENT_EXTRA_LIMIT, limit>0? limit:1); - return intent; - } - - /** - * 获取裁剪照片的Intent - * @param targetUri 要裁剪的照片 - * @param outPutUri 裁剪完成的照片 - * @param options 裁剪配置 - * @return - */ - public static Intent getCropIntentWithOtherApp(Uri targetUri, Uri outPutUri, CropOptions options) { - boolean isReturnData = TUtils.isReturnData(); - Log.w(TAG, "getCaptureIntentWithCrop:isReturnData:" + (isReturnData ? "true" : "false")); - Intent intent = new Intent("com.android.camera.action.CROP"); - intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - intent.setDataAndType(targetUri, "image/*"); - intent.putExtra("crop", "true"); - if (options.getAspectX()*options.getAspectY()>0){ - intent.putExtra("aspectX", options.getAspectX()); - intent.putExtra("aspectY", options.getAspectY()); - } - if (options.getOutputX()*options.getOutputY()>0){ - intent.putExtra("outputX", options.getOutputX()); - intent.putExtra("outputY", options.getOutputY()); - } - intent.putExtra("scale", true); - intent.putExtra(MediaStore.EXTRA_OUTPUT, outPutUri); - intent.putExtra("return-data", isReturnData); - intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString()); - intent.putExtra("noFaceDetection", true); // no face detection - return intent; - } + /** + * 获取图片多选的Intent + * + * @param limit 最多选择图片张数的限制 + */ + public static Intent getPickMultipleIntent(TContextWrap contextWrap, boolean cameraEnable, + int limit) { + Intent intent = new Intent(contextWrap.getActivity(), AlbumSelectActivity.class); + intent.putExtra(Constants.EXTRA_CAMERA_ENABLE, cameraEnable); + intent.putExtra(Constants.INTENT_EXTRA_LIMIT, limit > 0 ? limit : 1); + return intent; + } - /** - * 获取拍照的Intent - * @return - */ - public static Intent getCaptureIntent(Uri outPutUri) { - Intent intent = new Intent(); - intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);//设置Action为拍照 - intent.putExtra(MediaStore.EXTRA_OUTPUT, outPutUri);//将拍取的照片保存到指定URI - return intent; - } - /** - * 获取选择照片的Intent - * @return - */ - public static Intent getPickIntentWithGallery() { - Intent intent = new Intent(); - intent.setAction(Intent.ACTION_PICK);//Pick an item from the data - intent.setType("image/*");//从所有图片中进行选择 - return intent; + /** + * 获取裁剪照片的Intent + * + * @param targetUri 要裁剪的照片 + * @param outPutUri 裁剪完成的照片 + * @param options 裁剪配置 + */ + public static Intent getCropIntentWithOtherApp(Uri targetUri, Uri outPutUri, + CropOptions options) { + boolean isReturnData = TUtils.isReturnData(); + Log.w(TAG, "getCaptureIntentWithCrop:isReturnData:" + (isReturnData ? "true" : "false")); + Intent intent = new Intent("com.android.camera.action.CROP"); + intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + intent.setDataAndType(targetUri, "image/*"); + intent.putExtra("crop", "true"); + if (options.getAspectX() * options.getAspectY() > 0) { + intent.putExtra("aspectX", options.getAspectX()); + intent.putExtra("aspectY", options.getAspectY()); } - /** - * 获取从文件中选择照片的Intent - * @return - */ - public static Intent getPickIntentWithDocuments() { - Intent intent = new Intent(Intent.ACTION_GET_CONTENT); - intent.setType("image/*"); - return intent; + if (options.getOutputX() * options.getOutputY() > 0) { + intent.putExtra("outputX", options.getOutputX()); + intent.putExtra("outputY", options.getOutputY()); } + intent.putExtra("scale", true); + intent.putExtra(MediaStore.EXTRA_OUTPUT, outPutUri); + intent.putExtra("return-data", isReturnData); + intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString()); + intent.putExtra("noFaceDetection", true); // no face detection + return intent; + } + + /** + * 获取拍照的Intent + */ + public static Intent getCaptureIntent(Uri outPutUri) { + Intent intent = new Intent(); + intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);//设置Action为拍照 + intent.putExtra(MediaStore.EXTRA_OUTPUT, outPutUri);//将拍取的照片保存到指定URI + return intent; + } + + /** + * 获取选择照片的Intent + */ + public static Intent getPickIntentWithGallery() { + Intent intent = new Intent(); + intent.setAction(Intent.ACTION_PICK);//Pick an item from the data + intent.setType("image/*");//从所有图片中进行选择 + return intent; + } + + /** + * 获取从文件中选择照片的Intent + */ + public static Intent getPickIntentWithDocuments() { + Intent intent = new Intent(Intent.ACTION_GET_CONTENT); + intent.setType("image/*"); + return intent; + } } diff --git a/takephoto_library/src/main/java/com/jph/takephoto/uitl/TUtils.java b/takephoto_library/src/main/java/com/jph/takephoto/uitl/TUtils.java index 71e501fe..25bf837a 100644 --- a/takephoto_library/src/main/java/com/jph/takephoto/uitl/TUtils.java +++ b/takephoto_library/src/main/java/com/jph/takephoto/uitl/TUtils.java @@ -11,8 +11,6 @@ import android.text.TextUtils; import android.util.Log; import android.widget.Toast; - -import com.darsh.multipleimageselect.models.Image; import com.jph.takephoto.R; import com.jph.takephoto.model.CropOptions; import com.jph.takephoto.model.TContextWrap; @@ -20,11 +18,10 @@ import com.jph.takephoto.model.TExceptionType; import com.jph.takephoto.model.TImage; import com.jph.takephoto.model.TIntentWap; -import com.soundcloud.android.crop.Crop; - import java.io.File; import java.util.ArrayList; import java.util.List; +import multipleimageselect.models.Image; /** * 工具类 @@ -34,167 +31,180 @@ public class TUtils { private static final String TAG = IntentUtils.class.getName(); - /** * 将Image集合转换成Uri集合 - * @param images - * @return */ - public static ArrayList convertImageToUri(Context context,ArrayListimages) throws TException { - ArrayListuris=new ArrayList(); - for(Image image:images){ - uris.add(FileProvider.getUriForFile(context,TConstant.getFileProviderName(context), new File(image.path))); + public static ArrayList convertImageToUri(Context context, ArrayList images) + throws TException { + ArrayList uris = new ArrayList(); + for (Image image : images) { + uris.add(FileProvider.getUriForFile(context, TConstant.getFileProviderName(context), + new File(image.path))); } return uris; } + /** * 将Image集合转换成TImage集合 - * @param images - * @return */ - public static ArrayList getTImagesWithImages(ArrayListimages, TImage.FromType fromType){ - ArrayListtImages=new ArrayList(); - for(Image image:images){ - tImages.add(TImage.of(image.path, fromType)); + public static ArrayList getTImagesWithImages(ArrayList images) { + ArrayList tImages = new ArrayList(); + for (Image image : images) { + tImages.add(TImage.of(image.path)); } return tImages; } + /** * 将Uri集合转换成TImage集合 - * @param uris - * @return */ - public static ArrayList getTImagesWithUris(ArrayListuris, TImage.FromType fromType){ - ArrayListtImages=new ArrayList(); - for(Uri uri:uris){ - tImages.add(TImage.of(uri, fromType)); + public static ArrayList getTImagesWithUris(ArrayList uris) { + ArrayList tImages = new ArrayList(); + for (Uri uri : uris) { + tImages.add(TImage.of(uri)); } return tImages; } + /** * @param contextWrap * @param intentWap */ - public static void startActivityForResult(TContextWrap contextWrap,TIntentWap intentWap){ - if (contextWrap.getFragment()!=null){ - contextWrap.getFragment().startActivityForResult(intentWap.getIntent(),intentWap.getRequestCode()); - }else { - contextWrap.getActivity().startActivityForResult(intentWap.getIntent(),intentWap.getRequestCode()); + public static void startActivityForResult(TContextWrap contextWrap, TIntentWap intentWap) { + if (contextWrap.getFragment() != null) { + contextWrap.getFragment() + .startActivityForResult(intentWap.getIntent(), intentWap.getRequestCode()); + } else { + contextWrap.getActivity() + .startActivityForResult(intentWap.getIntent(), intentWap.getRequestCode()); } } + /** * 安全地发送Intent - * @param contextWrap + * * @param intentWapList 要发送的Intent以及候选Intent * @param defaultIndex 默认发送的Intent * @param isCrop 是否为裁切照片的Intent * @throws TException */ - public static void sendIntentBySafely(TContextWrap contextWrap, List intentWapList, int defaultIndex, boolean isCrop)throws TException{ - if (defaultIndex+1>intentWapList.size())throw new TException(isCrop? TExceptionType.TYPE_NO_MATCH_PICK_INTENT:TExceptionType.TYPE_NO_MATCH_CROP_INTENT); - TIntentWap intentWap=intentWapList.get(defaultIndex); - List result=contextWrap.getActivity().getPackageManager().queryIntentActivities(intentWap.getIntent(),PackageManager.MATCH_ALL); - if (result.isEmpty()){ - sendIntentBySafely(contextWrap,intentWapList,++defaultIndex,isCrop); - }else { - startActivityForResult(contextWrap,intentWap); + public static void sendIntentBySafely(TContextWrap contextWrap, List intentWapList, + int defaultIndex, boolean isCrop) throws TException { + if (defaultIndex + 1 > intentWapList.size()) { + throw new TException(isCrop ? TExceptionType.TYPE_NO_MATCH_PICK_INTENT + : TExceptionType.TYPE_NO_MATCH_CROP_INTENT); + } + TIntentWap intentWap = intentWapList.get(defaultIndex); + List result = contextWrap.getActivity() + .getPackageManager() + .queryIntentActivities(intentWap.getIntent(), PackageManager.MATCH_ALL); + if (result.isEmpty()) { + sendIntentBySafely(contextWrap, intentWapList, ++defaultIndex, isCrop); + } else { + startActivityForResult(contextWrap, intentWap); } } + /** * 拍照前检查是否有相机 **/ - public static void captureBySafely(TContextWrap contextWrap,TIntentWap intentWap)throws TException{ - List result=contextWrap.getActivity().getPackageManager().queryIntentActivities(intentWap.getIntent(),PackageManager.MATCH_ALL); - if (result.isEmpty()){ - Toast.makeText(contextWrap.getActivity(),contextWrap.getActivity().getResources().getText(R.string.tip_no_camera),Toast.LENGTH_SHORT).show(); + public static void captureBySafely(TContextWrap contextWrap, TIntentWap intentWap) + throws TException { + List result = contextWrap.getActivity() + .getPackageManager() + .queryIntentActivities(intentWap.getIntent(), PackageManager.MATCH_ALL); + if (result.isEmpty()) { + Toast.makeText(contextWrap.getActivity(), + contextWrap.getActivity().getResources().getText(R.string.tip_no_camera), + Toast.LENGTH_SHORT).show(); throw new TException(TExceptionType.TYPE_NO_CAMERA); - }else { - startActivityForResult(contextWrap,intentWap); + } else { + startActivityForResult(contextWrap, intentWap); } } + /** * 通过第三方工具裁切照片,当没有第三方裁切工具时,会自动使用自带裁切工具进行裁切 - * @param contextWrap - * @param imageUri - * @param outPutUri - * @param options */ - public static void cropWithOtherAppBySafely(TContextWrap contextWrap, Uri imageUri, Uri outPutUri, CropOptions options){ - Intent nativeCropIntent=IntentUtils.getCropIntentWithOtherApp(imageUri, outPutUri,options); - List result=contextWrap.getActivity().getPackageManager().queryIntentActivities(nativeCropIntent,PackageManager.MATCH_ALL); - if (result.isEmpty()){ - cropWithOwnApp(contextWrap,imageUri,outPutUri,options); - }else { -// try { -// imageUri=Uri.fromFile(new File(TUriParse.getFilePathWithDocumentsUri(imageUri,contextWrap.getActivity()))); -// } catch (TException e) { -// e.printStackTrace(); -// } - startActivityForResult(contextWrap,new TIntentWap(IntentUtils.getCropIntentWithOtherApp(imageUri, outPutUri,options), TConstant.RC_CROP)); - } - } - /** - * 通过TakePhoto自带的裁切工具裁切图片 - * @param contextWrap - * @param imageUri - * @param outPutUri - * @param options - */ - public static void cropWithOwnApp(TContextWrap contextWrap, Uri imageUri, Uri outPutUri, CropOptions options){ - if (options.getAspectX()*options.getAspectY()>0){ - if (contextWrap.getFragment()!=null){ - Crop.of(imageUri, outPutUri).withAspect(options.getAspectX(),options.getAspectY()).start(contextWrap.getActivity(),contextWrap.getFragment()); - }else { - Crop.of(imageUri, outPutUri).withAspect(options.getAspectX(),options.getAspectY()).start(contextWrap.getActivity()); - } - }else if (options.getOutputX()*options.getOutputY()>0){ - if (contextWrap.getFragment()!=null){ - Crop.of(imageUri, outPutUri).withMaxSize(options.getOutputX(),options.getOutputY()).start(contextWrap.getActivity(),contextWrap.getFragment()); - }else { - Crop.of(imageUri, outPutUri).withMaxSize(options.getOutputX(),options.getOutputY()).start(contextWrap.getActivity()); - } - }else { - if (contextWrap.getFragment()!=null){ - Crop.of(imageUri, outPutUri).asSquare().start(contextWrap.getActivity(),contextWrap.getFragment()); - }else { - Crop.of(imageUri, outPutUri).asSquare().start(contextWrap.getActivity()); - } + public static void cropWithOtherAppBySafely(TContextWrap contextWrap, Uri imageUri, Uri outPutUri, + CropOptions options) { + Intent nativeCropIntent = IntentUtils.getCropIntentWithOtherApp(imageUri, outPutUri, options); + List result = contextWrap.getActivity() + .getPackageManager() + .queryIntentActivities(nativeCropIntent, PackageManager.MATCH_ALL); + if (result.isEmpty()) { + //cropWithOwnApp(contextWrap,imageUri,outPutUri,options); + } else { + // try { + // imageUri=Uri.fromFile(new File(TUriParse.getFilePathWithDocumentsUri(imageUri,contextWrap.getActivity()))); + // } catch (TException e) { + // e.printStackTrace(); + // } + startActivityForResult(contextWrap, + new TIntentWap(IntentUtils.getCropIntentWithOtherApp(imageUri, outPutUri, options), + TConstant.RC_CROP)); } } + ///** + // * 通过TakePhoto自带的裁切工具裁切图片 + // * @param contextWrap + // * @param imageUri + // * @param outPutUri + // * @param options + // */ + //public static void cropWithOwnApp(TContextWrap contextWrap, Uri imageUri, Uri outPutUri, CropOptions options){ + // if (options.getAspectX()*options.getAspectY()>0){ + // if (contextWrap.getFragment()!=null){ + // Crop.of(imageUri, outPutUri).withAspect(options.getAspectX(),options.getAspectY()).start(contextWrap.getActivity(),contextWrap.getFragment()); + // }else { + // Crop.of(imageUri, outPutUri).withAspect(options.getAspectX(),options.getAspectY()).start(contextWrap.getActivity()); + // } + // }else if (options.getOutputX()*options.getOutputY()>0){ + // if (contextWrap.getFragment()!=null){ + // Crop.of(imageUri, outPutUri).withMaxSize(options.getOutputX(),options.getOutputY()).start(contextWrap.getActivity(),contextWrap.getFragment()); + // }else { + // Crop.of(imageUri, outPutUri).withMaxSize(options.getOutputX(),options.getOutputY()).start(contextWrap.getActivity()); + // } + // }else { + // if (contextWrap.getFragment()!=null){ + // Crop.of(imageUri, outPutUri).asSquare().start(contextWrap.getActivity(),contextWrap.getFragment()); + // }else { + // Crop.of(imageUri, outPutUri).asSquare().start(contextWrap.getActivity()); + // } + // } + //} + /** * 是否裁剪之后返回数据 **/ public static boolean isReturnData() { - String release= Build.VERSION.RELEASE; - int sdk= Build.VERSION.SDK_INT; - Log.i(TAG,"release:"+release+"sdk:"+sdk); - String manufacturer = android.os.Build.MANUFACTURER; + String release = Build.VERSION.RELEASE; + int sdk = Build.VERSION.SDK_INT; + Log.i(TAG, "release:" + release + "sdk:" + sdk); + String manufacturer = Build.MANUFACTURER; if (!TextUtils.isEmpty(manufacturer)) { if (manufacturer.toLowerCase().contains("lenovo")) {//对于联想的手机返回数据 return true; } } -// if (sdk>=21){//5.0或以上版本要求返回数据 -// return true; -// } + // if (sdk>=21){//5.0或以上版本要求返回数据 + // return true; + // } return false; } + /** * 显示圆形进度对话框 * + * @param progressTitle 显示的标题 * @author JPH * Date 2014-12-12 下午7:04:09 - * @param activity - * @param progressTitle - * 显示的标题 - * @return */ public static ProgressDialog showProgressDialog(final Activity activity, - String... progressTitle) { - if(activity==null||activity.isFinishing())return null; + String... progressTitle) { + if (activity == null || activity.isFinishing()) return null; String title = activity.getResources().getString(R.string.tip_tips); - if (progressTitle != null && progressTitle.length > 0) - title = progressTitle[0]; + if (progressTitle != null && progressTitle.length > 0) title = progressTitle[0]; ProgressDialog progressDialog = new ProgressDialog(activity); progressDialog.setTitle(title); progressDialog.setCancelable(false); diff --git a/takephoto_library/src/main/java/multipleimageselect/activities/AlbumSelectActivity.java b/takephoto_library/src/main/java/multipleimageselect/activities/AlbumSelectActivity.java new file mode 100644 index 00000000..92daa4fb --- /dev/null +++ b/takephoto_library/src/main/java/multipleimageselect/activities/AlbumSelectActivity.java @@ -0,0 +1,334 @@ +package multipleimageselect.activities; + +import android.content.Context; +import android.content.Intent; +import android.content.res.Configuration; +import android.database.ContentObserver; +import android.database.Cursor; +import android.net.Uri; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.os.Process; +import android.provider.MediaStore; +import android.support.v7.app.ActionBar; +import android.support.v7.widget.Toolbar; +import android.util.DisplayMetrics; +import android.view.MenuItem; +import android.view.View; +import android.view.WindowManager; +import android.widget.GridView; +import android.widget.ProgressBar; +import android.widget.TextView; +import com.jph.takephoto.R; +import java.io.File; +import java.util.ArrayList; +import java.util.HashSet; +import multipleimageselect.adapters.CustomAlbumSelectAdapter; +import multipleimageselect.helpers.Constants; +import multipleimageselect.models.Album; + +/** + * Created by Darshan on 4/14/2015. + */ +public class AlbumSelectActivity extends HelperActivity + implements CustomAlbumSelectAdapter.OnItemClick { + private ArrayList albums; + + private TextView errorDisplay, txtTitle; + + private ProgressBar progressBar; + private GridView gridView; + private CustomAlbumSelectAdapter adapter; + + private ActionBar actionBar; + + private ContentObserver observer; + private Handler handler; + private Thread thread; + + private final String[] projection = new String[] { + MediaStore.Images.Media.BUCKET_ID, MediaStore.Images.Media.BUCKET_DISPLAY_NAME, + MediaStore.Images.Media.DATA + }; + + @Override protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_album_select); + setView(findViewById(R.id.layout_album_select)); + + Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); + txtTitle = (TextView) findViewById(R.id.txt_title); + setSupportActionBar(toolbar); + //SystemBarHelper.immersiveStatusBar(this); + //SystemBarHelper.setHeightAndPadding(this, toolbar); + actionBar = getSupportActionBar(); + if (actionBar != null) { + actionBar.setDisplayHomeAsUpEnabled(true); + actionBar.setHomeAsUpIndicator(R.drawable.ic_arrow_back); + actionBar.setDisplayShowTitleEnabled(false); + txtTitle.setText(getString(R.string.album_view)); + } + + Intent intent = getIntent(); + if (intent == null) { + finish(); + } + Constants.limit = intent.getIntExtra(Constants.INTENT_EXTRA_LIMIT, Constants.DEFAULT_LIMIT); + Constants.cameraEnable = intent.getBooleanExtra(Constants.EXTRA_CAMERA_ENABLE, false); + + errorDisplay = (TextView) findViewById(R.id.text_view_error); + errorDisplay.setVisibility(View.INVISIBLE); + + progressBar = (ProgressBar) findViewById(R.id.progress_bar_album_select); + gridView = (GridView) findViewById(R.id.grid_view_album_select); + } + + @Override protected void onStart() { + super.onStart(); + + handler = new Handler() { + @Override public void handleMessage(Message msg) { + switch (msg.what) { + case Constants.PERMISSION_GRANTED: { + loadAlbums(); + break; + } + + case Constants.FETCH_STARTED: { + progressBar.setVisibility(View.VISIBLE); + gridView.setVisibility(View.INVISIBLE); + break; + } + + case Constants.FETCH_COMPLETED: { + if (adapter == null) { + adapter = new CustomAlbumSelectAdapter(getApplicationContext(), albums, + Constants.cameraEnable); + gridView.setAdapter(adapter); + adapter.setOnItemClick(AlbumSelectActivity.this); + + progressBar.setVisibility(View.INVISIBLE); + gridView.setVisibility(View.VISIBLE); + orientationBasedUI(getResources().getConfiguration().orientation); + } else { + adapter.notifyDataSetChanged(); + } + break; + } + + case Constants.ERROR: { + progressBar.setVisibility(View.INVISIBLE); + errorDisplay.setVisibility(View.VISIBLE); + break; + } + + default: { + super.handleMessage(msg); + } + } + } + }; + observer = new ContentObserver(handler) { + @Override public void onChange(boolean selfChange, Uri uri) { + loadAlbums(); + } + }; + getContentResolver().registerContentObserver(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, + false, observer); + + checkPermission(); + } + + @Override protected void onStop() { + super.onStop(); + + stopThread(); + + getContentResolver().unregisterContentObserver(observer); + observer = null; + + if (handler != null) { + handler.removeCallbacksAndMessages(null); + handler = null; + } + } + + @Override protected void onDestroy() { + super.onDestroy(); + + if (actionBar != null) { + actionBar.setHomeAsUpIndicator(null); + } + albums = null; + if (adapter != null) { + adapter.setOnItemClick(null); + adapter.releaseResources(); + } + } + + @Override public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + orientationBasedUI(newConfig.orientation); + } + + private void orientationBasedUI(int orientation) { + final WindowManager windowManager = + (WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE); + final DisplayMetrics metrics = new DisplayMetrics(); + windowManager.getDefaultDisplay().getMetrics(metrics); + + if (adapter != null) { + int size = orientation == Configuration.ORIENTATION_PORTRAIT ? metrics.widthPixels / 2 + : metrics.widthPixels / 4; + adapter.setLayoutParams(size); + } + gridView.setNumColumns(orientation == Configuration.ORIENTATION_PORTRAIT ? 2 : 4); + } + + @Override public void onBackPressed() { + super.onBackPressed(); + setResult(RESULT_CANCELED); + finish(); + } + + @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (requestCode == Constants.REQUEST_CODE && resultCode == RESULT_OK && data != null) { + setResult(RESULT_OK, data); + finish(); + } + } + + @Override public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: { + onBackPressed(); + return true; + } + + default: { + return false; + } + } + } + + private void loadAlbums() { + startThread(new AlbumLoaderRunnable()); + } + + /** + * 选择图片 + */ + @Override public void select(int position) { + Intent intent = new Intent(getApplicationContext(), ImageSelectActivity.class); + intent.putExtra(Constants.INTENT_EXTRA_ALBUM, albums.get(position).name); + startActivityForResult(intent, Constants.REQUEST_CODE); + } + + /** + * 拍照 + */ + @Override public void takePhoto() { + Intent intent = new Intent(); + intent.putExtra(Constants.INTENT_EXTRA_START_CAMERA, true); + setResult(RESULT_OK, intent); + finish(); + } + + private class AlbumLoaderRunnable implements Runnable { + @Override public void run() { + Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); + + if (adapter == null) { + sendMessage(Constants.FETCH_STARTED); + } + + Cursor cursor = getApplicationContext().getContentResolver() + .query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, projection, null, null, + MediaStore.Images.Media.DATE_ADDED); + if (cursor == null) { + sendMessage(Constants.ERROR); + return; + } + + ArrayList temp = new ArrayList<>(cursor.getCount()); + HashSet albumSet = new HashSet<>(); + File file; + if (cursor.moveToLast()) { + do { + if (Thread.interrupted()) { + return; + } + + long albumId = cursor.getLong(cursor.getColumnIndex(projection[0])); + String album = cursor.getString(cursor.getColumnIndex(projection[1])); + String image = cursor.getString(cursor.getColumnIndex(projection[2])); + + if (!albumSet.contains(albumId)) { + /* + It may happen that some image file paths are still present in cache, + though image file does not exist. These last as long as media + scanner is not run again. To avoid get such image file paths, check + if image file exists. + */ + file = new File(image); + if (file.exists()) { + temp.add(new Album(album, image)); + albumSet.add(albumId); + } + } + } while (cursor.moveToPrevious()); + } + cursor.close(); + + if (albums == null) { + albums = new ArrayList<>(); + } + albums.clear(); + albums.addAll(temp); + + sendMessage(Constants.FETCH_COMPLETED); + } + } + + private void startThread(Runnable runnable) { + stopThread(); + thread = new Thread(runnable); + thread.start(); + } + + private void stopThread() { + if (thread == null || !thread.isAlive()) { + return; + } + + thread.interrupt(); + try { + thread.join(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + private void sendMessage(int what) { + if (handler == null) { + return; + } + + Message message = handler.obtainMessage(); + message.what = what; + message.sendToTarget(); + } + + @Override protected void permissionGranted() { + Message message = handler.obtainMessage(); + message.what = Constants.PERMISSION_GRANTED; + message.sendToTarget(); + } + + @Override protected void hideViews() { + progressBar.setVisibility(View.INVISIBLE); + gridView.setVisibility(View.INVISIBLE); + } +} diff --git a/takephoto_library/src/main/java/multipleimageselect/activities/HelperActivity.java b/takephoto_library/src/main/java/multipleimageselect/activities/HelperActivity.java new file mode 100644 index 00000000..ba27f95a --- /dev/null +++ b/takephoto_library/src/main/java/multipleimageselect/activities/HelperActivity.java @@ -0,0 +1,117 @@ +package multipleimageselect.activities; + +import android.Manifest; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.net.Uri; +import android.provider.Settings; +import android.support.annotation.NonNull; +import android.support.design.widget.Snackbar; +import android.support.v4.app.ActivityCompat; +import android.support.v4.content.ContextCompat; +import android.support.v7.app.AppCompatActivity; +import android.view.View; +import com.jph.takephoto.R; +import multipleimageselect.helpers.Constants; + +/** + * Created by darshan on 26/9/16. + */ +public class HelperActivity extends AppCompatActivity { + protected View view; + + private final int maxLines = 4; + private final String[] permissions = new String[]{ Manifest.permission.WRITE_EXTERNAL_STORAGE }; + + protected void checkPermission() { + if (ContextCompat.checkSelfPermission(this, + Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) { + permissionGranted(); + + } else { + ActivityCompat.requestPermissions(this, permissions, Constants.PERMISSION_REQUEST_CODE); + } + } + + private void requestPermission() { + if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) { + showRequestPermissionRationale(); + + } else { + showAppPermissionSettings(); + } + } + + private void showRequestPermissionRationale() { + Snackbar snackbar = Snackbar.make( + view, + getString(R.string.permission_info), + Snackbar.LENGTH_INDEFINITE) + .setAction(getString(R.string.permission_ok), new View.OnClickListener() { + @Override + public void onClick(View v) { + ActivityCompat.requestPermissions( + HelperActivity.this, + permissions, + Constants.PERMISSION_REQUEST_CODE); + } + }); + + /*((TextView) snackbar.getView() + .findViewById(android.support.design.R.id.snackbar_text)).setMaxLines(maxLines);*/ + snackbar.show(); + } + + private void showAppPermissionSettings() { + Snackbar snackbar = Snackbar.make( + view, + getString(R.string.permission_force), + Snackbar.LENGTH_INDEFINITE) + .setAction(getString(R.string.permission_settings), new View.OnClickListener() { + @Override + public void onClick(View v) { + Uri uri = Uri.fromParts( + getString(R.string.permission_package), + HelperActivity.this.getPackageName(), + null); + + Intent intent = new Intent(); + intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); + intent.setData(uri); + startActivityForResult(intent, Constants.PERMISSION_REQUEST_CODE); + } + }); + + /*((TextView) snackbar.getView() + .findViewById(android.support.design.R.id.snackbar_text)).setMaxLines(maxLines);*/ + snackbar.show(); + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull + int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + if (requestCode != Constants.PERMISSION_REQUEST_CODE + || grantResults.length == 0 + || grantResults[0] == PackageManager.PERMISSION_DENIED) { + permissionDenied(); + + } else { + permissionGranted(); + } + } + + protected void permissionGranted() {} + + private void permissionDenied() { + hideViews(); + requestPermission(); + } + + protected void hideViews() {} + + protected void setView(View view) { + this.view = view; + } +} diff --git a/takephoto_library/src/main/java/multipleimageselect/activities/ImageSelectActivity.java b/takephoto_library/src/main/java/multipleimageselect/activities/ImageSelectActivity.java new file mode 100644 index 00000000..e1dc156a --- /dev/null +++ b/takephoto_library/src/main/java/multipleimageselect/activities/ImageSelectActivity.java @@ -0,0 +1,386 @@ +package multipleimageselect.activities; + +import android.content.Context; +import android.content.Intent; +import android.content.res.Configuration; +import android.database.ContentObserver; +import android.database.Cursor; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.os.Process; +import android.provider.MediaStore; +import android.support.v7.app.ActionBar; +import android.support.v7.widget.Toolbar; +import android.text.TextUtils; +import android.util.DisplayMetrics; +import android.view.View; +import android.view.WindowManager; +import android.widget.AdapterView; +import android.widget.GridView; +import android.widget.ProgressBar; +import android.widget.TextView; +import android.widget.Toast; +import com.jph.takephoto.R; +import java.io.File; +import java.util.ArrayList; +import java.util.HashSet; +import multipleimageselect.adapters.CustomImageSelectAdapter; +import multipleimageselect.helpers.Constants; +import multipleimageselect.models.Image; + +/** + * Created by Darshan on 4/18/2015. + */ +public class ImageSelectActivity extends HelperActivity { + private ArrayList images; + private String album; + + private TextView errorDisplay, txtFinish, txtTitle; + + private ProgressBar progressBar; + private GridView gridView; + private CustomImageSelectAdapter adapter; + + private ActionBar actionBar; + + private int countSelected; + + private ContentObserver observer; + private Handler handler; + private Thread thread; + + private final String[] projection = new String[] { + MediaStore.Images.Media._ID, MediaStore.Images.Media.DISPLAY_NAME, + MediaStore.Images.Media.DATA + }; + + @Override protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_image_select); + setView(findViewById(R.id.layout_image_select)); + Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); + txtFinish = (TextView) findViewById(R.id.txt_finish); + txtTitle = (TextView) findViewById(R.id.txt_title); + setSupportActionBar(toolbar); + //SystemBarHelper.immersiveStatusBar(this); + //SystemBarHelper.setHeightAndPadding(this, toolbar); + actionBar = getSupportActionBar(); + if (actionBar != null) { + actionBar.setDisplayHomeAsUpEnabled(true); + actionBar.setHomeAsUpIndicator(R.drawable.ic_arrow_back); + actionBar.setDisplayShowTitleEnabled(false); + setTitle(getString(R.string.image_view)); + } + toolbar.setNavigationOnClickListener(new View.OnClickListener() { + @Override public void onClick(View view) { + onBackPressed(); + } + }); + txtFinish.setOnClickListener(new View.OnClickListener() { + @Override public void onClick(View v) { + if (countSelected > 0) sendIntent(); + } + }); + Intent intent = getIntent(); + if (intent == null) { + finish(); + } + album = intent.getStringExtra(Constants.INTENT_EXTRA_ALBUM); + + errorDisplay = (TextView) findViewById(R.id.text_view_error); + errorDisplay.setVisibility(View.INVISIBLE); + + progressBar = (ProgressBar) findViewById(R.id.progress_bar_image_select); + gridView = (GridView) findViewById(R.id.grid_view_image_select); + gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override public void onItemClick(AdapterView parent, View view, int position, long id) { + toggleSelection(position); + String selectFormat = getString(R.string.selected); + setTitle(String.format(selectFormat, Constants.limit - countSelected + "张")); + txtFinish.setVisibility(View.VISIBLE); + if (countSelected == 0) { + setTitle(getString(R.string.image_view)); + txtFinish.setVisibility(View.INVISIBLE); + } + } + }); + } + + @Override protected void onStart() { + super.onStart(); + + handler = new Handler() { + @Override public void handleMessage(Message msg) { + switch (msg.what) { + case Constants.PERMISSION_GRANTED: { + loadImages(); + break; + } + + case Constants.FETCH_STARTED: { + progressBar.setVisibility(View.VISIBLE); + gridView.setVisibility(View.INVISIBLE); + break; + } + + case Constants.FETCH_COMPLETED: { + /* + If adapter is null, this implies that the loaded images will be shown + for the first time, hence send FETCH_COMPLETED message. + However, if adapter has been initialised, this thread was run either + due to the activity being restarted or content being changed. + */ + if (adapter == null) { + adapter = new CustomImageSelectAdapter(getApplicationContext(), images); + gridView.setAdapter(adapter); + + progressBar.setVisibility(View.INVISIBLE); + gridView.setVisibility(View.VISIBLE); + orientationBasedUI(getResources().getConfiguration().orientation); + } else { + adapter.notifyDataSetChanged(); + /* + Some selected images may have been deleted + hence update action mode title + */ + //if (actionMode != null) { + // countSelected = msg.arg1; + // actionMode.setTitle(countSelected + " 已选"); + //} + } + break; + } + + case Constants.ERROR: { + progressBar.setVisibility(View.INVISIBLE); + errorDisplay.setVisibility(View.VISIBLE); + break; + } + + default: { + super.handleMessage(msg); + } + } + } + }; + observer = new ContentObserver(handler) { + @Override public void onChange(boolean selfChange) { + loadImages(); + } + }; + getContentResolver().registerContentObserver(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, + false, observer); + + checkPermission(); + } + + @Override protected void onStop() { + super.onStop(); + + stopThread(); + + getContentResolver().unregisterContentObserver(observer); + observer = null; + + if (handler != null) { + handler.removeCallbacksAndMessages(null); + handler = null; + } + } + + @Override protected void onDestroy() { + super.onDestroy(); + + if (actionBar != null) { + actionBar.setHomeAsUpIndicator(null); + } + images = null; + if (adapter != null) { + adapter.releaseResources(); + } + gridView.setOnItemClickListener(null); + } + + @Override public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + orientationBasedUI(newConfig.orientation); + } + + private void orientationBasedUI(int orientation) { + final WindowManager windowManager = + (WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE); + final DisplayMetrics metrics = new DisplayMetrics(); + windowManager.getDefaultDisplay().getMetrics(metrics); + + if (adapter != null) { + int size = orientation == Configuration.ORIENTATION_PORTRAIT ? metrics.widthPixels / 3 + : metrics.widthPixels / 5; + adapter.setLayoutParams(size); + } + gridView.setNumColumns(orientation == Configuration.ORIENTATION_PORTRAIT ? 3 : 5); + } + + private void toggleSelection(int position) { + if (!images.get(position).isSelected && countSelected >= Constants.limit) { + Toast.makeText(getApplicationContext(), "照片已经达到上限", Toast.LENGTH_SHORT).show(); + //Toast.makeText(getApplicationContext(), + // String.format(getString(R.string.limit_exceeded), Constants.limit), Toast.LENGTH_SHORT) + // .show(); + return; + } + + images.get(position).isSelected = !images.get(position).isSelected; + if (images.get(position).isSelected) { + countSelected++; + } else { + countSelected--; + } + adapter.notifyDataSetChanged(); + } + + private ArrayList getSelected() { + ArrayList selectedImages = new ArrayList<>(); + for (int i = 0, l = images.size(); i < l; i++) { + if (images.get(i).isSelected) { + selectedImages.add(images.get(i)); + } + } + return selectedImages; + } + + private void sendIntent() { + Intent intent = new Intent(); + intent.putParcelableArrayListExtra(Constants.INTENT_EXTRA_IMAGES, getSelected()); + intent.putExtra(Constants.INTENT_EXTRA_START_CAMERA, false); + setResult(RESULT_OK, intent); + finish(); + } + + private void loadImages() { + startThread(new ImageLoaderRunnable()); + } + + private class ImageLoaderRunnable implements Runnable { + @Override public void run() { + Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); + /* + If the adapter is null, this is first time this activity's view is + being shown, hence send FETCH_STARTED message to show progress bar + while images are loaded from phone + */ + if (adapter == null) { + sendMessage(Constants.FETCH_STARTED); + } + + File file; + HashSet selectedImages = new HashSet<>(); + if (images != null) { + Image image; + for (int i = 0, l = images.size(); i < l; i++) { + image = images.get(i); + file = new File(image.path); + if (file.exists() && image.isSelected) { + selectedImages.add(image.id); + } + } + } + + Cursor cursor = + getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, projection, + MediaStore.Images.Media.BUCKET_DISPLAY_NAME + " =?", new String[] { album }, + MediaStore.Images.Media.DATE_ADDED); + if (cursor == null) { + sendMessage(Constants.ERROR); + return; + } + + /* + In case this runnable is executed to onChange calling loadImages, + using countSelected variable can result in a race condition. To avoid that, + tempCountSelected keeps track of number of selected images. On handling + FETCH_COMPLETED message, countSelected is assigned value of tempCountSelected. + */ + int tempCountSelected = 0; + ArrayList temp = new ArrayList<>(cursor.getCount()); + if (cursor.moveToLast()) { + do { + if (Thread.interrupted()) { + return; + } + + long id = cursor.getLong(cursor.getColumnIndex(projection[0])); + String name = cursor.getString(cursor.getColumnIndex(projection[1])); + String path = cursor.getString(cursor.getColumnIndex(projection[2])); + boolean isSelected = selectedImages.contains(id); + if (isSelected) { + tempCountSelected++; + } + + file = new File(path); + if (file.exists()) { + temp.add(new Image(id, name, path, isSelected)); + } + } while (cursor.moveToPrevious()); + } + cursor.close(); + + if (images == null) { + images = new ArrayList<>(); + } + images.clear(); + images.addAll(temp); + + sendMessage(Constants.FETCH_COMPLETED, tempCountSelected); + } + } + + private void startThread(Runnable runnable) { + stopThread(); + thread = new Thread(runnable); + thread.start(); + } + + private void stopThread() { + if (thread == null || !thread.isAlive()) { + return; + } + + thread.interrupt(); + try { + thread.join(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + private void sendMessage(int what) { + sendMessage(what, 0); + } + + private void sendMessage(int what, int arg1) { + if (handler == null) { + return; + } + + Message message = handler.obtainMessage(); + message.what = what; + message.arg1 = arg1; + message.sendToTarget(); + } + + @Override protected void permissionGranted() { + sendMessage(Constants.PERMISSION_GRANTED); + } + + @Override protected void hideViews() { + progressBar.setVisibility(View.INVISIBLE); + gridView.setVisibility(View.INVISIBLE); + } + + private void setTitle(String title) { + if (!TextUtils.isEmpty(title)) { + txtTitle.setText(title); + } + } +} diff --git a/takephoto_library/src/main/java/multipleimageselect/adapters/CustomAlbumSelectAdapter.java b/takephoto_library/src/main/java/multipleimageselect/adapters/CustomAlbumSelectAdapter.java new file mode 100644 index 00000000..8c3f9cb1 --- /dev/null +++ b/takephoto_library/src/main/java/multipleimageselect/adapters/CustomAlbumSelectAdapter.java @@ -0,0 +1,113 @@ +package multipleimageselect.adapters; + +import android.content.Context; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.TextView; +import com.bumptech.glide.Glide; +import com.jph.takephoto.R; +import java.util.ArrayList; +import multipleimageselect.models.Album; + +/** + * Created by Darshan on 4/14/2015. + */ +public class CustomAlbumSelectAdapter extends CustomGenericAdapter { + private boolean enableCamera; + private OnItemClick onItemClick; + + public CustomAlbumSelectAdapter(Context context, ArrayList albums, boolean enableCamera) { + super(context, albums); + this.enableCamera = enableCamera; + } + + public void setOnItemClick(OnItemClick onItemClick) { + this.onItemClick = onItemClick; + } + + @Override public int getCount() { + if (enableCamera) { + return super.getCount() + 1; + } + return super.getCount(); + } + + @Override public View getView(final int position, View convertView, ViewGroup parent) { + ViewHolder viewHolder; + + if (convertView == null) { + convertView = layoutInflater.inflate(R.layout.grid_view_item_album_select, null); + + viewHolder = new ViewHolder(); + viewHolder.imageView = (ImageView) convertView.findViewById(R.id.image_view_album_image); + viewHolder.textView = (TextView) convertView.findViewById(R.id.text_view_album_name); + viewHolder.frameLayout = (FrameLayout) convertView.findViewById(R.id.frame_album_item); + + convertView.setTag(viewHolder); + } else { + viewHolder = (ViewHolder) convertView.getTag(); + } + + viewHolder.imageView.getLayoutParams().width = size; + viewHolder.imageView.getLayoutParams().height = size; + //启用拍照 + if (enableCamera) { + if (0 == position) { + if (null != onItemClick) { + viewHolder.frameLayout.setOnClickListener(new View.OnClickListener() { + @Override public void onClick(View v) { + onItemClick.takePhoto(); + } + }); + } + viewHolder.textView.setText("拍照"); + Glide.with(context).load(R.drawable.ic_camera).centerCrop().into(viewHolder.imageView); + } else { + if (null != onItemClick) { + viewHolder.frameLayout.setOnClickListener(new View.OnClickListener() { + @Override public void onClick(View v) { + onItemClick.select(position-1); + } + }); + } + viewHolder.textView.setText(arrayList.get(position - 1).name); + Glide.with(context) + .load(arrayList.get(position - 1).cover) + .placeholder(R.drawable.image_placeholder) + .centerCrop() + .into(viewHolder.imageView); + } + } else { + //不启用拍照 + if (null != onItemClick) { + viewHolder.frameLayout.setOnClickListener(new View.OnClickListener() { + @Override public void onClick(View v) { + onItemClick.select(position); + } + }); + } + viewHolder.textView.setText(arrayList.get(position).name); + Glide.with(context) + .load(arrayList.get(position).cover) + .placeholder(R.drawable.image_placeholder) + .centerCrop() + .into(viewHolder.imageView); + } + + return convertView; + } + + private static class ViewHolder { + public FrameLayout frameLayout; + public ImageView imageView; + public TextView textView; + } + + public interface OnItemClick { + void select(int pos); + + void takePhoto(); + } +} diff --git a/takephoto_library/src/main/java/multipleimageselect/adapters/CustomGenericAdapter.java b/takephoto_library/src/main/java/multipleimageselect/adapters/CustomGenericAdapter.java new file mode 100644 index 00000000..c1ec2c1b --- /dev/null +++ b/takephoto_library/src/main/java/multipleimageselect/adapters/CustomGenericAdapter.java @@ -0,0 +1,46 @@ +package multipleimageselect.adapters; + +import android.content.Context; +import android.view.LayoutInflater; +import android.widget.BaseAdapter; +import java.util.ArrayList; + +/** + * Created by Darshan on 4/24/2015. + */ +public abstract class CustomGenericAdapter extends BaseAdapter { + protected ArrayList arrayList; + protected Context context; + protected LayoutInflater layoutInflater; + + protected int size; + + public CustomGenericAdapter(Context context, ArrayList arrayList) { + this.arrayList = arrayList; + this.context = context; + this.layoutInflater = LayoutInflater.from(this.context); + } + + @Override + public int getCount() { + return arrayList.size(); + } + + public T getItem(int position) { + return arrayList.get(position); + } + + @Override + public long getItemId(int position) { + return position; + } + + public void setLayoutParams(int size) { + this.size = size; + } + + public void releaseResources() { + arrayList = null; + context = null; + } +} diff --git a/takephoto_library/src/main/java/multipleimageselect/adapters/CustomImageSelectAdapter.java b/takephoto_library/src/main/java/multipleimageselect/adapters/CustomImageSelectAdapter.java new file mode 100644 index 00000000..c3fcdce4 --- /dev/null +++ b/takephoto_library/src/main/java/multipleimageselect/adapters/CustomImageSelectAdapter.java @@ -0,0 +1,65 @@ +package multipleimageselect.adapters; + +import android.content.Context; +import android.support.v4.content.ContextCompat; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.ImageView; +import com.bumptech.glide.Glide; +import com.jph.takephoto.R; +import java.util.ArrayList; +import multipleimageselect.models.Image; + +/** + * Created by Darshan on 4/18/2015. + */ +public class CustomImageSelectAdapter extends CustomGenericAdapter { + public CustomImageSelectAdapter(Context context, ArrayList images) { + super(context, images); + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + ViewHolder viewHolder; + + if (convertView == null) { + convertView = layoutInflater.inflate(R.layout.grid_view_item_image_select, null); + + viewHolder = new ViewHolder(); + viewHolder.imageView = (ImageView) convertView.findViewById(R.id.image_view_image_select); + viewHolder.view = convertView.findViewById(R.id.view_alpha); + + convertView.setTag(viewHolder); + + } else { + viewHolder = (ViewHolder) convertView.getTag(); + } + + viewHolder.imageView.getLayoutParams().width = size; + viewHolder.imageView.getLayoutParams().height = size; + + viewHolder.view.getLayoutParams().width = size; + viewHolder.view.getLayoutParams().height = size; + + if (arrayList.get(position).isSelected) { + viewHolder.view.setAlpha(0.5f); + ((FrameLayout) convertView).setForeground(ContextCompat.getDrawable(context,R.drawable.ic_done_white)); + + } else { + viewHolder.view.setAlpha(0.0f); + ((FrameLayout) convertView).setForeground(null); + } + + Glide.with(context) + .load(arrayList.get(position).path) + .placeholder(R.drawable.image_placeholder).into(viewHolder.imageView); + + return convertView; + } + + private static class ViewHolder { + public ImageView imageView; + public View view; + } +} diff --git a/takephoto_library/src/main/java/multipleimageselect/helpers/Constants.java b/takephoto_library/src/main/java/multipleimageselect/helpers/Constants.java new file mode 100644 index 00000000..10d83b49 --- /dev/null +++ b/takephoto_library/src/main/java/multipleimageselect/helpers/Constants.java @@ -0,0 +1,33 @@ +package multipleimageselect.helpers; + +/** + * Created by Darshan on 5/26/2015. + */ +public class Constants { + public static final int PERMISSION_REQUEST_CODE = 1000; + public static final int PERMISSION_GRANTED = 1001; + public static final int PERMISSION_DENIED = 1002; + + public static final int REQUEST_CODE = 2000; + + public static final int FETCH_STARTED = 2001; + public static final int FETCH_COMPLETED = 2002; + public static final int ERROR = 2005; + + /** + * Request code for permission has to be < (1 << 8) + * Otherwise throws java.lang.IllegalArgumentException: Can only use lower 8 bits for requestCode + */ + public static final int PERMISSION_REQUEST_READ_EXTERNAL_STORAGE = 23; + + public static final String INTENT_EXTRA_ALBUM = "album"; + public static final String INTENT_EXTRA_IMAGES = "images"; + public static final String INTENT_EXTRA_LIMIT = "limit"; + public static final String INTENT_EXTRA_START_CAMERA = "start_camera"; + public static final String EXTRA_CAMERA_ENABLE = "camera_enable"; + public static final int DEFAULT_LIMIT = 10; + + //Maximum number of images that can be selected at a time + public static int limit; + public static boolean cameraEnable; +} diff --git a/takephoto_library/src/main/java/multipleimageselect/models/Album.java b/takephoto_library/src/main/java/multipleimageselect/models/Album.java new file mode 100644 index 00000000..fd4de58f --- /dev/null +++ b/takephoto_library/src/main/java/multipleimageselect/models/Album.java @@ -0,0 +1,14 @@ +package multipleimageselect.models; + +/** + * Created by Darshan on 4/14/2015. + */ +public class Album { + public String name; + public String cover; + + public Album(String name, String cover) { + this.name = name; + this.cover = cover; + } +} diff --git a/takephoto_library/src/main/java/multipleimageselect/models/Image.java b/takephoto_library/src/main/java/multipleimageselect/models/Image.java new file mode 100644 index 00000000..e34a5ab2 --- /dev/null +++ b/takephoto_library/src/main/java/multipleimageselect/models/Image.java @@ -0,0 +1,51 @@ +package multipleimageselect.models; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * Created by Darshan on 4/18/2015. + */ +public class Image implements Parcelable { + public long id; + public String name; + public String path; + public boolean isSelected; + + public Image(long id, String name, String path, boolean isSelected) { + this.id = id; + this.name = name; + this.path = path; + this.isSelected = isSelected; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeLong(id); + dest.writeString(name); + dest.writeString(path); + } + + public static final Creator CREATOR = new Creator() { + @Override + public Image createFromParcel(Parcel source) { + return new Image(source); + } + + @Override + public Image[] newArray(int size) { + return new Image[size]; + } + }; + + private Image(Parcel in) { + id = in.readLong(); + name = in.readString(); + path = in.readString(); + } +} diff --git a/takephoto_library/src/main/res/drawable-xhdpi/ic_arrow_back.png b/takephoto_library/src/main/res/drawable-xhdpi/ic_arrow_back.png new file mode 100644 index 00000000..ce5b878b Binary files /dev/null and b/takephoto_library/src/main/res/drawable-xhdpi/ic_arrow_back.png differ diff --git a/takephoto_library/src/main/res/drawable-xhdpi/ic_camera.png b/takephoto_library/src/main/res/drawable-xhdpi/ic_camera.png new file mode 100644 index 00000000..17aa3be0 Binary files /dev/null and b/takephoto_library/src/main/res/drawable-xhdpi/ic_camera.png differ diff --git a/takephoto_library/src/main/res/drawable-xhdpi/ic_done_white.png b/takephoto_library/src/main/res/drawable-xhdpi/ic_done_white.png new file mode 100644 index 00000000..0ebb5555 Binary files /dev/null and b/takephoto_library/src/main/res/drawable-xhdpi/ic_done_white.png differ diff --git a/takephoto_library/src/main/res/drawable-xxhdpi/ic_arrow_back.png b/takephoto_library/src/main/res/drawable-xxhdpi/ic_arrow_back.png new file mode 100644 index 00000000..746d7757 Binary files /dev/null and b/takephoto_library/src/main/res/drawable-xxhdpi/ic_arrow_back.png differ diff --git a/takephoto_library/src/main/res/drawable-xxhdpi/ic_camera.png b/takephoto_library/src/main/res/drawable-xxhdpi/ic_camera.png new file mode 100644 index 00000000..8d9c05e3 Binary files /dev/null and b/takephoto_library/src/main/res/drawable-xxhdpi/ic_camera.png differ diff --git a/takephoto_library/src/main/res/drawable-xxhdpi/ic_done_white.png b/takephoto_library/src/main/res/drawable-xxhdpi/ic_done_white.png new file mode 100644 index 00000000..200dc733 Binary files /dev/null and b/takephoto_library/src/main/res/drawable-xxhdpi/ic_done_white.png differ diff --git a/takephoto_library/src/main/res/drawable/image_placeholder.xml b/takephoto_library/src/main/res/drawable/image_placeholder.xml new file mode 100644 index 00000000..43ad7823 --- /dev/null +++ b/takephoto_library/src/main/res/drawable/image_placeholder.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/takephoto_library/src/main/res/layout/activity_album_select.xml b/takephoto_library/src/main/res/layout/activity_album_select.xml new file mode 100644 index 00000000..16c8e360 --- /dev/null +++ b/takephoto_library/src/main/res/layout/activity_album_select.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/takephoto_library/src/main/res/layout/activity_image_select.xml b/takephoto_library/src/main/res/layout/activity_image_select.xml new file mode 100644 index 00000000..9903c168 --- /dev/null +++ b/takephoto_library/src/main/res/layout/activity_image_select.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/takephoto_library/src/main/res/layout/grid_view_item_album_select.xml b/takephoto_library/src/main/res/layout/grid_view_item_album_select.xml new file mode 100644 index 00000000..3b1a49ea --- /dev/null +++ b/takephoto_library/src/main/res/layout/grid_view_item_album_select.xml @@ -0,0 +1,27 @@ + + + + + + + + \ No newline at end of file diff --git a/takephoto_library/src/main/res/layout/grid_view_item_image_select.xml b/takephoto_library/src/main/res/layout/grid_view_item_image_select.xml new file mode 100644 index 00000000..19a32a91 --- /dev/null +++ b/takephoto_library/src/main/res/layout/grid_view_item_image_select.xml @@ -0,0 +1,21 @@ + + + + + + + \ No newline at end of file diff --git a/takephoto_library/src/main/res/layout/toolbar.xml b/takephoto_library/src/main/res/layout/toolbar.xml new file mode 100644 index 00000000..a2cce928 --- /dev/null +++ b/takephoto_library/src/main/res/layout/toolbar.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/takephoto_library/src/main/res/values-en/strings.xml b/takephoto_library/src/main/res/values-en/strings.xml deleted file mode 100644 index daa40bdc..00000000 --- a/takephoto_library/src/main/res/values-en/strings.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - Choose not pictures - No camera - Tips - Being compressed... - "%1$s Picture compression failure:%2$s picturePath:%3$s" - "There are pictures of crop failures." - "There are pictures of compress failures." - " canceled crop" - "Operation canceled." - No permission to use the camera, open the rights management - No permission to use the SD card, open the rights management - No permission to use the camera and SD card, open the rights management - - diff --git a/takephoto_library/src/main/res/values/color.xml b/takephoto_library/src/main/res/values/color.xml new file mode 100644 index 00000000..30605ab4 --- /dev/null +++ b/takephoto_library/src/main/res/values/color.xml @@ -0,0 +1,17 @@ + + + #FFFFFF + + #2E7D32 + #1B5E20 + #C8E6C9 + #4CAF50 + + #212121 + #727272 + #B6B6B6 + #FFFFFF + + #99FFFFFF + #000000 + \ No newline at end of file diff --git a/takephoto_library/src/main/res/values/strings.xml b/takephoto_library/src/main/res/values/strings.xml index 23c46910..aba0c364 100644 --- a/takephoto_library/src/main/res/values/strings.xml +++ b/takephoto_library/src/main/res/values/strings.xml @@ -1,24 +1,34 @@ - - 选择的不是图片 - 没有相机 - 提示 - 正在压缩照片... - "%1$s 图片压缩失败:%2$s picturePath:%3$s" - "有裁切失败的图片" - "有压缩失败的图片" - " 取消裁切" - "操作被取消" - 没有使用相机的权限,请在权限管理中开启 - 没有使用SD卡的权限,请在权限管理中开启 - 没有使用相机和SD卡的权限,请在权限管理中开启 + + 选择的不是图片 + 没有相机 + 提示 + 正在压缩照片... + "%1$s 图片压缩失败:%2$s picturePath:%3$s" + "有裁切失败的图片" + "有压缩失败的图片" + " 取消裁切" + "操作被取消" + 没有使用相机的权限,请在权限管理中开启 + 没有使用SD卡的权限,请在权限管理中开启 + 没有使用相机和SD卡的权限,请在权限管理中开启 - - 选择图片 - 单击选择 + - 确定 - 已选 - 最多能选 %d 张 + 单击选择 + 选择图片 + + 确定 + OK + Settings + package + App requires permission to Storage to view images. + App requires permission to Storage to view images. Tap Settings + and go to Permissions to grant permission. + + Oops, something went wrong! + + 还能选%1$s + 最多能选 %d 张 diff --git a/takephoto_library/src/main/res/values/style.xml b/takephoto_library/src/main/res/values/style.xml new file mode 100644 index 00000000..12f5e3b7 --- /dev/null +++ b/takephoto_library/src/main/res/values/style.xml @@ -0,0 +1,15 @@ + + + + + + \ No newline at end of file