├── .gitignore ├── LICENSE ├── README.md ├── demo ├── config.xml └── www │ ├── css │ └── index.css │ ├── index.html │ └── js │ └── index.js ├── dev ├── android │ ├── .gitignore │ ├── GalleryPicker.iml │ ├── android.iml │ ├── app │ │ ├── .gitignore │ │ ├── app.iml │ │ ├── build.gradle │ │ ├── proguard-rules.pro │ │ └── src │ │ │ ├── androidTest │ │ │ └── java │ │ │ │ └── com │ │ │ │ └── subitolabs │ │ │ │ └── cordova │ │ │ │ └── galleryapi │ │ │ │ └── ApplicationTest.java │ │ │ └── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── java │ │ │ └── com │ │ │ │ └── subitolabs │ │ │ │ └── cordova │ │ │ │ └── galleryapi │ │ │ │ ├── GalleryAPI.java │ │ │ │ └── MainActivity.java │ │ │ └── res │ │ │ ├── drawable-hdpi │ │ │ └── ic_launcher.png │ │ │ ├── drawable-mdpi │ │ │ └── ic_launcher.png │ │ │ ├── drawable-xhdpi │ │ │ └── ic_launcher.png │ │ │ ├── drawable-xxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── layout │ │ │ └── activity_main.xml │ │ │ ├── menu │ │ │ └── menu_main.xml │ │ │ ├── values-w820dp │ │ │ └── dimens.xml │ │ │ └── values │ │ │ ├── dimens.xml │ │ │ ├── strings.xml │ │ │ └── styles.xml │ ├── build.gradle │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ └── gradle-wrapper.properties │ ├── gradlew │ ├── gradlew.bat │ └── settings.gradle └── ios │ └── GalleryAPI │ ├── NSObject_GalleryAPI.h │ ├── galleryapi.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ ├── xcshareddata │ │ │ └── galleryapi.xccheckout │ │ └── xcuserdata │ │ │ └── tom.xcuserdatad │ │ │ └── UserInterfaceState.xcuserstate │ └── xcuserdata │ │ └── tom.xcuserdatad │ │ ├── xcdebugger │ │ └── Breakpoints_v2.xcbkptlist │ │ └── xcschemes │ │ ├── galleryapi.xcscheme │ │ └── xcschememanagement.plist │ ├── galleryapi │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Base.lproj │ │ ├── LaunchScreen.xib │ │ └── Main.storyboard │ ├── GalleryAPI.h │ ├── GalleryAPI.m │ ├── Images.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── Info.plist │ ├── ViewController.h │ ├── ViewController.m │ └── main.m │ └── galleryapiTests │ ├── Info.plist │ └── galleryapiTests.m ├── plugin.xml ├── src ├── android │ └── GalleryAPI.java └── ios │ ├── GalleryAPI.h │ └── GalleryAPI.m └── www └── gallery-api.js /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .idea 3 | .gradle 4 | 5 | /demo/platforms 6 | /demo/plugins 7 | 8 | *.class 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | *.war 16 | *.ear 17 | 18 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 19 | hs_err_pid* 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Subito Labs 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # cordova-gallery-api 2 | 3 | This plugin defines a global `galleryAPI` object, which offer methods to query gallery albums and media: 4 | 5 | - getAlbums 6 | - getMedia 7 | 8 | ### Method `getAlbums` 9 | 10 | Returns an array of object `{"id" : ..., "title" : ...}`. 11 | 12 | ### Method `getMedia` 13 | 14 | Returns an array of object with the following fields: 15 | 16 | - id 17 | - title 18 | - lat 19 | - lon 20 | - thumbnail 21 | - data 22 | - width 23 | - height 24 | - size 25 | - date_create 26 | 27 | ### Installation 28 | 29 | cordova plugin add https://github.com/subitolabs/cordova-gallery-api.git 30 | 31 | ### Quick example 32 | 33 | ```js 34 | document.addEventListener('deviceready', function() 35 | { 36 | var $content = document.getElementById("content"); 37 | 38 | $content.innerHTML = "Loading albums ..."; 39 | 40 | galleryAPI.getAlbums(function(items) 41 | { 42 | var html = ""; 43 | 44 | for(var i = 0; i < items.length; i++) 45 | { 46 | var album = items[i]; 47 | 48 | html += '' + escape(album.title) + ''; 49 | } 50 | 51 | $content.innerHTML = html; 52 | 53 | }, function(error){alert(error);}); 54 | 55 | window.loadAlbum = function(albumName) 56 | { 57 | galleryAPI.getMedia(albumName, function(items) 58 | { 59 | var html = ""; 60 | 61 | for(var i = 0; i < items.length; i++) 62 | { 63 | var media = items[i]; 64 | 65 | html += ''; 66 | } 67 | 68 | $content.innerHTML = html; 69 | 70 | }, function(error){alert(error);}); 71 | }; 72 | 73 | }, false); 74 | ``` 75 | -------------------------------------------------------------------------------- /demo/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | GalleryAPIDemo 4 | 5 | A sample Apache Cordova application that responds to the deviceready event. 6 | 7 | 8 | Apache Cordova Team 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /demo/www/css/index.css: -------------------------------------------------------------------------------- 1 | * { 2 | -webkit-tap-highlight-color: rgba(0,0,0,0); /* make transparent link selection, adjust last value opacity 0 to 1.0 */ 3 | box-sizing: border-box; 4 | } 5 | 6 | body { 7 | -webkit-touch-callout: none; /* prevent callout to copy image, etc when tap to hold */ 8 | -webkit-text-size-adjust: none; /* prevent webkit from resizing text to fit */ 9 | -webkit-user-select: none; /* prevent copy paste, to allow, change 'none' to 'text' */ 10 | background-color:#E4E4E4; 11 | font-family:'HelveticaNeue-Light', 'HelveticaNeue', Helvetica, Arial, sans-serif; 12 | font-size:12px; 13 | height:100%; 14 | margin:0px; 15 | padding:0px; 16 | width:100%; 17 | } 18 | 19 | a.album 20 | { 21 | display: block; 22 | line-height: 100px; 23 | padding: 10px; 24 | border-bottom:1px solid #D2D2D2; 25 | } 26 | 27 | a.media 28 | { 29 | display: inline-block; 30 | width:50%; 31 | height:150px; 32 | text-align: center; 33 | vertical-align: middle; 34 | } 35 | 36 | a.media > img 37 | { 38 | margin:1%; 39 | width: 100%; 40 | height: 100%; 41 | object-fit: cover; 42 | } -------------------------------------------------------------------------------- /demo/www/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Hello World 11 | 12 | 13 |
14 | 15 |
16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /demo/www/js/index.js: -------------------------------------------------------------------------------- 1 | document.addEventListener('deviceready', function() 2 | { 3 | var $content = document.getElementById("content"); 4 | 5 | $content.innerHTML = "Loading albums ..."; 6 | 7 | galleryAPI.getAlbums(function(items) 8 | { 9 | var html = ""; 10 | 11 | for(var i = 0; i < items.length; i++) 12 | { 13 | var album = items[i]; 14 | 15 | html += '' + escape(album.title) + ''; 16 | } 17 | 18 | $content.innerHTML = html; 19 | 20 | }, function(error){alert(error);}); 21 | 22 | window.loadAlbum = function(albumName) 23 | { 24 | galleryAPI.getMedia(albumName, function(items) 25 | { 26 | var html = ""; 27 | 28 | for(var i = 0; i < items.length; i++) 29 | { 30 | var media = items[i]; 31 | 32 | html += ''; 33 | } 34 | 35 | $content.innerHTML = html; 36 | 37 | }, function(error){alert(error);}); 38 | }; 39 | 40 | function escape(v) 41 | { 42 | return v.replace(/[\u00A0-\u9999<>\&]/gim, function(i) { 43 | return '&#'+i.charCodeAt(0)+';'; 44 | }); 45 | } 46 | 47 | 48 | }, false); 49 | -------------------------------------------------------------------------------- /dev/android/.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | local.properties 3 | .idea/workspace.xml 4 | .idea/libraries 5 | .DS_Store 6 | build 7 | -------------------------------------------------------------------------------- /dev/android/GalleryPicker.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /dev/android/android.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /dev/android/app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /dev/android/app/app.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | 11 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /dev/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 21 5 | buildToolsVersion "21.1.2" 6 | 7 | defaultConfig { 8 | applicationId "com.subitolabs.android.cordova.gallerypicker" 9 | minSdkVersion 15 10 | targetSdkVersion 21 11 | versionCode 1 12 | versionName "1.0" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(dir: 'libs', include: ['*.jar']) 24 | compile 'com.android.support:appcompat-v7:21.0.3' 25 | compile files('libs/cordova-3.7.1.jar') 26 | } 27 | -------------------------------------------------------------------------------- /dev/android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/tom/dev/adt/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /dev/android/app/src/androidTest/java/com/subitolabs/cordova/galleryapi/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.subitolabs.cordova.galleryapi; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /dev/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 13 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /dev/android/app/src/main/java/com/subitolabs/cordova/galleryapi/GalleryAPI.java: -------------------------------------------------------------------------------- 1 | package com.subitolabs.cordova.galleryapi; 2 | 3 | 4 | import android.Manifest; 5 | import android.content.Context; 6 | import android.content.pm.PackageManager; 7 | import android.database.Cursor; 8 | import android.graphics.Bitmap; 9 | import android.graphics.BitmapFactory; 10 | import android.graphics.Matrix; 11 | import android.net.Uri; 12 | import android.os.Build; 13 | import android.provider.MediaStore; 14 | import android.support.annotation.NonNull; 15 | import android.support.v4.app.ActivityCompat; 16 | import android.support.v4.content.ContextCompat; 17 | import android.util.Log; 18 | import android.widget.Toast; 19 | 20 | import org.apache.cordova.*; 21 | import org.json.JSONArray; 22 | import org.json.JSONException; 23 | import org.json.JSONObject; 24 | 25 | import java.io.ByteArrayOutputStream; 26 | import java.io.File; 27 | import java.io.FileOutputStream; 28 | import java.io.IOException; 29 | import java.util.ArrayList; 30 | import java.util.Collections; 31 | import java.util.Iterator; 32 | import java.util.List; 33 | 34 | public class GalleryAPI extends CordovaPlugin { 35 | public static final String ACTION_CHECK_PERMISSION = "checkPermission"; 36 | public static final String ACTION_GET_MEDIA = "getMedia"; 37 | public static final String ACTION_GET_MEDIA_THUMBNAIL = "getMediaThumbnail"; 38 | public static final String ACTION_GET_HQ_IMAGE_DATA = "getHQImageData"; 39 | public static final String ACTION_GET_ALBUMS = "getAlbums"; 40 | public static final String DIR_NAME = ".mendr"; 41 | public static final String SUB_DIR_NAME = ".mendr_hq"; 42 | 43 | private static final int BASE_SIZE = 300; 44 | 45 | private static BitmapFactory.Options ops = null; 46 | 47 | private static final int STORAGE_PERMISSIONS_REQUEST = 1; 48 | 49 | private CallbackContext cbc = null; 50 | 51 | @Override 52 | public boolean execute(String action, final JSONArray args, final CallbackContext callbackContext) throws JSONException { 53 | try { 54 | if (ACTION_GET_MEDIA.equals(action)) { 55 | cordova.getThreadPool().execute(new Runnable() { 56 | public void run() { 57 | try { 58 | JSONObject object = (JSONObject) args.get(0); 59 | ArrayOfObjects albums = getMedia(object.getString("title")); 60 | callbackContext.success(new JSONArray(albums)); 61 | } catch (Exception e) { 62 | e.printStackTrace(); 63 | callbackContext.error(e.getMessage()); 64 | } 65 | } 66 | }); 67 | 68 | return true; 69 | } else if (ACTION_CHECK_PERMISSION.equals(action)) { 70 | cordova.getThreadPool().execute(new Runnable() { 71 | public void run() { 72 | cbc = callbackContext; 73 | checkPermission(); 74 | } 75 | }); 76 | return true; 77 | } else if (ACTION_GET_MEDIA_THUMBNAIL.equals(action)) { 78 | cordova.getThreadPool().execute(new Runnable() { 79 | public void run() { 80 | try { 81 | JSONObject media = getMediaThumbnail((JSONObject) args.get(0)); 82 | callbackContext.success(media); 83 | } catch (Exception e) { 84 | e.printStackTrace(); 85 | callbackContext.error(e.getMessage()); 86 | } 87 | } 88 | }); 89 | return true; 90 | } else if (ACTION_GET_HQ_IMAGE_DATA.equals(action)) { 91 | cordova.getThreadPool().execute(new Runnable() { 92 | public void run() { 93 | try { 94 | File imagePath = getHQImageData((JSONObject) args.get(0)); 95 | callbackContext.success(imagePath.toString()); 96 | } catch (Exception e) { 97 | e.printStackTrace(); 98 | callbackContext.error(e.getMessage()); 99 | } 100 | } 101 | }); 102 | return true; 103 | } else if (ACTION_GET_ALBUMS.equals(action)) { 104 | cordova.getThreadPool().execute(new Runnable() { 105 | public void run() { 106 | try { 107 | ArrayOfObjects albums = getBuckets(); 108 | callbackContext.success(new JSONArray(albums)); 109 | } catch (Exception e) { 110 | e.printStackTrace(); 111 | callbackContext.error(e.getMessage()); 112 | } 113 | } 114 | }); 115 | 116 | return true; 117 | } 118 | callbackContext.error("Invalid action"); 119 | return false; 120 | } catch (Exception e) { 121 | e.printStackTrace(); 122 | callbackContext.error(e.getMessage()); 123 | return false; 124 | } 125 | } 126 | 127 | public ArrayOfObjects getBuckets() throws JSONException { 128 | Object columns = new Object() {{ 129 | put("id", MediaStore.Images.ImageColumns.BUCKET_ID); 130 | put("title", MediaStore.Images.ImageColumns.BUCKET_DISPLAY_NAME); 131 | }}; 132 | 133 | final ArrayOfObjects results = queryContentProvider(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, columns, "1) GROUP BY 1,(2"); 134 | 135 | Object collection = null; 136 | for (int i = 0; i < results.size(); i++) { 137 | collection = results.get(i); 138 | if (collection.getString("title").equals("Camera")) { 139 | results.remove(i); 140 | break; 141 | } 142 | } 143 | 144 | if (collection != null) 145 | results.add(0, collection); 146 | 147 | return results; 148 | } 149 | 150 | private ArrayOfObjects getMedia(String bucket) throws JSONException { 151 | Object columns = new Object() {{ 152 | put("int.id", MediaStore.Images.Media._ID); 153 | put("data", MediaStore.MediaColumns.DATA); 154 | put("int.date_added", MediaStore.Images.ImageColumns.DATE_ADDED); 155 | put("title", MediaStore.Images.ImageColumns.DISPLAY_NAME); 156 | put("int.height", MediaStore.Images.ImageColumns.HEIGHT); 157 | put("int.width", MediaStore.Images.ImageColumns.WIDTH); 158 | put("int.orientation", MediaStore.Images.ImageColumns.ORIENTATION); 159 | put("mime_type", MediaStore.Images.ImageColumns.MIME_TYPE); 160 | put("float.lat", MediaStore.Images.ImageColumns.LATITUDE); 161 | put("float.lon", MediaStore.Images.ImageColumns.LONGITUDE); 162 | put("int.size", MediaStore.Images.ImageColumns.SIZE); 163 | put("int.thumbnail_id", MediaStore.Images.ImageColumns.MINI_THUMB_MAGIC); 164 | }}; 165 | 166 | final ArrayOfObjects results = queryContentProvider(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, columns, "bucket_display_name = \"" + bucket + "\""); 167 | 168 | ArrayOfObjects temp = new ArrayOfObjects(); 169 | 170 | 171 | for (Object media : results) { 172 | media.put("thumbnail", ""); 173 | media.put("error", "false"); 174 | 175 | if (media.getInt("height") <= 0 || media.getInt("width") <= 0) { 176 | System.err.println(media); 177 | } else { 178 | temp.add(media); 179 | } 180 | } 181 | 182 | Collections.reverse(temp); 183 | return temp; 184 | } 185 | 186 | private void checkPermission() { 187 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 188 | List permissions = new ArrayList(); 189 | 190 | boolean isReadDenied = false; 191 | boolean isWriteDenied = false; 192 | 193 | if (ContextCompat.checkSelfPermission(this.getContext(), Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { 194 | if (ActivityCompat.shouldShowRequestPermissionRationale(this.cordova.getActivity(), Manifest.permission.READ_EXTERNAL_STORAGE)) 195 | isReadDenied = true; 196 | else 197 | permissions.add(Manifest.permission.READ_EXTERNAL_STORAGE); 198 | } 199 | 200 | if (ContextCompat.checkSelfPermission(this.getContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { 201 | if (ActivityCompat.shouldShowRequestPermissionRationale(this.cordova.getActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE)) 202 | isWriteDenied = true; 203 | else 204 | permissions.add(Manifest.permission.WRITE_EXTERNAL_STORAGE); 205 | } 206 | 207 | if (isReadDenied || isWriteDenied) { 208 | String message; 209 | 210 | if (isReadDenied && isWriteDenied) 211 | message = "Read and Write permissions are denied"; 212 | else if (isReadDenied) 213 | message = "Read permission is denied"; 214 | else 215 | message = "Write permission is denied"; 216 | 217 | sendCheckPermissionResult(false, message); 218 | } else if (permissions.size() > 0) { 219 | String[] pArray = new String[permissions.size()]; 220 | pArray = permissions.toArray(pArray); 221 | ActivityCompat.requestPermissions(this.cordova.getActivity(), pArray, STORAGE_PERMISSIONS_REQUEST); 222 | } else 223 | sendCheckPermissionResult(true, "Authorized"); 224 | } else 225 | sendCheckPermissionResult(true, "Authorized"); 226 | } 227 | 228 | public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { 229 | switch (requestCode) { 230 | case STORAGE_PERMISSIONS_REQUEST: { 231 | if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) 232 | sendCheckPermissionResult(true, "Authorized"); 233 | else 234 | sendCheckPermissionResult(false, "Denied"); 235 | return; 236 | } 237 | } 238 | } 239 | 240 | private void sendCheckPermissionResult(Boolean success, String message) { 241 | try { 242 | JSONObject result = new JSONObject(); 243 | result.put("success", success); 244 | result.put("message", message); 245 | cbc.success(result); 246 | } catch (Exception e) { 247 | e.printStackTrace(); 248 | cbc.error(e.getMessage()); 249 | } 250 | } 251 | 252 | private JSONObject getMediaThumbnail(JSONObject media) throws JSONException { 253 | 254 | File thumbnailPath = thumbnailPathFromMediaId(media.getString("id")); 255 | if (thumbnailPath.exists()) { 256 | System.out.println("Thumbnail Already Exists!!!. Not Creating New One"); 257 | media.put("thumbnail", thumbnailPath); 258 | } else { 259 | if (ops == null) { 260 | ops = new BitmapFactory.Options(); 261 | ops.inJustDecodeBounds = false; 262 | ops.inSampleSize = 1; 263 | } 264 | media.put("error", "true"); 265 | 266 | File image = new File(media.getString("data")); 267 | 268 | int sourceWidth = media.getInt("width"); 269 | int sourceHeight = media.getInt("height"); 270 | 271 | if (sourceHeight > 0 && sourceWidth > 0) { 272 | int destinationWidth, destinationHeight; 273 | 274 | if (sourceWidth > sourceHeight) { 275 | destinationHeight = BASE_SIZE; 276 | destinationWidth = (int) Math.ceil(destinationHeight * ((double) sourceWidth / sourceHeight)); 277 | } else { 278 | destinationWidth = BASE_SIZE; 279 | destinationHeight = (int) Math.ceil(destinationWidth * ((double) sourceHeight / sourceWidth)); 280 | } 281 | 282 | if (sourceWidth * sourceHeight > 600000 && sourceWidth * sourceHeight < 1000000) { 283 | ops.inSampleSize = 4; 284 | } else if (sourceWidth * sourceHeight > 1000000) { 285 | ops.inSampleSize = 8; 286 | } 287 | 288 | Bitmap originalImageBitmap = BitmapFactory.decodeFile(image.getAbsolutePath(), ops); //creating bitmap of original image 289 | 290 | if (originalImageBitmap == null) { 291 | ops.inSampleSize = 1; 292 | originalImageBitmap = BitmapFactory.decodeFile(image.getAbsolutePath(), ops); 293 | } 294 | 295 | if (originalImageBitmap != null) { 296 | 297 | if (destinationHeight <= 0 || destinationWidth <= 0) { 298 | System.out.println("destinationHeight: " + destinationHeight + " destinationWidth: " + destinationWidth); 299 | } 300 | 301 | Bitmap thumbnailBitmap = Bitmap.createScaledBitmap(originalImageBitmap, destinationWidth, destinationHeight, true); 302 | originalImageBitmap.recycle(); 303 | 304 | if (thumbnailBitmap != null) { 305 | int orientation = media.getInt("orientation"); 306 | if (orientation > 0) 307 | thumbnailBitmap = rotate(thumbnailBitmap, orientation); 308 | 309 | byte[] thumbnailData = getBytesFromBitmap(thumbnailBitmap); 310 | thumbnailBitmap.recycle(); 311 | if (thumbnailData != null) { 312 | FileOutputStream outStream; 313 | try { 314 | outStream = new FileOutputStream(thumbnailPath); 315 | outStream.write(thumbnailData); 316 | outStream.close(); 317 | } catch (IOException e) { 318 | Log.e("Mendr", "Couldn't write the thumbnail image data"); 319 | e.printStackTrace(); 320 | } 321 | 322 | if (thumbnailPath.exists()) { 323 | System.out.println("Thumbnail didn't Exists!!!. Created New One"); 324 | media.put("thumbnail", thumbnailPath); 325 | media.put("error", "false"); 326 | } 327 | } else 328 | Log.e("Mendr", "Couldn't convert thumbnail bitmap to byte array"); 329 | } else 330 | Log.e("Mendr", "Couldn't create the thumbnail bitmap"); 331 | } else 332 | Log.e("Mendr", "Couldn't decode the original image"); 333 | } else 334 | Log.e("Mendr", "Invalid Media!!! Image width or height is 0"); 335 | } 336 | 337 | return media; 338 | } 339 | 340 | private File getHQImageData(JSONObject media) throws JSONException { 341 | File imagePath = imagePathFromMediaId(media.getString("id")); 342 | 343 | BitmapFactory.Options ops = new BitmapFactory.Options(); 344 | ops.inJustDecodeBounds = false; 345 | ops.inSampleSize = 1; 346 | 347 | File image = new File(media.getString("data")); 348 | 349 | int sourceWidth = media.getInt("width"); 350 | int sourceHeight = media.getInt("height"); 351 | 352 | if (sourceHeight > 0 && sourceWidth > 0) { 353 | Bitmap originalImageBitmap = BitmapFactory.decodeFile(image.getAbsolutePath(), ops); //creating bitmap of original image 354 | 355 | if (originalImageBitmap != null) { 356 | int orientation = media.getInt("orientation"); 357 | if (orientation > 0) 358 | originalImageBitmap = rotate(originalImageBitmap, orientation); 359 | 360 | byte[] imageData = getBytesFromBitmap(originalImageBitmap); 361 | originalImageBitmap.recycle(); 362 | if (imageData != null) { 363 | FileOutputStream outStream; 364 | try { 365 | outStream = new FileOutputStream(imagePath); 366 | outStream.write(imageData); 367 | outStream.close(); 368 | } catch (IOException e) { 369 | Log.e("Mendr", "Couldn't write the image data"); 370 | e.printStackTrace(); 371 | } 372 | } 373 | } else 374 | Log.e("Mendr", "Couldn't decode the original image"); 375 | } else 376 | Log.e("Mendr", "Invalid Media!!! Image width or height is 0"); 377 | 378 | return imagePath; 379 | } 380 | 381 | private byte[] getBytesFromBitmap(Bitmap bitmap) { 382 | ByteArrayOutputStream stream = new ByteArrayOutputStream(); 383 | bitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream); 384 | return stream.toByteArray(); 385 | } 386 | 387 | private static Bitmap rotate(Bitmap source, int orientation) { 388 | Matrix matrix = new Matrix(); 389 | matrix.postRotate((float) orientation); 390 | return Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(), matrix, false); 391 | } 392 | 393 | private File thumbnailPathFromMediaId(String mediaId) { 394 | File thumbnailPath = null; 395 | 396 | String thumbnailName = mediaId + "_mthumb.png"; 397 | File dir = new File(this.getContext().getApplicationInfo().dataDir, DIR_NAME); 398 | if (!dir.exists()) { 399 | if (!dir.mkdirs()) { 400 | Log.e("Mendr", "Failed to create storage directory."); 401 | return thumbnailPath; 402 | } 403 | } 404 | 405 | thumbnailPath = new File(dir.getPath() + File.separator + thumbnailName); 406 | 407 | return thumbnailPath; 408 | } 409 | 410 | private File imagePathFromMediaId(String mediaId) { 411 | File imagePath = null; 412 | 413 | File rootDir = new File(this.getContext().getApplicationInfo().dataDir, DIR_NAME); 414 | File dir = new File(rootDir, SUB_DIR_NAME); 415 | 416 | //check if root directory exist 417 | if (rootDir.exists()) { 418 | //root directory exists 419 | if (dir.exists()) { 420 | //dir exists so deleting it 421 | deleteRecursive(dir); 422 | } 423 | 424 | if (!dir.mkdirs()) { 425 | Log.e("Mendr", "Failed to create hq storage directory."); 426 | return imagePath; 427 | } else { 428 | //dir created successfully 429 | } 430 | } else { 431 | //root directory doesn't exist 432 | //trying to create root directory 433 | if (!rootDir.mkdirs()) { 434 | Log.e("Mendr", "Failed to create root storage directory."); 435 | return imagePath; 436 | } else { 437 | //root dir created successfully 438 | if (!dir.mkdirs()) { 439 | Log.e("Mendr", "Failed to create hq storage directory."); 440 | return imagePath; 441 | } else { 442 | //dir created successfully 443 | } 444 | } 445 | } 446 | 447 | String imageName = mediaId + ".png"; 448 | imagePath = new File(dir.getPath() + File.separator + imageName); 449 | 450 | return imagePath; 451 | } 452 | 453 | void deleteRecursive(File fileOrDirectory) { 454 | if (fileOrDirectory.isDirectory()) 455 | for (File child : fileOrDirectory.listFiles()) 456 | deleteRecursive(child); 457 | 458 | fileOrDirectory.delete(); 459 | } 460 | 461 | private Context getContext() { 462 | return this.cordova.getActivity().getApplicationContext(); 463 | } 464 | 465 | private ArrayOfObjects queryContentProvider(Uri collection, Object columns, String whereClause) throws JSONException { 466 | final ArrayList columnNames = new ArrayList(); 467 | final ArrayList columnValues = new ArrayList(); 468 | 469 | Iterator iteratorFields = columns.keys(); 470 | 471 | while (iteratorFields.hasNext()) { 472 | String column = iteratorFields.next(); 473 | 474 | columnNames.add(column); 475 | columnValues.add("" + columns.getString(column)); 476 | } 477 | 478 | final Cursor cursor = getContext().getContentResolver().query(collection, columnValues.toArray(new String[columns.length()]), whereClause, null, null); 479 | final ArrayOfObjects buffer = new ArrayOfObjects(); 480 | 481 | if (cursor.moveToFirst()) { 482 | do { 483 | Object item = new Object(); 484 | 485 | for (String column : columnNames) { 486 | int columnIndex = cursor.getColumnIndex(columns.get(column).toString()); 487 | 488 | if (column.startsWith("int.")) { 489 | item.put(column.substring(4), cursor.getInt(columnIndex)); 490 | if (column.substring(4).equals("width") && item.getInt("width") == 0) { 491 | System.err.println("cursor: " + cursor.getInt(columnIndex)); 492 | 493 | } 494 | } else if (column.startsWith("float.")) { 495 | item.put(column.substring(6), cursor.getFloat(columnIndex)); 496 | } else { 497 | item.put(column, cursor.getString(columnIndex)); 498 | } 499 | } 500 | 501 | buffer.add(item); 502 | } 503 | while (cursor.moveToNext()); 504 | } 505 | 506 | cursor.close(); 507 | 508 | return buffer; 509 | } 510 | 511 | private class Object extends JSONObject { 512 | 513 | } 514 | 515 | private class ArrayOfObjects extends ArrayList { 516 | 517 | } 518 | } -------------------------------------------------------------------------------- /dev/android/app/src/main/java/com/subitolabs/cordova/galleryapi/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.subitolabs.cordova.galleryapi; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.support.v7.app.ActionBarActivity; 6 | import android.os.Bundle; 7 | import android.view.Menu; 8 | import android.view.MenuItem; 9 | 10 | import org.apache.cordova.CallbackContext; 11 | import org.apache.cordova.CordovaInterface; 12 | import org.apache.cordova.CordovaPlugin; 13 | import org.apache.cordova.PluginResult; 14 | import org.json.JSONArray; 15 | import org.json.JSONException; 16 | 17 | import java.util.concurrent.ExecutorService; 18 | import java.util.logging.Logger; 19 | 20 | 21 | public class MainActivity extends ActionBarActivity { 22 | 23 | @Override 24 | protected void onCreate(Bundle savedInstanceState) { 25 | super.onCreate(savedInstanceState); 26 | setContentView(R.layout.activity_main); 27 | 28 | GalleryAPI plugin = new GalleryAPI(); 29 | 30 | plugin.cordova = new MyCordova(); 31 | 32 | try { 33 | plugin.execute("getMedia", new JSONArray(), new MyCallbackContext()); 34 | } catch (JSONException e) { 35 | e.printStackTrace(); 36 | } 37 | } 38 | 39 | 40 | @Override 41 | public boolean onCreateOptionsMenu(Menu menu) { 42 | // Inflate the menu; this adds items to the action bar if it is present. 43 | getMenuInflater().inflate(R.menu.menu_main, menu); 44 | return true; 45 | } 46 | 47 | @Override 48 | public boolean onOptionsItemSelected(MenuItem item) { 49 | // Handle action bar item clicks here. The action bar will 50 | // automatically handle clicks on the Home/Up button, so long 51 | // as you specify a parent activity in AndroidManifest.xml. 52 | int id = item.getItemId(); 53 | 54 | //noinspection SimplifiableIfStatement 55 | if (id == R.id.action_settings) { 56 | return true; 57 | } 58 | 59 | return super.onOptionsItemSelected(item); 60 | } 61 | 62 | private class MyCordova implements CordovaInterface 63 | { 64 | @Override 65 | public void startActivityForResult(CordovaPlugin cordovaPlugin, Intent intent, int i) { 66 | 67 | } 68 | 69 | @Override 70 | public void setActivityResultCallback(CordovaPlugin cordovaPlugin) { 71 | 72 | } 73 | 74 | @Override 75 | public Activity getActivity() { 76 | return MainActivity.this; 77 | } 78 | 79 | @Override 80 | public Object onMessage(String s, Object o) { 81 | return null; 82 | } 83 | 84 | @Override 85 | public ExecutorService getThreadPool() { 86 | return null; 87 | } 88 | } 89 | 90 | private class MyCallbackContext extends CallbackContext 91 | { 92 | public MyCallbackContext() 93 | { 94 | super("", null); 95 | } 96 | 97 | public void sendPluginResult(PluginResult pluginResult) 98 | { 99 | Logger.getLogger("my.output").info("Result: " + pluginResult.getJSONString()); 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /dev/android/app/src/main/res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SuryaL/cordova-gallery-api/e4a77fbe72f3b61380450daa2fa1e4336b4af38e/dev/android/app/src/main/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /dev/android/app/src/main/res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SuryaL/cordova-gallery-api/e4a77fbe72f3b61380450daa2fa1e4336b4af38e/dev/android/app/src/main/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /dev/android/app/src/main/res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SuryaL/cordova-gallery-api/e4a77fbe72f3b61380450daa2fa1e4336b4af38e/dev/android/app/src/main/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /dev/android/app/src/main/res/drawable-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SuryaL/cordova-gallery-api/e4a77fbe72f3b61380450daa2fa1e4336b4af38e/dev/android/app/src/main/res/drawable-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /dev/android/app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /dev/android/app/src/main/res/menu/menu_main.xml: -------------------------------------------------------------------------------- 1 | 5 | 7 | 8 | -------------------------------------------------------------------------------- /dev/android/app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /dev/android/app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 6 | -------------------------------------------------------------------------------- /dev/android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | GalleryPicker 5 | MainActivity 6 | Hello world! 7 | Settings 8 | 9 | 10 | -------------------------------------------------------------------------------- /dev/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /dev/android/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:1.0.0' 9 | 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | jcenter() 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /dev/android/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true -------------------------------------------------------------------------------- /dev/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Apr 10 15:27:10 PDT 2013 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip 7 | -------------------------------------------------------------------------------- /dev/android/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /dev/android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /dev/android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | -------------------------------------------------------------------------------- /dev/ios/GalleryAPI/NSObject_GalleryAPI.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSObject_GalleryAPI.h 3 | // galleryapi 4 | // 5 | // Created by Thomas Decaux on 26/02/2015. 6 | // Copyright (c) 2015 SubitoLabs. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface NSObject () 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /dev/ios/GalleryAPI/galleryapi.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | E2E2104F1A9F682E003EA1E8 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = E2E2104E1A9F682E003EA1E8 /* main.m */; }; 11 | E2E210521A9F682E003EA1E8 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = E2E210511A9F682E003EA1E8 /* AppDelegate.m */; }; 12 | E2E210551A9F682E003EA1E8 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = E2E210541A9F682E003EA1E8 /* ViewController.m */; }; 13 | E2E210581A9F682E003EA1E8 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E2E210561A9F682E003EA1E8 /* Main.storyboard */; }; 14 | E2E2105A1A9F682E003EA1E8 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E2E210591A9F682E003EA1E8 /* Images.xcassets */; }; 15 | E2E2105D1A9F682E003EA1E8 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = E2E2105B1A9F682E003EA1E8 /* LaunchScreen.xib */; }; 16 | E2E210691A9F682E003EA1E8 /* galleryapiTests.m in Sources */ = {isa = PBXBuildFile; fileRef = E2E210681A9F682E003EA1E8 /* galleryapiTests.m */; }; 17 | E2E210761A9F68DC003EA1E8 /* AssetsLibrary.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E2E210751A9F68DC003EA1E8 /* AssetsLibrary.framework */; }; 18 | E2E2107A1A9F6AD4003EA1E8 /* GalleryAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = E2E210791A9F6AD4003EA1E8 /* GalleryAPI.m */; }; 19 | /* End PBXBuildFile section */ 20 | 21 | /* Begin PBXContainerItemProxy section */ 22 | E2E210631A9F682E003EA1E8 /* PBXContainerItemProxy */ = { 23 | isa = PBXContainerItemProxy; 24 | containerPortal = E2E210411A9F682E003EA1E8 /* Project object */; 25 | proxyType = 1; 26 | remoteGlobalIDString = E2E210481A9F682E003EA1E8; 27 | remoteInfo = galleryapi; 28 | }; 29 | /* End PBXContainerItemProxy section */ 30 | 31 | /* Begin PBXFileReference section */ 32 | E2E210491A9F682E003EA1E8 /* galleryapi.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = galleryapi.app; sourceTree = BUILT_PRODUCTS_DIR; }; 33 | E2E2104D1A9F682E003EA1E8 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 34 | E2E2104E1A9F682E003EA1E8 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 35 | E2E210501A9F682E003EA1E8 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 36 | E2E210511A9F682E003EA1E8 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 37 | E2E210531A9F682E003EA1E8 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 38 | E2E210541A9F682E003EA1E8 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 39 | E2E210571A9F682E003EA1E8 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 40 | E2E210591A9F682E003EA1E8 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 41 | E2E2105C1A9F682E003EA1E8 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; 42 | E2E210621A9F682E003EA1E8 /* galleryapiTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = galleryapiTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 43 | E2E210671A9F682E003EA1E8 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 44 | E2E210681A9F682E003EA1E8 /* galleryapiTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = galleryapiTests.m; sourceTree = ""; }; 45 | E2E210751A9F68DC003EA1E8 /* AssetsLibrary.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AssetsLibrary.framework; path = System/Library/Frameworks/AssetsLibrary.framework; sourceTree = SDKROOT; }; 46 | E2E210791A9F6AD4003EA1E8 /* GalleryAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GalleryAPI.m; sourceTree = ""; }; 47 | E2E2107B1A9F6AEC003EA1E8 /* GalleryAPI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GalleryAPI.h; sourceTree = ""; }; 48 | /* End PBXFileReference section */ 49 | 50 | /* Begin PBXFrameworksBuildPhase section */ 51 | E2E210461A9F682E003EA1E8 /* Frameworks */ = { 52 | isa = PBXFrameworksBuildPhase; 53 | buildActionMask = 2147483647; 54 | files = ( 55 | E2E210761A9F68DC003EA1E8 /* AssetsLibrary.framework in Frameworks */, 56 | ); 57 | runOnlyForDeploymentPostprocessing = 0; 58 | }; 59 | E2E2105F1A9F682E003EA1E8 /* Frameworks */ = { 60 | isa = PBXFrameworksBuildPhase; 61 | buildActionMask = 2147483647; 62 | files = ( 63 | ); 64 | runOnlyForDeploymentPostprocessing = 0; 65 | }; 66 | /* End PBXFrameworksBuildPhase section */ 67 | 68 | /* Begin PBXGroup section */ 69 | E2E210401A9F682E003EA1E8 = { 70 | isa = PBXGroup; 71 | children = ( 72 | E2E210751A9F68DC003EA1E8 /* AssetsLibrary.framework */, 73 | E2E2104B1A9F682E003EA1E8 /* galleryapi */, 74 | E2E210651A9F682E003EA1E8 /* galleryapiTests */, 75 | E2E2104A1A9F682E003EA1E8 /* Products */, 76 | ); 77 | sourceTree = ""; 78 | }; 79 | E2E2104A1A9F682E003EA1E8 /* Products */ = { 80 | isa = PBXGroup; 81 | children = ( 82 | E2E210491A9F682E003EA1E8 /* galleryapi.app */, 83 | E2E210621A9F682E003EA1E8 /* galleryapiTests.xctest */, 84 | ); 85 | name = Products; 86 | sourceTree = ""; 87 | }; 88 | E2E2104B1A9F682E003EA1E8 /* galleryapi */ = { 89 | isa = PBXGroup; 90 | children = ( 91 | E2E210501A9F682E003EA1E8 /* AppDelegate.h */, 92 | E2E210511A9F682E003EA1E8 /* AppDelegate.m */, 93 | E2E210531A9F682E003EA1E8 /* ViewController.h */, 94 | E2E210541A9F682E003EA1E8 /* ViewController.m */, 95 | E2E210561A9F682E003EA1E8 /* Main.storyboard */, 96 | E2E210591A9F682E003EA1E8 /* Images.xcassets */, 97 | E2E2105B1A9F682E003EA1E8 /* LaunchScreen.xib */, 98 | E2E2104C1A9F682E003EA1E8 /* Supporting Files */, 99 | E2E210791A9F6AD4003EA1E8 /* GalleryAPI.m */, 100 | E2E2107B1A9F6AEC003EA1E8 /* GalleryAPI.h */, 101 | ); 102 | path = galleryapi; 103 | sourceTree = ""; 104 | }; 105 | E2E2104C1A9F682E003EA1E8 /* Supporting Files */ = { 106 | isa = PBXGroup; 107 | children = ( 108 | E2E2104D1A9F682E003EA1E8 /* Info.plist */, 109 | E2E2104E1A9F682E003EA1E8 /* main.m */, 110 | ); 111 | name = "Supporting Files"; 112 | sourceTree = ""; 113 | }; 114 | E2E210651A9F682E003EA1E8 /* galleryapiTests */ = { 115 | isa = PBXGroup; 116 | children = ( 117 | E2E210681A9F682E003EA1E8 /* galleryapiTests.m */, 118 | E2E210661A9F682E003EA1E8 /* Supporting Files */, 119 | ); 120 | path = galleryapiTests; 121 | sourceTree = ""; 122 | }; 123 | E2E210661A9F682E003EA1E8 /* Supporting Files */ = { 124 | isa = PBXGroup; 125 | children = ( 126 | E2E210671A9F682E003EA1E8 /* Info.plist */, 127 | ); 128 | name = "Supporting Files"; 129 | sourceTree = ""; 130 | }; 131 | /* End PBXGroup section */ 132 | 133 | /* Begin PBXNativeTarget section */ 134 | E2E210481A9F682E003EA1E8 /* galleryapi */ = { 135 | isa = PBXNativeTarget; 136 | buildConfigurationList = E2E2106C1A9F682E003EA1E8 /* Build configuration list for PBXNativeTarget "galleryapi" */; 137 | buildPhases = ( 138 | E2E210451A9F682E003EA1E8 /* Sources */, 139 | E2E210461A9F682E003EA1E8 /* Frameworks */, 140 | E2E210471A9F682E003EA1E8 /* Resources */, 141 | ); 142 | buildRules = ( 143 | ); 144 | dependencies = ( 145 | ); 146 | name = galleryapi; 147 | productName = galleryapi; 148 | productReference = E2E210491A9F682E003EA1E8 /* galleryapi.app */; 149 | productType = "com.apple.product-type.application"; 150 | }; 151 | E2E210611A9F682E003EA1E8 /* galleryapiTests */ = { 152 | isa = PBXNativeTarget; 153 | buildConfigurationList = E2E2106F1A9F682E003EA1E8 /* Build configuration list for PBXNativeTarget "galleryapiTests" */; 154 | buildPhases = ( 155 | E2E2105E1A9F682E003EA1E8 /* Sources */, 156 | E2E2105F1A9F682E003EA1E8 /* Frameworks */, 157 | E2E210601A9F682E003EA1E8 /* Resources */, 158 | ); 159 | buildRules = ( 160 | ); 161 | dependencies = ( 162 | E2E210641A9F682E003EA1E8 /* PBXTargetDependency */, 163 | ); 164 | name = galleryapiTests; 165 | productName = galleryapiTests; 166 | productReference = E2E210621A9F682E003EA1E8 /* galleryapiTests.xctest */; 167 | productType = "com.apple.product-type.bundle.unit-test"; 168 | }; 169 | /* End PBXNativeTarget section */ 170 | 171 | /* Begin PBXProject section */ 172 | E2E210411A9F682E003EA1E8 /* Project object */ = { 173 | isa = PBXProject; 174 | attributes = { 175 | LastUpgradeCheck = 0610; 176 | ORGANIZATIONNAME = SubitoLabs; 177 | TargetAttributes = { 178 | E2E210481A9F682E003EA1E8 = { 179 | CreatedOnToolsVersion = 6.1.1; 180 | }; 181 | E2E210611A9F682E003EA1E8 = { 182 | CreatedOnToolsVersion = 6.1.1; 183 | TestTargetID = E2E210481A9F682E003EA1E8; 184 | }; 185 | }; 186 | }; 187 | buildConfigurationList = E2E210441A9F682E003EA1E8 /* Build configuration list for PBXProject "galleryapi" */; 188 | compatibilityVersion = "Xcode 3.2"; 189 | developmentRegion = English; 190 | hasScannedForEncodings = 0; 191 | knownRegions = ( 192 | en, 193 | Base, 194 | ); 195 | mainGroup = E2E210401A9F682E003EA1E8; 196 | productRefGroup = E2E2104A1A9F682E003EA1E8 /* Products */; 197 | projectDirPath = ""; 198 | projectRoot = ""; 199 | targets = ( 200 | E2E210481A9F682E003EA1E8 /* galleryapi */, 201 | E2E210611A9F682E003EA1E8 /* galleryapiTests */, 202 | ); 203 | }; 204 | /* End PBXProject section */ 205 | 206 | /* Begin PBXResourcesBuildPhase section */ 207 | E2E210471A9F682E003EA1E8 /* Resources */ = { 208 | isa = PBXResourcesBuildPhase; 209 | buildActionMask = 2147483647; 210 | files = ( 211 | E2E210581A9F682E003EA1E8 /* Main.storyboard in Resources */, 212 | E2E2105D1A9F682E003EA1E8 /* LaunchScreen.xib in Resources */, 213 | E2E2105A1A9F682E003EA1E8 /* Images.xcassets in Resources */, 214 | ); 215 | runOnlyForDeploymentPostprocessing = 0; 216 | }; 217 | E2E210601A9F682E003EA1E8 /* Resources */ = { 218 | isa = PBXResourcesBuildPhase; 219 | buildActionMask = 2147483647; 220 | files = ( 221 | ); 222 | runOnlyForDeploymentPostprocessing = 0; 223 | }; 224 | /* End PBXResourcesBuildPhase section */ 225 | 226 | /* Begin PBXSourcesBuildPhase section */ 227 | E2E210451A9F682E003EA1E8 /* Sources */ = { 228 | isa = PBXSourcesBuildPhase; 229 | buildActionMask = 2147483647; 230 | files = ( 231 | E2E210551A9F682E003EA1E8 /* ViewController.m in Sources */, 232 | E2E2107A1A9F6AD4003EA1E8 /* GalleryAPI.m in Sources */, 233 | E2E210521A9F682E003EA1E8 /* AppDelegate.m in Sources */, 234 | E2E2104F1A9F682E003EA1E8 /* main.m in Sources */, 235 | ); 236 | runOnlyForDeploymentPostprocessing = 0; 237 | }; 238 | E2E2105E1A9F682E003EA1E8 /* Sources */ = { 239 | isa = PBXSourcesBuildPhase; 240 | buildActionMask = 2147483647; 241 | files = ( 242 | E2E210691A9F682E003EA1E8 /* galleryapiTests.m in Sources */, 243 | ); 244 | runOnlyForDeploymentPostprocessing = 0; 245 | }; 246 | /* End PBXSourcesBuildPhase section */ 247 | 248 | /* Begin PBXTargetDependency section */ 249 | E2E210641A9F682E003EA1E8 /* PBXTargetDependency */ = { 250 | isa = PBXTargetDependency; 251 | target = E2E210481A9F682E003EA1E8 /* galleryapi */; 252 | targetProxy = E2E210631A9F682E003EA1E8 /* PBXContainerItemProxy */; 253 | }; 254 | /* End PBXTargetDependency section */ 255 | 256 | /* Begin PBXVariantGroup section */ 257 | E2E210561A9F682E003EA1E8 /* Main.storyboard */ = { 258 | isa = PBXVariantGroup; 259 | children = ( 260 | E2E210571A9F682E003EA1E8 /* Base */, 261 | ); 262 | name = Main.storyboard; 263 | sourceTree = ""; 264 | }; 265 | E2E2105B1A9F682E003EA1E8 /* LaunchScreen.xib */ = { 266 | isa = PBXVariantGroup; 267 | children = ( 268 | E2E2105C1A9F682E003EA1E8 /* Base */, 269 | ); 270 | name = LaunchScreen.xib; 271 | sourceTree = ""; 272 | }; 273 | /* End PBXVariantGroup section */ 274 | 275 | /* Begin XCBuildConfiguration section */ 276 | E2E2106A1A9F682E003EA1E8 /* Debug */ = { 277 | isa = XCBuildConfiguration; 278 | buildSettings = { 279 | ALWAYS_SEARCH_USER_PATHS = NO; 280 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 281 | CLANG_CXX_LIBRARY = "libc++"; 282 | CLANG_ENABLE_MODULES = YES; 283 | CLANG_ENABLE_OBJC_ARC = YES; 284 | CLANG_WARN_BOOL_CONVERSION = YES; 285 | CLANG_WARN_CONSTANT_CONVERSION = YES; 286 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 287 | CLANG_WARN_EMPTY_BODY = YES; 288 | CLANG_WARN_ENUM_CONVERSION = YES; 289 | CLANG_WARN_INT_CONVERSION = YES; 290 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 291 | CLANG_WARN_UNREACHABLE_CODE = YES; 292 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 293 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 294 | COPY_PHASE_STRIP = NO; 295 | ENABLE_STRICT_OBJC_MSGSEND = YES; 296 | GCC_C_LANGUAGE_STANDARD = gnu99; 297 | GCC_DYNAMIC_NO_PIC = NO; 298 | GCC_OPTIMIZATION_LEVEL = 0; 299 | GCC_PREPROCESSOR_DEFINITIONS = ( 300 | "DEBUG=1", 301 | "$(inherited)", 302 | ); 303 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 304 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 305 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 306 | GCC_WARN_UNDECLARED_SELECTOR = YES; 307 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 308 | GCC_WARN_UNUSED_FUNCTION = YES; 309 | GCC_WARN_UNUSED_VARIABLE = YES; 310 | IPHONEOS_DEPLOYMENT_TARGET = 8.1; 311 | MTL_ENABLE_DEBUG_INFO = YES; 312 | ONLY_ACTIVE_ARCH = YES; 313 | SDKROOT = iphoneos; 314 | TARGETED_DEVICE_FAMILY = "1,2"; 315 | }; 316 | name = Debug; 317 | }; 318 | E2E2106B1A9F682E003EA1E8 /* Release */ = { 319 | isa = XCBuildConfiguration; 320 | buildSettings = { 321 | ALWAYS_SEARCH_USER_PATHS = NO; 322 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 323 | CLANG_CXX_LIBRARY = "libc++"; 324 | CLANG_ENABLE_MODULES = YES; 325 | CLANG_ENABLE_OBJC_ARC = YES; 326 | CLANG_WARN_BOOL_CONVERSION = YES; 327 | CLANG_WARN_CONSTANT_CONVERSION = YES; 328 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 329 | CLANG_WARN_EMPTY_BODY = YES; 330 | CLANG_WARN_ENUM_CONVERSION = YES; 331 | CLANG_WARN_INT_CONVERSION = YES; 332 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 333 | CLANG_WARN_UNREACHABLE_CODE = YES; 334 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 335 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 336 | COPY_PHASE_STRIP = YES; 337 | ENABLE_NS_ASSERTIONS = NO; 338 | ENABLE_STRICT_OBJC_MSGSEND = YES; 339 | GCC_C_LANGUAGE_STANDARD = gnu99; 340 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 341 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 342 | GCC_WARN_UNDECLARED_SELECTOR = YES; 343 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 344 | GCC_WARN_UNUSED_FUNCTION = YES; 345 | GCC_WARN_UNUSED_VARIABLE = YES; 346 | IPHONEOS_DEPLOYMENT_TARGET = 8.1; 347 | MTL_ENABLE_DEBUG_INFO = NO; 348 | SDKROOT = iphoneos; 349 | TARGETED_DEVICE_FAMILY = "1,2"; 350 | VALIDATE_PRODUCT = YES; 351 | }; 352 | name = Release; 353 | }; 354 | E2E2106D1A9F682E003EA1E8 /* Debug */ = { 355 | isa = XCBuildConfiguration; 356 | buildSettings = { 357 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 358 | INFOPLIST_FILE = galleryapi/Info.plist; 359 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 360 | PRODUCT_NAME = "$(TARGET_NAME)"; 361 | }; 362 | name = Debug; 363 | }; 364 | E2E2106E1A9F682E003EA1E8 /* Release */ = { 365 | isa = XCBuildConfiguration; 366 | buildSettings = { 367 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 368 | INFOPLIST_FILE = galleryapi/Info.plist; 369 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 370 | PRODUCT_NAME = "$(TARGET_NAME)"; 371 | }; 372 | name = Release; 373 | }; 374 | E2E210701A9F682E003EA1E8 /* Debug */ = { 375 | isa = XCBuildConfiguration; 376 | buildSettings = { 377 | BUNDLE_LOADER = "$(TEST_HOST)"; 378 | FRAMEWORK_SEARCH_PATHS = ( 379 | "$(SDKROOT)/Developer/Library/Frameworks", 380 | "$(inherited)", 381 | ); 382 | GCC_PREPROCESSOR_DEFINITIONS = ( 383 | "DEBUG=1", 384 | "$(inherited)", 385 | ); 386 | INFOPLIST_FILE = galleryapiTests/Info.plist; 387 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 388 | PRODUCT_NAME = "$(TARGET_NAME)"; 389 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/galleryapi.app/galleryapi"; 390 | }; 391 | name = Debug; 392 | }; 393 | E2E210711A9F682E003EA1E8 /* Release */ = { 394 | isa = XCBuildConfiguration; 395 | buildSettings = { 396 | BUNDLE_LOADER = "$(TEST_HOST)"; 397 | FRAMEWORK_SEARCH_PATHS = ( 398 | "$(SDKROOT)/Developer/Library/Frameworks", 399 | "$(inherited)", 400 | ); 401 | INFOPLIST_FILE = galleryapiTests/Info.plist; 402 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 403 | PRODUCT_NAME = "$(TARGET_NAME)"; 404 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/galleryapi.app/galleryapi"; 405 | }; 406 | name = Release; 407 | }; 408 | /* End XCBuildConfiguration section */ 409 | 410 | /* Begin XCConfigurationList section */ 411 | E2E210441A9F682E003EA1E8 /* Build configuration list for PBXProject "galleryapi" */ = { 412 | isa = XCConfigurationList; 413 | buildConfigurations = ( 414 | E2E2106A1A9F682E003EA1E8 /* Debug */, 415 | E2E2106B1A9F682E003EA1E8 /* Release */, 416 | ); 417 | defaultConfigurationIsVisible = 0; 418 | defaultConfigurationName = Release; 419 | }; 420 | E2E2106C1A9F682E003EA1E8 /* Build configuration list for PBXNativeTarget "galleryapi" */ = { 421 | isa = XCConfigurationList; 422 | buildConfigurations = ( 423 | E2E2106D1A9F682E003EA1E8 /* Debug */, 424 | E2E2106E1A9F682E003EA1E8 /* Release */, 425 | ); 426 | defaultConfigurationIsVisible = 0; 427 | }; 428 | E2E2106F1A9F682E003EA1E8 /* Build configuration list for PBXNativeTarget "galleryapiTests" */ = { 429 | isa = XCConfigurationList; 430 | buildConfigurations = ( 431 | E2E210701A9F682E003EA1E8 /* Debug */, 432 | E2E210711A9F682E003EA1E8 /* Release */, 433 | ); 434 | defaultConfigurationIsVisible = 0; 435 | }; 436 | /* End XCConfigurationList section */ 437 | }; 438 | rootObject = E2E210411A9F682E003EA1E8 /* Project object */; 439 | } 440 | -------------------------------------------------------------------------------- /dev/ios/GalleryAPI/galleryapi.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /dev/ios/GalleryAPI/galleryapi.xcodeproj/project.xcworkspace/xcshareddata/galleryapi.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | 058B4D39-DA68-4CE0-A2FB-24A413AB4DBB 9 | IDESourceControlProjectName 10 | galleryapi 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | 72CD0FF6177CAB4092928FC5B16DB168789AF850 14 | github.com:subitolabs/cordova-gallery-api.git 15 | 16 | IDESourceControlProjectPath 17 | dev/ios/galleryapi/galleryapi.xcodeproj 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | 72CD0FF6177CAB4092928FC5B16DB168789AF850 21 | ../../../../.. 22 | 23 | IDESourceControlProjectURL 24 | github.com:subitolabs/cordova-gallery-api.git 25 | IDESourceControlProjectVersion 26 | 111 27 | IDESourceControlProjectWCCIdentifier 28 | 72CD0FF6177CAB4092928FC5B16DB168789AF850 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | 72CD0FF6177CAB4092928FC5B16DB168789AF850 36 | IDESourceControlWCCName 37 | cordova-gallery-api 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /dev/ios/GalleryAPI/galleryapi.xcodeproj/project.xcworkspace/xcuserdata/tom.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SuryaL/cordova-gallery-api/e4a77fbe72f3b61380450daa2fa1e4336b4af38e/dev/ios/GalleryAPI/galleryapi.xcodeproj/project.xcworkspace/xcuserdata/tom.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /dev/ios/GalleryAPI/galleryapi.xcodeproj/xcuserdata/tom.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 8 | 20 | 21 | 22 | 24 | 36 | 37 | 38 | 40 | 52 | 53 | 54 | 56 | 68 | 69 | 70 | 72 | 84 | 85 | 86 | 88 | 100 | 101 | 102 | 104 | 116 | 117 | 118 | 120 | 132 | 133 | 134 | 136 | 148 | 149 | 150 | 151 | 152 | -------------------------------------------------------------------------------- /dev/ios/GalleryAPI/galleryapi.xcodeproj/xcuserdata/tom.xcuserdatad/xcschemes/galleryapi.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 47 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 65 | 66 | 75 | 76 | 82 | 83 | 84 | 85 | 86 | 87 | 93 | 94 | 100 | 101 | 102 | 103 | 105 | 106 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /dev/ios/GalleryAPI/galleryapi.xcodeproj/xcuserdata/tom.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | galleryapi.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | E2E210481A9F682E003EA1E8 16 | 17 | primary 18 | 19 | 20 | E2E210611A9F682E003EA1E8 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /dev/ios/GalleryAPI/galleryapi/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // galleryapi 4 | // 5 | // Created by Thomas Decaux on 26/02/2015. 6 | // Copyright (c) 2015 SubitoLabs. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /dev/ios/GalleryAPI/galleryapi/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // galleryapi 4 | // 5 | // Created by Thomas Decaux on 26/02/2015. 6 | // Copyright (c) 2015 SubitoLabs. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | // Override point for customization after application launch. 20 | return YES; 21 | } 22 | 23 | - (void)applicationWillResignActive:(UIApplication *)application { 24 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 25 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 26 | } 27 | 28 | - (void)applicationDidEnterBackground:(UIApplication *)application { 29 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 30 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 31 | } 32 | 33 | - (void)applicationWillEnterForeground:(UIApplication *)application { 34 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 35 | } 36 | 37 | - (void)applicationDidBecomeActive:(UIApplication *)application { 38 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 39 | } 40 | 41 | - (void)applicationWillTerminate:(UIApplication *)application { 42 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 43 | } 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /dev/ios/GalleryAPI/galleryapi/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 20 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /dev/ios/GalleryAPI/galleryapi/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /dev/ios/GalleryAPI/galleryapi/GalleryAPI.h: -------------------------------------------------------------------------------- 1 | // 2 | // GalleryAPI.h 3 | // galleryapi 4 | // 5 | // Created by Thomas Decaux on 26/02/2015. 6 | // Copyright (c) 2015 SubitoLabs. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface GalleryAPI : NSObject 13 | 14 | - (void) getAlbums:(void (^) (NSArray *))successHandler withErrorHandler:(void (^) (NSString *))errorHandler; 15 | 16 | - (void) getAlbumAssets:(NSString*) album withSuccessHandler:(void (^) (NSArray *))successHandler andErrorHandler:(void (^) (NSString *))errorHandler; 17 | 18 | @end -------------------------------------------------------------------------------- /dev/ios/GalleryAPI/galleryapi/GalleryAPI.m: -------------------------------------------------------------------------------- 1 | // 2 | // GalleryAPI.m 3 | // galleryapi 4 | // 5 | // Created by Thomas Decaux on 26/02/2015. 6 | // Copyright (c) 2015 SubitoLabs. All rights reserved. 7 | // 8 | 9 | #import "GalleryAPI.h" 10 | 11 | @interface GalleryAPI () 12 | 13 | @end 14 | 15 | @implementation GalleryAPI 16 | 17 | - (void) getAlbums:(void (^) (NSArray *))successHandler withErrorHandler:(void (^) (NSString *))errorHandler 18 | { 19 | __block ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init]; 20 | __block NSMutableArray *albums = [[NSMutableArray alloc] init]; 21 | 22 | [library enumerateGroupsWithTypes:ALAssetsGroupAll usingBlock:^(ALAssetsGroup *group, BOOL *stop) 23 | { 24 | if (group == nil) 25 | { 26 | successHandler(albums); 27 | } 28 | else 29 | { 30 | [albums addObject:@{ 31 | @"id" : [group valueForProperty:ALAssetsGroupPropertyPersistentID], 32 | @"title" : [group valueForProperty:ALAssetsGroupPropertyName], 33 | @"assets" : [NSString stringWithFormat:@"%ld", group.numberOfAssets] 34 | }]; 35 | } 36 | 37 | } 38 | failureBlock: ^(NSError *error) 39 | { 40 | errorHandler(error.localizedDescription); 41 | }]; 42 | } 43 | 44 | - (void) getAlbumAssets:(NSString*) album withSuccessHandler:(void (^) (NSArray *))successHandler andErrorHandler:(void (^)(NSString *))errorHandler 45 | { 46 | __block ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init]; 47 | __block NSMutableArray *assets = [[NSMutableArray alloc] init]; 48 | 49 | [library enumerateGroupsWithTypes:ALAssetsGroupAll usingBlock:^(ALAssetsGroup *group, BOOL *stop) 50 | { 51 | if (group == nil) 52 | { 53 | successHandler(assets); 54 | } 55 | else 56 | { 57 | if (album == [group valueForProperty:ALAssetsGroupPropertyName]) 58 | { 59 | [group enumerateAssetsWithOptions:NSEnumerationReverse usingBlock: 60 | ^(ALAsset *result, NSUInteger index, BOOL *stop) 61 | { 62 | if(result == nil) 63 | { 64 | successHandler(assets); 65 | } 66 | else 67 | { 68 | ALAssetRepresentation *representation = result.defaultRepresentation; 69 | CGSize dimensions = representation.dimensions; 70 | 71 | 72 | [assets addObject:@{ 73 | @"id" : [[result valueForProperty:ALAssetPropertyAssetURL] absoluteString], 74 | @"title" : representation.filename, 75 | @"orientation" : @"up", 76 | @"lat" : @4, 77 | @"lng" : @5, 78 | @"width" : [NSNumber numberWithFloat:dimensions.width], 79 | @"height" : [NSNumber numberWithFloat:dimensions.height], 80 | @"size" : [NSNumber numberWithLongLong:representation.size], 81 | @"data" : representation.url.absoluteString, 82 | @"thumbnail" : representation.url.absoluteString 83 | }]; 84 | } 85 | } 86 | ]; 87 | } 88 | 89 | } 90 | } 91 | failureBlock: ^(NSError *error) 92 | { 93 | errorHandler(error.localizedDescription); 94 | }]; 95 | } 96 | 97 | @end -------------------------------------------------------------------------------- /dev/ios/GalleryAPI/galleryapi/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "ipad", 35 | "size" : "29x29", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "ipad", 40 | "size" : "29x29", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "40x40", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "40x40", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "76x76", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "76x76", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } -------------------------------------------------------------------------------- /dev/ios/GalleryAPI/galleryapi/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | com.subitolabs.cordova.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | UISupportedInterfaceOrientations~ipad 40 | 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationPortraitUpsideDown 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /dev/ios/GalleryAPI/galleryapi/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // galleryapi 4 | // 5 | // Created by Thomas Decaux on 26/02/2015. 6 | // Copyright (c) 2015 SubitoLabs. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /dev/ios/GalleryAPI/galleryapi/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // galleryapi 4 | // 5 | // Created by Thomas Decaux on 26/02/2015. 6 | // Copyright (c) 2015 SubitoLabs. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | 11 | #import "GalleryAPI.h" 12 | 13 | @interface ViewController () 14 | 15 | @end 16 | 17 | @implementation ViewController 18 | 19 | - (void)viewDidLoad 20 | { 21 | [super viewDidLoad]; 22 | 23 | GalleryAPI *api = [GalleryAPI alloc]; 24 | 25 | [api getAlbums:^(NSArray *albums) 26 | { 27 | for (NSDictionary *album in albums) 28 | { 29 | NSLog(@"-> Album %@", [album objectForKey:@"title"]); 30 | 31 | [api getAlbumAssets:[album objectForKey:@"title"] withSuccessHandler:^(NSArray *assets) 32 | { 33 | for (NSDictionary *asset in assets) 34 | { 35 | NSLog(@"----> Asset %@ %@", [asset objectForKey:@"title"], [asset objectForKey:@"thumbnail"]); 36 | } 37 | } 38 | andErrorHandler:^(NSString *error) 39 | { 40 | NSLog(@" ERROR: %@ ", error); 41 | }]; 42 | } 43 | 44 | } 45 | withErrorHandler:^(NSString *error) 46 | { 47 | NSLog(@" ERROR: %@ ", error); 48 | }]; 49 | } 50 | 51 | - (void)didReceiveMemoryWarning { 52 | [super didReceiveMemoryWarning]; 53 | // Dispose of any resources that can be recreated. 54 | } 55 | 56 | @end 57 | -------------------------------------------------------------------------------- /dev/ios/GalleryAPI/galleryapi/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // galleryapi 4 | // 5 | // Created by Thomas Decaux on 26/02/2015. 6 | // Copyright (c) 2015 SubitoLabs. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /dev/ios/GalleryAPI/galleryapiTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | com.subitolabs.cordova.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /dev/ios/GalleryAPI/galleryapiTests/galleryapiTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // galleryapiTests.m 3 | // galleryapiTests 4 | // 5 | // Created by Thomas Decaux on 26/02/2015. 6 | // Copyright (c) 2015 SubitoLabs. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface galleryapiTests : XCTestCase 13 | 14 | @end 15 | 16 | @implementation galleryapiTests 17 | 18 | - (void)setUp { 19 | [super setUp]; 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | } 22 | 23 | - (void)tearDown { 24 | // Put teardown code here. This method is called after the invocation of each test method in the class. 25 | [super tearDown]; 26 | } 27 | 28 | - (void)testExample { 29 | // This is an example of a functional test case. 30 | XCTAssert(YES, @"Pass"); 31 | } 32 | 33 | - (void)testPerformanceExample { 34 | // This is an example of a performance test case. 35 | [self measureBlock:^{ 36 | // Put the code you want to measure the time of here. 37 | }]; 38 | } 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /plugin.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | GalleryAPI 4 | Cordova gallery API plugin 5 | MIT 6 | cordova,gallery,media,api 7 | git@github.com:subitolabs/cordova-gallery-api.git 8 | https://github.com/subitolabs/cordova-gallery-api/issues 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | $PHOTO_LIBRARY_USAGE_DESCRIPTION 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /src/android/GalleryAPI.java: -------------------------------------------------------------------------------- 1 | package com.subitolabs.cordova.galleryapi; 2 | 3 | 4 | import android.Manifest; 5 | import android.content.Context; 6 | import android.content.pm.PackageManager; 7 | import android.database.Cursor; 8 | import android.graphics.Bitmap; 9 | import android.graphics.BitmapFactory; 10 | import android.graphics.Matrix; 11 | import android.net.Uri; 12 | import android.os.Build; 13 | import android.provider.MediaStore; 14 | import android.support.annotation.NonNull; 15 | import android.support.v4.app.ActivityCompat; 16 | import android.support.v4.content.ContextCompat; 17 | import android.util.Log; 18 | import android.widget.Toast; 19 | 20 | import org.apache.cordova.*; 21 | import org.json.JSONArray; 22 | import org.json.JSONException; 23 | import org.json.JSONObject; 24 | 25 | import java.io.ByteArrayOutputStream; 26 | import java.io.File; 27 | import java.io.FileOutputStream; 28 | import java.io.IOException; 29 | import java.util.ArrayList; 30 | import java.util.Collections; 31 | import java.util.Iterator; 32 | import java.util.List; 33 | 34 | public class GalleryAPI extends CordovaPlugin { 35 | public static final String ACTION_CHECK_PERMISSION = "checkPermission"; 36 | public static final String ACTION_GET_MEDIA = "getMedia"; 37 | public static final String ACTION_GET_MEDIA_THUMBNAIL = "getMediaThumbnail"; 38 | public static final String ACTION_GET_HQ_IMAGE_DATA = "getHQImageData"; 39 | public static final String ACTION_GET_ALBUMS = "getAlbums"; 40 | public static final String DIR_NAME = ".mendr"; 41 | public static final String SUB_DIR_NAME = ".mendr_hq"; 42 | 43 | private static final int BASE_SIZE = 300; 44 | 45 | private static BitmapFactory.Options ops = null; 46 | 47 | private static final int STORAGE_PERMISSIONS_REQUEST = 1; 48 | 49 | private CallbackContext cbc = null; 50 | 51 | @Override 52 | public boolean execute(String action, final JSONArray args, final CallbackContext callbackContext) throws JSONException { 53 | try { 54 | if (ACTION_GET_MEDIA.equals(action)) { 55 | cordova.getThreadPool().execute(new Runnable() { 56 | public void run() { 57 | try { 58 | JSONObject object = (JSONObject) args.get(0); 59 | ArrayOfObjects albums = getMedia(object.getString("title")); 60 | callbackContext.success(new JSONArray(albums)); 61 | } catch (Exception e) { 62 | e.printStackTrace(); 63 | callbackContext.error(e.getMessage()); 64 | } 65 | } 66 | }); 67 | 68 | return true; 69 | } else if (ACTION_CHECK_PERMISSION.equals(action)) { 70 | cordova.getThreadPool().execute(new Runnable() { 71 | public void run() { 72 | cbc = callbackContext; 73 | checkPermission(); 74 | } 75 | }); 76 | return true; 77 | } else if (ACTION_GET_MEDIA_THUMBNAIL.equals(action)) { 78 | cordova.getThreadPool().execute(new Runnable() { 79 | public void run() { 80 | try { 81 | JSONObject media = getMediaThumbnail((JSONObject) args.get(0)); 82 | callbackContext.success(media); 83 | } catch (Exception e) { 84 | e.printStackTrace(); 85 | callbackContext.error(e.getMessage()); 86 | } 87 | } 88 | }); 89 | return true; 90 | } else if (ACTION_GET_HQ_IMAGE_DATA.equals(action)) { 91 | cordova.getThreadPool().execute(new Runnable() { 92 | public void run() { 93 | try { 94 | File imagePath = getHQImageData((JSONObject) args.get(0)); 95 | callbackContext.success(imagePath.toString()); 96 | } catch (Exception e) { 97 | e.printStackTrace(); 98 | callbackContext.error(e.getMessage()); 99 | } 100 | } 101 | }); 102 | return true; 103 | } else if (ACTION_GET_ALBUMS.equals(action)) { 104 | cordova.getThreadPool().execute(new Runnable() { 105 | public void run() { 106 | try { 107 | ArrayOfObjects albums = getBuckets(); 108 | callbackContext.success(new JSONArray(albums)); 109 | } catch (Exception e) { 110 | e.printStackTrace(); 111 | callbackContext.error(e.getMessage()); 112 | } 113 | } 114 | }); 115 | 116 | return true; 117 | } 118 | callbackContext.error("Invalid action"); 119 | return false; 120 | } catch (Exception e) { 121 | e.printStackTrace(); 122 | callbackContext.error(e.getMessage()); 123 | return false; 124 | } 125 | } 126 | 127 | public ArrayOfObjects getBuckets() throws JSONException { 128 | Object columns = new Object() {{ 129 | put("id", MediaStore.Images.ImageColumns.BUCKET_ID); 130 | put("title", MediaStore.Images.ImageColumns.BUCKET_DISPLAY_NAME); 131 | }}; 132 | 133 | final ArrayOfObjects results = queryContentProvider(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, columns, "1) GROUP BY 1,(2"); 134 | 135 | Object collection = null; 136 | for (int i = 0; i < results.size(); i++) { 137 | collection = results.get(i); 138 | if (collection.getString("title").equals("Camera")) { 139 | results.remove(i); 140 | break; 141 | } 142 | } 143 | 144 | if (collection != null) 145 | results.add(0, collection); 146 | 147 | return results; 148 | } 149 | 150 | private ArrayOfObjects getMedia(String bucket) throws JSONException { 151 | Object columns = new Object() {{ 152 | put("int.id", MediaStore.Images.Media._ID); 153 | put("data", MediaStore.MediaColumns.DATA); 154 | put("int.date_added", MediaStore.Images.ImageColumns.DATE_ADDED); 155 | put("title", MediaStore.Images.ImageColumns.DISPLAY_NAME); 156 | put("int.height", MediaStore.Images.ImageColumns.HEIGHT); 157 | put("int.width", MediaStore.Images.ImageColumns.WIDTH); 158 | put("int.orientation", MediaStore.Images.ImageColumns.ORIENTATION); 159 | put("mime_type", MediaStore.Images.ImageColumns.MIME_TYPE); 160 | put("float.lat", MediaStore.Images.ImageColumns.LATITUDE); 161 | put("float.lon", MediaStore.Images.ImageColumns.LONGITUDE); 162 | put("int.size", MediaStore.Images.ImageColumns.SIZE); 163 | put("int.thumbnail_id", MediaStore.Images.ImageColumns.MINI_THUMB_MAGIC); 164 | }}; 165 | 166 | final ArrayOfObjects results = queryContentProvider(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, columns, "bucket_display_name = \"" + bucket + "\""); 167 | 168 | ArrayOfObjects temp = new ArrayOfObjects(); 169 | 170 | 171 | for (Object media : results) { 172 | media.put("thumbnail", ""); 173 | media.put("error", "false"); 174 | 175 | if (media.getInt("height") <= 0 || media.getInt("width") <= 0) { 176 | System.err.println(media); 177 | } else { 178 | temp.add(media); 179 | } 180 | } 181 | 182 | Collections.reverse(temp); 183 | return temp; 184 | } 185 | 186 | private void checkPermission() { 187 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 188 | List permissions = new ArrayList(); 189 | 190 | boolean isReadDenied = false; 191 | boolean isWriteDenied = false; 192 | 193 | if (ContextCompat.checkSelfPermission(this.getContext(), Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { 194 | if (ActivityCompat.shouldShowRequestPermissionRationale(this.cordova.getActivity(), Manifest.permission.READ_EXTERNAL_STORAGE)) 195 | isReadDenied = true; 196 | else 197 | permissions.add(Manifest.permission.READ_EXTERNAL_STORAGE); 198 | } 199 | 200 | if (ContextCompat.checkSelfPermission(this.getContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { 201 | if (ActivityCompat.shouldShowRequestPermissionRationale(this.cordova.getActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE)) 202 | isWriteDenied = true; 203 | else 204 | permissions.add(Manifest.permission.WRITE_EXTERNAL_STORAGE); 205 | } 206 | 207 | if (isReadDenied || isWriteDenied) { 208 | String message; 209 | 210 | if (isReadDenied && isWriteDenied) 211 | message = "Read and Write permissions are denied"; 212 | else if (isReadDenied) 213 | message = "Read permission is denied"; 214 | else 215 | message = "Write permission is denied"; 216 | 217 | sendCheckPermissionResult(false, message); 218 | } else if (permissions.size() > 0) { 219 | String[] pArray = new String[permissions.size()]; 220 | pArray = permissions.toArray(pArray); 221 | ActivityCompat.requestPermissions(this.cordova.getActivity(), pArray, STORAGE_PERMISSIONS_REQUEST); 222 | } else 223 | sendCheckPermissionResult(true, "Authorized"); 224 | } else 225 | sendCheckPermissionResult(true, "Authorized"); 226 | } 227 | 228 | public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { 229 | switch (requestCode) { 230 | case STORAGE_PERMISSIONS_REQUEST: { 231 | if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) 232 | sendCheckPermissionResult(true, "Authorized"); 233 | else 234 | sendCheckPermissionResult(false, "Denied"); 235 | return; 236 | } 237 | } 238 | } 239 | 240 | private void sendCheckPermissionResult(Boolean success, String message) { 241 | try { 242 | JSONObject result = new JSONObject(); 243 | result.put("success", success); 244 | result.put("message", message); 245 | cbc.success(result); 246 | } catch (Exception e) { 247 | e.printStackTrace(); 248 | cbc.error(e.getMessage()); 249 | } 250 | } 251 | 252 | private JSONObject getMediaThumbnail(JSONObject media) throws JSONException { 253 | 254 | File thumbnailPath = thumbnailPathFromMediaId(media.getString("id")); 255 | if (thumbnailPath.exists()) { 256 | System.out.println("Thumbnail Already Exists!!!. Not Creating New One"); 257 | media.put("thumbnail", thumbnailPath); 258 | } else { 259 | if (ops == null) { 260 | ops = new BitmapFactory.Options(); 261 | ops.inJustDecodeBounds = false; 262 | ops.inSampleSize = 1; 263 | } 264 | media.put("error", "true"); 265 | 266 | File image = new File(media.getString("data")); 267 | 268 | int sourceWidth = media.getInt("width"); 269 | int sourceHeight = media.getInt("height"); 270 | 271 | if (sourceHeight > 0 && sourceWidth > 0) { 272 | int destinationWidth, destinationHeight; 273 | 274 | if (sourceWidth > sourceHeight) { 275 | destinationHeight = BASE_SIZE; 276 | destinationWidth = (int) Math.ceil(destinationHeight * ((double) sourceWidth / sourceHeight)); 277 | } else { 278 | destinationWidth = BASE_SIZE; 279 | destinationHeight = (int) Math.ceil(destinationWidth * ((double) sourceHeight / sourceWidth)); 280 | } 281 | 282 | if (sourceWidth * sourceHeight > 600000 && sourceWidth * sourceHeight < 1000000) { 283 | ops.inSampleSize = 4; 284 | } else if (sourceWidth * sourceHeight > 1000000) { 285 | ops.inSampleSize = 8; 286 | } 287 | 288 | Bitmap originalImageBitmap = BitmapFactory.decodeFile(image.getAbsolutePath(), ops); //creating bitmap of original image 289 | 290 | if (originalImageBitmap == null) { 291 | ops.inSampleSize = 1; 292 | originalImageBitmap = BitmapFactory.decodeFile(image.getAbsolutePath(), ops); 293 | } 294 | 295 | if (originalImageBitmap != null) { 296 | 297 | if (destinationHeight <= 0 || destinationWidth <= 0) { 298 | System.out.println("destinationHeight: " + destinationHeight + " destinationWidth: " + destinationWidth); 299 | } 300 | 301 | Bitmap thumbnailBitmap = Bitmap.createScaledBitmap(originalImageBitmap, destinationWidth, destinationHeight, true); 302 | originalImageBitmap.recycle(); 303 | 304 | if (thumbnailBitmap != null) { 305 | int orientation = media.getInt("orientation"); 306 | if (orientation > 0) 307 | thumbnailBitmap = rotate(thumbnailBitmap, orientation); 308 | 309 | byte[] thumbnailData = getBytesFromBitmap(thumbnailBitmap); 310 | thumbnailBitmap.recycle(); 311 | if (thumbnailData != null) { 312 | FileOutputStream outStream; 313 | try { 314 | outStream = new FileOutputStream(thumbnailPath); 315 | outStream.write(thumbnailData); 316 | outStream.close(); 317 | } catch (IOException e) { 318 | Log.e("Mendr", "Couldn't write the thumbnail image data"); 319 | e.printStackTrace(); 320 | } 321 | 322 | if (thumbnailPath.exists()) { 323 | System.out.println("Thumbnail didn't Exists!!!. Created New One"); 324 | media.put("thumbnail", thumbnailPath); 325 | media.put("error", "false"); 326 | } 327 | } else 328 | Log.e("Mendr", "Couldn't convert thumbnail bitmap to byte array"); 329 | } else 330 | Log.e("Mendr", "Couldn't create the thumbnail bitmap"); 331 | } else 332 | Log.e("Mendr", "Couldn't decode the original image"); 333 | } else 334 | Log.e("Mendr", "Invalid Media!!! Image width or height is 0"); 335 | } 336 | 337 | return media; 338 | } 339 | 340 | private File getHQImageData(JSONObject media) throws JSONException { 341 | File imagePath = imagePathFromMediaId(media.getString("id")); 342 | 343 | BitmapFactory.Options ops = new BitmapFactory.Options(); 344 | ops.inJustDecodeBounds = false; 345 | ops.inSampleSize = 1; 346 | 347 | File image = new File(media.getString("data")); 348 | 349 | int sourceWidth = media.getInt("width"); 350 | int sourceHeight = media.getInt("height"); 351 | 352 | if (sourceHeight > 0 && sourceWidth > 0) { 353 | Bitmap originalImageBitmap = BitmapFactory.decodeFile(image.getAbsolutePath(), ops); //creating bitmap of original image 354 | 355 | if (originalImageBitmap != null) { 356 | int orientation = media.getInt("orientation"); 357 | if (orientation > 0) 358 | originalImageBitmap = rotate(originalImageBitmap, orientation); 359 | 360 | byte[] imageData = getBytesFromBitmap(originalImageBitmap); 361 | originalImageBitmap.recycle(); 362 | if (imageData != null) { 363 | FileOutputStream outStream; 364 | try { 365 | outStream = new FileOutputStream(imagePath); 366 | outStream.write(imageData); 367 | outStream.close(); 368 | } catch (IOException e) { 369 | Log.e("Mendr", "Couldn't write the image data"); 370 | e.printStackTrace(); 371 | } 372 | } 373 | } else 374 | Log.e("Mendr", "Couldn't decode the original image"); 375 | } else 376 | Log.e("Mendr", "Invalid Media!!! Image width or height is 0"); 377 | 378 | return imagePath; 379 | } 380 | 381 | private byte[] getBytesFromBitmap(Bitmap bitmap) { 382 | ByteArrayOutputStream stream = new ByteArrayOutputStream(); 383 | bitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream); 384 | return stream.toByteArray(); 385 | } 386 | 387 | private static Bitmap rotate(Bitmap source, int orientation) { 388 | Matrix matrix = new Matrix(); 389 | matrix.postRotate((float) orientation); 390 | return Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(), matrix, false); 391 | } 392 | 393 | private File thumbnailPathFromMediaId(String mediaId) { 394 | File thumbnailPath = null; 395 | 396 | String thumbnailName = mediaId + "_mthumb.png"; 397 | File dir = new File(this.getContext().getApplicationInfo().dataDir, DIR_NAME); 398 | if (!dir.exists()) { 399 | if (!dir.mkdirs()) { 400 | Log.e("Mendr", "Failed to create storage directory."); 401 | return thumbnailPath; 402 | } 403 | } 404 | 405 | thumbnailPath = new File(dir.getPath() + File.separator + thumbnailName); 406 | 407 | return thumbnailPath; 408 | } 409 | 410 | private File imagePathFromMediaId(String mediaId) { 411 | File imagePath = null; 412 | 413 | File rootDir = new File(this.getContext().getApplicationInfo().dataDir, DIR_NAME); 414 | File dir = new File(rootDir, SUB_DIR_NAME); 415 | 416 | //check if root directory exist 417 | if (rootDir.exists()) { 418 | //root directory exists 419 | if (dir.exists()) { 420 | //dir exists so deleting it 421 | deleteRecursive(dir); 422 | } 423 | 424 | if (!dir.mkdirs()) { 425 | Log.e("Mendr", "Failed to create hq storage directory."); 426 | return imagePath; 427 | } else { 428 | //dir created successfully 429 | } 430 | } else { 431 | //root directory doesn't exist 432 | //trying to create root directory 433 | if (!rootDir.mkdirs()) { 434 | Log.e("Mendr", "Failed to create root storage directory."); 435 | return imagePath; 436 | } else { 437 | //root dir created successfully 438 | if (!dir.mkdirs()) { 439 | Log.e("Mendr", "Failed to create hq storage directory."); 440 | return imagePath; 441 | } else { 442 | //dir created successfully 443 | } 444 | } 445 | } 446 | 447 | String imageName = mediaId + ".png"; 448 | imagePath = new File(dir.getPath() + File.separator + imageName); 449 | 450 | return imagePath; 451 | } 452 | 453 | void deleteRecursive(File fileOrDirectory) { 454 | if (fileOrDirectory.isDirectory()) 455 | for (File child : fileOrDirectory.listFiles()) 456 | deleteRecursive(child); 457 | 458 | fileOrDirectory.delete(); 459 | } 460 | 461 | private Context getContext() { 462 | return this.cordova.getActivity().getApplicationContext(); 463 | } 464 | 465 | private ArrayOfObjects queryContentProvider(Uri collection, Object columns, String whereClause) throws JSONException { 466 | final ArrayList columnNames = new ArrayList(); 467 | final ArrayList columnValues = new ArrayList(); 468 | 469 | Iterator iteratorFields = columns.keys(); 470 | 471 | while (iteratorFields.hasNext()) { 472 | String column = iteratorFields.next(); 473 | 474 | columnNames.add(column); 475 | columnValues.add("" + columns.getString(column)); 476 | } 477 | 478 | final Cursor cursor = getContext().getContentResolver().query(collection, columnValues.toArray(new String[columns.length()]), whereClause, null, null); 479 | final ArrayOfObjects buffer = new ArrayOfObjects(); 480 | 481 | if (cursor.moveToFirst()) { 482 | do { 483 | Object item = new Object(); 484 | 485 | for (String column : columnNames) { 486 | int columnIndex = cursor.getColumnIndex(columns.get(column).toString()); 487 | 488 | if (column.startsWith("int.")) { 489 | item.put(column.substring(4), cursor.getInt(columnIndex)); 490 | if (column.substring(4).equals("width") && item.getInt("width") == 0) { 491 | System.err.println("cursor: " + cursor.getInt(columnIndex)); 492 | 493 | } 494 | } else if (column.startsWith("float.")) { 495 | item.put(column.substring(6), cursor.getFloat(columnIndex)); 496 | } else { 497 | item.put(column, cursor.getString(columnIndex)); 498 | } 499 | } 500 | 501 | buffer.add(item); 502 | } 503 | while (cursor.moveToNext()); 504 | } 505 | 506 | cursor.close(); 507 | 508 | return buffer; 509 | } 510 | 511 | private class Object extends JSONObject { 512 | 513 | } 514 | 515 | private class ArrayOfObjects extends ArrayList { 516 | 517 | } 518 | } -------------------------------------------------------------------------------- /src/ios/GalleryAPI.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @interface GalleryAPI : CDVPlugin 5 | 6 | - (void) checkPermission:(CDVInvokedUrlCommand*)command; 7 | 8 | - (void) getAlbums:(CDVInvokedUrlCommand*)command; 9 | 10 | - (void) getMedia:(CDVInvokedUrlCommand*)command; 11 | 12 | - (void) getMediaThumbnail:(CDVInvokedUrlCommand*)command; 13 | 14 | - (void) getHQImageData:(CDVInvokedUrlCommand*)command; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /src/ios/GalleryAPI.m: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | #import "GalleryAPI.h" 4 | 5 | #define kDirectoryName @"mendr" 6 | 7 | @interface GalleryAPI () 8 | 9 | @end 10 | 11 | @implementation GalleryAPI 12 | 13 | - (void) checkPermission:(CDVInvokedUrlCommand*)command { 14 | [self.commandDelegate runInBackground:^{ 15 | __block NSDictionary *result; 16 | PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus]; 17 | 18 | if (status == PHAuthorizationStatusAuthorized) { 19 | // Access has been granted. 20 | result = @{@"success":@(true), @"message":@"Authorized"}; 21 | [self.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:result] 22 | callbackId:command.callbackId]; 23 | } 24 | 25 | else if (status == PHAuthorizationStatusDenied) { 26 | // Access has been denied. 27 | result = @{@"success":@(false), @"message":@"Denied"}; 28 | [self.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:result] 29 | callbackId:command.callbackId]; 30 | } 31 | 32 | else if (status == PHAuthorizationStatusNotDetermined) { 33 | 34 | // Access has not been determined. 35 | [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) { 36 | 37 | if (status == PHAuthorizationStatusAuthorized) { 38 | // Access has been granted. 39 | result = @{@"success":@(true), @"message":@"Authorized"}; 40 | [self.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:result] 41 | callbackId:command.callbackId]; 42 | } 43 | 44 | else { 45 | // Access has been denied. 46 | result = @{@"success":@(false), @"message":@"Denied"}; 47 | [self.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:result] 48 | callbackId:command.callbackId]; 49 | } 50 | }]; 51 | } 52 | 53 | else if (status == PHAuthorizationStatusRestricted) { 54 | // Restricted access - normally won't happen. 55 | result = @{@"success":@(false), @"message":@"Restricted"}; 56 | [self.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:result] 57 | callbackId:command.callbackId]; 58 | } 59 | }]; 60 | } 61 | 62 | - (void)getAlbums:(CDVInvokedUrlCommand*)command 63 | { 64 | [self.commandDelegate runInBackground:^{ 65 | NSDictionary* subtypes = [GalleryAPI subtypes]; 66 | __block NSMutableArray* albums = [[NSMutableArray alloc] init]; 67 | __block NSDictionary* cameraRoll; 68 | 69 | NSArray* collectionTypes = @[ 70 | @{ @"title" : @"smart", 71 | @"type" : [NSNumber numberWithInteger:PHAssetCollectionTypeSmartAlbum] }, 72 | @{ @"title" : @"album", 73 | @"type" : [NSNumber numberWithInteger:PHAssetCollectionTypeAlbum] } 74 | ]; 75 | 76 | for (NSDictionary* collectionType in collectionTypes) { 77 | [[PHAssetCollection fetchAssetCollectionsWithType:[collectionType[@"type"] integerValue] subtype:PHAssetCollectionSubtypeAny options:nil] enumerateObjectsUsingBlock:^(PHAssetCollection* collection, NSUInteger idx, BOOL* stop) { 78 | if (collection != nil && collection.localizedTitle != nil && collection.localIdentifier != nil && ([subtypes.allKeys indexOfObject:@(collection.assetCollectionSubtype)] != NSNotFound)) { 79 | PHFetchResult* result = [PHAsset fetchAssetsInAssetCollection:collection 80 | options:nil]; 81 | if (result.count > 0) { 82 | if ([collection.localizedTitle isEqualToString:@"Camera Roll"] && collection.assetCollectionType == PHAssetCollectionTypeSmartAlbum) { 83 | cameraRoll = @{ 84 | @"id" : collection.localIdentifier, 85 | @"title" : collection.localizedTitle, 86 | @"type" : subtypes[@(collection.assetCollectionSubtype)], 87 | @"assets" : [NSString stringWithFormat:@"%ld", (long)collection.estimatedAssetCount] 88 | }; 89 | } 90 | else { 91 | [albums addObject:@{ 92 | @"id" : collection.localIdentifier, 93 | @"title" : collection.localizedTitle, 94 | @"type" : subtypes[@(collection.assetCollectionSubtype)], 95 | @"assets" : [NSString stringWithFormat:@"%ld", (long)collection.estimatedAssetCount] 96 | }]; 97 | } 98 | } 99 | } 100 | }]; 101 | } 102 | 103 | if (cameraRoll) 104 | [albums insertObject:cameraRoll atIndex:0]; 105 | 106 | CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArray:albums]; 107 | 108 | [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; 109 | }]; 110 | } 111 | 112 | - (void)getMedia:(CDVInvokedUrlCommand*)command 113 | { 114 | [self.commandDelegate runInBackground:^{ 115 | NSDictionary* subtypes = [GalleryAPI subtypes]; 116 | NSDictionary* album = [command argumentAtIndex:0]; 117 | __block NSMutableArray* assets = [[NSMutableArray alloc] init]; 118 | __block PHImageRequestOptions* options = [[PHImageRequestOptions alloc] init]; 119 | options.synchronous = YES; 120 | options.resizeMode = PHImageRequestOptionsResizeModeFast; 121 | options.networkAccessAllowed = true; 122 | 123 | PHFetchResult* collections = [PHAssetCollection fetchAssetCollectionsWithLocalIdentifiers:@[ album[@"id"] ] 124 | options:nil]; 125 | 126 | if (collections && collections.count > 0) { 127 | PHAssetCollection* collection = collections[0]; 128 | [[PHAsset fetchAssetsInAssetCollection:collection 129 | options:nil] enumerateObjectsUsingBlock:^(PHAsset* obj, NSUInteger idx, BOOL* stop) { 130 | if (obj.mediaType == PHAssetMediaTypeImage) 131 | [assets addObject:@{ 132 | @"id" : obj.localIdentifier, 133 | @"title" : @"", 134 | @"orientation" : @"up", 135 | @"lat" : @4, 136 | @"lng" : @5, 137 | @"width" : [NSNumber numberWithFloat:obj.pixelWidth], 138 | @"height" : [NSNumber numberWithFloat:obj.pixelHeight], 139 | @"size" : @0, 140 | @"data" : @"", 141 | @"thumbnail" : @"", 142 | @"error" : @"false", 143 | @"type" : subtypes[@(collection.assetCollectionSubtype)] 144 | }]; 145 | }]; 146 | } 147 | 148 | NSArray* reversedAssests = [[assets reverseObjectEnumerator] allObjects]; 149 | 150 | CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArray:reversedAssests]; 151 | 152 | [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; 153 | }]; 154 | } 155 | 156 | - (void)getMediaThumbnail:(CDVInvokedUrlCommand*)command 157 | { 158 | // Check command.arguments here. 159 | [self.commandDelegate runInBackground:^{ 160 | 161 | PHImageRequestOptions* options = [PHImageRequestOptions new]; 162 | options.synchronous = YES; 163 | options.resizeMode = PHImageRequestOptionsResizeModeFast; 164 | options.networkAccessAllowed = true; 165 | 166 | NSMutableDictionary* media = [command argumentAtIndex:0]; 167 | 168 | NSString* imageId = [media[@"id"] stringByReplacingOccurrencesOfString:@"/" withString:@"^"]; 169 | NSString* docsPath = [NSTemporaryDirectory() stringByStandardizingPath]; 170 | NSString* thumbnailPath = [NSString stringWithFormat:@"%@/%@_mthumb.png", docsPath, imageId]; 171 | 172 | NSFileManager* fileMgr = [[NSFileManager alloc] init]; 173 | 174 | media[@"thumbnail"] = thumbnailPath; 175 | if ([fileMgr fileExistsAtPath:thumbnailPath]) 176 | NSLog(@"file exist"); 177 | else { 178 | NSLog(@"file doesn't exist"); 179 | media[@"error"] = @"true"; 180 | 181 | PHFetchResult* assets = [PHAsset fetchAssetsWithLocalIdentifiers:@[ media[@"id"] ] 182 | options:nil]; 183 | if (assets && assets.count > 0) { 184 | [[PHImageManager defaultManager] requestImageForAsset:assets[0] 185 | targetSize:CGSizeMake(300, 300) 186 | contentMode:PHImageContentModeAspectFill 187 | options:options 188 | resultHandler:^(UIImage* _Nullable result, NSDictionary* _Nullable info) { 189 | if (result) { 190 | NSError* err = nil; 191 | if ([UIImagePNGRepresentation(result) writeToFile:thumbnailPath 192 | options:NSAtomicWrite 193 | error:&err]) 194 | media[@"error"] = @"false"; 195 | else { 196 | if (err) { 197 | media[@"thumbnail"] = @""; 198 | NSLog(@"Error saving image: %@", [err localizedDescription]); 199 | } 200 | } 201 | } 202 | }]; 203 | } 204 | else { 205 | if ([media[@"type"] isEqualToString:@"PHAssetCollectionSubtypeAlbumMyPhotoStream"]) { 206 | 207 | [[PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum 208 | subtype:PHAssetCollectionSubtypeAlbumMyPhotoStream 209 | options:nil] enumerateObjectsUsingBlock:^(PHAssetCollection* collection, NSUInteger idx, BOOL* stop) { 210 | if (collection != nil && collection.localizedTitle != nil && collection.localIdentifier != nil) { 211 | [[PHAsset fetchAssetsInAssetCollection:collection 212 | options:nil] enumerateObjectsUsingBlock:^(PHAsset* _Nonnull obj, NSUInteger idx, BOOL* _Nonnull stop) { 213 | if ([obj.localIdentifier isEqualToString:media[@"id"]]) { 214 | [[PHImageManager defaultManager] requestImageForAsset:obj 215 | targetSize:CGSizeMake(300, 300) 216 | contentMode:PHImageContentModeAspectFill 217 | options:options 218 | resultHandler:^(UIImage* _Nullable result, NSDictionary* _Nullable info) { 219 | if (result) { 220 | NSError* err = nil; 221 | if ([UIImagePNGRepresentation(result) writeToFile:thumbnailPath 222 | options:NSAtomicWrite 223 | error:&err]) 224 | media[@"error"] = @"false"; 225 | else { 226 | if (err) { 227 | media[@"thumbnail"] = @""; 228 | NSLog(@"Error saving image: %@", [err localizedDescription]); 229 | } 230 | } 231 | } 232 | }]; 233 | } 234 | }]; 235 | } 236 | }]; 237 | } 238 | } 239 | } 240 | 241 | CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK 242 | messageAsDictionary:media]; 243 | 244 | [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; 245 | }]; 246 | } 247 | 248 | - (void)getHQImageData:(CDVInvokedUrlCommand*)command 249 | { 250 | [self.commandDelegate runInBackground:^{ 251 | 252 | PHImageRequestOptions* options = [PHImageRequestOptions new]; 253 | options.synchronous = YES; 254 | options.resizeMode = PHImageRequestOptionsResizeModeNone; 255 | options.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat; 256 | options.networkAccessAllowed = true; 257 | 258 | NSString* mediaURL = nil; 259 | 260 | NSMutableDictionary* media = [command argumentAtIndex:0]; 261 | 262 | NSString* docsPath = [[NSTemporaryDirectory() stringByStandardizingPath] stringByAppendingPathComponent:kDirectoryName]; 263 | NSError* error; 264 | 265 | NSFileManager* fileMgr = [NSFileManager new]; 266 | 267 | BOOL canCreateDirectory = false; 268 | 269 | if ([fileMgr fileExistsAtPath:docsPath]) { 270 | if (![fileMgr removeItemAtPath:docsPath 271 | error:&error]) 272 | NSLog(@"Delete directory error: %@", error); 273 | else 274 | canCreateDirectory = true; 275 | } 276 | else 277 | canCreateDirectory = true; 278 | 279 | BOOL canWriteFile = true; 280 | 281 | if (canCreateDirectory) { 282 | if (![[NSFileManager defaultManager] createDirectoryAtPath:docsPath 283 | withIntermediateDirectories:NO 284 | attributes:nil 285 | error:&error]) { 286 | NSLog(@"Create directory error: %@", error); 287 | canWriteFile = false; 288 | } 289 | } 290 | 291 | if (canWriteFile) { 292 | NSString* imageId = [media[@"id"] stringByReplacingOccurrencesOfString:@"/" withString:@"^"]; 293 | NSString* imagePath = [NSString stringWithFormat:@"%@/%@.jpg", docsPath, imageId]; 294 | // NSString* imagePath = [NSString stringWithFormat:@"%@/temp.png", docsPath]; 295 | 296 | __block NSData* mediaData; 297 | mediaURL = imagePath; 298 | 299 | PHFetchResult* assets = [PHAsset fetchAssetsWithLocalIdentifiers:@[ media[@"id"] ] 300 | options:nil]; 301 | if (assets && assets.count > 0) { 302 | [[PHImageManager defaultManager] requestImageDataForAsset:assets[0] 303 | options:options 304 | resultHandler:^(NSData* _Nullable imageData, NSString* _Nullable dataUTI, UIImageOrientation orientation, NSDictionary* _Nullable info) { 305 | if (imageData) { 306 | // Processing Image Data if needed 307 | // if (orientation == UIImageOrientationUp) { 308 | //BUGFIX: Landscape images was not rendering 309 | // mediaData = imageData; 310 | // } 311 | // else { 312 | UIImage* image = [UIImage imageWithData:imageData]; 313 | image = [self fixrotation:image]; 314 | mediaData = UIImageJPEGRepresentation(image, 1); 315 | // } 316 | 317 | //writing image to a file 318 | NSError* err = nil; 319 | if ([mediaData writeToFile:imagePath 320 | options:NSAtomicWrite 321 | error:&err]) { 322 | // media[@"error"] = @"false"; 323 | } 324 | else { 325 | if (err) { 326 | // media[@"thumbnail"] = @""; 327 | NSLog(@"Error saving image: %@", [err localizedDescription]); 328 | } 329 | } 330 | } else { 331 | @autoreleasepool { 332 | PHAsset *asset = assets[0]; 333 | [[PHImageManager defaultManager] requestImageForAsset:asset 334 | targetSize:CGSizeMake(asset.pixelWidth, asset.pixelHeight) 335 | contentMode:PHImageContentModeAspectFit 336 | options:options 337 | resultHandler:^(UIImage* _Nullable result, NSDictionary* _Nullable info) { 338 | if (result) 339 | mediaData =UIImageJPEGRepresentation(result, 1); 340 | NSError* err = nil; 341 | if ([mediaData writeToFile:imagePath 342 | options:NSAtomicWrite 343 | error:&err]) { 344 | // media[@"error"] = @"false"; 345 | } 346 | else { 347 | if (err) { 348 | // media[@"thumbnail"] = @""; 349 | NSLog(@"Error saving image: %@", [err localizedDescription]); 350 | } 351 | } 352 | }]; 353 | }; 354 | } 355 | }]; 356 | 357 | } 358 | else { 359 | if ([media[@"type"] isEqualToString:@"PHAssetCollectionSubtypeAlbumMyPhotoStream"]) { 360 | 361 | [[PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum 362 | subtype:PHAssetCollectionSubtypeAlbumMyPhotoStream 363 | options:nil] enumerateObjectsUsingBlock:^(PHAssetCollection* collection, NSUInteger idx, BOOL* stop) { 364 | if (collection != nil && collection.localizedTitle != nil && collection.localIdentifier != nil) { 365 | [[PHAsset fetchAssetsInAssetCollection:collection 366 | options:nil] enumerateObjectsUsingBlock:^(PHAsset* _Nonnull obj, NSUInteger idx, BOOL* _Nonnull stop) { 367 | if ([obj.localIdentifier isEqualToString:media[@"id"]]) { 368 | [[PHImageManager defaultManager] requestImageDataForAsset:obj 369 | options:options 370 | resultHandler:^(NSData* _Nullable imageData, NSString* _Nullable dataUTI, UIImageOrientation orientation, NSDictionary* _Nullable info) { 371 | if (imageData) { 372 | // Processing Image Data if needed 373 | // if (orientation == UIImageOrientationUp) { 374 | //BUGFIX: Landscape images was not rendering 375 | // mediaData = imageData; 376 | // } 377 | // else { 378 | UIImage* image = [UIImage imageWithData:imageData]; 379 | image = [self fixrotation:image]; 380 | mediaData = UIImageJPEGRepresentation(image, 1); 381 | // } 382 | 383 | //writing image to a file 384 | NSError* err = nil; 385 | if ([mediaData writeToFile:imagePath 386 | options:NSAtomicWrite 387 | error:&err]) { 388 | // media[@"error"] = @"false"; 389 | } 390 | else { 391 | if (err) { 392 | // media[@"thumbnail"] = @""; 393 | NSLog(@"Error saving image: %@", [err localizedDescription]); 394 | } 395 | } 396 | } 397 | }]; 398 | } 399 | }]; 400 | } 401 | }]; 402 | } 403 | } 404 | } 405 | 406 | CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:mediaURL ? CDVCommandStatus_OK : CDVCommandStatus_ERROR 407 | messageAsString:mediaURL]; 408 | 409 | [self.commandDelegate sendPluginResult:pluginResult 410 | callbackId:command.callbackId]; 411 | }]; 412 | } 413 | 414 | + (NSDictionary*)subtypes 415 | { 416 | NSDictionary* subtypes = @{ @(PHAssetCollectionSubtypeAlbumRegular) : @"PHAssetCollectionSubtypeAlbumRegular", 417 | @(PHAssetCollectionSubtypeAlbumImported) : @"PHAssetCollectionSubtypeAlbumImported", 418 | @(PHAssetCollectionSubtypeAlbumMyPhotoStream) : @"PHAssetCollectionSubtypeAlbumMyPhotoStream", 419 | @(PHAssetCollectionSubtypeAlbumCloudShared) : @"PHAssetCollectionSubtypeAlbumCloudShared", 420 | @(PHAssetCollectionSubtypeSmartAlbumFavorites) : @"PHAssetCollectionSubtypeSmartAlbumFavorites", 421 | @(PHAssetCollectionSubtypeSmartAlbumRecentlyAdded) : @"PHAssetCollectionSubtypeSmartAlbumRecentlyAdded", 422 | @(PHAssetCollectionSubtypeSmartAlbumUserLibrary) : @"PHAssetCollectionSubtypeSmartAlbumUserLibrary", 423 | @(PHAssetCollectionSubtypeSmartAlbumSelfPortraits) : @"PHAssetCollectionSubtypeSmartAlbumSelfPortraits", 424 | @(PHAssetCollectionSubtypeSmartAlbumScreenshots) : @"PHAssetCollectionSubtypeSmartAlbumScreenshots", 425 | }; 426 | return subtypes; 427 | } 428 | 429 | - (UIImage*)fixrotation:(UIImage*)image 430 | { 431 | 432 | if (image.imageOrientation == UIImageOrientationUp) 433 | return image; 434 | CGAffineTransform transform = CGAffineTransformIdentity; 435 | 436 | switch (image.imageOrientation) { 437 | case UIImageOrientationDown: 438 | case UIImageOrientationDownMirrored: 439 | transform = CGAffineTransformTranslate(transform, image.size.width, image.size.height); 440 | transform = CGAffineTransformRotate(transform, M_PI); 441 | break; 442 | 443 | case UIImageOrientationLeft: 444 | case UIImageOrientationLeftMirrored: 445 | transform = CGAffineTransformTranslate(transform, image.size.width, 0); 446 | transform = CGAffineTransformRotate(transform, M_PI_2); 447 | break; 448 | 449 | case UIImageOrientationRight: 450 | case UIImageOrientationRightMirrored: 451 | transform = CGAffineTransformTranslate(transform, 0, image.size.height); 452 | transform = CGAffineTransformRotate(transform, -M_PI_2); 453 | break; 454 | case UIImageOrientationUp: 455 | case UIImageOrientationUpMirrored: 456 | break; 457 | } 458 | 459 | switch (image.imageOrientation) { 460 | case UIImageOrientationUpMirrored: 461 | case UIImageOrientationDownMirrored: 462 | transform = CGAffineTransformTranslate(transform, image.size.width, 0); 463 | transform = CGAffineTransformScale(transform, -1, 1); 464 | break; 465 | 466 | case UIImageOrientationLeftMirrored: 467 | case UIImageOrientationRightMirrored: 468 | transform = CGAffineTransformTranslate(transform, image.size.height, 0); 469 | transform = CGAffineTransformScale(transform, -1, 1); 470 | break; 471 | case UIImageOrientationUp: 472 | case UIImageOrientationDown: 473 | case UIImageOrientationLeft: 474 | case UIImageOrientationRight: 475 | break; 476 | } 477 | 478 | // Now we draw the underlying CGImage into a new context, applying the transform 479 | // calculated above. 480 | CGContextRef ctx = CGBitmapContextCreate(NULL, image.size.width, image.size.height, 481 | CGImageGetBitsPerComponent(image.CGImage), 0, 482 | CGImageGetColorSpace(image.CGImage), 483 | CGImageGetBitmapInfo(image.CGImage)); 484 | CGContextConcatCTM(ctx, transform); 485 | switch (image.imageOrientation) { 486 | case UIImageOrientationLeft: 487 | case UIImageOrientationLeftMirrored: 488 | case UIImageOrientationRight: 489 | case UIImageOrientationRightMirrored: 490 | // Grr... 491 | CGContextDrawImage(ctx, CGRectMake(0, 0, image.size.height, image.size.width), image.CGImage); 492 | break; 493 | 494 | default: 495 | CGContextDrawImage(ctx, CGRectMake(0, 0, image.size.width, image.size.height), image.CGImage); 496 | break; 497 | } 498 | 499 | // And now we just create a new UIImage from the drawing context 500 | CGImageRef cgimg = CGBitmapContextCreateImage(ctx); 501 | UIImage* img = [UIImage imageWithCGImage:cgimg]; 502 | CGContextRelease(ctx); 503 | CGImageRelease(cgimg); 504 | return img; 505 | } 506 | 507 | + (NSString*)cordovaVersion 508 | { 509 | return CDV_VERSION; 510 | } 511 | 512 | @end 513 | -------------------------------------------------------------------------------- /www/gallery-api.js: -------------------------------------------------------------------------------- 1 | 2 | function GalleryAPI() 3 | { 4 | 5 | } 6 | 7 | GalleryAPI.prototype.checkPermission = function(successCallback, errorCallback) { 8 | cordova.exec( 9 | successCallback, 10 | errorCallback, 11 | 'GalleryAPI', 12 | 'checkPermission', 13 | [] 14 | ); 15 | }; 16 | 17 | 18 | GalleryAPI.prototype.getAlbums = function(successCallback, errorCallback) { 19 | cordova.exec( 20 | successCallback, 21 | errorCallback, 22 | 'GalleryAPI', 23 | 'getAlbums', 24 | [] 25 | ); 26 | }; 27 | 28 | GalleryAPI.prototype.getMedia = function(albumName, successCallback, errorCallback) { 29 | cordova.exec( 30 | successCallback, 31 | errorCallback, 32 | 'GalleryAPI', 33 | 'getMedia', 34 | [albumName] 35 | ); 36 | }; 37 | 38 | GalleryAPI.prototype.getMediaThumbnail = function(media, successCallback, errorCallback) { 39 | cordova.exec( 40 | successCallback, 41 | errorCallback, 42 | 'GalleryAPI', 43 | 'getMediaThumbnail', 44 | [media] 45 | ); 46 | }; 47 | 48 | GalleryAPI.prototype.getHQImageData = function(media, successCallback, errorCallback) { 49 | cordova.exec( 50 | successCallback, 51 | errorCallback, 52 | 'GalleryAPI', 53 | 'getHQImageData', 54 | [media] 55 | ); 56 | }; 57 | 58 | module.exports = new GalleryAPI(); 59 | --------------------------------------------------------------------------------