PageRenderTime 50ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 1ms

/app/src/main/java/de/danoeh/antennapod/activity/DirectoryChooserActivity.java

https://gitlab.com/jnettome/AntennaPod
Java | 336 lines | 271 code | 33 blank | 32 comment | 53 complexity | e1d39244cbf775d6acffe2cb1595139e MD5 | raw file
  1. package de.danoeh.antennapod.activity;
  2. import android.app.Activity;
  3. import android.content.Intent;
  4. import android.os.Bundle;
  5. import android.os.Environment;
  6. import android.os.FileObserver;
  7. import android.support.v4.app.NavUtils;
  8. import android.support.v7.app.ActionBarActivity;
  9. import android.support.v7.app.AlertDialog;
  10. import android.util.Log;
  11. import android.view.Menu;
  12. import android.view.MenuInflater;
  13. import android.view.MenuItem;
  14. import android.view.View;
  15. import android.view.View.OnClickListener;
  16. import android.widget.ArrayAdapter;
  17. import android.widget.Button;
  18. import android.widget.ImageButton;
  19. import android.widget.ListView;
  20. import android.widget.TextView;
  21. import android.widget.Toast;
  22. import java.io.File;
  23. import java.util.ArrayList;
  24. import java.util.Arrays;
  25. import java.util.Collections;
  26. import de.danoeh.antennapod.BuildConfig;
  27. import de.danoeh.antennapod.R;
  28. import de.danoeh.antennapod.core.preferences.UserPreferences;
  29. /**
  30. * Let's the user choose a directory on the storage device. The selected folder
  31. * will be sent back to the starting activity as an activity result.
  32. */
  33. public class DirectoryChooserActivity extends ActionBarActivity {
  34. private static final String TAG = "DirectoryChooserActivit";
  35. private static final String CREATE_DIRECTORY_NAME = "AntennaPod";
  36. public static final String RESULT_SELECTED_DIR = "selected_dir";
  37. public static final int RESULT_CODE_DIR_SELECTED = 1;
  38. private Button butConfirm;
  39. private Button butCancel;
  40. private ImageButton butNavUp;
  41. private TextView txtvSelectedFolder;
  42. private ListView listDirectories;
  43. private ArrayAdapter<String> listDirectoriesAdapter;
  44. private ArrayList<String> filenames;
  45. /** The directory that is currently being shown. */
  46. private File selectedDir;
  47. private File[] filesInDir;
  48. private FileObserver fileObserver;
  49. @Override
  50. protected void onCreate(Bundle savedInstanceState) {
  51. setTheme(UserPreferences.getTheme());
  52. super.onCreate(savedInstanceState);
  53. getSupportActionBar().setDisplayHomeAsUpEnabled(true);
  54. setContentView(R.layout.directory_chooser);
  55. butConfirm = (Button) findViewById(R.id.butConfirm);
  56. butCancel = (Button) findViewById(R.id.butCancel);
  57. butNavUp = (ImageButton) findViewById(R.id.butNavUp);
  58. txtvSelectedFolder = (TextView) findViewById(R.id.txtvSelectedFolder);
  59. listDirectories = (ListView) findViewById(R.id.directory_list);
  60. butConfirm.setOnClickListener(new OnClickListener() {
  61. @Override
  62. public void onClick(View v) {
  63. if (isValidFile(selectedDir)) {
  64. if (selectedDir.list().length == 0) {
  65. returnSelectedFolder();
  66. } else {
  67. showNonEmptyDirectoryWarning();
  68. }
  69. }
  70. }
  71. private void showNonEmptyDirectoryWarning() {
  72. AlertDialog.Builder adb = new AlertDialog.Builder(
  73. DirectoryChooserActivity.this);
  74. adb.setTitle(R.string.folder_not_empty_dialog_title);
  75. adb.setMessage(R.string.folder_not_empty_dialog_msg);
  76. adb.setNegativeButton(R.string.cancel_label,
  77. (dialog, which) -> {
  78. dialog.dismiss();
  79. });
  80. adb.setPositiveButton(R.string.confirm_label,
  81. (dialog, which) -> {
  82. dialog.dismiss();
  83. returnSelectedFolder();
  84. });
  85. adb.create().show();
  86. }
  87. });
  88. butCancel.setOnClickListener(v -> {
  89. setResult(Activity.RESULT_CANCELED);
  90. finish();
  91. });
  92. listDirectories.setOnItemClickListener((adapter, view, position, id) -> {
  93. Log.d(TAG, "Selected index: " + position);
  94. if (filesInDir != null && position >= 0
  95. && position < filesInDir.length) {
  96. changeDirectory(filesInDir[position]);
  97. }
  98. });
  99. butNavUp.setOnClickListener(v -> {
  100. File parent = null;
  101. if (selectedDir != null
  102. && (parent = selectedDir.getParentFile()) != null) {
  103. changeDirectory(parent);
  104. }
  105. });
  106. filenames = new ArrayList<>();
  107. listDirectoriesAdapter = new ArrayAdapter<>(this,
  108. android.R.layout.simple_list_item_1, filenames);
  109. listDirectories.setAdapter(listDirectoriesAdapter);
  110. changeDirectory(Environment.getExternalStorageDirectory());
  111. }
  112. /**
  113. * Finishes the activity and returns the selected folder as a result. The
  114. * selected folder can also be null.
  115. */
  116. private void returnSelectedFolder() {
  117. if (selectedDir != null && BuildConfig.DEBUG)
  118. Log.d(TAG, "Returning " + selectedDir.getAbsolutePath()
  119. + " as result");
  120. Intent resultData = new Intent();
  121. if (selectedDir != null) {
  122. resultData.putExtra(RESULT_SELECTED_DIR,
  123. selectedDir.getAbsolutePath());
  124. }
  125. setResult(Activity.RESULT_OK, resultData);
  126. finish();
  127. }
  128. @Override
  129. protected void onPause() {
  130. super.onPause();
  131. if (fileObserver != null) {
  132. fileObserver.stopWatching();
  133. }
  134. }
  135. @Override
  136. protected void onResume() {
  137. super.onResume();
  138. if (fileObserver != null) {
  139. fileObserver.startWatching();
  140. }
  141. }
  142. @Override
  143. public void onStop() {
  144. super.onStop();
  145. listDirectoriesAdapter = null;
  146. fileObserver = null;
  147. }
  148. /**
  149. * Change the directory that is currently being displayed.
  150. *
  151. * @param dir
  152. * The file the activity should switch to. This File must be
  153. * non-null and a directory, otherwise the displayed directory
  154. * will not be changed
  155. */
  156. private void changeDirectory(File dir) {
  157. if (dir != null && dir.isDirectory()) {
  158. File[] contents = dir.listFiles();
  159. if (contents != null) {
  160. int numDirectories = 0;
  161. for (File f : contents) {
  162. if (f.isDirectory()) {
  163. numDirectories++;
  164. }
  165. }
  166. filesInDir = new File[numDirectories];
  167. filenames.clear();
  168. for (int i = 0, counter = 0; i < numDirectories; counter++) {
  169. if (contents[counter].isDirectory()) {
  170. filesInDir[i] = contents[counter];
  171. filenames.add(contents[counter].getName());
  172. i++;
  173. }
  174. }
  175. Arrays.sort(filesInDir);
  176. Collections.sort(filenames);
  177. selectedDir = dir;
  178. txtvSelectedFolder.setText(dir.getAbsolutePath());
  179. listDirectoriesAdapter.notifyDataSetChanged();
  180. fileObserver = createFileObserver(dir.getAbsolutePath());
  181. fileObserver.startWatching();
  182. Log.d(TAG, "Changed directory to " + dir.getAbsolutePath());
  183. } else {
  184. Log.d(TAG, "Could not change folder: contents of dir were null");
  185. }
  186. } else {
  187. if (dir == null) {
  188. Log.d(TAG, "Could not change folder: dir was null");
  189. } else {
  190. Log.d(TAG, "Could not change folder: dir is no directory");
  191. }
  192. }
  193. refreshButtonState();
  194. }
  195. /**
  196. * Changes the state of the buttons depending on the currently selected file
  197. * or folder.
  198. */
  199. private void refreshButtonState() {
  200. if (selectedDir != null) {
  201. butConfirm.setEnabled(isValidFile(selectedDir));
  202. supportInvalidateOptionsMenu();
  203. }
  204. }
  205. /** Refresh the contents of the directory that is currently shown. */
  206. private void refreshDirectory() {
  207. if (selectedDir != null) {
  208. changeDirectory(selectedDir);
  209. }
  210. }
  211. /** Sets up a FileObserver to watch the current directory. */
  212. private FileObserver createFileObserver(String path) {
  213. return new FileObserver(path, FileObserver.CREATE | FileObserver.DELETE
  214. | FileObserver.MOVED_FROM | FileObserver.MOVED_TO) {
  215. @Override
  216. public void onEvent(int event, String path) {
  217. Log.d(TAG, "FileObserver received event " + event);
  218. runOnUiThread(() -> refreshDirectory());
  219. }
  220. };
  221. }
  222. @Override
  223. public boolean onPrepareOptionsMenu(Menu menu) {
  224. super.onPrepareOptionsMenu(menu);
  225. menu.findItem(R.id.new_folder_item)
  226. .setVisible(isValidFile(selectedDir));
  227. return true;
  228. }
  229. @Override
  230. public boolean onCreateOptionsMenu(Menu menu) {
  231. super.onCreateOptionsMenu(menu);
  232. MenuInflater inflater = getMenuInflater();
  233. inflater.inflate(R.menu.directory_chooser, menu);
  234. return true;
  235. }
  236. @Override
  237. public boolean onOptionsItemSelected(MenuItem item) {
  238. switch (item.getItemId()) {
  239. case android.R.id.home:
  240. NavUtils.navigateUpFromSameTask(this);
  241. return true;
  242. case R.id.new_folder_item:
  243. openNewFolderDialog();
  244. return true;
  245. case R.id.set_to_default_folder_item:
  246. selectedDir = null;
  247. returnSelectedFolder();
  248. return true;
  249. default:
  250. return false;
  251. }
  252. }
  253. /**
  254. * Shows a confirmation dialog that asks the user if he wants to create a
  255. * new folder.
  256. */
  257. private void openNewFolderDialog() {
  258. AlertDialog.Builder builder = new AlertDialog.Builder(this);
  259. builder.setTitle(R.string.create_folder_label);
  260. builder.setMessage(String.format(getString(R.string.create_folder_msg),
  261. CREATE_DIRECTORY_NAME));
  262. builder.setNegativeButton(R.string.cancel_label,
  263. (dialog, which) -> {
  264. dialog.dismiss();
  265. });
  266. builder.setPositiveButton(R.string.confirm_label,
  267. (dialog, which) -> {
  268. dialog.dismiss();
  269. int msg = createFolder();
  270. Toast t = Toast.makeText(DirectoryChooserActivity.this,
  271. msg, Toast.LENGTH_SHORT);
  272. t.show();
  273. });
  274. builder.create().show();
  275. }
  276. /**
  277. * Creates a new folder in the current directory with the name
  278. * CREATE_DIRECTORY_NAME.
  279. */
  280. private int createFolder() {
  281. if (selectedDir == null) {
  282. return R.string.create_folder_error;
  283. } else if (selectedDir.canWrite()) {
  284. File newDir = new File(selectedDir, CREATE_DIRECTORY_NAME);
  285. if (!newDir.exists()) {
  286. boolean result = newDir.mkdir();
  287. if (result) {
  288. return R.string.create_folder_success;
  289. } else {
  290. return R.string.create_folder_error;
  291. }
  292. } else {
  293. return R.string.create_folder_error_already_exists;
  294. }
  295. } else {
  296. return R.string.create_folder_error_no_write_access;
  297. }
  298. }
  299. /** Returns true if the selected file or directory would be valid selection. */
  300. private boolean isValidFile(File file) {
  301. return file != null && file.isDirectory() && file.canRead() && file.canWrite();
  302. }
  303. }