├── LICENSE.md └── OpenFileDialog.java /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013-2014 Sergey Antonov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /OpenFileDialog.java: -------------------------------------------------------------------------------- 1 | package edu.android.openfiledialog; 2 | 3 | import android.app.AlertDialog; 4 | import android.content.Context; 5 | import android.content.DialogInterface; 6 | import android.graphics.Paint; 7 | import android.graphics.Point; 8 | import android.graphics.Rect; 9 | import android.graphics.drawable.Drawable; 10 | import android.os.Environment; 11 | import android.util.DisplayMetrics; 12 | import android.util.TypedValue; 13 | import android.view.*; 14 | import android.widget.*; 15 | 16 | import java.io.File; 17 | import java.io.FilenameFilter; 18 | import java.util.*; 19 | 20 | /** 21 | * Created with IntelliJ IDEA. 22 | * User: Scogun 23 | * Date: 27.11.13 24 | * Time: 10:47 25 | */ 26 | public class OpenFileDialog extends AlertDialog.Builder { 27 | 28 | private String currentPath = Environment.getExternalStorageDirectory().getPath(); 29 | private List files = new ArrayList(); 30 | private TextView title; 31 | private ListView listView; 32 | private FilenameFilter filenameFilter; 33 | private int selectedIndex = -1; 34 | private OpenDialogListener listener; 35 | private Drawable folderIcon; 36 | private Drawable fileIcon; 37 | private String accessDeniedMessage; 38 | private boolean isOnlyFoldersFilter; 39 | 40 | public interface OpenDialogListener { 41 | public void OnSelectedFile(String fileName); 42 | } 43 | 44 | private class FileAdapter extends ArrayAdapter { 45 | 46 | public FileAdapter(Context context, List files) { 47 | super(context, android.R.layout.simple_list_item_1, files); 48 | } 49 | 50 | @Override 51 | public View getView(int position, View convertView, ViewGroup parent) { 52 | TextView view = (TextView) super.getView(position, convertView, parent); 53 | File file = getItem(position); 54 | if (view != null) { 55 | view.setText(file.getName()); 56 | if (file.isDirectory()) { 57 | setDrawable(view, folderIcon); 58 | } else { 59 | setDrawable(view, fileIcon); 60 | if (selectedIndex == position) 61 | view.setBackgroundColor(getContext().getResources().getColor(android.R.color.holo_blue_dark)); 62 | else 63 | view.setBackgroundColor(getContext().getResources().getColor(android.R.color.transparent)); 64 | } 65 | } 66 | return view; 67 | } 68 | 69 | private void setDrawable(TextView view, Drawable drawable) { 70 | if (view != null) { 71 | if (drawable != null) { 72 | drawable.setBounds(0, 0, 60, 60); 73 | view.setCompoundDrawables(drawable, null, null, null); 74 | } else { 75 | view.setCompoundDrawables(null, null, null, null); 76 | } 77 | } 78 | } 79 | } 80 | 81 | public OpenFileDialog(Context context) { 82 | super(context); 83 | isOnlyFoldersFilter = false; 84 | title = createTitle(context); 85 | changeTitle(); 86 | LinearLayout linearLayout = createMainLayout(context); 87 | linearLayout.addView(createBackItem(context)); 88 | listView = createListView(context); 89 | linearLayout.addView(listView); 90 | setCustomTitle(title) 91 | .setView(linearLayout) 92 | .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { 93 | @Override 94 | public void onClick(DialogInterface dialog, int which) { 95 | if (selectedIndex > -1 && listener != null) { 96 | listener.OnSelectedFile(listView.getItemAtPosition(selectedIndex).toString()); 97 | } 98 | if (listener != null && isOnlyFoldersFilter) { 99 | listener.OnSelectedFile(currentPath); 100 | } 101 | } 102 | }) 103 | .setNegativeButton(android.R.string.cancel, null); 104 | } 105 | 106 | @Override 107 | public AlertDialog show() { 108 | files.addAll(getFiles(currentPath)); 109 | listView.setAdapter(new FileAdapter(getContext(), files)); 110 | return super.show(); 111 | } 112 | 113 | public OpenFileDialog setFilter(final String filter) { 114 | filenameFilter = new FilenameFilter() { 115 | 116 | @Override 117 | public boolean accept(File file, String fileName) { 118 | File tempFile = new File(String.format("%s/%s", file.getPath(), fileName)); 119 | if (tempFile.isFile()) 120 | return tempFile.getName().matches(filter); 121 | return true; 122 | } 123 | }; 124 | return this; 125 | } 126 | 127 | public OpenFileDialog setOnlyFoldersFilter() { 128 | isOnlyFoldersFilter = true; 129 | filenameFilter = new FilenameFilter() { 130 | 131 | @Override 132 | public boolean accept(File file, String fileName) { 133 | File tempFile = new File(String.format("%s/%s", file.getPath(), fileName)); 134 | return tempFile.isDirectory(); 135 | } 136 | }; 137 | return this; 138 | } 139 | 140 | public OpenFileDialog setOpenDialogListener(OpenDialogListener listener) { 141 | this.listener = listener; 142 | return this; 143 | } 144 | 145 | public OpenFileDialog setFolderIcon(Drawable drawable) { 146 | this.folderIcon = drawable; 147 | return this; 148 | } 149 | 150 | public OpenFileDialog setFileIcon(Drawable drawable) { 151 | this.fileIcon = drawable; 152 | return this; 153 | } 154 | 155 | public OpenFileDialog setAccessDeniedMessage(String message) { 156 | this.accessDeniedMessage = message; 157 | return this; 158 | } 159 | 160 | private static Display getDefaultDisplay(Context context) { 161 | return ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay(); 162 | } 163 | 164 | private static Point getScreenSize(Context context) { 165 | Point screeSize = new Point(); 166 | getDefaultDisplay(context).getSize(screeSize); 167 | return screeSize; 168 | } 169 | 170 | private static int getLinearLayoutMinHeight(Context context) { 171 | return getScreenSize(context).y; 172 | } 173 | 174 | private LinearLayout createMainLayout(Context context) { 175 | LinearLayout linearLayout = new LinearLayout(context); 176 | linearLayout.setOrientation(LinearLayout.VERTICAL); 177 | linearLayout.setMinimumHeight(getLinearLayoutMinHeight(context)); 178 | return linearLayout; 179 | } 180 | 181 | private int getItemHeight(Context context) { 182 | TypedValue value = new TypedValue(); 183 | DisplayMetrics metrics = new DisplayMetrics(); 184 | context.getTheme().resolveAttribute(android.R.attr.listPreferredItemHeightSmall, value, true); 185 | getDefaultDisplay(context).getMetrics(metrics); 186 | return (int) TypedValue.complexToDimension(value.data, metrics); 187 | } 188 | 189 | private TextView createTextView(Context context, int style) { 190 | TextView textView = new TextView(context); 191 | textView.setTextAppearance(context, style); 192 | int itemHeight = getItemHeight(context); 193 | textView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, itemHeight)); 194 | textView.setMinHeight(itemHeight); 195 | textView.setGravity(Gravity.CENTER_VERTICAL); 196 | textView.setPadding(15, 0, 0, 0); 197 | return textView; 198 | } 199 | 200 | private TextView createTitle(Context context) { 201 | TextView textView = createTextView(context, android.R.style.TextAppearance_DeviceDefault_DialogWindowTitle); 202 | return textView; 203 | } 204 | 205 | private TextView createBackItem(Context context) { 206 | TextView textView = createTextView(context, android.R.style.TextAppearance_DeviceDefault_Small); 207 | Drawable drawable = getContext().getResources().getDrawable(android.R.drawable.ic_menu_directions); 208 | drawable.setBounds(0, 0, 60, 60); 209 | textView.setCompoundDrawables(drawable, null, null, null); 210 | textView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); 211 | textView.setOnClickListener(new View.OnClickListener() { 212 | 213 | @Override 214 | public void onClick(View view) { 215 | File file = new File(currentPath); 216 | File parentDirectory = file.getParentFile(); 217 | if (parentDirectory != null) { 218 | currentPath = parentDirectory.getPath(); 219 | RebuildFiles(((FileAdapter) listView.getAdapter())); 220 | } 221 | } 222 | }); 223 | return textView; 224 | } 225 | 226 | public int getTextWidth(String text, Paint paint) { 227 | Rect bounds = new Rect(); 228 | paint.getTextBounds(text, 0, text.length(), bounds); 229 | return bounds.left + bounds.width() + 80; 230 | } 231 | 232 | private void changeTitle() { 233 | String titleText = currentPath; 234 | int screenWidth = getScreenSize(getContext()).x; 235 | int maxWidth = (int) (screenWidth * 0.99); 236 | if (getTextWidth(titleText, title.getPaint()) > maxWidth) { 237 | while (getTextWidth("..." + titleText, title.getPaint()) > maxWidth) { 238 | int start = titleText.indexOf("/", 2); 239 | if (start > 0) 240 | titleText = titleText.substring(start); 241 | else 242 | titleText = titleText.substring(2); 243 | } 244 | title.setText("..." + titleText); 245 | } else { 246 | title.setText(titleText); 247 | } 248 | } 249 | 250 | private List getFiles(String directoryPath) { 251 | File directory = new File(directoryPath); 252 | File[] list = directory.listFiles(filenameFilter); 253 | if(list == null) 254 | list = new File[]{}; 255 | List fileList = Arrays.asList(list); 256 | Collections.sort(fileList, new Comparator() { 257 | @Override 258 | public int compare(File file, File file2) { 259 | if (file.isDirectory() && file2.isFile()) 260 | return -1; 261 | else if (file.isFile() && file2.isDirectory()) 262 | return 1; 263 | else 264 | return file.getPath().compareTo(file2.getPath()); 265 | } 266 | }); 267 | return fileList; 268 | } 269 | 270 | private void RebuildFiles(ArrayAdapter adapter) { 271 | try { 272 | List fileList = getFiles(currentPath); 273 | files.clear(); 274 | selectedIndex = -1; 275 | files.addAll(fileList); 276 | adapter.notifyDataSetChanged(); 277 | changeTitle(); 278 | } catch (NullPointerException e) { 279 | String message = getContext().getResources().getString(android.R.string.unknownName); 280 | if (!accessDeniedMessage.equals("")) 281 | message = accessDeniedMessage; 282 | Toast.makeText(getContext(), message, Toast.LENGTH_SHORT).show(); 283 | } 284 | } 285 | 286 | private ListView createListView(Context context) { 287 | ListView listView = new ListView(context); 288 | listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { 289 | 290 | @Override 291 | public void onItemClick(AdapterView adapterView, View view, int index, long l) { 292 | final ArrayAdapter adapter = (FileAdapter) adapterView.getAdapter(); 293 | File file = adapter.getItem(index); 294 | if (file.isDirectory()) { 295 | currentPath = file.getPath(); 296 | RebuildFiles(adapter); 297 | } else { 298 | if (index != selectedIndex) 299 | selectedIndex = index; 300 | else 301 | selectedIndex = -1; 302 | adapter.notifyDataSetChanged(); 303 | } 304 | } 305 | }); 306 | return listView; 307 | } 308 | } 309 | --------------------------------------------------------------------------------