From 32f3c646fd4be7e1d8ae92478a34790d017ea174 Mon Sep 17 00:00:00 2001 From: D4rthR4tz3 Date: Fri, 22 Apr 2016 15:02:26 +0200 Subject: [PATCH 01/10] Update ImagePicker.java Added localization feature for message boxes --- .../synconset/ImagePicker/ImagePicker.java | 757 ++++++++++++++++-- 1 file changed, 695 insertions(+), 62 deletions(-) diff --git a/src/android/com/synconset/ImagePicker/ImagePicker.java b/src/android/com/synconset/ImagePicker/ImagePicker.java index 2f4939a..ec3822e 100644 --- a/src/android/com/synconset/ImagePicker/ImagePicker.java +++ b/src/android/com/synconset/ImagePicker/ImagePicker.java @@ -1,72 +1,705 @@ -/** - * An Image Picker Plugin for Cordova/PhoneGap. +/* + * Copyright (c) 2012, David Erosa + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDIN G NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE + * + * Code modified by Andrew Stephan for Sync OnSet + * */ + package com.synconset; -import org.apache.cordova.CallbackContext; -import org.apache.cordova.CordovaPlugin; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - +import java.net.URI; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import com.synconset.FakeR; import android.app.Activity; +import android.app.ActionBar; +import android.app.AlertDialog; +import android.app.LoaderManager; +import android.app.ProgressDialog; +import android.content.Context; +import android.content.CursorLoader; +import android.content.DialogInterface; import android.content.Intent; +import android.content.Loader; +import android.content.res.Resources; +import android.database.Cursor; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Color; +import android.graphics.Matrix; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Bundle; +import android.provider.MediaStore; import android.util.Log; +import android.util.SparseBooleanArray; +import android.view.Display; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AbsListView; +import android.widget.AbsListView.OnScrollListener; +import android.widget.AdapterView; +import android.widget.AdapterView.OnItemClickListener; +import android.widget.BaseAdapter; +import android.widget.GridView; +import android.widget.ImageView; +import android.widget.TextView; -public class ImagePicker extends CordovaPlugin { - public static String TAG = "ImagePicker"; - - private CallbackContext callbackContext; - private JSONObject params; - - public boolean execute(String action, final JSONArray args, final CallbackContext callbackContext) throws JSONException { - this.callbackContext = callbackContext; - this.params = args.getJSONObject(0); - if (action.equals("getPictures")) { - Intent intent = new Intent(cordova.getActivity(), MultiImageChooserActivity.class); - int max = 20; - int desiredWidth = 0; - int desiredHeight = 0; - int quality = 100; - if (this.params.has("maximumImagesCount")) { - max = this.params.getInt("maximumImagesCount"); - } - if (this.params.has("width")) { - desiredWidth = this.params.getInt("width"); - } - if (this.params.has("height")) { - desiredWidth = this.params.getInt("height"); - } - if (this.params.has("quality")) { - quality = this.params.getInt("quality"); - } - intent.putExtra("MAX_IMAGES", max); - intent.putExtra("WIDTH", desiredWidth); - intent.putExtra("HEIGHT", desiredHeight); - intent.putExtra("QUALITY", quality); - if (this.cordova != null) { - this.cordova.startActivityForResult((CordovaPlugin) this, intent, 0); - } +import org.chromium.ui.resources.Resource; + +import de.awenko.mobile.R; + +public class MultiImageChooserActivity extends Activity implements OnItemClickListener, + LoaderManager.LoaderCallbacks { + private static final String TAG = "ImagePicker"; + + public static final int NOLIMIT = -1; + public static final String MAX_IMAGES_KEY = "MAX_IMAGES"; + public static final String WIDTH_KEY = "WIDTH"; + public static final String HEIGHT_KEY = "HEIGHT"; + public static final String QUALITY_KEY = "QUALITY"; + + private ImageAdapter ia; + + private Cursor imagecursor, actualimagecursor; + private int image_column_index, image_column_orientation, actual_image_column_index, orientation_column_index; + private int colWidth; + + private static final int CURSORLOADER_THUMBS = 0; + private static final int CURSORLOADER_REAL = 1; + + private Map fileNames = new HashMap(); + + private SparseBooleanArray checkStatus = new SparseBooleanArray(); + + private int maxImages; + private int maxImageCount; + + private int desiredWidth; + private int desiredHeight; + private int quality; + + private GridView gridView; + + private final ImageFetcher fetcher = new ImageFetcher(); + + private int selectedColor = 0xff32b2e1; + private boolean shouldRequestThumb = true; + + private FakeR fakeR; + + private ProgressDialog progress; + + private Resources resources; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + fakeR = new FakeR(this); + setContentView(fakeR.getId("layout", "multiselectorgrid")); + fileNames.clear(); + + maxImages = getIntent().getIntExtra(MAX_IMAGES_KEY, NOLIMIT); + desiredWidth = getIntent().getIntExtra(WIDTH_KEY, 0); + desiredHeight = getIntent().getIntExtra(HEIGHT_KEY, 0); + quality = getIntent().getIntExtra(QUALITY_KEY, 0); + maxImageCount = maxImages; + + Display display = getWindowManager().getDefaultDisplay(); + int width = display.getWidth(); + + colWidth = width / 4; + + gridView = (GridView) findViewById(fakeR.getId("id", "gridview")); + gridView.setOnItemClickListener(this); + gridView.setOnScrollListener(new OnScrollListener() { + private int lastFirstItem = 0; + private long timestamp = System.currentTimeMillis(); + + @Override + public void onScrollStateChanged(AbsListView view, int scrollState) { + if (scrollState == SCROLL_STATE_IDLE) { + shouldRequestThumb = true; + ia.notifyDataSetChanged(); + } + } + + @Override + public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { + float dt = System.currentTimeMillis() - timestamp; + if (firstVisibleItem != lastFirstItem) { + double speed = 1 / dt * 1000; + lastFirstItem = firstVisibleItem; + timestamp = System.currentTimeMillis(); + + // Limit if we go faster than a page a second + shouldRequestThumb = speed < visibleItemCount; + } + } + }); + + ia = new ImageAdapter(this); + gridView.setAdapter(ia); + + resources = getResources(); + + LoaderManager.enableDebugLogging(false); + getLoaderManager().initLoader(CURSORLOADER_THUMBS, null, this); + getLoaderManager().initLoader(CURSORLOADER_REAL, null, this); + setupHeader(); + updateAcceptButton(); + progress = new ProgressDialog(this); + progress.setTitle(resources.getString(R.string.processing_images_header)); + progress.setMessage(resources.getString(R.string.processing_images_message)); + } + + @Override + public void onItemClick(AdapterView arg0, View view, int position, long id) { + String name = getImageName(position); + int rotation = getImageRotation(position); + + if (name == null) { + return; + } + boolean isChecked = !isChecked(position); + if (maxImages == 0 && isChecked) { + isChecked = false; + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle(resources.getString(R.string.maximum_selection_count_error_header)); + builder.setMessage(String.format(resources.getString(R.string.maximum_selection_count_error_message), maxImageCount)); + builder.setPositiveButton("OK", new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + dialog.cancel(); + } + }); + AlertDialog alert = builder.create(); + alert.show(); + } else if (isChecked) { + fileNames.put(name, new Integer(rotation)); + if (maxImageCount == 1) { + this.selectClicked(null); + } else { + maxImages--; + ImageView imageView = (ImageView)view; + if (android.os.Build.VERSION.SDK_INT>=16) { + imageView.setImageAlpha(128); + } else { + imageView.setAlpha(128); + } + view.setBackgroundColor(selectedColor); + } + } else { + fileNames.remove(name); + maxImages++; + ImageView imageView = (ImageView)view; + if (android.os.Build.VERSION.SDK_INT>=16) { + imageView.setImageAlpha(255); + } else { + imageView.setAlpha(255); + } + view.setBackgroundColor(Color.TRANSPARENT); + } + + checkStatus.put(position, isChecked); + updateAcceptButton(); + } + + @Override + public Loader onCreateLoader(int cursorID, Bundle arg1) { + CursorLoader cl = null; + + ArrayList img = new ArrayList(); + switch (cursorID) { + + case CURSORLOADER_THUMBS: + img.add(MediaStore.Images.Media._ID); + img.add(MediaStore.Images.Media.ORIENTATION); + break; + case CURSORLOADER_REAL: + img.add(MediaStore.Images.Thumbnails.DATA); + img.add(MediaStore.Images.Media.ORIENTATION); + break; + default: + break; + } + + cl = new CursorLoader(MultiImageChooserActivity.this, MediaStore.Images.Media.EXTERNAL_CONTENT_URI, + img.toArray(new String[img.size()]), null, null, "DATE_MODIFIED DESC"); + return cl; + } + + @Override + public void onLoadFinished(Loader loader, Cursor cursor) { + if (cursor == null) { + // NULL cursor. This usually means there's no image database yet.... + return; + } + + switch (loader.getId()) { + case CURSORLOADER_THUMBS: + imagecursor = cursor; + image_column_index = imagecursor.getColumnIndex(MediaStore.Images.Media._ID); + image_column_orientation = imagecursor.getColumnIndex(MediaStore.Images.Media.ORIENTATION); + ia.notifyDataSetChanged(); + break; + case CURSORLOADER_REAL: + actualimagecursor = cursor; + String[] columns = actualimagecursor.getColumnNames(); + actual_image_column_index = actualimagecursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); + orientation_column_index = actualimagecursor.getColumnIndexOrThrow(MediaStore.Images.Media.ORIENTATION); + break; + default: + break; + } + } + + @Override + public void onLoaderReset(Loader loader) { + if (loader.getId() == CURSORLOADER_THUMBS) { + imagecursor = null; + } else if (loader.getId() == CURSORLOADER_REAL) { + actualimagecursor = null; + } + } + + public void cancelClicked(View ignored) { + setResult(RESULT_CANCELED); + finish(); + } + + public void selectClicked(View ignored) { + ((TextView) getActionBar().getCustomView().findViewById(fakeR.getId("id", "actionbar_done_textview"))).setEnabled(false); + getActionBar().getCustomView().findViewById(fakeR.getId("id", "actionbar_done")).setEnabled(false); + progress.show(); + Intent data = new Intent(); + if (fileNames.isEmpty()) { + this.setResult(RESULT_CANCELED); + progress.dismiss(); + finish(); + } else { + new ResizeImagesTask().execute(fileNames.entrySet()); + } + } + + + /********************* + * Helper Methods + ********************/ + private void updateAcceptButton() { + ((TextView) getActionBar().getCustomView().findViewById(fakeR.getId("id", "actionbar_done_textview"))) + .setEnabled(fileNames.size() != 0); + getActionBar().getCustomView().findViewById(fakeR.getId("id", "actionbar_done")).setEnabled(fileNames.size() != 0); + } + + private void setupHeader() { + // From Roman Nkk's code + // https://plus.google.com/113735310430199015092/posts/R49wVvcDoEW + // Inflate a "Done/Discard" custom action bar view + /* + * Copyright 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + LayoutInflater inflater = (LayoutInflater) getActionBar().getThemedContext().getSystemService( + LAYOUT_INFLATER_SERVICE); + final View customActionBarView = inflater.inflate(fakeR.getId("layout", "actionbar_custom_view_done_discard"), null); + customActionBarView.findViewById(fakeR.getId("id", "actionbar_done")).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + // "Done" + selectClicked(null); + } + }); + customActionBarView.findViewById(fakeR.getId("id", "actionbar_discard")).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + finish(); + } + }); + + // Show the custom action bar view and hide the normal Home icon and title. + final ActionBar actionBar = getActionBar(); + actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM, ActionBar.DISPLAY_SHOW_CUSTOM + | ActionBar.DISPLAY_SHOW_HOME | ActionBar.DISPLAY_SHOW_TITLE); + actionBar.setCustomView(customActionBarView, new ActionBar.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT)); + } + + private String getImageName(int position) { + actualimagecursor.moveToPosition(position); + String name = null; + + try { + name = actualimagecursor.getString(actual_image_column_index); + } catch (Exception e) { + return null; + } + return name; + } + + private int getImageRotation(int position) { + actualimagecursor.moveToPosition(position); + int rotation = 0; + + try { + rotation = actualimagecursor.getInt(orientation_column_index); + } catch (Exception e) { + return rotation; + } + return rotation; + } + + public boolean isChecked(int position) { + boolean ret = checkStatus.get(position); + return ret; + } + + + /********************* + * Nested Classes + ********************/ + private class SquareImageView extends ImageView { + public SquareImageView(Context context) { + super(context); } - return true; - } - - public void onActivityResult(int requestCode, int resultCode, Intent data) { - if (resultCode == Activity.RESULT_OK && data != null) { - ArrayList fileNames = data.getStringArrayListExtra("MULTIPLEFILENAMES"); - JSONArray res = new JSONArray(fileNames); - this.callbackContext.success(res); - } else if (resultCode == Activity.RESULT_CANCELED && data != null) { - String error = data.getStringExtra("ERRORMESSAGE"); - this.callbackContext.error(error); - } else if (resultCode == Activity.RESULT_CANCELED) { - JSONArray res = new JSONArray(); - this.callbackContext.success(res); - } else { - this.callbackContext.error("No images selected"); - } - } -} \ No newline at end of file + + @Override + public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, widthMeasureSpec); + } + } + + + private class ImageAdapter extends BaseAdapter { + private final Bitmap mPlaceHolderBitmap; + + public ImageAdapter(Context c) { + Bitmap tmpHolderBitmap = BitmapFactory.decodeResource(getResources(), fakeR.getId("drawable", "loading_icon")); + mPlaceHolderBitmap = Bitmap.createScaledBitmap(tmpHolderBitmap, colWidth, colWidth, false); + if (tmpHolderBitmap != mPlaceHolderBitmap) { + tmpHolderBitmap.recycle(); + tmpHolderBitmap = null; + } + } + + public int getCount() { + if (imagecursor != null) { + return imagecursor.getCount(); + } else { + return 0; + } + } + + public Object getItem(int position) { + return position; + } + + public long getItemId(int position) { + return position; + } + + // create a new ImageView for each item referenced by the Adapter + public View getView(int pos, View convertView, ViewGroup parent) { + + if (convertView == null) { + ImageView temp = new SquareImageView(MultiImageChooserActivity.this); + temp.setScaleType(ImageView.ScaleType.CENTER_CROP); + convertView = (View)temp; + } + + ImageView imageView = (ImageView)convertView; + imageView.setImageBitmap(null); + + final int position = pos; + + if (!imagecursor.moveToPosition(position)) { + return imageView; + } + + if (image_column_index == -1) { + return imageView; + } + + final int id = imagecursor.getInt(image_column_index); + final int rotate = imagecursor.getInt(image_column_orientation); + if (isChecked(pos)) { + if (android.os.Build.VERSION.SDK_INT>=16) { + imageView.setImageAlpha(128); + } else { + imageView.setAlpha(128); + } + imageView.setBackgroundColor(selectedColor); + } else { + if (android.os.Build.VERSION.SDK_INT>=16) { + imageView.setImageAlpha(255); + } else { + imageView.setAlpha(255); + } + imageView.setBackgroundColor(Color.TRANSPARENT); + } + if (shouldRequestThumb) { + fetcher.fetch(Integer.valueOf(id), imageView, colWidth, rotate); + } + + return imageView; + } + } + + + private class ResizeImagesTask extends AsyncTask>, Void, ArrayList> { + private Exception asyncTaskError = null; + + @Override + protected ArrayList doInBackground(Set>... fileSets) { + Set> fileNames = fileSets[0]; + ArrayList al = new ArrayList(); + try { + Iterator> i = fileNames.iterator(); + Bitmap bmp; + while(i.hasNext()) { + Entry imageInfo = i.next(); + File file = new File(imageInfo.getKey()); + int rotate = imageInfo.getValue().intValue(); + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inSampleSize = 1; + options.inJustDecodeBounds = true; + BitmapFactory.decodeFile(file.getAbsolutePath(), options); + int width = options.outWidth; + int height = options.outHeight; + float scale = calculateScale(width, height); + if (scale < 1) { + int finalWidth = (int)(width * scale); + int finalHeight = (int)(height * scale); + int inSampleSize = calculateInSampleSize(options, finalWidth, finalHeight); + options = new BitmapFactory.Options(); + options.inSampleSize = inSampleSize; + try { + bmp = this.tryToGetBitmap(file, options, rotate, true); + } catch (OutOfMemoryError e) { + options.inSampleSize = calculateNextSampleSize(options.inSampleSize); + try { + bmp = this.tryToGetBitmap(file, options, rotate, false); + } catch (OutOfMemoryError e2) { + throw new IOException("Unable to load image into memory."); + } + } + } else { + try { + bmp = this.tryToGetBitmap(file, null, rotate, false); + } catch(OutOfMemoryError e) { + options = new BitmapFactory.Options(); + options.inSampleSize = 2; + try { + bmp = this.tryToGetBitmap(file, options, rotate, false); + } catch(OutOfMemoryError e2) { + options = new BitmapFactory.Options(); + options.inSampleSize = 4; + try { + bmp = this.tryToGetBitmap(file, options, rotate, false); + } catch (OutOfMemoryError e3) { + throw new IOException("Unable to load image into memory."); + } + } + } + } + + file = this.storeImage(bmp, file.getName()); + al.add(Uri.fromFile(file).toString()); + } + return al; + } catch(IOException e) { + try { + asyncTaskError = e; + for (int i = 0; i < al.size(); i++) { + URI uri = new URI(al.get(i)); + File file = new File(uri); + file.delete(); + } + } catch(Exception exception) { + // the finally does what we want to do + } finally { + return new ArrayList(); + } + } + } + + @Override + protected void onPostExecute(ArrayList al) { + Intent data = new Intent(); + + if (asyncTaskError != null) { + Bundle res = new Bundle(); + res.putString("ERRORMESSAGE", asyncTaskError.getMessage()); + data.putExtras(res); + setResult(RESULT_CANCELED, data); + } else if (al.size() > 0) { + Bundle res = new Bundle(); + res.putStringArrayList("MULTIPLEFILENAMES", al); + if (imagecursor != null) { + res.putInt("TOTALFILES", imagecursor.getCount()); + } + data.putExtras(res); + setResult(RESULT_OK, data); + } else { + setResult(RESULT_CANCELED, data); + } + + progress.dismiss(); + finish(); + } + + private Bitmap tryToGetBitmap(File file, BitmapFactory.Options options, int rotate, boolean shouldScale) throws IOException, OutOfMemoryError { + Bitmap bmp; + if (options == null) { + bmp = BitmapFactory.decodeFile(file.getAbsolutePath()); + } else { + bmp = BitmapFactory.decodeFile(file.getAbsolutePath(), options); + } + if (bmp == null) { + throw new IOException("The image file could not be opened."); + } + if (options != null && shouldScale) { + float scale = calculateScale(options.outWidth, options.outHeight); + bmp = this.getResizedBitmap(bmp, scale); + } + if (rotate != 0) { + Matrix matrix = new Matrix(); + matrix.setRotate(rotate); + bmp = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(), matrix, true); + } + return bmp; + } + + /* + * The following functions are originally from + * https://github.com/raananw/PhoneGap-Image-Resizer + * + * They have been modified by Andrew Stephan for Sync OnSet + * + * The software is open source, MIT Licensed. + * Copyright (C) 2012, webXells GmbH All Rights Reserved. + */ + private File storeImage(Bitmap bmp, String fileName) throws IOException { + int index = fileName.lastIndexOf('.'); + String name = fileName.substring(0, index); + String ext = fileName.substring(index); + File file = File.createTempFile("tmp_" + name, ext); + OutputStream outStream = new FileOutputStream(file); + if (ext.compareToIgnoreCase(".png") == 0) { + bmp.compress(Bitmap.CompressFormat.PNG, quality, outStream); + } else { + bmp.compress(Bitmap.CompressFormat.JPEG, quality, outStream); + } + outStream.flush(); + outStream.close(); + return file; + } + + private Bitmap getResizedBitmap(Bitmap bm, float factor) { + int width = bm.getWidth(); + int height = bm.getHeight(); + // create a matrix for the manipulation + Matrix matrix = new Matrix(); + // resize the bit map + matrix.postScale(factor, factor); + // recreate the new Bitmap + Bitmap resizedBitmap = Bitmap.createBitmap(bm, 0, 0, width, height, matrix, false); + return resizedBitmap; + } + } + + private int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { + // Raw height and width of image + final int height = options.outHeight; + final int width = options.outWidth; + int inSampleSize = 1; + + if (height > reqHeight || width > reqWidth) { + final int halfHeight = height / 2; + final int halfWidth = width / 2; + + // Calculate the largest inSampleSize value that is a power of 2 and keeps both + // height and width larger than the requested height and width. + while ((halfHeight / inSampleSize) > reqHeight && (halfWidth / inSampleSize) > reqWidth) { + inSampleSize *= 2; + } + } + + return inSampleSize; + } + + private int calculateNextSampleSize(int sampleSize) { + double logBaseTwo = (int)(Math.log(sampleSize) / Math.log(2)); + return (int)Math.pow(logBaseTwo + 1, 2); + } + + private float calculateScale(int width, int height) { + float widthScale = 1.0f; + float heightScale = 1.0f; + float scale = 1.0f; + if (desiredWidth > 0 || desiredHeight > 0) { + if (desiredHeight == 0 && desiredWidth < width) { + scale = (float)desiredWidth/width; + } else if (desiredWidth == 0 && desiredHeight < height) { + scale = (float)desiredHeight/height; + } else { + if (desiredWidth > 0 && desiredWidth < width) { + widthScale = (float)desiredWidth/width; + } + if (desiredHeight > 0 && desiredHeight < height) { + heightScale = (float)desiredHeight/height; + } + if (widthScale < heightScale) { + scale = widthScale; + } else { + scale = heightScale; + } + } + } + + return scale; + } +} From 440ad7c694c07f925efae7f160e48b50aa43c97e Mon Sep 17 00:00:00 2001 From: D4rthR4tz3 Date: Fri, 22 Apr 2016 15:03:37 +0200 Subject: [PATCH 02/10] Update multiimagechooser_strings_de.xml --- .../res/values-de/multiimagechooser_strings_de.xml | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/android/Library/res/values-de/multiimagechooser_strings_de.xml b/src/android/Library/res/values-de/multiimagechooser_strings_de.xml index 2566b2f..0c808d2 100644 --- a/src/android/Library/res/values-de/multiimagechooser_strings_de.xml +++ b/src/android/Library/res/values-de/multiimagechooser_strings_de.xml @@ -1,9 +1,13 @@ MultiImageChooser - Free version - Images left: %d - There was an error opening the images database. Please report the problem. - Requesting thumbnails, please be patient - Cancel + Kostenlose Version - Sie können noch %d Bilder wählen + Beim Öffnen der Bilder-Datenbank kam es zu einem Fehler. + Lade Vorschaubilder, bitte warten + Verarbeite Bildauswahl + Dies kann einen kurzen Augenblick dauern. + Auswahllimit erreicht + Sie können maximal %d Bilder auf einmal auswählen. + Abbrechen OK From be2a40518a2ed7f04e1056a8586663fe99e894ac Mon Sep 17 00:00:00 2001 From: D4rthR4tz3 Date: Fri, 22 Apr 2016 15:03:57 +0200 Subject: [PATCH 03/10] Update multiimagechooser_strings_en.xml --- .../Library/res/values/multiimagechooser_strings_en.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/android/Library/res/values/multiimagechooser_strings_en.xml b/src/android/Library/res/values/multiimagechooser_strings_en.xml index db4107b..6776c9b 100644 --- a/src/android/Library/res/values/multiimagechooser_strings_en.xml +++ b/src/android/Library/res/values/multiimagechooser_strings_en.xml @@ -4,6 +4,10 @@ Free version - Images left: %d There was an error opening the images database. Please report the problem. Requesting thumbnails, please be patient + Processing Images + This may take a few moments + Limit reached + You can only select %d photos at once. Cancel OK From 22f843bdac4f430feb7a49ab418e93256f314d9f Mon Sep 17 00:00:00 2001 From: D4rthR4tz3 Date: Fri, 22 Apr 2016 15:04:18 +0200 Subject: [PATCH 04/10] Update multiimagechooser_strings_es.xml --- .../Library/res/values-es/multiimagechooser_strings_es.xml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/android/Library/res/values-es/multiimagechooser_strings_es.xml b/src/android/Library/res/values-es/multiimagechooser_strings_es.xml index fee94e8..0a2b6e3 100644 --- a/src/android/Library/res/values-es/multiimagechooser_strings_es.xml +++ b/src/android/Library/res/values-es/multiimagechooser_strings_es.xml @@ -4,6 +4,10 @@ Solicitando miniaturas. Por favor, espere… Versión gratuita - Imágenes restantes: %d Error al abrir la base de datos de imágenes. + Processing Images + This may take a few moments + Limit reached + You can only select %d photos at once. Cancelar OK - \ No newline at end of file + From 185bb35b268204a8a54e98dc7fc9377c2d4c4e58 Mon Sep 17 00:00:00 2001 From: D4rthR4tz3 Date: Fri, 22 Apr 2016 15:04:32 +0200 Subject: [PATCH 05/10] Update multiimagechooser_strings_fr.xml --- .../Library/res/values-fr/multiimagechooser_strings_fr.xml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/android/Library/res/values-fr/multiimagechooser_strings_fr.xml b/src/android/Library/res/values-fr/multiimagechooser_strings_fr.xml index e951b1a..8602994 100644 --- a/src/android/Library/res/values-fr/multiimagechooser_strings_fr.xml +++ b/src/android/Library/res/values-fr/multiimagechooser_strings_fr.xml @@ -3,6 +3,10 @@ Version gratuite - Images restantes:%d" "Il y eu une erreur avec les images. Veuillez nous signaler le problème." Récupération des vignettes, soyez patient + Processing Images + This may take a few moments + Limit reached + You can only select %d photos at once. Annuler OK - \ No newline at end of file + From d7333b5ada4e27eb6426e3a543bea5d98e32bf4e Mon Sep 17 00:00:00 2001 From: D4rthR4tz3 Date: Fri, 22 Apr 2016 15:04:44 +0200 Subject: [PATCH 06/10] Update multiimagechooser_strings_hu.xml --- .../Library/res/values-hu/multiimagechooser_strings_hu.xml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/android/Library/res/values-hu/multiimagechooser_strings_hu.xml b/src/android/Library/res/values-hu/multiimagechooser_strings_hu.xml index 82fb469..0fefc17 100644 --- a/src/android/Library/res/values-hu/multiimagechooser_strings_hu.xml +++ b/src/android/Library/res/values-hu/multiimagechooser_strings_hu.xml @@ -4,6 +4,10 @@ Ingyenes verzió - hátralévő képek: %d Képadatbázis megnyitási hiba történt. Kérjük, jelentse a problémát. Miniatűrök lekérése, kérjük legyen türelemmel + Processing Images + This may take a few moments + Limit reached + You can only select %d photos at once. Cancel OK - \ No newline at end of file + From 76de9ca223af21b847be0519af8708b8240d8a51 Mon Sep 17 00:00:00 2001 From: D4rthR4tz3 Date: Fri, 22 Apr 2016 15:05:02 +0200 Subject: [PATCH 07/10] Update multiimagechooser_strings_ja.xml --- .../Library/res/values-ja/multiimagechooser_strings_ja.xml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/android/Library/res/values-ja/multiimagechooser_strings_ja.xml b/src/android/Library/res/values-ja/multiimagechooser_strings_ja.xml index 7925737..c96dc1c 100644 --- a/src/android/Library/res/values-ja/multiimagechooser_strings_ja.xml +++ b/src/android/Library/res/values-ja/multiimagechooser_strings_ja.xml @@ -4,6 +4,10 @@ 無料版 - 残りの画像: %d 画像データベースを開く際にエラーがありました。問題を報告してください。 サムネイルをリクエスト中です。お待ちください。 - Cancel + Processing Images + This may take a few moments + Limit reached + You can only select %d photos at once. + Cancel OK From 0358d94f035795f303bf7f5b838ace32a8de1a4a Mon Sep 17 00:00:00 2001 From: D4rthR4tz3 Date: Fri, 22 Apr 2016 15:05:11 +0200 Subject: [PATCH 08/10] Update multiimagechooser_strings_ja.xml From d6609ac5a09b76cf8dfdf180c064ddf495ff7a69 Mon Sep 17 00:00:00 2001 From: D4rthR4tz3 Date: Fri, 22 Apr 2016 15:05:24 +0200 Subject: [PATCH 09/10] Update multiimagechooser_strings_ko.xml --- .../Library/res/values-ko/multiimagechooser_strings_ko.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/android/Library/res/values-ko/multiimagechooser_strings_ko.xml b/src/android/Library/res/values-ko/multiimagechooser_strings_ko.xml index 62636cc..d08b41e 100644 --- a/src/android/Library/res/values-ko/multiimagechooser_strings_ko.xml +++ b/src/android/Library/res/values-ko/multiimagechooser_strings_ko.xml @@ -4,6 +4,10 @@ 무료 버전 - 남은 이미지: %d 이미지 데이터베이스를 여는 데 오류가 발생했습니다. 문제를 보고하세요. 썸네일 요청 중. 기다려주세요 + Processing Images + This may take a few moments + Limit reached + You can only select %d photos at once. Cancel OK From 5eb55a58f7e37691cfe04c214b69d3fe4a6f2915 Mon Sep 17 00:00:00 2001 From: D4rthR4tz3 Date: Fri, 22 Apr 2016 15:19:56 +0200 Subject: [PATCH 10/10] Update ImagePicker.java --- .../synconset/ImagePicker/ImagePicker.java | 755 ++---------------- 1 file changed, 61 insertions(+), 694 deletions(-) diff --git a/src/android/com/synconset/ImagePicker/ImagePicker.java b/src/android/com/synconset/ImagePicker/ImagePicker.java index ec3822e..a8be003 100644 --- a/src/android/com/synconset/ImagePicker/ImagePicker.java +++ b/src/android/com/synconset/ImagePicker/ImagePicker.java @@ -1,705 +1,72 @@ -/* - * Copyright (c) 2012, David Erosa - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDIN G NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE - * - * Code modified by Andrew Stephan for Sync OnSet - * +/** + * An Image Picker Plugin for Cordova/PhoneGap. */ - package com.synconset; -import java.net.URI; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStream; +import org.apache.cordova.CallbackContext; +import org.apache.cordova.CordovaPlugin; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; -import com.synconset.FakeR; import android.app.Activity; -import android.app.ActionBar; -import android.app.AlertDialog; -import android.app.LoaderManager; -import android.app.ProgressDialog; -import android.content.Context; -import android.content.CursorLoader; -import android.content.DialogInterface; import android.content.Intent; -import android.content.Loader; -import android.content.res.Resources; -import android.database.Cursor; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.Color; -import android.graphics.Matrix; -import android.net.Uri; -import android.os.AsyncTask; -import android.os.Bundle; -import android.provider.MediaStore; import android.util.Log; -import android.util.SparseBooleanArray; -import android.view.Display; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.AbsListView; -import android.widget.AbsListView.OnScrollListener; -import android.widget.AdapterView; -import android.widget.AdapterView.OnItemClickListener; -import android.widget.BaseAdapter; -import android.widget.GridView; -import android.widget.ImageView; -import android.widget.TextView; -import org.chromium.ui.resources.Resource; - -import de.awenko.mobile.R; - -public class MultiImageChooserActivity extends Activity implements OnItemClickListener, - LoaderManager.LoaderCallbacks { - private static final String TAG = "ImagePicker"; - - public static final int NOLIMIT = -1; - public static final String MAX_IMAGES_KEY = "MAX_IMAGES"; - public static final String WIDTH_KEY = "WIDTH"; - public static final String HEIGHT_KEY = "HEIGHT"; - public static final String QUALITY_KEY = "QUALITY"; - - private ImageAdapter ia; - - private Cursor imagecursor, actualimagecursor; - private int image_column_index, image_column_orientation, actual_image_column_index, orientation_column_index; - private int colWidth; - - private static final int CURSORLOADER_THUMBS = 0; - private static final int CURSORLOADER_REAL = 1; - - private Map fileNames = new HashMap(); - - private SparseBooleanArray checkStatus = new SparseBooleanArray(); - - private int maxImages; - private int maxImageCount; - - private int desiredWidth; - private int desiredHeight; - private int quality; - - private GridView gridView; - - private final ImageFetcher fetcher = new ImageFetcher(); - - private int selectedColor = 0xff32b2e1; - private boolean shouldRequestThumb = true; - - private FakeR fakeR; - - private ProgressDialog progress; - - private Resources resources; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - fakeR = new FakeR(this); - setContentView(fakeR.getId("layout", "multiselectorgrid")); - fileNames.clear(); - - maxImages = getIntent().getIntExtra(MAX_IMAGES_KEY, NOLIMIT); - desiredWidth = getIntent().getIntExtra(WIDTH_KEY, 0); - desiredHeight = getIntent().getIntExtra(HEIGHT_KEY, 0); - quality = getIntent().getIntExtra(QUALITY_KEY, 0); - maxImageCount = maxImages; - - Display display = getWindowManager().getDefaultDisplay(); - int width = display.getWidth(); - - colWidth = width / 4; - - gridView = (GridView) findViewById(fakeR.getId("id", "gridview")); - gridView.setOnItemClickListener(this); - gridView.setOnScrollListener(new OnScrollListener() { - private int lastFirstItem = 0; - private long timestamp = System.currentTimeMillis(); - - @Override - public void onScrollStateChanged(AbsListView view, int scrollState) { - if (scrollState == SCROLL_STATE_IDLE) { - shouldRequestThumb = true; - ia.notifyDataSetChanged(); - } - } - - @Override - public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { - float dt = System.currentTimeMillis() - timestamp; - if (firstVisibleItem != lastFirstItem) { - double speed = 1 / dt * 1000; - lastFirstItem = firstVisibleItem; - timestamp = System.currentTimeMillis(); - - // Limit if we go faster than a page a second - shouldRequestThumb = speed < visibleItemCount; - } - } - }); - - ia = new ImageAdapter(this); - gridView.setAdapter(ia); - - resources = getResources(); - - LoaderManager.enableDebugLogging(false); - getLoaderManager().initLoader(CURSORLOADER_THUMBS, null, this); - getLoaderManager().initLoader(CURSORLOADER_REAL, null, this); - setupHeader(); - updateAcceptButton(); - progress = new ProgressDialog(this); - progress.setTitle(resources.getString(R.string.processing_images_header)); - progress.setMessage(resources.getString(R.string.processing_images_message)); - } - - @Override - public void onItemClick(AdapterView arg0, View view, int position, long id) { - String name = getImageName(position); - int rotation = getImageRotation(position); - - if (name == null) { - return; - } - boolean isChecked = !isChecked(position); - if (maxImages == 0 && isChecked) { - isChecked = false; - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setTitle(resources.getString(R.string.maximum_selection_count_error_header)); - builder.setMessage(String.format(resources.getString(R.string.maximum_selection_count_error_message), maxImageCount)); - builder.setPositiveButton("OK", new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - dialog.cancel(); - } - }); - AlertDialog alert = builder.create(); - alert.show(); - } else if (isChecked) { - fileNames.put(name, new Integer(rotation)); - if (maxImageCount == 1) { - this.selectClicked(null); - } else { - maxImages--; - ImageView imageView = (ImageView)view; - if (android.os.Build.VERSION.SDK_INT>=16) { - imageView.setImageAlpha(128); - } else { - imageView.setAlpha(128); - } - view.setBackgroundColor(selectedColor); - } - } else { - fileNames.remove(name); - maxImages++; - ImageView imageView = (ImageView)view; - if (android.os.Build.VERSION.SDK_INT>=16) { - imageView.setImageAlpha(255); - } else { - imageView.setAlpha(255); - } - view.setBackgroundColor(Color.TRANSPARENT); - } - - checkStatus.put(position, isChecked); - updateAcceptButton(); - } - - @Override - public Loader onCreateLoader(int cursorID, Bundle arg1) { - CursorLoader cl = null; - - ArrayList img = new ArrayList(); - switch (cursorID) { - - case CURSORLOADER_THUMBS: - img.add(MediaStore.Images.Media._ID); - img.add(MediaStore.Images.Media.ORIENTATION); - break; - case CURSORLOADER_REAL: - img.add(MediaStore.Images.Thumbnails.DATA); - img.add(MediaStore.Images.Media.ORIENTATION); - break; - default: - break; - } - - cl = new CursorLoader(MultiImageChooserActivity.this, MediaStore.Images.Media.EXTERNAL_CONTENT_URI, - img.toArray(new String[img.size()]), null, null, "DATE_MODIFIED DESC"); - return cl; - } - - @Override - public void onLoadFinished(Loader loader, Cursor cursor) { - if (cursor == null) { - // NULL cursor. This usually means there's no image database yet.... - return; - } - - switch (loader.getId()) { - case CURSORLOADER_THUMBS: - imagecursor = cursor; - image_column_index = imagecursor.getColumnIndex(MediaStore.Images.Media._ID); - image_column_orientation = imagecursor.getColumnIndex(MediaStore.Images.Media.ORIENTATION); - ia.notifyDataSetChanged(); - break; - case CURSORLOADER_REAL: - actualimagecursor = cursor; - String[] columns = actualimagecursor.getColumnNames(); - actual_image_column_index = actualimagecursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); - orientation_column_index = actualimagecursor.getColumnIndexOrThrow(MediaStore.Images.Media.ORIENTATION); - break; - default: - break; - } - } - - @Override - public void onLoaderReset(Loader loader) { - if (loader.getId() == CURSORLOADER_THUMBS) { - imagecursor = null; - } else if (loader.getId() == CURSORLOADER_REAL) { - actualimagecursor = null; - } - } - - public void cancelClicked(View ignored) { - setResult(RESULT_CANCELED); - finish(); - } - - public void selectClicked(View ignored) { - ((TextView) getActionBar().getCustomView().findViewById(fakeR.getId("id", "actionbar_done_textview"))).setEnabled(false); - getActionBar().getCustomView().findViewById(fakeR.getId("id", "actionbar_done")).setEnabled(false); - progress.show(); - Intent data = new Intent(); - if (fileNames.isEmpty()) { - this.setResult(RESULT_CANCELED); - progress.dismiss(); - finish(); - } else { - new ResizeImagesTask().execute(fileNames.entrySet()); - } - } - - - /********************* - * Helper Methods - ********************/ - private void updateAcceptButton() { - ((TextView) getActionBar().getCustomView().findViewById(fakeR.getId("id", "actionbar_done_textview"))) - .setEnabled(fileNames.size() != 0); - getActionBar().getCustomView().findViewById(fakeR.getId("id", "actionbar_done")).setEnabled(fileNames.size() != 0); - } - - private void setupHeader() { - // From Roman Nkk's code - // https://plus.google.com/113735310430199015092/posts/R49wVvcDoEW - // Inflate a "Done/Discard" custom action bar view - /* - * Copyright 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - LayoutInflater inflater = (LayoutInflater) getActionBar().getThemedContext().getSystemService( - LAYOUT_INFLATER_SERVICE); - final View customActionBarView = inflater.inflate(fakeR.getId("layout", "actionbar_custom_view_done_discard"), null); - customActionBarView.findViewById(fakeR.getId("id", "actionbar_done")).setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - // "Done" - selectClicked(null); - } - }); - customActionBarView.findViewById(fakeR.getId("id", "actionbar_discard")).setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - finish(); - } - }); - - // Show the custom action bar view and hide the normal Home icon and title. - final ActionBar actionBar = getActionBar(); - actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM, ActionBar.DISPLAY_SHOW_CUSTOM - | ActionBar.DISPLAY_SHOW_HOME | ActionBar.DISPLAY_SHOW_TITLE); - actionBar.setCustomView(customActionBarView, new ActionBar.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.MATCH_PARENT)); - } - - private String getImageName(int position) { - actualimagecursor.moveToPosition(position); - String name = null; - - try { - name = actualimagecursor.getString(actual_image_column_index); - } catch (Exception e) { - return null; - } - return name; - } - - private int getImageRotation(int position) { - actualimagecursor.moveToPosition(position); - int rotation = 0; - - try { - rotation = actualimagecursor.getInt(orientation_column_index); - } catch (Exception e) { - return rotation; - } - return rotation; - } - - public boolean isChecked(int position) { - boolean ret = checkStatus.get(position); - return ret; - } - - - /********************* - * Nested Classes - ********************/ - private class SquareImageView extends ImageView { - public SquareImageView(Context context) { - super(context); +public class ImagePicker extends CordovaPlugin { + public static String TAG = "ImagePicker"; + + private CallbackContext callbackContext; + private JSONObject params; + + public boolean execute(String action, final JSONArray args, final CallbackContext callbackContext) throws JSONException { + this.callbackContext = callbackContext; + this.params = args.getJSONObject(0); + if (action.equals("getPictures")) { + Intent intent = new Intent(cordova.getActivity(), MultiImageChooserActivity.class); + int max = 20; + int desiredWidth = 0; + int desiredHeight = 0; + int quality = 100; + if (this.params.has("maximumImagesCount")) { + max = this.params.getInt("maximumImagesCount"); + } + if (this.params.has("width")) { + desiredWidth = this.params.getInt("width"); + } + if (this.params.has("height")) { + desiredWidth = this.params.getInt("height"); + } + if (this.params.has("quality")) { + quality = this.params.getInt("quality"); + } + intent.putExtra("MAX_IMAGES", max); + intent.putExtra("WIDTH", desiredWidth); + intent.putExtra("HEIGHT", desiredHeight); + intent.putExtra("QUALITY", quality); + if (this.cordova != null) { + this.cordova.startActivityForResult((CordovaPlugin) this, intent, 0); + } } - - @Override - public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, widthMeasureSpec); - } - } - - - private class ImageAdapter extends BaseAdapter { - private final Bitmap mPlaceHolderBitmap; - - public ImageAdapter(Context c) { - Bitmap tmpHolderBitmap = BitmapFactory.decodeResource(getResources(), fakeR.getId("drawable", "loading_icon")); - mPlaceHolderBitmap = Bitmap.createScaledBitmap(tmpHolderBitmap, colWidth, colWidth, false); - if (tmpHolderBitmap != mPlaceHolderBitmap) { - tmpHolderBitmap.recycle(); - tmpHolderBitmap = null; - } - } - - public int getCount() { - if (imagecursor != null) { - return imagecursor.getCount(); - } else { - return 0; - } - } - - public Object getItem(int position) { - return position; - } - - public long getItemId(int position) { - return position; - } - - // create a new ImageView for each item referenced by the Adapter - public View getView(int pos, View convertView, ViewGroup parent) { - - if (convertView == null) { - ImageView temp = new SquareImageView(MultiImageChooserActivity.this); - temp.setScaleType(ImageView.ScaleType.CENTER_CROP); - convertView = (View)temp; - } - - ImageView imageView = (ImageView)convertView; - imageView.setImageBitmap(null); - - final int position = pos; - - if (!imagecursor.moveToPosition(position)) { - return imageView; - } - - if (image_column_index == -1) { - return imageView; - } - - final int id = imagecursor.getInt(image_column_index); - final int rotate = imagecursor.getInt(image_column_orientation); - if (isChecked(pos)) { - if (android.os.Build.VERSION.SDK_INT>=16) { - imageView.setImageAlpha(128); - } else { - imageView.setAlpha(128); - } - imageView.setBackgroundColor(selectedColor); - } else { - if (android.os.Build.VERSION.SDK_INT>=16) { - imageView.setImageAlpha(255); - } else { - imageView.setAlpha(255); - } - imageView.setBackgroundColor(Color.TRANSPARENT); - } - if (shouldRequestThumb) { - fetcher.fetch(Integer.valueOf(id), imageView, colWidth, rotate); - } - - return imageView; - } - } - - - private class ResizeImagesTask extends AsyncTask>, Void, ArrayList> { - private Exception asyncTaskError = null; - - @Override - protected ArrayList doInBackground(Set>... fileSets) { - Set> fileNames = fileSets[0]; - ArrayList al = new ArrayList(); - try { - Iterator> i = fileNames.iterator(); - Bitmap bmp; - while(i.hasNext()) { - Entry imageInfo = i.next(); - File file = new File(imageInfo.getKey()); - int rotate = imageInfo.getValue().intValue(); - BitmapFactory.Options options = new BitmapFactory.Options(); - options.inSampleSize = 1; - options.inJustDecodeBounds = true; - BitmapFactory.decodeFile(file.getAbsolutePath(), options); - int width = options.outWidth; - int height = options.outHeight; - float scale = calculateScale(width, height); - if (scale < 1) { - int finalWidth = (int)(width * scale); - int finalHeight = (int)(height * scale); - int inSampleSize = calculateInSampleSize(options, finalWidth, finalHeight); - options = new BitmapFactory.Options(); - options.inSampleSize = inSampleSize; - try { - bmp = this.tryToGetBitmap(file, options, rotate, true); - } catch (OutOfMemoryError e) { - options.inSampleSize = calculateNextSampleSize(options.inSampleSize); - try { - bmp = this.tryToGetBitmap(file, options, rotate, false); - } catch (OutOfMemoryError e2) { - throw new IOException("Unable to load image into memory."); - } - } - } else { - try { - bmp = this.tryToGetBitmap(file, null, rotate, false); - } catch(OutOfMemoryError e) { - options = new BitmapFactory.Options(); - options.inSampleSize = 2; - try { - bmp = this.tryToGetBitmap(file, options, rotate, false); - } catch(OutOfMemoryError e2) { - options = new BitmapFactory.Options(); - options.inSampleSize = 4; - try { - bmp = this.tryToGetBitmap(file, options, rotate, false); - } catch (OutOfMemoryError e3) { - throw new IOException("Unable to load image into memory."); - } - } - } - } - - file = this.storeImage(bmp, file.getName()); - al.add(Uri.fromFile(file).toString()); - } - return al; - } catch(IOException e) { - try { - asyncTaskError = e; - for (int i = 0; i < al.size(); i++) { - URI uri = new URI(al.get(i)); - File file = new File(uri); - file.delete(); - } - } catch(Exception exception) { - // the finally does what we want to do - } finally { - return new ArrayList(); - } - } - } - - @Override - protected void onPostExecute(ArrayList al) { - Intent data = new Intent(); - - if (asyncTaskError != null) { - Bundle res = new Bundle(); - res.putString("ERRORMESSAGE", asyncTaskError.getMessage()); - data.putExtras(res); - setResult(RESULT_CANCELED, data); - } else if (al.size() > 0) { - Bundle res = new Bundle(); - res.putStringArrayList("MULTIPLEFILENAMES", al); - if (imagecursor != null) { - res.putInt("TOTALFILES", imagecursor.getCount()); - } - data.putExtras(res); - setResult(RESULT_OK, data); - } else { - setResult(RESULT_CANCELED, data); - } - - progress.dismiss(); - finish(); - } - - private Bitmap tryToGetBitmap(File file, BitmapFactory.Options options, int rotate, boolean shouldScale) throws IOException, OutOfMemoryError { - Bitmap bmp; - if (options == null) { - bmp = BitmapFactory.decodeFile(file.getAbsolutePath()); - } else { - bmp = BitmapFactory.decodeFile(file.getAbsolutePath(), options); - } - if (bmp == null) { - throw new IOException("The image file could not be opened."); - } - if (options != null && shouldScale) { - float scale = calculateScale(options.outWidth, options.outHeight); - bmp = this.getResizedBitmap(bmp, scale); - } - if (rotate != 0) { - Matrix matrix = new Matrix(); - matrix.setRotate(rotate); - bmp = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(), matrix, true); - } - return bmp; - } - - /* - * The following functions are originally from - * https://github.com/raananw/PhoneGap-Image-Resizer - * - * They have been modified by Andrew Stephan for Sync OnSet - * - * The software is open source, MIT Licensed. - * Copyright (C) 2012, webXells GmbH All Rights Reserved. - */ - private File storeImage(Bitmap bmp, String fileName) throws IOException { - int index = fileName.lastIndexOf('.'); - String name = fileName.substring(0, index); - String ext = fileName.substring(index); - File file = File.createTempFile("tmp_" + name, ext); - OutputStream outStream = new FileOutputStream(file); - if (ext.compareToIgnoreCase(".png") == 0) { - bmp.compress(Bitmap.CompressFormat.PNG, quality, outStream); - } else { - bmp.compress(Bitmap.CompressFormat.JPEG, quality, outStream); - } - outStream.flush(); - outStream.close(); - return file; - } - - private Bitmap getResizedBitmap(Bitmap bm, float factor) { - int width = bm.getWidth(); - int height = bm.getHeight(); - // create a matrix for the manipulation - Matrix matrix = new Matrix(); - // resize the bit map - matrix.postScale(factor, factor); - // recreate the new Bitmap - Bitmap resizedBitmap = Bitmap.createBitmap(bm, 0, 0, width, height, matrix, false); - return resizedBitmap; - } - } - - private int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { - // Raw height and width of image - final int height = options.outHeight; - final int width = options.outWidth; - int inSampleSize = 1; - - if (height > reqHeight || width > reqWidth) { - final int halfHeight = height / 2; - final int halfWidth = width / 2; - - // Calculate the largest inSampleSize value that is a power of 2 and keeps both - // height and width larger than the requested height and width. - while ((halfHeight / inSampleSize) > reqHeight && (halfWidth / inSampleSize) > reqWidth) { - inSampleSize *= 2; - } - } - - return inSampleSize; - } - - private int calculateNextSampleSize(int sampleSize) { - double logBaseTwo = (int)(Math.log(sampleSize) / Math.log(2)); - return (int)Math.pow(logBaseTwo + 1, 2); - } - - private float calculateScale(int width, int height) { - float widthScale = 1.0f; - float heightScale = 1.0f; - float scale = 1.0f; - if (desiredWidth > 0 || desiredHeight > 0) { - if (desiredHeight == 0 && desiredWidth < width) { - scale = (float)desiredWidth/width; - } else if (desiredWidth == 0 && desiredHeight < height) { - scale = (float)desiredHeight/height; - } else { - if (desiredWidth > 0 && desiredWidth < width) { - widthScale = (float)desiredWidth/width; - } - if (desiredHeight > 0 && desiredHeight < height) { - heightScale = (float)desiredHeight/height; - } - if (widthScale < heightScale) { - scale = widthScale; - } else { - scale = heightScale; - } - } - } - - return scale; - } + return true; + } + + public void onActivityResult(int requestCode, int resultCode, Intent data) { + if (resultCode == Activity.RESULT_OK && data != null) { + ArrayList fileNames = data.getStringArrayListExtra("MULTIPLEFILENAMES"); + JSONArray res = new JSONArray(fileNames); + this.callbackContext.success(res); + } else if (resultCode == Activity.RESULT_CANCELED && data != null) { + String error = data.getStringExtra("ERRORMESSAGE"); + this.callbackContext.error(error); + } else if (resultCode == Activity.RESULT_CANCELED) { + JSONArray res = new JSONArray(); + this.callbackContext.success(res); + } else { + this.callbackContext.error("No images selected"); + } + } }