1 // DirectoryChooserDialog.java
2 
3 package com.beloko.idtech;
4 
5 import java.io.File;
6 import java.io.IOException;
7 import java.util.ArrayList;
8 import java.util.Collections;
9 import java.util.Comparator;
10 import java.util.List;
11 
12 import android.app.AlertDialog;
13 import android.content.Context;
14 import android.content.DialogInterface;
15 import android.content.DialogInterface.OnClickListener;
16 import android.content.DialogInterface.OnKeyListener;
17 import android.os.Environment;
18 import android.text.Editable;
19 import android.util.Log;
20 import android.view.Gravity;
21 import android.view.KeyEvent;
22 import android.view.View;
23 import android.view.ViewGroup;
24 import android.view.ViewGroup.LayoutParams;
25 import android.widget.ArrayAdapter;
26 import android.widget.Button;
27 import android.widget.EditText;
28 import android.widget.LinearLayout;
29 import android.widget.TextView;
30 import android.widget.Toast;
31 
32 public class DirectoryChooserDialog
33 {
34 	private boolean m_isNewFolderEnabled = true;
35 	private String m_sdcardDirectory = "";
36 	private Context m_context;
37 	private TextView m_titleView;
38 
39 	private String m_dir = "";
40 	private List<String> m_subdirs = null;
41 	private ChosenDirectoryListener m_chosenDirectoryListener = null;
42 	private ArrayAdapter<String> m_listAdapter = null;
43 
44 	//////////////////////////////////////////////////////
45 	// Callback interface for selected directory
46 	//////////////////////////////////////////////////////
47 	public interface ChosenDirectoryListener
48 	{
onChosenDir(String chosenDir)49 		public void onChosenDir(String chosenDir);
50 	}
51 
DirectoryChooserDialog(Context context, ChosenDirectoryListener chosenDirectoryListener)52 	public DirectoryChooserDialog(Context context, ChosenDirectoryListener chosenDirectoryListener)
53 	{
54 		m_context = context;
55 		m_sdcardDirectory = Environment.getExternalStorageDirectory().getAbsolutePath();
56 		m_chosenDirectoryListener = chosenDirectoryListener;
57 
58 		try
59 		{
60 			m_sdcardDirectory = new File(m_sdcardDirectory).getCanonicalPath();
61 		}
62 		catch (IOException ioe)
63 		{
64 		}
65 	}
66 
67 	///////////////////////////////////////////////////////////////////////
68 	// setNewFolderEnabled() - enable/disable new folder button
69 	///////////////////////////////////////////////////////////////////////
70 
setNewFolderEnabled(boolean isNewFolderEnabled)71 	public void setNewFolderEnabled(boolean isNewFolderEnabled)
72 	{
73 		m_isNewFolderEnabled = isNewFolderEnabled;
74 	}
75 
getNewFolderEnabled()76 	public boolean getNewFolderEnabled()
77 	{
78 		return m_isNewFolderEnabled;
79 	}
80 
81 	///////////////////////////////////////////////////////////////////////
82 	// chooseDirectory() - load directory chooser dialog for initial
83 	// default sdcard directory
84 	///////////////////////////////////////////////////////////////////////
85 
chooseDirectory()86 	public void chooseDirectory()
87 	{
88 		// Initial directory is sdcard directory
89 		chooseDirectory(m_sdcardDirectory);
90 	}
91 
92 	////////////////////////////////////////////////////////////////////////////////
93 	// chooseDirectory(String dir) - load directory chooser dialog for initial
94 	// input 'dir' directory
95 	////////////////////////////////////////////////////////////////////////////////
96 
chooseDirectory(String dir)97 	public void chooseDirectory(String dir)
98 	{
99 		File dirFile = new File(dir);;
100 
101 		Log.d("dir","dir = " + dir);
102 
103 		if (! dirFile.exists() || ! dirFile.isDirectory())
104 		{
105 			dir = m_sdcardDirectory;
106 		}
107 
108 		try
109 		{
110 			dir = new File(dir).getCanonicalPath();
111 		}
112 		catch (IOException ioe)
113 		{
114 			return;
115 		}
116 
117 		m_dir = dir;
118 
119 		m_subdirs = getDirectories(dir);
120 
121 		class DirectoryOnClickListener implements DialogInterface.OnClickListener
122 		{
123 			public void onClick(DialogInterface dialog, int item)
124 			{
125 				// Navigate into the sub-directory
126 				m_dir += "/" + ((AlertDialog) dialog).getListView().getAdapter().getItem(item);
127 
128 				try {
129 					m_dir =  new File(m_dir).getCanonicalPath();
130 				} catch (IOException e) {
131 					// TODO Auto-generated catch block
132 					e.printStackTrace();
133 				}
134 
135 				updateDirectory();
136 			}
137 		}
138 
139 		AlertDialog.Builder dialogBuilder =
140 				createDirectoryChooserDialog(dir, m_subdirs, new DirectoryOnClickListener());
141 
142 		dialogBuilder.setPositiveButton("OK", new OnClickListener()
143 		{
144 			@Override
145 			public void onClick(DialogInterface dialog, int which)
146 			{
147 				// Current directory chosen
148 				if (m_chosenDirectoryListener != null)
149 				{
150 					// Call registered listener supplied with the chosen directory
151 					m_chosenDirectoryListener.onChosenDir(m_dir);
152 				}
153 			}
154 		}).setNegativeButton("Cancel", null);
155 
156 		final AlertDialog dirsDialog = dialogBuilder.create();
157 
158 		dirsDialog.setOnKeyListener(new OnKeyListener()
159 		{
160 			@Override
161 			public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event)
162 			{
163 				if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_DOWN)
164 				{
165 					// Back button pressed
166 					if ( m_dir.equals("/") )
167 					{
168 						// The very top level directory, do nothing
169 						return false;
170 					}
171 					else
172 					{
173 						// Navigate back to an upper directory
174 						m_dir = new File(m_dir).getParent();
175 						updateDirectory();
176 					}
177 
178 					return true;
179 				}
180 				else
181 				{
182 					return false;
183 				}
184 			}
185 		});
186 
187 		// Show directory chooser dialog
188 		dirsDialog.show();
189 	}
190 
createSubDir(String newDir)191 	private boolean createSubDir(String newDir)
192 	{
193 		File newDirFile = new File(newDir);
194 		if (! newDirFile.exists() )
195 		{
196 			return newDirFile.mkdir();
197 		}
198 
199 		return false;
200 	}
201 
getDirectories(String dir)202 	private List<String> getDirectories(String dir)
203 	{
204 		List<String> dirs = new ArrayList<String>();
205 
206 		dirs.add("..");
207 
208 		try
209 		{
210 			File dirFile = new File(dir);
211 			if (! dirFile.exists() || ! dirFile.isDirectory())
212 			{
213 				return dirs;
214 			}
215 
216 			for (File file : dirFile.listFiles())
217 			{
218 				if ( file.isDirectory() )
219 				{
220 					dirs.add( file.getName() );
221 				}
222 			}
223 		}
224 		catch (Exception e)
225 		{
226 		}
227 
228 		Collections.sort(dirs, new Comparator<String>()
229 				{
230 			public int compare(String o1, String o2)
231 			{
232 				return o1.compareTo(o2);
233 			}
234 				});
235 
236 		return dirs;
237 	}
238 
createDirectoryChooserDialog(String title, List<String> listItems, DialogInterface.OnClickListener onClickListener)239 	private AlertDialog.Builder createDirectoryChooserDialog(String title, List<String> listItems,
240 			DialogInterface.OnClickListener onClickListener)
241 	{
242 		AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(m_context);
243 
244 		// Create custom view for AlertDialog title containing
245 		// current directory TextView and possible 'New folder' button.
246 		// Current directory TextView allows long directory path to be wrapped to multiple lines.
247 		LinearLayout titleLayout = new LinearLayout(m_context);
248 		titleLayout.setOrientation(LinearLayout.VERTICAL);
249 
250 		m_titleView = new TextView(m_context);
251 		m_titleView.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
252 		m_titleView.setTextAppearance(m_context, android.R.style.TextAppearance_Large);
253 		m_titleView.setTextColor( m_context.getResources().getColor(android.R.color.white) );
254 		m_titleView.setGravity(Gravity.CENTER_VERTICAL | Gravity.CENTER_HORIZONTAL);
255 		m_titleView.setText(title);
256 
257 		Button newDirButton = new Button(m_context);
258 		newDirButton.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
259 		newDirButton.setText("New folder");
260 		newDirButton.setOnClickListener(new View.OnClickListener()
261 		{
262 			@Override
263 			public void onClick(View v)
264 			{
265 				final EditText input = new EditText(m_context);
266 
267 				// Show new folder name input dialog
268 				new AlertDialog.Builder(m_context).
269 				setTitle("New folder name").
270 				setView(input).setPositiveButton("OK", new DialogInterface.OnClickListener()
271 				{
272 					public void onClick(DialogInterface dialog, int whichButton)
273 					{
274 						Editable newDir = input.getText();
275 						String newDirName = newDir.toString();
276 						// Create new directory
277 						if ( createSubDir(m_dir + "/" + newDirName) )
278 						{
279 							// Navigate into the new directory
280 							m_dir += "/" + newDirName;
281 							updateDirectory();
282 						}
283 						else
284 						{
285 							Toast.makeText(
286 									m_context, "Failed to create '" + newDirName +
287 									"' folder", Toast.LENGTH_SHORT).show();
288 						}
289 					}
290 				}).setNegativeButton("Cancel", null).show();
291 			}
292 		});
293 
294 		if (! m_isNewFolderEnabled)
295 		{
296 			newDirButton.setVisibility(View.GONE);
297 		}
298 
299 		titleLayout.addView(m_titleView);
300 		titleLayout.addView(newDirButton);
301 
302 		dialogBuilder.setCustomTitle(titleLayout);
303 
304 		m_listAdapter = createListAdapter(listItems);
305 
306 		dialogBuilder.setSingleChoiceItems(m_listAdapter, -1, onClickListener);
307 		dialogBuilder.setCancelable(false);
308 
309 		return dialogBuilder;
310 	}
311 
updateDirectory()312 	private void updateDirectory()
313 	{
314 		m_subdirs.clear();
315 		m_subdirs.addAll( getDirectories(m_dir) );
316 		m_titleView.setText(m_dir);
317 
318 		m_listAdapter.notifyDataSetChanged();
319 	}
320 
createListAdapter(List<String> items)321 	private ArrayAdapter<String> createListAdapter(List<String> items)
322 	{
323 		return new ArrayAdapter<String>(m_context,
324 				android.R.layout.select_dialog_item, android.R.id.text1, items)
325 				{
326 			@Override
327 			public View getView(int position, View convertView,
328 					ViewGroup parent)
329 			{
330 				View v = super.getView(position, convertView, parent);
331 
332 				if (v instanceof TextView)
333 				{
334 					// Enable list item (directory) text wrapping
335 					TextView tv = (TextView) v;
336 					tv.getLayoutParams().height = LayoutParams.WRAP_CONTENT;
337 					tv.setEllipsize(null);
338 				}
339 				return v;
340 			}
341 				};
342 	}
343 }