├── .gitignore ├── CONTRIBUTING.md ├── LICENSE ├── Readme.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── github │ │ └── angads25 │ │ └── filepickerdemo │ │ ├── FileListAdapter.java │ │ ├── FilePickerApplication.java │ │ ├── ListItem.java │ │ ├── MainActivity.java │ │ └── SettingsActivity.java │ └── res │ ├── drawable-hdpi │ └── ic_action_settings.png │ ├── drawable-mdpi │ └── ic_action_settings.png │ ├── drawable-xhdpi │ └── ic_action_settings.png │ ├── drawable-xxhdpi │ └── ic_action_settings.png │ ├── drawable-xxxhdpi │ └── ic_action_settings.png │ ├── drawable │ └── ic_up_navigation.png │ ├── layout │ ├── activity_main.xml │ ├── file_list_item.xml │ └── toolbar.xml │ ├── menu │ └── main_menu.xml │ ├── mipmap-hdpi │ └── ic_launcher.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ └── ic_launcher.png │ ├── mipmap-xxhdpi │ └── ic_launcher.png │ ├── mipmap-xxxhdpi │ └── ic_launcher.png │ ├── values-de │ └── strings.xml │ ├── values-fr │ └── strings.xml │ ├── values-w820dp │ └── dimens.xml │ ├── values-zh-rTW │ └── strings.xml │ ├── values │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml │ └── xml │ └── pref_general.xml ├── build.gradle ├── crowdin.yml ├── filepicker ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── github │ │ └── angads25 │ │ └── filepicker │ │ ├── controller │ │ ├── DialogSelectionListener.java │ │ ├── NotifyItemChecked.java │ │ └── adapters │ │ │ └── FileListAdapter.java │ │ ├── model │ │ ├── DialogConfigs.java │ │ ├── DialogProperties.java │ │ ├── FileListItem.java │ │ └── MarkedItemList.java │ │ ├── utils │ │ ├── ColorUtils.java │ │ ├── ExtensionFilter.java │ │ └── Utility.java │ │ └── view │ │ ├── FilePickerDialog.java │ │ └── FilePickerPreference.java │ └── res │ ├── anim │ ├── marked_item_animation.xml │ └── unmarked_item_animation.xml │ ├── drawable │ ├── bottom_shadow.9.png │ ├── ic_directory_parent.xml │ ├── ic_type_file.xml │ └── ic_type_folder.xml │ ├── layout-v21 │ ├── dialog_file_list_item.xml │ └── dialog_header.xml │ ├── layout │ ├── dialog_file_list.xml │ ├── dialog_file_list_item.xml │ ├── dialog_footer.xml │ ├── dialog_header.xml │ └── dialog_main.xml │ ├── values-ar │ ├── arrays.xml │ └── strings.xml │ ├── values-az │ ├── arrays.xml │ └── strings.xml │ ├── values-bg │ ├── arrays.xml │ └── strings.xml │ ├── values-de │ ├── arrays.xml │ └── strings.xml │ ├── values-es │ ├── arrays.xml │ └── strings.xml │ ├── values-fr │ ├── arrays.xml │ └── strings.xml │ ├── values-it │ ├── arrays.xml │ └── strings.xml │ ├── values-ja │ ├── arrays.xml │ └── strings.xml │ ├── values-ko │ ├── arrays.xml │ └── strings.xml │ ├── values-pl │ ├── arrays.xml │ └── strings.xml │ ├── values-pt-rBR │ ├── arrays.xml │ └── strings.xml │ ├── values-ru │ ├── arrays.xml │ └── strings.xml │ ├── values-sv-rSE │ ├── arrays.xml │ └── strings.xml │ ├── values-tr │ ├── arrays.xml │ └── strings.xml │ ├── values-uk │ ├── arrays.xml │ └── strings.xml │ ├── values-vi │ ├── arrays.xml │ └── strings.xml │ ├── values-w820dp │ └── dimens.xml │ ├── values-zh-rCN │ ├── arrays.xml │ └── strings.xml │ ├── values-zh-rTW │ ├── arrays.xml │ └── strings.xml │ └── values │ ├── arrays.xml │ ├── attrs.xml │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── screenshots ├── performance_overdraw.png ├── profile_gpu_rendering.png ├── theme_black.png ├── theme_device_default.png ├── theme_holo.png ├── theme_holo_light.png └── theme_material.png └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | # [Android] ======================== 2 | # Built application files 3 | *.apk 4 | *.ap_ 5 | 6 | # Files for the Dalvik VM 7 | *.dex 8 | 9 | # Java class files 10 | *.class 11 | 12 | # Generated files 13 | bin/ 14 | gen/ 15 | 16 | # Gradle files 17 | .gradle/ 18 | build/ 19 | /*/build/ 20 | .gradletasknamecache 21 | 22 | # Local configuration file (sdk path, etc) 23 | local.properties 24 | 25 | # Proguard folder generated by Eclipse 26 | proguard/ 27 | 28 | # Log Files 29 | *.log 30 | 31 | 32 | ## Directory-based project format: 33 | .idea/ 34 | 35 | ## File-based project format: 36 | *.ipr 37 | *.iws 38 | 39 | ## Plugin-specific files: 40 | 41 | # IntelliJ 42 | out/ 43 | 44 | # mpeltonen/sbt-idea plugin 45 | .idea_modules/ 46 | 47 | # JIRA plugin 48 | atlassian-ide-plugin.xml 49 | 50 | # Crashlytics plugin (for Android Studio and IntelliJ) 51 | com_crashlytics_export_strings.xml 52 | 53 | 54 | # [Maven] ======================== 55 | target/ 56 | pom.xml.tag 57 | pom.xml.releaseBackup 58 | pom.xml.versionsBackup 59 | pom.xml.next 60 | release.properties 61 | 62 | 63 | # [Gradle-Android] ======================== 64 | # Ignore Gradle GUI config 65 | gradle-app.setting 66 | 67 | # Properties 68 | gradle.properties 69 | 70 | # Mobile Tools for Java (J2ME) 71 | .mtj.tmp/ 72 | 73 | # Package Files # 74 | *.war 75 | *.ear 76 | 77 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 78 | hs_err_pid* 79 | 80 | # Misc 81 | /.idea/workspace.xml 82 | /.idea/libraries 83 | .DS_Store 84 | /captures 85 | **/*.iml -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to become a contributor and submit your own code 2 | 3 | ## Contributor License Agreements 4 | 5 | We'd love to accept your sample apps and patches! Before we can take them, we 6 | have to jump a couple of legal hurdles. 7 | 8 | Please fill out either the individual or corporate Contributor License Agreement (CLA). 9 | 10 | * If you are an individual writing original source code and you're sure you 11 | own the intellectual property, then you'll need to sign an [individual CLA] 12 | (https://cla.developers.google.com). 13 | * If you work for a company that wants to allow you to contribute your work, 14 | then you'll need to sign a [corporate CLA] 15 | (https://cla.developers.google.com). 16 | 17 | Follow either of the two links above to access the appropriate CLA and 18 | instructions for how to sign and return it. Once we receive it, we'll be able to 19 | accept your pull requests. 20 | 21 | ## Contributing A Patch 22 | 23 | 1. Submit an issue describing your proposed change to the repo in question. 24 | 2. The repo owner will respond to your issue promptly. 25 | 3. If your proposed change is accepted, and you haven't already done so, sign a 26 | Contributor License Agreement (see details above). 27 | 4. Fork the desired repo, develop and test your code changes. 28 | 5. Ensure that your code adheres to the existing style in the sample to which 29 | you are contributing. Refer to the 30 | [Android Code Style Guide] 31 | (https://source.android.com/source/code-style.html) for the 32 | recommended coding standards for this organization. 33 | 6. Ensure that your code has an appropriate set of unit tests which all pass. 34 | 7. Submit a pull request. -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # FilePicker 2 | Super Lite Android Library to select files/directories from Device Storage. 3 | 4 | ### Developed by 5 | [Angad Singh](https://www.github.com/angads25) ([@angads25](https://www.twitter.com/angads25)) 6 | 7 | ### Benchmark: 8 | [![API](https://img.shields.io/badge/API-9%2B-brightgreen.svg?style=flat)](https://android-arsenal.com/api?level=9) 9 | 10 | ### Where to Find: 11 | [ ![Download](https://api.bintray.com/packages/angads25/maven/filepicker/images/download.svg) ](https://bintray.com/angads25/maven/filepicker/_latestVersion) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.github.angads25/filepicker/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.github.angads25/filepicker) [![Android Arsenal](https://img.shields.io/badge/Android%20Arsenal-FilePicker-blue.svg?style=flat)](http://android-arsenal.com/details/1/3950) 12 | 13 | ### Read all about internal classes and functions in the [wiki](https://github.com/Angads25/android-filepicker/wiki). 14 | 15 | ### Features 16 | 17 | * Easy to Implement. 18 | * No permissions required. 19 | * Files, Directory Selection. 20 | * Single or Multiple File selection. 21 | 22 | ### Installation 23 | 24 | * Library is also Available in MavenCentral, So just put this in your app dependencies to use it: 25 | ```gradle 26 | compile 'com.github.angads25:filepicker:1.1.1' 27 | ``` 28 | 29 | ### Usage 30 | ## FilePickerDialog 31 | 1. Start by creating an instance of `DialogProperties`. 32 | 33 | ```java 34 | DialogProperties properties = new DialogProperties(); 35 | ``` 36 | 37 | Now 'DialogProperties' has certain parameters. 38 | 39 | 2. Assign values to each Dialog Property using `DialogConfig` class. 40 | 41 | ```java 42 | properties.selection_mode = DialogConfigs.SINGLE_MODE; 43 | properties.selection_type = DialogConfigs.FILE_SELECT; 44 | properties.root = new File(DialogConfigs.DEFAULT_DIR); 45 | properties.error_dir = new File(DialogConfigs.DEFAULT_DIR); 46 | properties.offset = new File(DialogConfigs.DEFAULT_DIR); 47 | properties.extensions = null; 48 | ``` 49 | 50 | 3. Next create an instance of `FilePickerDialog`, and pass `Context` and `DialogProperties` references as parameters. Optional: You can change the title of dialog. Default is current directory name. Set the positive button string. Default is Select. Set the negative button string. Defalut is Cancel. 51 | 52 | ```java 53 | FilePickerDialog dialog = new FilePickerDialog(MainActivity.this,properties); 54 | dialog.setTitle("Select a File"); 55 | ``` 56 | 57 | 4. Next, Attach `DialogSelectionListener` to `FilePickerDialog` as below, 58 | ```java 59 | dialog.setDialogSelectionListener(new DialogSelectionListener() { 60 | @Override 61 | public void onSelectedFilePaths(String[] files) { 62 | //files is the array of the paths of files selected by the Application User. 63 | } 64 | }); 65 | ``` 66 | An array of paths is returned whenever user press the `select` button`. 67 | 68 | 5. Use ```dialog.show()``` method to show dialog. 69 | 70 | ### NOTE: 71 | Marshmallow and above requests for the permission on runtime. You should override `onRequestPermissionsResult` in Activity/AppCompatActivity class and show the dialog only if permissions have been granted. 72 | 73 | ```java 74 | //Add this method to show Dialog when the required permission has been granted to the app. 75 | @Override 76 | public void onRequestPermissionsResult(int requestCode,@NonNull String permissions[],@NonNull int[] grantResults) { 77 | switch (requestCode) { 78 | case FilePickerDialog.EXTERNAL_READ_PERMISSION_GRANT: { 79 | if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { 80 | if(dialog!=null) 81 | { //Show dialog if the read permission has been granted. 82 | dialog.show(); 83 | } 84 | } 85 | else { 86 | //Permission has not been granted. Notify the user. 87 | Toast.makeText(MainActivity.this,"Permission is Required for getting list of files",Toast.LENGTH_SHORT).show(); 88 | } 89 | } 90 | } 91 | } 92 | ``` 93 | 94 | That's It. You are good to proceed further. 95 | 96 | ### FilePickerPreference 97 | 98 | 1. Start by declaring [FilePickerPreference](https://github.com/angads25/android-filepicker/wiki/filepicker-preference) in your settings xml file as: 99 | 100 | ```xml 101 | 113 | ``` 114 | 115 | 2. Implement [Preference.OnPreferenceChangeListener](https://developer.android.com/reference/android/preference/Preference.OnPreferenceChangeListener.html) to class requiring selected values and `Override` `onPreferenceChange(Preference, Object)` method. Check for preference key using [Preference](https://developer.android.com/reference/android/preference/Preference.html) reference. 116 | 117 | ```java 118 | @Override 119 | public boolean onPreferenceChange(Preference preference, Object o) 120 | { if(preference.getKey().equals("your_preference_key")) 121 | { ... 122 | } 123 | return false; 124 | } 125 | ``` 126 | 3. Typecast `Object o` into `String` Object and use `split(String)` function in `String` class to get array of selected files. 127 | 128 | ```java 129 | @Override 130 | public boolean onPreferenceChange(Preference preference, Object o) 131 | { if(preference.getKey().equals("your_preference_key")) 132 | { String value=(String)o; 133 | String arr[]=value.split(":"); 134 | ... 135 | ... 136 | } 137 | return false; 138 | } 139 | ``` 140 | 141 | That's It. You are good to move further. 142 | 143 | ### Important: 144 | * `defaultValue`, `error_dir`, `root_dir`, `offset_dir` must have valid directory/file paths. 145 | * `defaultValue` paths should end with ':'. 146 | * `defaultValue` can have multiple paths, there should be a ':' between two paths. 147 | * `extensions` must not have '.'. 148 | * `extensions` should end with ':' , also have ':' between two extensions. 149 | eg. /sdcard:/mnt: 150 | 151 | ### Note: 152 | [FilePickerPreference](https://github.com/angads25/android-filepicker/wiki/filepicker-preference) stores selected directories/files as a `String`. It delimits multiple files/directories using ':' `char`. 153 | 154 | ## Read more on implementation [here](https://github.com/Angads25/android-filepicker/wiki/Implementation). 155 | 156 | ### Screenshot 157 | 158 | #### Theme.Black 159 | 160 | ![Screenshot 1](https://raw.githubusercontent.com/Angads25/android-filepicker/release/screenshots/theme_black.png) 161 | 162 | #### Theme.Holo 163 | 164 | ![Screenshot 2](https://raw.githubusercontent.com/Angads25/android-filepicker/release/screenshots/theme_holo.png) 165 | 166 | #### Theme.Holo.Light 167 | 168 | ![Screenshot 3](https://raw.githubusercontent.com/Angads25/android-filepicker/release/screenshots/theme_holo_light.png) 169 | 170 | #### Theme.Material 171 | 172 | ![Screenshot 4](https://raw.githubusercontent.com/Angads25/android-filepicker/release/screenshots/theme_material.png) 173 | 174 | #### Theme.DeviceDefault 175 | 176 | ![Screenshot 5](https://raw.githubusercontent.com/Angads25/android-filepicker/release/screenshots/theme_device_default.png) 177 | 178 | ### Performance 179 | 180 | #### GPU Overdraw 181 | 182 | ![Performance 1](https://raw.githubusercontent.com/Angads25/android-filepicker/release/screenshots/performance_overdraw.png) 183 | 184 | #### GPU Rendering 185 | 186 | ![Performance 2](https://raw.githubusercontent.com/Angads25/android-filepicker/release/screenshots/profile_gpu_rendering.png) 187 | 188 | ### License 189 | Copyright (C) 2016 Angad Singh 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 28 5 | 6 | defaultConfig { 7 | applicationId "com.github.angads25.filepickerdemo" 8 | minSdkVersion 19 9 | targetSdkVersion 28 10 | versionCode 4 11 | versionName "1.0.3" 12 | } 13 | buildTypes { 14 | release { 15 | minifyEnabled false 16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 17 | } 18 | } 19 | 20 | allprojects { 21 | repositories { 22 | jcenter() 23 | maven { 24 | url "https://maven.google.com" 25 | } 26 | } 27 | } 28 | } 29 | 30 | dependencies { 31 | implementation fileTree(include: ['*.jar'], dir: 'libs') 32 | implementation project(':filepicker') 33 | implementation 'androidx.appcompat:appcompat:1.1.0-alpha04' 34 | implementation 'androidx.recyclerview:recyclerview:1.1.0-alpha04' 35 | implementation 'com.google.android.material:material:1.1.0-alpha05' 36 | debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.5.4' 37 | releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.4' 38 | } 39 | -------------------------------------------------------------------------------- /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 D:\Android\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 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 23 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/angads25/filepickerdemo/FileListAdapter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Angad Singh 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.github.angads25.filepickerdemo; 18 | 19 | import android.content.Context; 20 | import android.view.LayoutInflater; 21 | import android.view.View; 22 | import android.view.ViewGroup; 23 | import android.widget.TextView; 24 | 25 | import java.util.ArrayList; 26 | 27 | import androidx.recyclerview.widget.RecyclerView; 28 | 29 | /** 30 | *

31 | * Created by Angad Singh on 11-07-2016. 32 | *

33 | */ 34 | 35 | class FileListAdapter extends RecyclerView.Adapter { 36 | private ArrayList listItems; 37 | private Context context; 38 | 39 | FileListAdapter(ArrayList listItems, Context context) { 40 | this.listItems = listItems; 41 | this.context = context; 42 | } 43 | 44 | @Override 45 | public FileListViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 46 | View view = LayoutInflater.from(context).inflate(R.layout.file_list_item, parent, false); 47 | return new FileListViewHolder(view); 48 | } 49 | 50 | @Override 51 | public void onBindViewHolder(FileListViewHolder holder, int position) { 52 | holder.name.setText(listItems.get(position).getName()); 53 | holder.path.setText(listItems.get(position).getPath()); 54 | } 55 | 56 | @Override 57 | public long getItemId(int i) { 58 | return i; 59 | } 60 | 61 | @Override 62 | public int getItemCount() { 63 | return listItems.size(); 64 | } 65 | 66 | class FileListViewHolder extends RecyclerView.ViewHolder { 67 | private TextView name; 68 | private TextView path; 69 | 70 | FileListViewHolder(View itemView) { 71 | super(itemView); 72 | name = itemView.findViewById(R.id.name); 73 | path = itemView.findViewById(R.id.path); 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/angads25/filepickerdemo/FilePickerApplication.java: -------------------------------------------------------------------------------- 1 | package com.github.angads25.filepickerdemo; 2 | 3 | import android.app.Application; 4 | 5 | import com.squareup.leakcanary.LeakCanary; 6 | 7 | /** 8 | *

9 | * Created by Angad on 28-10-2017. 10 | *

11 | */ 12 | 13 | public class FilePickerApplication extends Application { 14 | 15 | @Override 16 | public void onCreate() { 17 | super.onCreate(); 18 | if (LeakCanary.isInAnalyzerProcess(this)) { 19 | return; 20 | } 21 | LeakCanary.install(this); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/angads25/filepickerdemo/ListItem.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Angad Singh 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.github.angads25.filepickerdemo; 18 | 19 | /** 20 | *

21 | * Created by Angad Singh on 11-07-2016. 22 | *

23 | */ 24 | public class ListItem { 25 | private String name, path; 26 | 27 | public String getName() { 28 | return name; 29 | } 30 | 31 | public void setName(String name) { 32 | this.name = name; 33 | } 34 | 35 | public String getPath() { 36 | return path; 37 | } 38 | 39 | public void setPath(String path) { 40 | this.path = path; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/angads25/filepickerdemo/MainActivity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Angad Singh 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.github.angads25.filepickerdemo; 18 | 19 | import android.content.Intent; 20 | import android.content.pm.PackageManager; 21 | import android.os.Bundle; 22 | import android.view.Menu; 23 | import android.view.MenuInflater; 24 | import android.view.MenuItem; 25 | import android.view.View; 26 | import android.widget.Button; 27 | import android.widget.EditText; 28 | import android.widget.RadioGroup; 29 | import android.widget.Toast; 30 | 31 | import com.github.angads25.filepicker.controller.DialogSelectionListener; 32 | import com.github.angads25.filepicker.model.DialogConfigs; 33 | import com.github.angads25.filepicker.model.DialogProperties; 34 | import com.github.angads25.filepicker.view.FilePickerDialog; 35 | 36 | import java.io.File; 37 | import java.util.ArrayList; 38 | 39 | import androidx.annotation.NonNull; 40 | import androidx.appcompat.app.AppCompatActivity; 41 | import androidx.recyclerview.widget.LinearLayoutManager; 42 | import androidx.recyclerview.widget.RecyclerView; 43 | 44 | public class MainActivity extends AppCompatActivity { 45 | private FilePickerDialog dialog; 46 | private ArrayList listItem; 47 | private FileListAdapter mFileListAdapter; 48 | private RecyclerView fileList; 49 | 50 | @Override 51 | protected void onCreate(Bundle savedInstanceState) { 52 | super.onCreate(savedInstanceState); 53 | setContentView(R.layout.activity_main); 54 | listItem = new ArrayList<>(); 55 | fileList = findViewById(R.id.listView); 56 | mFileListAdapter = new FileListAdapter(listItem, MainActivity.this); 57 | fileList.setAdapter(mFileListAdapter); 58 | fileList.setLayoutManager(new LinearLayoutManager(MainActivity.this)); 59 | fileList.setNestedScrollingEnabled(false); 60 | 61 | //Create a DialogProperties object. 62 | final DialogProperties properties = new DialogProperties(); 63 | 64 | //Instantiate FilePickerDialog with Context and DialogProperties. 65 | dialog = new FilePickerDialog(MainActivity.this, properties); 66 | dialog.setTitle("Select a File"); 67 | dialog.setPositiveBtnName("Select"); 68 | dialog.setNegativeBtnName("Cancel"); 69 | RadioGroup modeRadio = (RadioGroup) findViewById(R.id.modeRadio); 70 | modeRadio.check(R.id.singleRadio); 71 | modeRadio.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() { 72 | @Override 73 | public void onCheckedChanged(RadioGroup group, int checkedId) { 74 | switch (checkedId) { 75 | case R.id.singleRadio: //Setting selection mode to single selection. 76 | properties.selection_mode = DialogConfigs.SINGLE_MODE; 77 | break; 78 | 79 | case R.id.multiRadio: //Setting selection mode to multiple selection. 80 | properties.selection_mode = DialogConfigs.MULTI_MODE; 81 | break; 82 | } 83 | } 84 | }); 85 | RadioGroup typeRadio = (RadioGroup) findViewById(R.id.typeRadio); 86 | typeRadio.check(R.id.selFile); 87 | typeRadio.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() { 88 | @Override 89 | public void onCheckedChanged(RadioGroup group, int checkedId) { 90 | switch (checkedId) { 91 | case R.id.selFile: //Setting selection type to files. 92 | properties.selection_type = DialogConfigs.FILE_SELECT; 93 | break; 94 | 95 | case R.id.selDir: //Setting selection type to directories. 96 | properties.selection_type = DialogConfigs.DIR_SELECT; 97 | break; 98 | 99 | case R.id.selfilenddir: //Setting selection type to files and directories. 100 | properties.selection_type = DialogConfigs.FILE_AND_DIR_SELECT; 101 | break; 102 | } 103 | } 104 | }); 105 | final EditText extension = findViewById(R.id.extensions); 106 | final EditText root = findViewById(R.id.root); 107 | final EditText offset = findViewById(R.id.offset); 108 | Button apply = findViewById(R.id.apply); 109 | Button showDialog = findViewById(R.id.show_dialog); 110 | apply.setOnClickListener(new View.OnClickListener() { 111 | @Override 112 | public void onClick(View view) { 113 | String fextension = extension.getText().toString(); 114 | if (fextension.length() > 0) { 115 | //Add extensions to be sorted from the EditText input to the array of String. 116 | int commas = countCommas(fextension); 117 | 118 | //Array representing extensions. 119 | String[] exts = new String[commas + 1]; 120 | StringBuffer buff = new StringBuffer(); 121 | int i = 0; 122 | for (int j = 0; j < fextension.length(); j++) { 123 | if (fextension.charAt(j) == ',') { 124 | exts[i] = buff.toString(); 125 | buff = new StringBuffer(); 126 | i++; 127 | } else { 128 | buff.append(fextension.charAt(j)); 129 | } 130 | } 131 | exts[i] = buff.toString(); 132 | 133 | //Set String Array of extensions. 134 | properties.extensions = exts; 135 | } else { //If EditText is empty, Initialise with null reference. 136 | properties.extensions = null; 137 | } 138 | String foffset = root.getText().toString(); 139 | if (foffset.length() > 0 || !foffset.equals("")) { 140 | //Setting Parent Directory. 141 | properties.root = new File(foffset); 142 | } else { 143 | //Setting Parent Directory to Default SDCARD. 144 | properties.root = new File(DialogConfigs.DEFAULT_DIR); 145 | } 146 | 147 | String fset = offset.getText().toString(); 148 | if (fset.length() > 0 || !fset.equals("")) { 149 | //Setting Offset Directory. 150 | properties.offset = new File(fset); 151 | } else { 152 | //Setting Parent Directory to Default SDCARD. 153 | properties.offset = new File(DialogConfigs.DEFAULT_DIR); 154 | } 155 | 156 | properties.sortBy = DialogConfigs.SORT_BY_LAST_MODIFIED; 157 | 158 | //Setting Alternative Directory, in case root is not accessible.This will be 159 | //used. 160 | 161 | properties.error_dir = new File("/mnt"); 162 | //Set new properties of dialog. 163 | dialog = new FilePickerDialog(MainActivity.this, properties); 164 | dialog.setDialogSelectionListener(new DialogSelectionListener() { 165 | @Override 166 | public void onSelectedFilePaths(String[] files) { 167 | //files is the array of paths selected by the App User. 168 | int size = listItem.size(); 169 | listItem.clear(); 170 | mFileListAdapter.notifyItemRangeRemoved(0, size); 171 | for (String path : files) { 172 | File file = new File(path); 173 | ListItem item = new ListItem(); 174 | item.setName(file.getName()); 175 | item.setPath(file.getAbsolutePath()); 176 | listItem.add(item); 177 | } 178 | mFileListAdapter.notifyItemRangeInserted(0, listItem.size()); 179 | } 180 | }); 181 | // Pre marking of files in Dialog 182 | // ArrayList paths=new ArrayList<>(); 183 | // paths.add("/mnt/sdcard/.VOD"); 184 | // paths.add("/mnt/sdcard/.VOD/100.jpg"); 185 | // paths.add("/mnt/sdcard/.VOD/1000.jpg"); 186 | // paths.add("/mnt/sdcard/.VOD/1010.jpg"); 187 | // paths.add("/mnt/sdcard/.VOD/1020.jpg"); 188 | // paths.add("/mnt/sdcard/.VOD/1070.jpg"); 189 | // dialog.markFiles(paths); 190 | } 191 | }); 192 | 193 | showDialog.setOnClickListener(new View.OnClickListener() { 194 | @Override 195 | public void onClick(View view) { 196 | //Showing dialog when Show Dialog button is clicked. 197 | dialog.show(); 198 | } 199 | }); 200 | 201 | //Method handle selected files. 202 | dialog.setDialogSelectionListener(new DialogSelectionListener() { 203 | @Override 204 | public void onSelectedFilePaths(String[] files) { 205 | //files is the array of paths selected by the App User. 206 | int size = listItem.size(); 207 | listItem.clear(); 208 | mFileListAdapter.notifyItemRangeRemoved(0, size); 209 | for (String path : files) { 210 | File file = new File(path); 211 | ListItem item = new ListItem(); 212 | item.setName(file.getName()); 213 | item.setPath(file.getAbsolutePath()); 214 | listItem.add(item); 215 | } 216 | mFileListAdapter.notifyItemRangeInserted(0, listItem.size()); 217 | } 218 | }); 219 | } 220 | 221 | private int countCommas(String fextension) { 222 | int count = 0; 223 | for (char ch : fextension.toCharArray()) { 224 | if (ch == ',') { 225 | count++; 226 | } 227 | } 228 | return count; 229 | } 230 | 231 | //Add this method to show Dialog when the required permission has been granted to the app. 232 | @Override 233 | public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) { 234 | switch (requestCode) { 235 | case FilePickerDialog.EXTERNAL_READ_PERMISSION_GRANT: { 236 | if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { 237 | if (dialog != null) { 238 | //Show dialog if the read permission has been granted. 239 | dialog.show(); 240 | } 241 | } else { 242 | //Permission has not been granted. Notify the user. 243 | Toast.makeText(MainActivity.this, "Permission is Required for getting list of files", Toast.LENGTH_SHORT).show(); 244 | } 245 | } 246 | } 247 | } 248 | 249 | public boolean onCreateOptionsMenu(Menu menu) { 250 | MenuInflater inflater = getMenuInflater(); 251 | inflater.inflate(R.menu.main_menu, menu); 252 | return true; 253 | } 254 | 255 | public boolean onOptionsItemSelected(MenuItem item) { 256 | switch (item.getItemId()) { 257 | case R.id.settings: 258 | startActivity(new Intent(this, SettingsActivity.class)); 259 | return true; 260 | default: 261 | return super.onOptionsItemSelected(item); 262 | } 263 | } 264 | } -------------------------------------------------------------------------------- /app/src/main/java/com/github/angads25/filepickerdemo/SettingsActivity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Angad Singh 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.github.angads25.filepickerdemo; 18 | 19 | import android.graphics.Color; 20 | import android.os.Build; 21 | import android.os.Bundle; 22 | import android.preference.Preference; 23 | import android.preference.PreferenceActivity; 24 | import android.util.TypedValue; 25 | import android.view.LayoutInflater; 26 | import android.view.View; 27 | import android.view.ViewGroup; 28 | import android.widget.LinearLayout; 29 | import android.widget.ListView; 30 | import android.widget.Toast; 31 | 32 | import com.github.angads25.filepicker.view.FilePickerPreference; 33 | 34 | import androidx.appcompat.widget.Toolbar; 35 | 36 | /** 37 | *

38 | * Created by Angad on 22/07/2016. 39 | *

40 | */ 41 | 42 | public class SettingsActivity extends PreferenceActivity implements Preference.OnPreferenceChangeListener { 43 | @SuppressWarnings("deprecation") 44 | @Override 45 | protected void onCreate(Bundle savedInstanceState) { 46 | super.onCreate(savedInstanceState); 47 | addPreferencesFromResource(R.xml.pref_general); 48 | FilePickerPreference fileDialog = (FilePickerPreference) findPreference("directories"); 49 | fileDialog.setOnPreferenceChangeListener(this); 50 | } 51 | 52 | @SuppressWarnings("deprecation") 53 | @Override 54 | protected void onPostCreate(Bundle savedInstanceState) { 55 | super.onPostCreate(savedInstanceState); 56 | Toolbar toolbar; 57 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { 58 | LinearLayout root = (LinearLayout) findViewById(android.R.id.list).getParent().getParent().getParent(); 59 | toolbar = (Toolbar) LayoutInflater.from(this).inflate(R.layout.toolbar, root, false); 60 | root.addView(toolbar, 0); 61 | } else { 62 | ViewGroup root = findViewById(android.R.id.content); 63 | ListView content = (ListView) root.getChildAt(0); 64 | root.removeAllViews(); 65 | toolbar = (Toolbar) LayoutInflater.from(this).inflate(R.layout.toolbar, root, false); 66 | int height; 67 | TypedValue tv = new TypedValue(); 68 | if (getTheme().resolveAttribute(R.attr.actionBarSize, tv, true)) { 69 | height = TypedValue.complexToDimensionPixelSize(tv.data, getResources().getDisplayMetrics()); 70 | } else { 71 | height = toolbar.getHeight(); 72 | } 73 | content.setPadding(0, height, 0, 0); 74 | root.addView(content); 75 | root.addView(toolbar); 76 | } 77 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 78 | toolbar.setBackgroundColor(getResources().getColor(R.color.colorPrimary, getTheme())); 79 | } else { 80 | toolbar.setBackgroundColor(getResources().getColor(R.color.colorPrimary)); 81 | } 82 | toolbar.setNavigationIcon(R.drawable.ic_up_navigation); 83 | toolbar.setTitleTextColor(Color.WHITE); 84 | toolbar.setTitle(getResources().getString(R.string.title_activity_settings)); 85 | toolbar.setNavigationOnClickListener(new View.OnClickListener() { 86 | @Override 87 | public void onClick(View v) { 88 | finish(); 89 | } 90 | }); 91 | } 92 | 93 | @Override 94 | public boolean onPreferenceChange(Preference preference, Object o) { 95 | if (preference.getKey().equals("directories")) { 96 | String value = (String) o; 97 | String arr[] = value.split(":"); 98 | for (String path : arr) 99 | Toast.makeText(SettingsActivity.this, path, Toast.LENGTH_SHORT).show(); 100 | } 101 | return false; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_action_settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aefyr/android-filepicker/f50f1bcbd8c8a5cb109cad28511466d40f2d47c8/app/src/main/res/drawable-hdpi/ic_action_settings.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_action_settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aefyr/android-filepicker/f50f1bcbd8c8a5cb109cad28511466d40f2d47c8/app/src/main/res/drawable-mdpi/ic_action_settings.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_action_settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aefyr/android-filepicker/f50f1bcbd8c8a5cb109cad28511466d40f2d47c8/app/src/main/res/drawable-xhdpi/ic_action_settings.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_action_settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aefyr/android-filepicker/f50f1bcbd8c8a5cb109cad28511466d40f2d47c8/app/src/main/res/drawable-xxhdpi/ic_action_settings.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_action_settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aefyr/android-filepicker/f50f1bcbd8c8a5cb109cad28511466d40f2d47c8/app/src/main/res/drawable-xxxhdpi/ic_action_settings.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_up_navigation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aefyr/android-filepicker/f50f1bcbd8c8a5cb109cad28511466d40f2d47c8/app/src/main/res/drawable/ic_up_navigation.png -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 17 | 18 | 27 | 28 | 34 | 35 | 40 | 41 | 45 | 46 | 52 | 53 | 59 | 60 | 61 | 67 | 68 | 72 | 73 | 79 | 80 | 86 | 87 | 93 | 94 | 95 | 101 | 102 | 108 | 109 | 115 | 116 | 122 | 123 | 129 | 130 | 136 | 137 | 138 | 139 | 146 | 147 | 153 | 154 | 160 | 161 | -------------------------------------------------------------------------------- /app/src/main/res/layout/file_list_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 17 | 18 | 25 | -------------------------------------------------------------------------------- /app/src/main/res/layout/toolbar.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/menu/main_menu.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aefyr/android-filepicker/f50f1bcbd8c8a5cb109cad28511466d40f2d47c8/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aefyr/android-filepicker/f50f1bcbd8c8a5cb109cad28511466d40f2d47c8/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aefyr/android-filepicker/f50f1bcbd8c8a5cb109cad28511466d40f2d47c8/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aefyr/android-filepicker/f50f1bcbd8c8a5cb109cad28511466d40f2d47c8/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aefyr/android-filepicker/f50f1bcbd8c8a5cb109cad28511466d40f2d47c8/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/values-de/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Datei Auswahl Demo 4 | Auswählen 5 | Dialog zeigen 6 | Einstellungen 7 | -------------------------------------------------------------------------------- /app/src/main/res/values-fr/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Démo gestionnaire de fichiers 4 | Choisir 5 | Montrer le dialogue 6 | Réglages 7 | -------------------------------------------------------------------------------- /app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values-zh-rTW/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | FilePickerDemo 4 | 選擇 5 | Show Dialog 6 | Settings 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | @color/colorNeutralGray 4 | @color/colorNeutralGray 5 | @color/colorHotPink 6 | 7 | #9e9e9e 8 | 9 | #ff4e3e 10 | #ffffff 11 | 12 | #3a404a 13 | #343944 14 | #e5e5e5 15 | #ffbcbc 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | FilePickerDemo 4 | Select 5 | Show Dialog 6 | Settings 7 | Apply 8 | eg. /mnt/sdcard/Music or leave empty 9 | Offset Directory 10 | eg. /mnt/sdcard or leave empty 11 | Root Directory 12 | eg. jpg, zip, rar or leave empty 13 | Single 14 | Multiple 15 | Selection Mode 16 | Selection Type 17 | File 18 | Directory 19 | Files and Directories 20 | Filter Extensions(Seperate with Commas, Don\'t use dots) 21 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/xml/pref_general.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 15 | 16 | -------------------------------------------------------------------------------- /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 | maven { 7 | url 'https://maven.google.com/' 8 | name 'Google' 9 | } 10 | google() 11 | } 12 | dependencies { 13 | classpath 'com.android.tools.build:gradle:3.5.3' 14 | classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.4' 15 | classpath 'com.github.dcendents:android-maven-gradle-plugin:1.4.1' 16 | } 17 | } 18 | 19 | allprojects { 20 | repositories { 21 | jcenter() 22 | maven { 23 | url 'https://maven.google.com/' 24 | name 'Google' 25 | } 26 | } 27 | } 28 | 29 | task clean(type: Delete) { 30 | delete rootProject.buildDir 31 | } 32 | -------------------------------------------------------------------------------- /crowdin.yml: -------------------------------------------------------------------------------- 1 | files: 2 | - source: /filepicker/src/main/res/values/strings.xml 3 | translation: /filepicker/src/main/res/values-%two_letters_code%/%original_file_name% 4 | translate_attributes: 0 5 | - source: /filepicker/src/main/res/values/arrays.xml 6 | translation: /filepicker/src/main/res/values-%two_letters_code%/%original_file_name% 7 | translate_attributes: 0 8 | -------------------------------------------------------------------------------- /filepicker/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /filepicker/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | ext { 4 | bintrayRepo = 'maven' 5 | bintrayName = 'filepicker' 6 | 7 | publishedGroupId = 'com.github.angads25' 8 | libraryName = 'File Picker' 9 | artifact = 'filepicker' 10 | 11 | libraryDescription = 'Android Library To pick Files from Device Storage.' 12 | 13 | siteUrl = 'https://github.com/angads25/android-filepicker' 14 | gitUrl = 'https://github.com/angads25/android-filepicker.git' 15 | 16 | libraryVersion = '1.1.1' 17 | 18 | developerId = 'angads25' 19 | developerName = 'Angad Singh' 20 | developerEmail = 'angads25@gmail.com' 21 | 22 | licenseName = 'The Apache Software License, Version 2.0' 23 | licenseUrl = 'http://www.apache.org/licenses/LICENSE-2.0.txt' 24 | allLicenses = ["Apache-2.0"] 25 | } 26 | 27 | android { 28 | compileSdkVersion 28 29 | 30 | defaultConfig { 31 | minSdkVersion 19 32 | targetSdkVersion 28 33 | versionCode 12 34 | versionName "1.1.1" 35 | } 36 | buildTypes { 37 | release { 38 | minifyEnabled false 39 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 40 | } 41 | } 42 | lintOptions { 43 | abortOnError false 44 | } 45 | } 46 | 47 | dependencies { 48 | implementation 'com.google.android.material:material:1.1.0-alpha05' 49 | } 50 | 51 | //apply from: 'https://raw.githubusercontent.com/angads25/JCenter/master/installv1.gradle' 52 | //apply from: 'https://raw.githubusercontent.com/angads25/JCenter/master/bintrayv1.gradle' -------------------------------------------------------------------------------- /filepicker/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 D:\Android\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 | -------------------------------------------------------------------------------- /filepicker/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /filepicker/src/main/java/com/github/angads25/filepicker/controller/DialogSelectionListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Angad Singh 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.github.angads25.filepicker.controller; 18 | 19 | /*

20 | * Created by Angad Singh on 10-07-2016. 21 | *

22 | */ 23 | 24 | /** 25 | * Interface definition for a callback to be invoked 26 | * when dialog selects files. 27 | */ 28 | public interface DialogSelectionListener { 29 | 30 | /** 31 | * The method is called when files or directories are selected. 32 | * 33 | * @param files The array of String containing selected file paths. 34 | */ 35 | void onSelectedFilePaths(String files[]); 36 | } 37 | -------------------------------------------------------------------------------- /filepicker/src/main/java/com/github/angads25/filepicker/controller/NotifyItemChecked.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Angad Singh 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.github.angads25.filepicker.controller; 18 | 19 | /** 20 | *

21 | * Created by Angad Singh on 11-07-2016. 22 | *

23 | */ 24 | 25 | /** 26 | * Interface definition for a callback to be invoked 27 | * when a checkbox is checked. 28 | */ 29 | public interface NotifyItemChecked { 30 | 31 | /** 32 | * Called when a checkbox is checked. 33 | */ 34 | void notifyCheckBoxIsClicked(); 35 | } 36 | -------------------------------------------------------------------------------- /filepicker/src/main/java/com/github/angads25/filepicker/controller/adapters/FileListAdapter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Angad Singh 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.github.angads25.filepicker.controller.adapters; 18 | 19 | import android.content.Context; 20 | import android.view.LayoutInflater; 21 | import android.view.View; 22 | import android.view.ViewGroup; 23 | import android.view.animation.Animation; 24 | import android.view.animation.AnimationUtils; 25 | import android.widget.BaseAdapter; 26 | import android.widget.CompoundButton; 27 | import android.widget.ImageView; 28 | import android.widget.ListView; 29 | import android.widget.TextView; 30 | 31 | import com.github.angads25.filepicker.R; 32 | import com.github.angads25.filepicker.controller.NotifyItemChecked; 33 | import com.github.angads25.filepicker.model.DialogConfigs; 34 | import com.github.angads25.filepicker.model.DialogProperties; 35 | import com.github.angads25.filepicker.model.FileListItem; 36 | import com.github.angads25.filepicker.model.MarkedItemList; 37 | import com.github.angads25.filepicker.utils.ColorUtils; 38 | import com.github.angads25.filepicker.utils.Utility; 39 | import com.google.android.material.checkbox.MaterialCheckBox; 40 | 41 | import java.text.SimpleDateFormat; 42 | import java.util.ArrayList; 43 | import java.util.Date; 44 | import java.util.Locale; 45 | 46 | /*

47 | * Created by Angad Singh on 09-07-2016. 48 | *

49 | */ 50 | 51 | /** 52 | * Adapter Class that extends {@link BaseAdapter} that is 53 | * used to populate {@link ListView} with file info. 54 | */ 55 | public class FileListAdapter extends BaseAdapter { 56 | private ArrayList listItem; 57 | private Context context; 58 | private DialogProperties properties; 59 | private NotifyItemChecked notifyItemChecked; 60 | 61 | public FileListAdapter(ArrayList listItem, Context context, DialogProperties properties) { 62 | this.listItem = listItem; 63 | this.context = context; 64 | this.properties = properties; 65 | } 66 | 67 | @Override 68 | public int getCount() { 69 | return listItem.size(); 70 | } 71 | 72 | @Override 73 | public FileListItem getItem(int i) { 74 | return listItem.get(i); 75 | } 76 | 77 | @Override 78 | public long getItemId(int i) { 79 | return i; 80 | } 81 | 82 | @Override 83 | public View getView(final int i, View view, ViewGroup viewGroup) { 84 | final ViewHolder holder; 85 | if (view == null) { 86 | view = LayoutInflater.from(context).inflate(R.layout.dialog_file_list_item, viewGroup, false); 87 | holder = new ViewHolder(view); 88 | view.setTag(holder); 89 | } else { 90 | holder = (ViewHolder) view.getTag(); 91 | } 92 | final FileListItem item = listItem.get(i); 93 | if (MarkedItemList.hasItem(item.getLocation())) { 94 | Animation animation = AnimationUtils.loadAnimation(context, R.anim.marked_item_animation); 95 | view.setAnimation(animation); 96 | } else { 97 | Animation animation = AnimationUtils.loadAnimation(context, R.anim.unmarked_item_animation); 98 | view.setAnimation(animation); 99 | } 100 | if (item.isDirectory()) { 101 | holder.icon.setImageResource(R.drawable.ic_type_folder); 102 | holder.icon.setColorFilter(null); 103 | if (properties.selection_type == DialogConfigs.FILE_SELECT) { 104 | holder.checkbox.setVisibility(View.INVISIBLE); 105 | } else { 106 | holder.checkbox.setVisibility(View.VISIBLE); 107 | } 108 | } else { 109 | holder.icon.setImageResource(R.drawable.ic_type_file); 110 | holder.icon.setColorFilter(ColorUtils.getAccentColor(context)); 111 | if (properties.selection_type == DialogConfigs.DIR_SELECT) { 112 | holder.checkbox.setVisibility(View.INVISIBLE); 113 | } else { 114 | holder.checkbox.setVisibility(View.VISIBLE); 115 | } 116 | } 117 | holder.icon.setContentDescription(item.getFilename()); 118 | holder.name.setText(item.getFilename()); 119 | SimpleDateFormat sdate = new SimpleDateFormat("dd.MM.yyyy, HH:mm", Locale.getDefault()); 120 | Date date = new Date(item.getTime()); 121 | if (i == 0 && item.getFilename().startsWith(context.getString(R.string.label_parent_dir))) { 122 | holder.type.setText(R.string.label_parent_directory); 123 | } else if (item.isDirectory()) { 124 | holder.type.setText(String.format(context.getString(R.string.last_edit), sdate.format(date))); 125 | } else { 126 | holder.type.setText(String.format(context.getString(R.string.last_edit_with_size), Utility.formatSize(context, item.getSize()), sdate.format(date))); 127 | } 128 | 129 | holder.checkbox.setOnCheckedChangeListener(null); 130 | if (holder.checkbox.getVisibility() == View.VISIBLE) { 131 | if (i == 0 && item.getFilename().startsWith(context.getString(R.string.label_parent_dir))) { 132 | holder.checkbox.setVisibility(View.INVISIBLE); 133 | } 134 | 135 | if (properties.selection_mode == DialogConfigs.SINGLE_MODE) { 136 | holder.checkbox.setVisibility(View.INVISIBLE); 137 | } 138 | 139 | if (MarkedItemList.hasItem(item.getLocation())) { 140 | holder.checkbox.setChecked(true); 141 | holder.checkbox.jumpDrawablesToCurrentState(); 142 | } else { 143 | holder.checkbox.setChecked(false); 144 | holder.checkbox.jumpDrawablesToCurrentState(); 145 | } 146 | } 147 | 148 | holder.checkbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { 149 | @Override 150 | public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 151 | item.setMarked(isChecked); 152 | if (item.isMarked()) { 153 | if (properties.selection_mode == DialogConfigs.MULTI_MODE) { 154 | MarkedItemList.addSelectedItem(item); 155 | } else { 156 | MarkedItemList.addSingleFile(item); 157 | } 158 | } else { 159 | MarkedItemList.removeSelectedItem(item.getLocation()); 160 | } 161 | notifyItemChecked.notifyCheckBoxIsClicked(); 162 | } 163 | }); 164 | return view; 165 | } 166 | 167 | private class ViewHolder { 168 | ImageView icon; 169 | TextView name, type; 170 | MaterialCheckBox checkbox; 171 | 172 | ViewHolder(View itemView) { 173 | name = (TextView) itemView.findViewById(R.id.fname); 174 | type = (TextView) itemView.findViewById(R.id.ftype); 175 | icon = (ImageView) itemView.findViewById(R.id.image_type); 176 | checkbox = itemView.findViewById(R.id.file_mark); 177 | } 178 | } 179 | 180 | public void setNotifyItemCheckedListener(NotifyItemChecked notifyItemChecked) { 181 | this.notifyItemChecked = notifyItemChecked; 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /filepicker/src/main/java/com/github/angads25/filepicker/model/DialogConfigs.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Angad Singh 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.github.angads25.filepicker.model; 18 | 19 | /** 20 | *

21 | * Created by Angad Singh on 11-07-2016. 22 | *

23 | */ 24 | 25 | /* Helper class for setting properties of Dialog. 26 | */ 27 | public abstract class DialogConfigs { 28 | /* SELECTION_MODES*/ 29 | 30 | /* SINGLE_MODE specifies that a single File/Directory has to be selected 31 | * from the list of Files/Directories. It is the default Selection Mode. 32 | */ 33 | public static final int SINGLE_MODE = 0; 34 | 35 | /* MULTI_MODE specifies that multiple Files/Directories has to be selected 36 | * from the list of Files/Directories. 37 | */ 38 | public static final int MULTI_MODE = 1; 39 | 40 | /* SELECTION_TYPES*/ 41 | 42 | /* FILE_SELECT specifies that from list of Files/Directories a File has to 43 | * be selected. It is the default Selection Type. 44 | */ 45 | public static final int FILE_SELECT = 0; 46 | 47 | /* DIR_SELECT specifies that from list of Files/Directories a Directory has to 48 | * be selected. 49 | */ 50 | public static final int DIR_SELECT = 1; 51 | 52 | /* FILE_AND_DIR_SELECT specifies that from list of Files/Directories both 53 | * can be selected. 54 | */ 55 | public static final int FILE_AND_DIR_SELECT = 2; 56 | 57 | /* PARENT_DIRECTORY*/ 58 | public static final String DIRECTORY_SEPERATOR = "/"; 59 | public static final String STORAGE_DIR = "mnt"; 60 | 61 | /* DEFAULT_DIR is the default mount point of the SDCARD. It is the default 62 | * mount point. 63 | */ 64 | public static final String DEFAULT_DIR = DIRECTORY_SEPERATOR + STORAGE_DIR; 65 | 66 | public static final int SORT_BY_NAME = 0; 67 | 68 | public static final int SORT_BY_LAST_MODIFIED = 1; 69 | 70 | public static final int SORT_BY_SIZE = 2; 71 | 72 | public static final int SORT_ORDER_NORMAL = 0; 73 | 74 | public static final int SORT_ORDER_REVERSE = 1; 75 | } 76 | -------------------------------------------------------------------------------- /filepicker/src/main/java/com/github/angads25/filepicker/model/DialogProperties.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Angad Singh 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.github.angads25.filepicker.model; 18 | 19 | import java.io.File; 20 | 21 | /** 22 | *

23 | * Created by Angad Singh on 11-07-2016. 24 | *

25 | */ 26 | 27 | /* Descriptor class to define properties of the Dialog. Actions are performed upon 28 | * these Properties 29 | */ 30 | public class DialogProperties { 31 | /** 32 | * Selection Mode defines whether a single of multiple Files/Directories 33 | * have to be selected. 34 | *

35 | * SINGLE_MODE and MULTI_MODE are the two selection modes, See DialogConfigs 36 | * for more info. Set to SINGLE_MODE as default value by constructor. 37 | */ 38 | public int selection_mode; 39 | 40 | /** 41 | * Selection Type defines that whether a File/Directory or both of these has 42 | * to be selected. 43 | *

44 | * FILE_SELECT ,DIR_SELECT, FILE_AND_DIR_SELECT are the three selection modes, 45 | * See DialogConfigs for more info. Set to FILE_SELECT as default value by constructor. 46 | */ 47 | public int selection_type; 48 | 49 | /** 50 | * The Parent/Root Directory. List of Files are populated from here. Can be set 51 | * to any readable directory. /sdcard is the default location. 52 | *

53 | * Eg. /sdcard 54 | * Eg. /mnt 55 | */ 56 | public File root; 57 | 58 | /** 59 | * The Directory is used when Root Directory is not readable or accessible. / 60 | * sdcard is the default location. 61 | *

62 | * Eg. /sdcard 63 | * Eg. /mnt 64 | */ 65 | public File error_dir; 66 | 67 | /** 68 | * The Directory can be used as an offset. It is the first directory that is 69 | * shown in dialog. Consider making it Root's sub-directory. 70 | *

71 | * Eg. Root: /sdcard 72 | * Eg. Offset: /sdcard/Music/Country 73 | */ 74 | public File offset; 75 | 76 | /** 77 | * An Array of String containing extensions, Files with only that will be shown. 78 | * Others will be ignored. Set to null as default value by constructor. 79 | * Eg. String ext={"jpg","jpeg","png","gif"}; 80 | */ 81 | public String[] extensions; 82 | 83 | public int sortBy; 84 | 85 | public int sortOrder; 86 | 87 | public DialogProperties() { 88 | selection_mode = DialogConfigs.SINGLE_MODE; 89 | selection_type = DialogConfigs.FILE_SELECT; 90 | root = new File(DialogConfigs.DEFAULT_DIR); 91 | error_dir = new File(DialogConfigs.DEFAULT_DIR); 92 | offset = new File(DialogConfigs.DEFAULT_DIR); 93 | extensions = null; 94 | sortBy = DialogConfigs.SORT_BY_NAME; 95 | sortOrder = DialogConfigs.SORT_ORDER_NORMAL; 96 | } 97 | } -------------------------------------------------------------------------------- /filepicker/src/main/java/com/github/angads25/filepicker/model/FileListItem.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Angad Singh 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.github.angads25.filepicker.model; 18 | 19 | /*

20 | * Created by Angad Singh on 09-07-2016. 21 | *

22 | */ 23 | 24 | import java.util.Locale; 25 | 26 | /** 27 | * The model/container class holding file list data. 28 | */ 29 | public class FileListItem implements Comparable { 30 | private String filename, location; 31 | private boolean directory, marked; 32 | private long time; 33 | private long size; 34 | 35 | public String getFilename() { 36 | return filename; 37 | } 38 | 39 | public void setFilename(String filename) { 40 | this.filename = filename; 41 | } 42 | 43 | public String getLocation() { 44 | return location; 45 | } 46 | 47 | public void setLocation(String location) { 48 | this.location = location; 49 | } 50 | 51 | public boolean isDirectory() { 52 | return directory; 53 | } 54 | 55 | public void setDirectory(boolean directory) { 56 | this.directory = directory; 57 | } 58 | 59 | public long getTime() { 60 | return time; 61 | } 62 | 63 | public void setTime(long time) { 64 | this.time = time; 65 | } 66 | 67 | public boolean isMarked() { 68 | return marked; 69 | } 70 | 71 | public void setMarked(boolean marked) { 72 | this.marked = marked; 73 | } 74 | 75 | public long getSize() { 76 | return size; 77 | } 78 | 79 | public void setSize(long size) { 80 | this.size = size; 81 | } 82 | 83 | @Override 84 | public int compareTo(FileListItem fileListItem) { 85 | if (fileListItem.isDirectory() && isDirectory()) { //If the comparison is between two directories, return the directory with 86 | //alphabetic order first. 87 | return filename.toLowerCase().compareTo(fileListItem.getFilename().toLowerCase(Locale.getDefault())); 88 | } else if (!fileListItem.isDirectory() && !isDirectory()) { //If the comparison is not between two directories, return the file with 89 | //alphabetic order first. 90 | return filename.toLowerCase().compareTo(fileListItem.getFilename().toLowerCase(Locale.getDefault())); 91 | } else if (fileListItem.isDirectory() && !isDirectory()) { //If the comparison is between a directory and a file, return the directory. 92 | return 1; 93 | } else { //Same as above but order of occurence is different. 94 | return -1; 95 | } 96 | } 97 | } -------------------------------------------------------------------------------- /filepicker/src/main/java/com/github/angads25/filepicker/model/MarkedItemList.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Angad Singh 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.github.angads25.filepicker.model; 18 | 19 | import java.util.HashMap; 20 | import java.util.Set; 21 | 22 | /** 23 | *

24 | * Created by Angad Singh on 11-07-2016. 25 | *

26 | */ 27 | 28 | /* SingleTon containing pair of all the selected files. 29 | * Key: Directory/File path. 30 | * Value: FileListItem Object. 31 | */ 32 | public class MarkedItemList { 33 | private static HashMap ourInstance = new HashMap<>(); 34 | 35 | public static void addSelectedItem(FileListItem item) { 36 | ourInstance.put(item.getLocation(), item); 37 | } 38 | 39 | public static void removeSelectedItem(String key) { 40 | ourInstance.remove(key); 41 | } 42 | 43 | public static boolean hasItem(String key) { 44 | return ourInstance.containsKey(key); 45 | } 46 | 47 | public static void clearSelectionList() { 48 | ourInstance = new HashMap<>(); 49 | } 50 | 51 | public static void addSingleFile(FileListItem item) { 52 | ourInstance = new HashMap<>(); 53 | ourInstance.put(item.getLocation(), item); 54 | } 55 | 56 | public static String[] getSelectedPaths() { 57 | Set paths = ourInstance.keySet(); 58 | String fpaths[] = new String[paths.size()]; 59 | int i = 0; 60 | for (String path : paths) { 61 | fpaths[i++] = path; 62 | } 63 | return fpaths; 64 | } 65 | 66 | public static int getFileCount() { 67 | return ourInstance.size(); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /filepicker/src/main/java/com/github/angads25/filepicker/utils/ColorUtils.java: -------------------------------------------------------------------------------- 1 | package com.github.angads25.filepicker.utils; 2 | 3 | import android.content.Context; 4 | import android.graphics.Color; 5 | import android.os.Build; 6 | import android.util.TypedValue; 7 | 8 | import com.github.angads25.filepicker.R; 9 | 10 | public class ColorUtils { 11 | 12 | public static int getAccentColor(Context context) { 13 | int color; 14 | if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 15 | TypedValue accentColor = new TypedValue(); 16 | context.getTheme().resolveAttribute(android.R.attr.colorAccent, accentColor, true); 17 | color = accentColor.data; 18 | } else { 19 | color = context.getResources().getColor(R.color.colorAccent); 20 | } 21 | 22 | return color; 23 | } 24 | 25 | public static int muteColor(int color) { 26 | return Color.argb(128, Color.red(color), Color.green(color), Color.blue(color)); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /filepicker/src/main/java/com/github/angads25/filepicker/utils/ExtensionFilter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Angad Singh 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.github.angads25.filepicker.utils; 18 | 19 | import com.github.angads25.filepicker.model.DialogConfigs; 20 | import com.github.angads25.filepicker.model.DialogProperties; 21 | 22 | import java.io.File; 23 | import java.io.FileFilter; 24 | import java.util.Locale; 25 | 26 | /** 27 | *

28 | * Created by Angad Singh on 11-07-2016. 29 | *

30 | */ 31 | 32 | /* Class to filter the list of files. 33 | */ 34 | public class ExtensionFilter implements FileFilter { 35 | private final String[] validExtensions; 36 | private DialogProperties properties; 37 | 38 | public ExtensionFilter(DialogProperties properties) { 39 | if (properties.extensions != null) { 40 | this.validExtensions = properties.extensions; 41 | } else { 42 | this.validExtensions = new String[]{""}; 43 | } 44 | this.properties = properties; 45 | } 46 | 47 | /** 48 | * Function to filter files based on defined rules. 49 | */ 50 | @Override 51 | public boolean accept(File file) { 52 | //All directories are added in the least that can be read by the Application 53 | if (file.isDirectory() && file.canRead()) { 54 | return true; 55 | } else if (properties.selection_type == DialogConfigs.DIR_SELECT) { /* True for files, If the selection type is Directory type, ie. 56 | * Only directory has to be selected from the list, then all files are 57 | * ignored. 58 | */ 59 | return false; 60 | } else { /* Check whether name of the file ends with the extension. Added if it 61 | * does. 62 | */ 63 | String name = file.getName().toLowerCase(Locale.getDefault()); 64 | for (String ext : validExtensions) { 65 | if (name.endsWith(ext)) { 66 | return true; 67 | } 68 | } 69 | } 70 | return false; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /filepicker/src/main/java/com/github/angads25/filepicker/utils/Utility.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Angad Singh 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.github.angads25.filepicker.utils; 18 | 19 | import android.content.Context; 20 | import android.content.pm.PackageManager; 21 | 22 | import com.github.angads25.filepicker.R; 23 | import com.github.angads25.filepicker.model.DialogConfigs; 24 | import com.github.angads25.filepicker.model.DialogProperties; 25 | import com.github.angads25.filepicker.model.FileListItem; 26 | 27 | import java.io.File; 28 | import java.text.DecimalFormat; 29 | import java.text.DecimalFormatSymbols; 30 | import java.util.ArrayList; 31 | import java.util.Collections; 32 | import java.util.Comparator; 33 | import java.util.Locale; 34 | 35 | /** 36 | *

37 | * Created by Angad Singh on 11-07-2016. 38 | *

39 | */ 40 | public class Utility { 41 | /** 42 | * Post Lollipop Devices require permissions on Runtime (Risky Ones), even though it has been 43 | * specified in the uses-permission tag of manifest. checkStorageAccessPermissions 44 | * method checks whether the READ EXTERNAL STORAGE permission has been granted to 45 | * the Application. 46 | * 47 | * @return a boolean value notifying whether the permission is granted or not. 48 | */ 49 | public static boolean checkStorageAccessPermissions(Context context) { //Only for Android M and above. 50 | if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) { 51 | String permission = "android.permission.READ_EXTERNAL_STORAGE"; 52 | int res = context.checkCallingOrSelfPermission(permission); 53 | return (res == PackageManager.PERMISSION_GRANTED); 54 | } else { //Pre Marshmallow can rely on Manifest defined permissions. 55 | return true; 56 | } 57 | } 58 | 59 | /** 60 | * Prepares the list of Files and Folders inside 'inter' Directory. 61 | * The list can be filtered through extensions. 'filter' reference 62 | * is the FileFilter. A reference of ArrayList is passed, in case it 63 | * may contain the ListItem for parent directory. Returns the List of 64 | * Directories/files in the form of ArrayList. 65 | * 66 | * @param internalList ArrayList containing parent directory. 67 | * @param inter The present directory to look into. 68 | * @param filter Extension filter class reference, for filtering files. 69 | * @return ArrayList of FileListItem containing file info of current directory. 70 | */ 71 | public static ArrayList prepareFileListEntries(ArrayList internalList, File inter, ExtensionFilter filter, Comparator sorter) { 72 | try { 73 | //Check for each and every directory/file in 'inter' directory. 74 | //Filter by extension using 'filter' reference. 75 | 76 | for (File name : inter.listFiles(filter)) { 77 | //If file/directory can be read by the Application 78 | if (name.canRead()) { 79 | //Create a row item for the directory list and define properties. 80 | FileListItem item = new FileListItem(); 81 | item.setFilename(name.getName()); 82 | item.setDirectory(name.isDirectory()); 83 | item.setLocation(name.getAbsolutePath()); 84 | item.setTime(name.lastModified()); 85 | item.setSize(name.length()); 86 | //Add row to the List of directories/files 87 | internalList.add(item); 88 | } 89 | } 90 | //Sort the files and directories in alphabetical order. 91 | //See compareTo method in FileListItem class. 92 | Collections.sort(internalList, sorter); 93 | } catch (NullPointerException e) { //Just dont worry, it rarely occurs. 94 | e.printStackTrace(); 95 | internalList = new ArrayList<>(); 96 | } 97 | return internalList; 98 | } 99 | 100 | public static Comparator createFileListItemsComparator(DialogProperties properties) { 101 | final Comparator comparator; 102 | final boolean reversed = properties.sortOrder == DialogConfigs.SORT_ORDER_REVERSE; 103 | 104 | switch (properties.sortBy) { 105 | case DialogConfigs.SORT_BY_LAST_MODIFIED: 106 | comparator = new Comparator() { 107 | @Override 108 | public int compare(FileListItem item1, FileListItem item2) { 109 | if (item2.isDirectory() && item1.isDirectory()) { 110 | if (item1.getFilename().equals("...")) 111 | return -1; 112 | 113 | if (item2.getFilename().equals("...")) 114 | return 1; 115 | 116 | return -Long.compare(item1.getTime(), item2.getTime()) * (reversed ? -1 : 1); 117 | } else if (!item2.isDirectory() && !item1.isDirectory()) { //If the comparison is not between two directories, return the file with 118 | //alphabetic order first. 119 | return -Long.compare(item1.getTime(), item2.getTime()) * (reversed ? -1 : 1); 120 | } else if (item2.isDirectory() && !item1.isDirectory()) { //If the comparison is between a directory and a file, return the directory. 121 | return 1; 122 | } else { //Same as above but order of occurence is different. 123 | return -1; 124 | } 125 | } 126 | }; 127 | break; 128 | case DialogConfigs.SORT_BY_NAME: 129 | comparator = new Comparator() { 130 | @Override 131 | public int compare(FileListItem item1, FileListItem item2) { 132 | if (item2.isDirectory() && item1.isDirectory()) { 133 | if (item1.getFilename().equals("...")) 134 | return -1; 135 | 136 | if (item2.getFilename().equals("...")) 137 | return 1; 138 | 139 | return item1.getFilename().toLowerCase().compareTo(item2.getFilename().toLowerCase(Locale.getDefault())) * (reversed ? -1 : 1); 140 | } else if (!item2.isDirectory() && !item1.isDirectory()) { //If the comparison is not between two directories, return the file with 141 | //alphabetic order first. 142 | return item1.getFilename().toLowerCase().compareTo(item2.getFilename().toLowerCase(Locale.getDefault())) * (reversed ? -1 : 1); 143 | } else if (item2.isDirectory() && !item1.isDirectory()) { //If the comparison is between a directory and a file, return the directory. 144 | return 1; 145 | } else { //Same as above but order of occurence is different. 146 | return -1; 147 | } 148 | } 149 | }; 150 | break; 151 | case DialogConfigs.SORT_BY_SIZE: 152 | comparator = new Comparator() { 153 | @Override 154 | public int compare(FileListItem item1, FileListItem item2) { 155 | if (item2.isDirectory() && item1.isDirectory()) { 156 | if (item1.getFilename().equals("...")) 157 | return -1; 158 | 159 | if (item2.getFilename().equals("...")) 160 | return 1; 161 | 162 | return item1.getFilename().toLowerCase().compareTo(item2.getFilename().toLowerCase(Locale.getDefault())); 163 | } else if (!item2.isDirectory() && !item1.isDirectory()) { //If the comparison is not between two directories, return the file with 164 | //alphabetic order first. 165 | return -Long.compare(item1.getSize(), item2.getSize()) * (reversed ? -1 : 1); 166 | } else if (item2.isDirectory() && !item1.isDirectory()) { //If the comparison is between a directory and a file, return the directory. 167 | return 1; 168 | } else { //Same as above but order of occurence is different. 169 | return -1; 170 | } 171 | } 172 | }; 173 | break; 174 | default: 175 | comparator = new Comparator() { 176 | @Override 177 | public int compare(FileListItem o1, FileListItem o2) { 178 | return o1.compareTo(o2); 179 | } 180 | }; 181 | } 182 | 183 | return comparator; 184 | } 185 | 186 | private static DecimalFormat sSizeDecimalFormat; 187 | 188 | public static String formatSize(Context c, long bytes) { 189 | if (sSizeDecimalFormat == null) { 190 | sSizeDecimalFormat = new DecimalFormat("#.##"); 191 | sSizeDecimalFormat.setDecimalFormatSymbols(DecimalFormatSymbols.getInstance(Locale.US)); 192 | } 193 | 194 | String[] units = c.getResources().getStringArray(R.array.size_units); 195 | 196 | for (int i = 0; i < units.length; i++) { 197 | 198 | float size = (float) bytes / (float) Math.pow(1024, i); 199 | 200 | if (size < 1024) 201 | return String.format("%s %s", sSizeDecimalFormat.format(size), units[i]); 202 | 203 | } 204 | 205 | return bytes + " B"; 206 | } 207 | } 208 | -------------------------------------------------------------------------------- /filepicker/src/main/java/com/github/angads25/filepicker/view/FilePickerDialog.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Angad Singh 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.github.angads25.filepicker.view; 18 | 19 | import android.Manifest; 20 | import android.app.Activity; 21 | import android.app.Dialog; 22 | import android.content.Context; 23 | import android.os.Build; 24 | import android.os.Bundle; 25 | import android.view.View; 26 | import android.view.Window; 27 | import android.widget.AdapterView; 28 | import android.widget.Button; 29 | import android.widget.ListView; 30 | import android.widget.TextView; 31 | import android.widget.Toast; 32 | 33 | import com.github.angads25.filepicker.R; 34 | import com.github.angads25.filepicker.controller.DialogSelectionListener; 35 | import com.github.angads25.filepicker.controller.NotifyItemChecked; 36 | import com.github.angads25.filepicker.controller.adapters.FileListAdapter; 37 | import com.github.angads25.filepicker.model.DialogConfigs; 38 | import com.github.angads25.filepicker.model.DialogProperties; 39 | import com.github.angads25.filepicker.model.FileListItem; 40 | import com.github.angads25.filepicker.model.MarkedItemList; 41 | import com.github.angads25.filepicker.utils.ExtensionFilter; 42 | import com.github.angads25.filepicker.utils.Utility; 43 | import com.google.android.material.checkbox.MaterialCheckBox; 44 | 45 | import java.io.File; 46 | import java.util.ArrayList; 47 | import java.util.List; 48 | 49 | /** 50 | *

51 | * Created by Angad Singh on 09-07-2016. 52 | *

53 | */ 54 | 55 | public class FilePickerDialog extends Dialog implements AdapterView.OnItemClickListener { 56 | private Context context; 57 | private ListView listView; 58 | private TextView dname, dir_path, title; 59 | private DialogProperties properties; 60 | private DialogSelectionListener callbacks; 61 | private ArrayList internalList; 62 | private ExtensionFilter filter; 63 | private FileListAdapter mFileListAdapter; 64 | private Button select; 65 | private String titleStr = null; 66 | private String positiveBtnNameStr = null; 67 | private String negativeBtnNameStr = null; 68 | private File currentDirectory; 69 | 70 | public static final int EXTERNAL_READ_PERMISSION_GRANT = 112; 71 | 72 | public FilePickerDialog(Context context) { 73 | super(context, R.style.FilePickerDialog_DefaultTheme); 74 | this.context = context; 75 | properties = new DialogProperties(); 76 | filter = new ExtensionFilter(properties); 77 | internalList = new ArrayList<>(); 78 | } 79 | 80 | public FilePickerDialog(Context context, DialogProperties properties) { 81 | super(context, R.style.FilePickerDialog_DefaultTheme); 82 | this.context = context; 83 | this.properties = properties; 84 | filter = new ExtensionFilter(properties); 85 | internalList = new ArrayList<>(); 86 | } 87 | 88 | public FilePickerDialog(Context context, DialogProperties properties, int themeResId) { 89 | super(context, themeResId); 90 | this.context = context; 91 | this.properties = properties; 92 | filter = new ExtensionFilter(properties); 93 | internalList = new ArrayList<>(); 94 | } 95 | 96 | @Override 97 | protected void onCreate(Bundle savedInstanceState) { 98 | super.onCreate(savedInstanceState); 99 | requestWindowFeature(Window.FEATURE_NO_TITLE); 100 | setContentView(R.layout.dialog_main); 101 | listView = findViewById(R.id.fileList); 102 | select = findViewById(R.id.select); 103 | int size = MarkedItemList.getFileCount(); 104 | if (size == 0 && !(properties.selection_mode == DialogConfigs.SINGLE_MODE && (properties.selection_type == DialogConfigs.DIR_SELECT || properties.selection_type == DialogConfigs.FILE_AND_DIR_SELECT))) { 105 | select.setEnabled(false); 106 | } 107 | if (properties.selection_mode == DialogConfigs.SINGLE_MODE && properties.selection_type == DialogConfigs.FILE_SELECT) 108 | select.setVisibility(View.GONE); 109 | else 110 | select.setVisibility(View.VISIBLE); 111 | 112 | dname = findViewById(R.id.dname); 113 | title = findViewById(R.id.title); 114 | dir_path = findViewById(R.id.dir_path); 115 | Button cancel = findViewById(R.id.cancel); 116 | if (negativeBtnNameStr != null) { 117 | cancel.setText(negativeBtnNameStr); 118 | } 119 | select.setOnClickListener(new View.OnClickListener() { 120 | @Override 121 | public void onClick(View view) { 122 | /* Select Button is clicked. Get the array of all selected items 123 | * from MarkedItemList singleton. 124 | */ 125 | if (properties.selection_mode == DialogConfigs.SINGLE_MODE && (properties.selection_type == DialogConfigs.DIR_SELECT || properties.selection_type == DialogConfigs.FILE_AND_DIR_SELECT)) { 126 | FileListItem item = new FileListItem(); 127 | item.setFilename(currentDirectory.getName()); 128 | item.setDirectory(currentDirectory.isDirectory()); 129 | item.setLocation(currentDirectory.getAbsolutePath()); 130 | item.setTime(currentDirectory.lastModified()); 131 | item.setSize(currentDirectory.length()); 132 | MarkedItemList.addSingleFile(item); 133 | } 134 | finishSelection(); 135 | } 136 | }); 137 | cancel.setOnClickListener(new View.OnClickListener() { 138 | @Override 139 | public void onClick(View view) { 140 | cancel(); 141 | } 142 | }); 143 | mFileListAdapter = new FileListAdapter(internalList, context, properties); 144 | mFileListAdapter.setNotifyItemCheckedListener(new NotifyItemChecked() { 145 | @Override 146 | public void notifyCheckBoxIsClicked() { 147 | /* Handler function, called when a checkbox is checked ie. a file is 148 | * selected. 149 | */ 150 | positiveBtnNameStr = positiveBtnNameStr == null ? 151 | context.getResources().getString(R.string.choose_button_label) : positiveBtnNameStr; 152 | int size = MarkedItemList.getFileCount(); 153 | if (size == 0) { 154 | select.setEnabled(false); 155 | select.setText(positiveBtnNameStr); 156 | } else { 157 | select.setEnabled(true); 158 | String button_label = positiveBtnNameStr + " (" + size + ") "; 159 | select.setText(button_label); 160 | } 161 | if (properties.selection_mode == DialogConfigs.SINGLE_MODE) { 162 | /* If a single file has to be selected, clear the previously checked 163 | * checkbox from the list. 164 | */ 165 | mFileListAdapter.notifyDataSetChanged(); 166 | } 167 | } 168 | }); 169 | listView.setAdapter(mFileListAdapter); 170 | 171 | //Title method added in version 1.0.5 172 | setTitle(); 173 | } 174 | 175 | private void setTitle() { 176 | if (title == null || dname == null) { 177 | return; 178 | } 179 | if (titleStr != null) { 180 | if (title.getVisibility() == View.INVISIBLE) { 181 | title.setVisibility(View.VISIBLE); 182 | } 183 | title.setText(titleStr); 184 | if (dname.getVisibility() == View.VISIBLE) { 185 | dname.setVisibility(View.INVISIBLE); 186 | } 187 | } else { 188 | if (title.getVisibility() == View.VISIBLE) { 189 | title.setVisibility(View.INVISIBLE); 190 | } 191 | if (dname.getVisibility() == View.INVISIBLE) { 192 | dname.setVisibility(View.VISIBLE); 193 | } 194 | } 195 | } 196 | 197 | @Override 198 | protected void onStart() { 199 | super.onStart(); 200 | positiveBtnNameStr = ( 201 | positiveBtnNameStr == null ? 202 | context.getResources().getString(R.string.choose_button_label) : 203 | positiveBtnNameStr 204 | ); 205 | select.setText(positiveBtnNameStr); 206 | if (Utility.checkStorageAccessPermissions(context)) { 207 | internalList.clear(); 208 | if (properties.offset.isDirectory() && validateOffsetPath()) { 209 | currentDirectory = new File(properties.offset.getAbsolutePath()); 210 | FileListItem parent = new FileListItem(); 211 | parent.setFilename(context.getString(R.string.label_parent_dir)); 212 | parent.setDirectory(true); 213 | parent.setLocation(currentDirectory.getParentFile().getAbsolutePath()); 214 | parent.setTime(currentDirectory.lastModified()); 215 | parent.setSize(currentDirectory.length()); 216 | internalList.add(parent); 217 | } else if (properties.root.exists() && properties.root.isDirectory()) { 218 | currentDirectory = new File(properties.root.getAbsolutePath()); 219 | } else { 220 | currentDirectory = new File(properties.error_dir.getAbsolutePath()); 221 | } 222 | dname.setText(currentDirectory.getName()); 223 | dir_path.setText(currentDirectory.getAbsolutePath()); 224 | setTitle(); 225 | internalList = Utility.prepareFileListEntries(internalList, currentDirectory, filter, Utility.createFileListItemsComparator(properties)); 226 | mFileListAdapter.notifyDataSetChanged(); 227 | listView.setOnItemClickListener(this); 228 | } 229 | } 230 | 231 | private boolean validateOffsetPath() { 232 | String offset_path = properties.offset.getAbsolutePath(); 233 | String root_path = properties.root.getAbsolutePath(); 234 | return !offset_path.equals(root_path) && offset_path.contains(root_path); 235 | } 236 | 237 | @Override 238 | public void onItemClick(AdapterView adapterView, View view, int i, long l) { 239 | if (internalList.size() > i) { 240 | FileListItem fitem = internalList.get(i); 241 | if (fitem.isDirectory()) { 242 | if (new File(fitem.getLocation()).canRead()) { 243 | currentDirectory = new File(fitem.getLocation()); 244 | dname.setText(currentDirectory.getName()); 245 | setTitle(); 246 | dir_path.setText(currentDirectory.getAbsolutePath()); 247 | internalList.clear(); 248 | if (!currentDirectory.getName().equals(properties.root.getName())) { 249 | FileListItem parent = new FileListItem(); 250 | parent.setFilename(context.getString(R.string.label_parent_dir)); 251 | parent.setDirectory(true); 252 | parent.setLocation(currentDirectory.getParentFile().getAbsolutePath()); 253 | parent.setTime(currentDirectory.lastModified()); 254 | parent.setSize(currentDirectory.length()); 255 | internalList.add(parent); 256 | } 257 | internalList = Utility.prepareFileListEntries(internalList, currentDirectory, filter, Utility.createFileListItemsComparator(properties)); 258 | mFileListAdapter.notifyDataSetChanged(); 259 | } else { 260 | Toast.makeText(context, R.string.error_dir_access, Toast.LENGTH_SHORT).show(); 261 | } 262 | } else { 263 | if (properties.selection_mode == DialogConfigs.SINGLE_MODE) { 264 | MarkedItemList.addSingleFile(fitem); 265 | finishSelection(); 266 | } else { 267 | MaterialCheckBox fmark = view.findViewById(R.id.file_mark); 268 | fmark.performClick(); 269 | } 270 | } 271 | } 272 | } 273 | 274 | public DialogProperties getProperties() { 275 | return properties; 276 | } 277 | 278 | void setProperties(DialogProperties properties) { 279 | this.properties = properties; 280 | filter = new ExtensionFilter(properties); 281 | } 282 | 283 | public void setDialogSelectionListener(DialogSelectionListener callbacks) { 284 | this.callbacks = callbacks; 285 | } 286 | 287 | @Override 288 | public void setTitle(CharSequence titleStr) { 289 | if (titleStr != null) { 290 | this.titleStr = titleStr.toString(); 291 | } else { 292 | this.titleStr = null; 293 | } 294 | setTitle(); 295 | } 296 | 297 | public void setPositiveBtnName(CharSequence positiveBtnNameStr) { 298 | if (positiveBtnNameStr != null) { 299 | this.positiveBtnNameStr = positiveBtnNameStr.toString(); 300 | } else { 301 | this.positiveBtnNameStr = null; 302 | } 303 | } 304 | 305 | public void setNegativeBtnName(CharSequence negativeBtnNameStr) { 306 | if (negativeBtnNameStr != null) { 307 | this.negativeBtnNameStr = negativeBtnNameStr.toString(); 308 | } else { 309 | this.negativeBtnNameStr = null; 310 | } 311 | } 312 | 313 | public void markFiles(List paths) { 314 | if (paths != null && paths.size() > 0) { 315 | if (properties.selection_mode == DialogConfigs.SINGLE_MODE) { 316 | File temp = new File(paths.get(0)); 317 | switch (properties.selection_type) { 318 | case DialogConfigs.DIR_SELECT: 319 | if (temp.exists() && temp.isDirectory()) { 320 | FileListItem item = new FileListItem(); 321 | item.setFilename(temp.getName()); 322 | item.setDirectory(temp.isDirectory()); 323 | item.setMarked(true); 324 | item.setTime(temp.lastModified()); 325 | item.setLocation(temp.getAbsolutePath()); 326 | item.setSize(temp.length()); 327 | MarkedItemList.addSelectedItem(item); 328 | } 329 | break; 330 | 331 | case DialogConfigs.FILE_SELECT: 332 | if (temp.exists() && temp.isFile()) { 333 | FileListItem item = new FileListItem(); 334 | item.setFilename(temp.getName()); 335 | item.setDirectory(temp.isDirectory()); 336 | item.setMarked(true); 337 | item.setTime(temp.lastModified()); 338 | item.setLocation(temp.getAbsolutePath()); 339 | item.setSize(temp.length()); 340 | MarkedItemList.addSelectedItem(item); 341 | } 342 | break; 343 | 344 | case DialogConfigs.FILE_AND_DIR_SELECT: 345 | if (temp.exists()) { 346 | FileListItem item = new FileListItem(); 347 | item.setFilename(temp.getName()); 348 | item.setDirectory(temp.isDirectory()); 349 | item.setMarked(true); 350 | item.setTime(temp.lastModified()); 351 | item.setLocation(temp.getAbsolutePath()); 352 | item.setSize(temp.length()); 353 | MarkedItemList.addSelectedItem(item); 354 | } 355 | break; 356 | } 357 | } else { 358 | for (String path : paths) { 359 | switch (properties.selection_type) { 360 | case DialogConfigs.DIR_SELECT: 361 | File temp = new File(path); 362 | if (temp.exists() && temp.isDirectory()) { 363 | FileListItem item = new FileListItem(); 364 | item.setFilename(temp.getName()); 365 | item.setDirectory(temp.isDirectory()); 366 | item.setMarked(true); 367 | item.setTime(temp.lastModified()); 368 | item.setLocation(temp.getAbsolutePath()); 369 | item.setSize(temp.length()); 370 | MarkedItemList.addSelectedItem(item); 371 | } 372 | break; 373 | 374 | case DialogConfigs.FILE_SELECT: 375 | temp = new File(path); 376 | if (temp.exists() && temp.isFile()) { 377 | FileListItem item = new FileListItem(); 378 | item.setFilename(temp.getName()); 379 | item.setDirectory(temp.isDirectory()); 380 | item.setMarked(true); 381 | item.setTime(temp.lastModified()); 382 | item.setLocation(temp.getAbsolutePath()); 383 | item.setSize(temp.length()); 384 | MarkedItemList.addSelectedItem(item); 385 | } 386 | break; 387 | 388 | case DialogConfigs.FILE_AND_DIR_SELECT: 389 | temp = new File(path); 390 | if (temp.exists() && (temp.isFile() || temp.isDirectory())) { 391 | FileListItem item = new FileListItem(); 392 | item.setFilename(temp.getName()); 393 | item.setDirectory(temp.isDirectory()); 394 | item.setMarked(true); 395 | item.setTime(temp.lastModified()); 396 | item.setLocation(temp.getAbsolutePath()); 397 | item.setSize(temp.length()); 398 | MarkedItemList.addSelectedItem(item); 399 | } 400 | break; 401 | } 402 | } 403 | } 404 | } 405 | } 406 | 407 | @Override 408 | public void show() { 409 | if (!Utility.checkStorageAccessPermissions(context)) { 410 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 411 | ((Activity) context).requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, EXTERNAL_READ_PERMISSION_GRANT); 412 | } 413 | } else { 414 | super.show(); 415 | positiveBtnNameStr = positiveBtnNameStr == null ? 416 | context.getResources().getString(R.string.choose_button_label) : positiveBtnNameStr; 417 | select.setText(positiveBtnNameStr); 418 | int size = MarkedItemList.getFileCount(); 419 | if (size == 0) { 420 | select.setText(positiveBtnNameStr); 421 | } else { 422 | String button_label = positiveBtnNameStr + " (" + size + ") "; 423 | select.setText(button_label); 424 | } 425 | } 426 | } 427 | 428 | @Override 429 | public void onBackPressed() { 430 | //currentDirName is dependent on dname 431 | String currentDirName = dname.getText().toString(); 432 | if (internalList.size() > 0) { 433 | FileListItem fitem = internalList.get(0); 434 | File currLoc = new File(fitem.getLocation()); 435 | if (currentDirName.equals(properties.root.getName()) || 436 | !currLoc.canRead()) { 437 | super.onBackPressed(); 438 | } else { 439 | dname.setText(currLoc.getName()); 440 | dir_path.setText(currLoc.getAbsolutePath()); 441 | internalList.clear(); 442 | if (!currLoc.getName().equals(properties.root.getName())) { 443 | FileListItem parent = new FileListItem(); 444 | parent.setFilename(context.getString(R.string.label_parent_dir)); 445 | parent.setDirectory(true); 446 | parent.setLocation(currLoc.getParentFile().getAbsolutePath()); 447 | parent.setTime(currLoc.lastModified()); 448 | parent.setSize(currLoc.length()); 449 | internalList.add(parent); 450 | } 451 | internalList = Utility.prepareFileListEntries(internalList, currLoc, filter, Utility.createFileListItemsComparator(properties)); 452 | mFileListAdapter.notifyDataSetChanged(); 453 | } 454 | setTitle(); 455 | } else { 456 | super.onBackPressed(); 457 | } 458 | } 459 | 460 | @Override 461 | public void dismiss() { 462 | MarkedItemList.clearSelectionList(); 463 | internalList.clear(); 464 | super.dismiss(); 465 | } 466 | 467 | private void finishSelection() { 468 | String paths[] = MarkedItemList.getSelectedPaths(); 469 | if (callbacks != null) 470 | callbacks.onSelectedFilePaths(paths); 471 | 472 | dismiss(); 473 | } 474 | } 475 | -------------------------------------------------------------------------------- /filepicker/src/main/java/com/github/angads25/filepicker/view/FilePickerPreference.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Angad Singh 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.github.angads25.filepicker.view; 18 | 19 | import android.content.Context; 20 | import android.content.res.TypedArray; 21 | import android.os.Bundle; 22 | import android.os.Parcel; 23 | import android.os.Parcelable; 24 | import android.preference.Preference; 25 | import android.util.AttributeSet; 26 | import android.view.View; 27 | 28 | import com.github.angads25.filepicker.R; 29 | import com.github.angads25.filepicker.controller.DialogSelectionListener; 30 | import com.github.angads25.filepicker.model.DialogConfigs; 31 | import com.github.angads25.filepicker.model.DialogProperties; 32 | 33 | import java.io.File; 34 | 35 | /** 36 | *

37 | * Created by angads25 on 15-07-2016. 38 | *

39 | */ 40 | 41 | public class FilePickerPreference extends Preference implements 42 | DialogSelectionListener, 43 | Preference.OnPreferenceClickListener { 44 | private FilePickerDialog mDialog; 45 | private DialogProperties properties; 46 | private String titleText = null; 47 | 48 | public FilePickerPreference(Context context) { 49 | super(context); 50 | properties = new DialogProperties(); 51 | setOnPreferenceClickListener(this); 52 | } 53 | 54 | public FilePickerPreference(Context context, AttributeSet attrs) { 55 | super(context, attrs); 56 | properties = new DialogProperties(); 57 | initProperties(attrs); 58 | setOnPreferenceClickListener(this); 59 | } 60 | 61 | public FilePickerPreference(Context context, AttributeSet attrs, int defStyleAttr) { 62 | super(context, attrs, defStyleAttr); 63 | properties = new DialogProperties(); 64 | initProperties(attrs); 65 | setOnPreferenceClickListener(this); 66 | } 67 | 68 | @Override 69 | protected Object onGetDefaultValue(TypedArray a, int index) { 70 | return super.onGetDefaultValue(a, index); 71 | } 72 | 73 | @Override 74 | protected void onSetInitialValue(boolean restorePersistedValue, Object defaultValue) { 75 | super.onSetInitialValue(restorePersistedValue, defaultValue); 76 | } 77 | 78 | @Override 79 | protected void onBindView(View view) { 80 | super.onBindView(view); 81 | } 82 | 83 | @Override 84 | protected Parcelable onSaveInstanceState() { 85 | final Parcelable superState = super.onSaveInstanceState(); 86 | if (mDialog == null || !mDialog.isShowing()) { 87 | return superState; 88 | } 89 | 90 | final SavedState myState = new SavedState(superState); 91 | myState.dialogBundle = mDialog.onSaveInstanceState(); 92 | return myState; 93 | } 94 | 95 | @Override 96 | protected void onRestoreInstanceState(Parcelable state) { 97 | if (state == null || !(state instanceof SavedState)) { 98 | super.onRestoreInstanceState(state); 99 | return; 100 | } 101 | SavedState myState = (SavedState) state; 102 | super.onRestoreInstanceState(myState.getSuperState()); 103 | showDialog(myState.dialogBundle); 104 | } 105 | 106 | private void showDialog(Bundle state) { 107 | mDialog = new FilePickerDialog(getContext()); 108 | setProperties(properties); 109 | mDialog.setDialogSelectionListener(this); 110 | if (state != null) { 111 | mDialog.onRestoreInstanceState(state); 112 | } 113 | mDialog.setTitle(titleText); 114 | mDialog.show(); 115 | } 116 | 117 | @Override 118 | public void onSelectedFilePaths(String[] files) { 119 | StringBuilder buff = new StringBuilder(); 120 | for (String path : files) { 121 | buff.append(path).append(":"); 122 | } 123 | String dFiles = buff.toString(); 124 | if (isPersistent()) { 125 | persistString(dFiles); 126 | } 127 | try { 128 | getOnPreferenceChangeListener().onPreferenceChange(this, dFiles); 129 | } catch (NullPointerException e) { 130 | e.printStackTrace(); 131 | } 132 | } 133 | 134 | @Override 135 | public boolean onPreferenceClick(Preference preference) { 136 | showDialog(null); 137 | return false; 138 | } 139 | 140 | public void setProperties(DialogProperties properties) { 141 | mDialog.setProperties(properties); 142 | } 143 | 144 | private static class SavedState extends BaseSavedState { 145 | Bundle dialogBundle; 146 | 147 | public SavedState(Parcel source) { 148 | super(source); 149 | dialogBundle = source.readBundle(getClass().getClassLoader()); 150 | } 151 | 152 | @Override 153 | public void writeToParcel(Parcel dest, int flags) { 154 | super.writeToParcel(dest, flags); 155 | dest.writeBundle(dialogBundle); 156 | } 157 | 158 | public SavedState(Parcelable superState) { 159 | super(superState); 160 | } 161 | 162 | @SuppressWarnings("unused") 163 | public static final Creator CREATOR = 164 | new Creator() { 165 | public SavedState createFromParcel(Parcel in) { 166 | return new SavedState(in); 167 | } 168 | 169 | public SavedState[] newArray(int size) { 170 | return new SavedState[size]; 171 | } 172 | }; 173 | } 174 | 175 | private void initProperties(AttributeSet attrs) { 176 | TypedArray tarr = getContext().getTheme().obtainStyledAttributes(attrs, R.styleable.FilePickerPreference, 0, 0); 177 | final int N = tarr.getIndexCount(); 178 | for (int i = 0; i < N; ++i) { 179 | int attr = tarr.getIndex(i); 180 | if (attr == R.styleable.FilePickerPreference_selection_mode) { 181 | properties.selection_mode = tarr.getInteger(R.styleable.FilePickerPreference_selection_mode, DialogConfigs.SINGLE_MODE); 182 | } else if (attr == R.styleable.FilePickerPreference_selection_type) { 183 | properties.selection_type = tarr.getInteger(R.styleable.FilePickerPreference_selection_type, DialogConfigs.FILE_SELECT); 184 | } else if (attr == R.styleable.FilePickerPreference_root_dir) { 185 | String root_dir = tarr.getString(R.styleable.FilePickerPreference_root_dir); 186 | if (root_dir != null && !root_dir.equals("")) { 187 | properties.root = new File(root_dir); 188 | } 189 | } else if (attr == R.styleable.FilePickerPreference_error_dir) { 190 | String error_dir = tarr.getString(R.styleable.FilePickerPreference_error_dir); 191 | if (error_dir != null && !error_dir.equals("")) { 192 | properties.error_dir = new File(error_dir); 193 | } 194 | } else if (attr == R.styleable.FilePickerPreference_offset_dir) { 195 | String offset_dir = tarr.getString(R.styleable.FilePickerPreference_offset_dir); 196 | if (offset_dir != null && !offset_dir.equals("")) { 197 | properties.offset = new File(offset_dir); 198 | } 199 | } else if (attr == R.styleable.FilePickerPreference_extensions) { 200 | String extensions = tarr.getString(R.styleable.FilePickerPreference_extensions); 201 | if (extensions != null && !extensions.equals("")) { 202 | properties.extensions = extensions.split(":"); 203 | } 204 | } else if (attr == R.styleable.FilePickerPreference_title_text) { 205 | titleText = tarr.getString(R.styleable.FilePickerPreference_title_text); 206 | } 207 | } 208 | tarr.recycle(); 209 | } 210 | } 211 | -------------------------------------------------------------------------------- /filepicker/src/main/res/anim/marked_item_animation.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /filepicker/src/main/res/anim/unmarked_item_animation.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /filepicker/src/main/res/drawable/bottom_shadow.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aefyr/android-filepicker/f50f1bcbd8c8a5cb109cad28511466d40f2d47c8/filepicker/src/main/res/drawable/bottom_shadow.9.png -------------------------------------------------------------------------------- /filepicker/src/main/res/drawable/ic_directory_parent.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /filepicker/src/main/res/drawable/ic_type_file.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /filepicker/src/main/res/drawable/ic_type_folder.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /filepicker/src/main/res/layout-v21/dialog_file_list_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 18 | 19 | 28 | 29 | 37 | 38 | 44 | 45 | 46 | 52 | 53 | -------------------------------------------------------------------------------- /filepicker/src/main/res/layout-v21/dialog_header.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 18 | 19 | 25 | 26 | 30 | 31 | 41 | 42 | 53 | 54 | 55 | 56 | 64 | 65 | -------------------------------------------------------------------------------- /filepicker/src/main/res/layout/dialog_file_list.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | -------------------------------------------------------------------------------- /filepicker/src/main/res/layout/dialog_file_list_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 18 | 19 | 29 | 30 | 37 | 38 | 44 | 45 | 46 | 52 | -------------------------------------------------------------------------------- /filepicker/src/main/res/layout/dialog_footer.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 16 | 17 | 24 | 25 | 32 | -------------------------------------------------------------------------------- /filepicker/src/main/res/layout/dialog_header.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 18 | 19 | 25 | 26 | 30 | 31 | 42 | 43 | 55 | 56 | 57 | 58 | 67 | 68 | -------------------------------------------------------------------------------- /filepicker/src/main/res/layout/dialog_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 12 | 13 | 22 | 23 | 26 | -------------------------------------------------------------------------------- /filepicker/src/main/res/values-ar/arrays.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | بت 5 | كيلوبايت 6 | ميجابايت 7 | جيجابايت 8 | تيرابايت 9 | بيتابايت 10 | 11 | 12 | -------------------------------------------------------------------------------- /filepicker/src/main/res/values-ar/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | إلغاء 4 | تحديد 5 | المجلد الأصل 6 | آخر تعديل:%s 7 | %1$s, last modified: %2$s 8 | لا يمكن الوصول إلى المجلد 9 | 10 | -------------------------------------------------------------------------------- /filepicker/src/main/res/values-az/arrays.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | B 5 | KB 6 | MB 7 | GB 8 | TB 9 | PB 10 | 11 | 12 | -------------------------------------------------------------------------------- /filepicker/src/main/res/values-az/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Ləğv et 4 | Seç 5 | Valideyn yeri 6 | Son dəyişdirilmə: %s 7 | %1$s, son dəyişdirilmə: %2$s 8 | Yer əlçatan deyil 9 | 10 | -------------------------------------------------------------------------------- /filepicker/src/main/res/values-bg/arrays.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Б 5 | КБ 6 | МБ 7 | ГБ 8 | ТБ 9 | ПБ 10 | 11 | 12 | -------------------------------------------------------------------------------- /filepicker/src/main/res/values-bg/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Cancel 4 | Select 5 | Parent Directory 6 | Last edited: %s 7 | %1$s, last modified: %2$s 8 | Directory cannot be accessed 9 | 10 | -------------------------------------------------------------------------------- /filepicker/src/main/res/values-de/arrays.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | B 5 | KB 6 | MB 7 | GB 8 | TB 9 | PB 10 | 11 | 12 | -------------------------------------------------------------------------------- /filepicker/src/main/res/values-de/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Abbrechen 4 | Auswählen 5 | Übergeordnetes Verzeichnis 6 | Zuletzt bearbeitet: %s 7 | %1$s, zuletzt bearbeitet: %2$s 8 | Auf Verzeichnis kann nicht zugegriffen werden 9 | 10 | -------------------------------------------------------------------------------- /filepicker/src/main/res/values-es/arrays.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | B 5 | KB 6 | MB 7 | GB 8 | TB 9 | PB 10 | 11 | 12 | -------------------------------------------------------------------------------- /filepicker/src/main/res/values-es/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Canclear 4 | Seleccionar 5 | Directorio Padre 6 | Ult. edición: %s 7 | %1$s, ult. edición: %2$s 8 | No se puede acceder al directorio 9 | 10 | -------------------------------------------------------------------------------- /filepicker/src/main/res/values-fr/arrays.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | B 5 | KB 6 | MB 7 | GB 8 | TB 9 | PB 10 | 11 | 12 | -------------------------------------------------------------------------------- /filepicker/src/main/res/values-fr/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Annuler 4 | Choisir 5 | Répertoire parent 6 | Dernière modification: %s 7 | %1$s, dernière modification: %2$s 8 | L\'annuaire ne peut pas être consulté 9 | 10 | -------------------------------------------------------------------------------- /filepicker/src/main/res/values-it/arrays.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | B 5 | KB 6 | MB 7 | GB 8 | TB 9 | PB 10 | 11 | 12 | -------------------------------------------------------------------------------- /filepicker/src/main/res/values-it/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Annulla 4 | Seleziona 5 | Cartella Superiore 6 | Ultima modifica: %s 7 | %1$s, ultima modifica: %2$s 8 | Impossibile accedere alla directory 9 | 10 | -------------------------------------------------------------------------------- /filepicker/src/main/res/values-ja/arrays.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | B 5 | KB 6 | MB 7 | GB 8 | TB 9 | PB 10 | 11 | 12 | -------------------------------------------------------------------------------- /filepicker/src/main/res/values-ja/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | キャンセル 4 | 選択 5 | 親フォルダ 6 | 最終編集: %s 7 | %1$s, 最終変更: %2$s 8 | フォルダにアクセスできません 9 | 10 | -------------------------------------------------------------------------------- /filepicker/src/main/res/values-ko/arrays.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | B 5 | KB 6 | MB 7 | GB 8 | TB 9 | PB 10 | 11 | 12 | -------------------------------------------------------------------------------- /filepicker/src/main/res/values-ko/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 취소 4 | 선택 5 | 상위 디렉토리 6 | 마지막으로 수정됨: %s 7 | %1$s, 마지막으로 변경됨: %2$s 8 | 디렉토리에 접근할 수 없음 9 | 10 | -------------------------------------------------------------------------------- /filepicker/src/main/res/values-pl/arrays.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | B 5 | KB 6 | MB 7 | GB 8 | TB 9 | PB 10 | 11 | 12 | -------------------------------------------------------------------------------- /filepicker/src/main/res/values-pl/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Anuluj 4 | Wybierz 5 | Katalog nadrzędny 6 | Ostatnia edycja: %s 7 | %1$s, ostatnia modyfikacja: %2$s 8 | Brak dostępu do katalogu 9 | 10 | -------------------------------------------------------------------------------- /filepicker/src/main/res/values-pt-rBR/arrays.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | B 5 | KB 6 | MB 7 | GB 8 | TB 9 | PB 10 | 11 | 12 | -------------------------------------------------------------------------------- /filepicker/src/main/res/values-pt-rBR/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Cancelar 4 | Selecionar 5 | Diretório superior 6 | Última edição: %s 7 | %1$s, última modificação: %2$s 8 | O diretório não pode ser acessado 9 | 10 | -------------------------------------------------------------------------------- /filepicker/src/main/res/values-ru/arrays.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Б 5 | КБ 6 | МБ 7 | ГБ 8 | ТБ 9 | ПБ 10 | 11 | 12 | -------------------------------------------------------------------------------- /filepicker/src/main/res/values-ru/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Отмена 4 | Выбрать 5 | Родительская директория 6 | Последнее изменение: %s 7 | %1$s, последнее изменение: %2$s 8 | Директория недоступна 9 | 10 | -------------------------------------------------------------------------------- /filepicker/src/main/res/values-sv-rSE/arrays.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | B 5 | KB 6 | MB 7 | GB 8 | TB 9 | PB 10 | 11 | 12 | -------------------------------------------------------------------------------- /filepicker/src/main/res/values-sv-rSE/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Cancel 4 | Select 5 | Parent Directory 6 | Last edited: %s 7 | %1$s, last modified: %2$s 8 | Directory cannot be accessed 9 | 10 | -------------------------------------------------------------------------------- /filepicker/src/main/res/values-tr/arrays.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | B 5 | KB 6 | MB 7 | GB 8 | TB 9 | PB 10 | 11 | 12 | -------------------------------------------------------------------------------- /filepicker/src/main/res/values-tr/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Cancel 4 | Select 5 | Parent Directory 6 | Last edited: %s 7 | %1$s, last modified: %2$s 8 | Directory cannot be accessed 9 | 10 | -------------------------------------------------------------------------------- /filepicker/src/main/res/values-uk/arrays.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | B 5 | KB 6 | MB 7 | GB 8 | TB 9 | PB 10 | 11 | 12 | -------------------------------------------------------------------------------- /filepicker/src/main/res/values-uk/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Відміна 4 | Вибрати 5 | Батьківська тека 6 | Останні зміни: %s 7 | %1$s, останні зміни: %2$s 8 | Тека недоступна 9 | 10 | -------------------------------------------------------------------------------- /filepicker/src/main/res/values-vi/arrays.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | B 5 | KB 6 | MB 7 | GB 8 | TB 9 | PB 10 | 11 | 12 | -------------------------------------------------------------------------------- /filepicker/src/main/res/values-vi/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Hủy bỏ 4 | Chọn 5 | Thư mục cha mẹ 6 | Lần chỉnh sửa cuối: %s 7 | %1$s, lần thay đổi cuối: %2$s 8 | Không thể truy cập thư mục 9 | 10 | -------------------------------------------------------------------------------- /filepicker/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 8dp 3 | 16dp 4 | 32dp 5 | 32dp 6 | 7 | -------------------------------------------------------------------------------- /filepicker/src/main/res/values-zh-rCN/arrays.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | B 5 | KB 6 | MB 7 | GB 8 | TB 9 | PB 10 | 11 | 12 | -------------------------------------------------------------------------------- /filepicker/src/main/res/values-zh-rCN/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 取消 4 | 选择 5 | 上级目录 6 | 最近修改:%s 7 | %1$s, 最近修改:%2$s 8 | 目录无法访问 9 | 10 | -------------------------------------------------------------------------------- /filepicker/src/main/res/values-zh-rTW/arrays.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | B 5 | KB 6 | MB 7 | GB 8 | TB 9 | PB 10 | 11 | 12 | -------------------------------------------------------------------------------- /filepicker/src/main/res/values-zh-rTW/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 取消 4 | 選擇 5 | 上層資料夾 6 | 最後修改:%s 7 | %1$s, 最後修改:%2$s 8 | Directory cannot be accessed 9 | 10 | -------------------------------------------------------------------------------- /filepicker/src/main/res/values/arrays.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | B 6 | KB 7 | MB 8 | GB 9 | TB 10 | PB 11 | 12 | 13 | -------------------------------------------------------------------------------- /filepicker/src/main/res/values/attrs.xml: -------------------------------------------------------------------------------- 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 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /filepicker/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #3F51B5 6 | #FFFFFF 7 | #FFFFFF 8 | @color/colorPrimary 9 | 10 | -------------------------------------------------------------------------------- /filepicker/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 4dp 3 | 8dp 4 | 16dp 5 | 24dp 6 | 7 | -------------------------------------------------------------------------------- /filepicker/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Cancel 4 | Select 5 | /sdcard 6 | Parent Directory 7 | Last edited: %s 8 | %1$s, last modified: %2$s 9 | Directory cannot be accessed 10 | ... 11 | -------------------------------------------------------------------------------- /filepicker/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aefyr/android-filepicker/f50f1bcbd8c8a5cb109cad28511466d40f2d47c8/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Tue Jan 21 19:18:36 MSK 2020 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-5.4.1-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /screenshots/performance_overdraw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aefyr/android-filepicker/f50f1bcbd8c8a5cb109cad28511466d40f2d47c8/screenshots/performance_overdraw.png -------------------------------------------------------------------------------- /screenshots/profile_gpu_rendering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aefyr/android-filepicker/f50f1bcbd8c8a5cb109cad28511466d40f2d47c8/screenshots/profile_gpu_rendering.png -------------------------------------------------------------------------------- /screenshots/theme_black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aefyr/android-filepicker/f50f1bcbd8c8a5cb109cad28511466d40f2d47c8/screenshots/theme_black.png -------------------------------------------------------------------------------- /screenshots/theme_device_default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aefyr/android-filepicker/f50f1bcbd8c8a5cb109cad28511466d40f2d47c8/screenshots/theme_device_default.png -------------------------------------------------------------------------------- /screenshots/theme_holo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aefyr/android-filepicker/f50f1bcbd8c8a5cb109cad28511466d40f2d47c8/screenshots/theme_holo.png -------------------------------------------------------------------------------- /screenshots/theme_holo_light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aefyr/android-filepicker/f50f1bcbd8c8a5cb109cad28511466d40f2d47c8/screenshots/theme_holo_light.png -------------------------------------------------------------------------------- /screenshots/theme_material.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Aefyr/android-filepicker/f50f1bcbd8c8a5cb109cad28511466d40f2d47c8/screenshots/theme_material.png -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app', ':filepicker' 2 | --------------------------------------------------------------------------------