diff --git a/.travis.yml b/.travis.yml index 1fe5dcb..b3ece8d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,10 +7,10 @@ android: # - tools # The BuildTools version used by your project - - build-tools-19.1.0 + - build-tools-22.0.1 # The SDK version used to compile your project - - android-19 + - android-22 # Additional components - extra-google-m2repository diff --git a/android_commons.gradle b/android_commons.gradle index bab67bd..bb3c81f 100644 --- a/android_commons.gradle +++ b/android_commons.gradle @@ -5,12 +5,12 @@ repositories { android { - compileSdkVersion 21 - buildToolsVersion '21.1.2' + compileSdkVersion 22 + buildToolsVersion '22.0.1' defaultConfig { minSdkVersion 14 - targetSdkVersion 21 + targetSdkVersion 22 } lintOptions { diff --git a/app/build.gradle b/app/build.gradle index 3f7ce20..e9b166f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -15,9 +15,9 @@ dependencies { compile 'commons-io:commons-io:2.4' - compile 'com.android.support:appcompat-v7:21.0.3' + compile 'com.android.support:appcompat-v7:22.1.1' compile 'com.android.support:recyclerview-v7:21.0.3' - compile 'com.android.support:support-v4:21.0.3' + compile 'com.android.support:support-v4:22.1.1' compile 'com.github.chrisbanes.photoview:library:1.2.3' compile 'com.path:android-priority-jobqueue:1.1.2' compile 'de.greenrobot:eventbus:2.2.0' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 4ec482d..a685066 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -28,9 +28,9 @@ android:resource="@xml/file_path" /> - + - diff --git a/app/src/main/java/com/doplgangr/secrecy/activities/ChooseFolder.java b/app/src/main/java/com/doplgangr/secrecy/activities/ChooseFolder.java deleted file mode 100644 index b7af611..0000000 --- a/app/src/main/java/com/doplgangr/secrecy/activities/ChooseFolder.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package com.doplgangr.secrecy.activities; - -import android.content.Intent; -import android.os.Bundle; -import android.support.v7.app.ActionBarActivity; -import android.view.MenuItem; - -import com.doplgangr.secrecy.R; -import com.ipaulpro.afilechooser.FileChooserActivity; - -import java.util.ArrayList; - - -public class ChooseFolder extends ActionBarActivity { - private static final int REQUEST_CODE = 6384; // onActivityResult request code - private static final ArrayList INCLUDE_EXTENSIONS_LIST = new ArrayList(); - - static { - INCLUDE_EXTENSIONS_LIST.add("."); - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - Intent intent = new Intent(this, FileChooserActivity.class); - - intent.putStringArrayListExtra( - FileChooserActivity.EXTRA_FILTER_INCLUDE_EXTENSIONS, - INCLUDE_EXTENSIONS_LIST); - intent.putExtra(FileChooserActivity.EXTRA_SELECT_FOLDER, true); - startActivityForResult(intent, REQUEST_CODE); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - // Handle action bar item clicks here. The action bar will - // automatically handle clicks on the Home/Up button, so long - // as you specify a parent activity in AndroidManifest.xml. - int id = item.getItemId(); - return id == R.id.action_settings || super.onOptionsItemSelected(item); - } - -} diff --git a/app/src/main/java/com/doplgangr/secrecy/activities/FileChooserActivity.java b/app/src/main/java/com/doplgangr/secrecy/activities/FileChooserActivity.java new file mode 100644 index 0000000..1378b53 --- /dev/null +++ b/app/src/main/java/com/doplgangr/secrecy/activities/FileChooserActivity.java @@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package com.doplgangr.secrecy.activities; + +import android.content.Intent; +import android.os.Bundle; +import android.support.v7.app.ActionBarActivity; +import android.support.v7.widget.Toolbar; +import android.util.Log; + +import com.doplgangr.secrecy.R; +import com.doplgangr.secrecy.fragments.FileChooserFragment; + +import java.io.File; +import java.lang.reflect.Array; +import java.util.ArrayList; + + +public class FileChooserActivity extends ActionBarActivity implements FileChooserFragment.OnFileChosen{ + public static final String FOLDERS_ONLY = "FOLDERS_ONLY"; // folders only extra + public static final String FILE_SELECTED = "FILE_SELECTED"; // selected file extra + public static final String ROOT_FOLDER = "ROOT_FOLDER"; // root folder extra + public static final String FILE_EXTENSIONS = "FILE_EXTENSIONS"; // file extensions to show + private File root = null; + private Boolean foldersOnly = false; + private ArrayList fileExtensions = new ArrayList<>(); + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_file_chooser); + Toolbar mToolbar = (Toolbar) findViewById(R.id.toolbar); + if (mToolbar!=null) + setSupportActionBar(mToolbar); + Intent intent = getIntent(); + if (intent!=null) { + String root_folder = intent.getStringExtra(ROOT_FOLDER); + if (root_folder!=null) + root=new File(root_folder); + foldersOnly = intent.getBooleanExtra(FOLDERS_ONLY, false); + fileExtensions = intent.getStringArrayListExtra(FILE_EXTENSIONS); + } + FileChooserFragment fragment = FileChooserFragment.newInstance(root, foldersOnly, fileExtensions); + getFragmentManager().beginTransaction() + .replace(R.id.content_frame, fragment) + .setTransition(android.support.v4.app.FragmentTransaction.TRANSIT_FRAGMENT_OPEN) + .commit(); + } + + @Override + public void onFileSelected(File path, Boolean confirmed) { + if (confirmed) { + Intent returnIntent = new Intent(); + returnIntent.putExtra(FILE_SELECTED,path); + setResult(RESULT_OK, returnIntent); + finish(); + }else { + FileChooserFragment fragment = FileChooserFragment.newInstance(path, foldersOnly, fileExtensions); + getFragmentManager().beginTransaction() + .replace(R.id.content_frame, fragment) + .setTransition(android.support.v4.app.FragmentTransaction.TRANSIT_FRAGMENT_OPEN) + .addToBackStack(path.getAbsolutePath()).commit(); + } + } +} diff --git a/app/src/main/java/com/doplgangr/secrecy/adapters/FileChooserAdapter.java b/app/src/main/java/com/doplgangr/secrecy/adapters/FileChooserAdapter.java new file mode 100644 index 0000000..926cc8e --- /dev/null +++ b/app/src/main/java/com/doplgangr/secrecy/adapters/FileChooserAdapter.java @@ -0,0 +1,130 @@ +package com.doplgangr.secrecy.adapters; + +import android.app.Activity; +import android.content.Context; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import com.doplgangr.secrecy.R; +import com.doplgangr.secrecy.filesystem.Storage; +import com.doplgangr.secrecy.fragments.FileChooserFragment; +import com.doplgangr.secrecy.utils.Util; + +import java.io.File; +import java.util.List; + +public class FileChooserAdapter extends RecyclerView.Adapter { + + private Context context; + /** + * Inflater of the context; + */ + private LayoutInflater inflater; + /** + * File object of the directory to be displayed + */ + private File rootFile; + /** + * File object of the children to the directory to be displayed + */ + private List files; + + private FileChooserFragment.OnFileChosen mListener; + + + public FileChooserAdapter(Activity context, + List files, File rootFile, FileChooserFragment.OnFileChosen mListener) { + this.context = context; + this.inflater = context.getLayoutInflater(); + this.files = files; + this.rootFile = rootFile; + this.mListener = mListener; + } + + @Override + public FileChooserViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + return new FileChooserViewHolder(inflater.inflate(R.layout.listitem_single_line_text, parent, false)); + } + + @Override + public void onBindViewHolder(FileChooserViewHolder holder, int position) { + + final File item = files.get(position); + Boolean isParent = rootFile.getParentFile()!=null && rootFile.getParentFile().getAbsolutePath().equals(item.getAbsolutePath()); + Boolean isFile = item.isFile(); + Boolean isReadableDir = Util.canReadDir(item); + + if (holder.textView!=null){ + // TODO: create a more intuitive way to let user know this is "up" + // If the rootFile has a parent, display as "up" + if (isParent) + holder.textView.setText(".."); + else { + holder.textView.setText(item.getName()); + } + holder.textView.setEnabled(isFile || isReadableDir); + if (isSubDirectory(item, Storage.getRoot()) && !isParent) + holder.textView.setTextColor(context.getResources().getColor(R.color.accent)); + else + holder.textView.setTextColor(context.getResources().getColor(R.color.text_primary)); + } + if (holder.iconView!=null){ + if (isFile) + holder.iconView.setImageResource(R.drawable.ic_file); + if (isReadableDir) + holder.iconView.setImageResource(R.drawable.ic_action_folder); + if (isSubDirectory(item, Storage.getRoot()) && !isParent) + holder.iconView.setColorFilter(context.getResources().getColor(R.color.accent)); + else + holder.iconView.setColorFilter(context.getResources().getColor(R.color.button)); + } + holder.itemView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (null != mListener) { + // Notify the active callbacks interface (the activity, if the + // fragment is attached to one) that an item has been selected. + if (Util.canReadDir(item)) + mListener.onFileSelected(item, false); + else + mListener.onFileSelected(item, true); + } + } + }); + } + + @Override + public int getItemCount() { + if (files!=null) + return files.size(); + return 0; + } + + /** + * Checks whether a directory is a subdirectory under certain root directory + * @param directory root directory to be checked against + * @param file file suspected of being a subdirectory + * @return true if file is in directory, false if not. + */ + public static boolean isSubDirectory(File directory, File file) { + if (file == null) + return false; + if (file.equals(directory)) + return true; + return isSubDirectory(directory, file.getParentFile()); + } + + public class FileChooserViewHolder extends RecyclerView.ViewHolder{ + TextView textView; + ImageView iconView; + public FileChooserViewHolder(View itemView) { + super(itemView); + textView =(TextView) itemView.findViewById(R.id.text1); + iconView =(ImageView) itemView.findViewById(R.id.icon1); + } + } +} diff --git a/app/src/main/java/com/doplgangr/secrecy/adapters/VaultsListFragment.java b/app/src/main/java/com/doplgangr/secrecy/adapters/VaultsListFragment.java index 2bbf6d9..7292efd 100644 --- a/app/src/main/java/com/doplgangr/secrecy/adapters/VaultsListFragment.java +++ b/app/src/main/java/com/doplgangr/secrecy/adapters/VaultsListFragment.java @@ -50,6 +50,7 @@ import com.doplgangr.secrecy.CustomApp; import com.doplgangr.secrecy.R; +import com.doplgangr.secrecy.activities.FileChooserActivity; import com.doplgangr.secrecy.utils.Util; import com.doplgangr.secrecy.activities.FilesActivity; import com.doplgangr.secrecy.events.RestoreDoneEvent; @@ -59,12 +60,14 @@ import com.doplgangr.secrecy.filesystem.encryption.VaultHolder; import com.doplgangr.secrecy.jobs.RestoreJob; import com.doplgangr.secrecy.fragments.SettingsFragment; -import com.ipaulpro.afilechooser.FileChooserActivity; import com.ipaulpro.afilechooser.utils.FileUtils; +import org.apache.commons.io.FilenameUtils; + import java.io.File; import java.io.IOException; import java.util.ArrayList; +import java.util.zip.ZipFile; import de.greenrobot.event.EventBus; @@ -294,15 +297,12 @@ public void onClick(DialogInterface dialog, int whichButton) { } void restore() { - ArrayList INCLUDE_EXTENSIONS_LIST = new ArrayList(); - INCLUDE_EXTENSIONS_LIST.add(".zip"); - + ArrayList fileExtensions = new ArrayList<>(); + fileExtensions.add("zip"); Intent intent = new Intent(context, FileChooserActivity.class); + intent.putExtra(FileChooserActivity.ROOT_FOLDER, Storage.getRoot().getAbsolutePath()); + intent.putExtra(FileChooserActivity.FILE_EXTENSIONS, fileExtensions); - intent.putStringArrayListExtra( - FileChooserActivity.EXTRA_FILTER_INCLUDE_EXTENSIONS, - INCLUDE_EXTENSIONS_LIST); - intent.putExtra(FileChooserActivity.PATH, Storage.getRoot().getAbsolutePath()); startActivityForResult(intent, REQUESTCODE); } @@ -382,8 +382,7 @@ public void run() { new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { - final Uri uri = data.getData(); - final String path = FileUtils.getPath(context, uri); + final File file = (File) data.getSerializableExtra(FileChooserActivity.FILE_SELECTED); mNotifyManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); mBuilder = new NotificationCompat.Builder(context); mBuilder.setContentTitle(CustomApp.context.getString(R.string.Restore__title)) @@ -392,7 +391,7 @@ public void onClick(DialogInterface dialog, int which) { .setOngoing(true); mBuilder.setProgress(0, 0, true); mNotifyManager.notify(REQUESTCODE, mBuilder.build()); - CustomApp.jobManager.addJobInBackground(new RestoreJob(context, new File(path))); + CustomApp.jobManager.addJobInBackground(new RestoreJob(context, file)); } }, diff --git a/app/src/main/java/com/doplgangr/secrecy/fragments/FileChooserFragment.java b/app/src/main/java/com/doplgangr/secrecy/fragments/FileChooserFragment.java new file mode 100644 index 0000000..2b58cd0 --- /dev/null +++ b/app/src/main/java/com/doplgangr/secrecy/fragments/FileChooserFragment.java @@ -0,0 +1,248 @@ +package com.doplgangr.secrecy.fragments; + +import android.app.Activity; +import android.support.v7.app.AlertDialog; +import android.content.DialogInterface; +import android.os.Bundle; +import android.app.Fragment; +import android.os.Environment; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.EditText; + +import com.doplgangr.secrecy.R; +import com.doplgangr.secrecy.activities.FileChooserActivity; +import com.doplgangr.secrecy.adapters.FileChooserAdapter; + +import org.apache.commons.io.FilenameUtils; + +import java.io.File; +import java.io.FilenameFilter; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +/** + * A fragment to display a file chooser interface + */ +public class FileChooserFragment extends Fragment { + + /** + * Fragment parameter ROOT + * String, denotes absolute path of the file root to display + */ + private static final String ROOT = "root"; + /** + * Fragment parameter FOLDERS_ONLY + * Boolean, if only folders should be displayed on the interface + */ + private static final String FOLDERS_ONLY = "folders_only"; + + private List ITEMS = new ArrayList<>(); + + private OnFileChosen mListener; + + /** + * The fragment's ListView/GridView. + */ + private RecyclerView mRecyclerView; + + /** + * The Adapter which will be used to populate the ListView/GridView with + * Views. + */ + private FileChooserAdapter mAdapter; + + /** + * The location of directory where views are displaying. + */ + private File rootFile; + + /** + * If only folders should be displayed. Additional menu icon "OK" + * Will be displayed to allow confirming. Additional add folder icon + * will also be added. + */ + private Boolean foldersOnly; + + + /** + * The extensions that will be displayed. + */ + private ArrayList fileExtensions; + + public static FileChooserFragment newInstance(File root, Boolean foldersOnly, ArrayList fileExtensions) { + FileChooserFragment fragment = new FileChooserFragment(); + Bundle args = new Bundle(); + + // Default implementation: accessing the internal SDcard. + if (root!=null) + args.putString(ROOT, root.getAbsolutePath()); + else + args.putString(ROOT, Environment.getExternalStorageDirectory().getAbsolutePath()); + + // Default implementation: displaying all files and directory + if (foldersOnly!=null) + args.putBoolean(FOLDERS_ONLY, foldersOnly); + else + args.putBoolean(FOLDERS_ONLY, false); + + args.putStringArrayList(FileChooserActivity.FILE_EXTENSIONS, fileExtensions); + fragment.setArguments(args); + return fragment; + } + + /** + * Mandatory empty constructor for the fragment manager to instantiate the + * fragment (e.g. upon screen orientation changes). + */ + public FileChooserFragment() { + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + if (getArguments() != null) { + rootFile = new File(getArguments().getString(ROOT)); + foldersOnly = getArguments().getBoolean(FOLDERS_ONLY, false); + fileExtensions = getArguments().getStringArrayList(FileChooserActivity.FILE_EXTENSIONS); + }else{ + rootFile = Environment.getExternalStorageDirectory(); + foldersOnly = false; + fileExtensions = null; + } + + // If a parent exists, add the parent to the list of children so that users can traverse up. + if (!Environment.getRootDirectory().equals(rootFile.getAbsoluteFile())) + if (rootFile.getParentFile()!=null) + ITEMS.add(rootFile.getParentFile()); + + // Lists all children, optionally display only folders. + File[] filesListed = rootFile.listFiles(new FilenameFilter() { + @Override + public boolean accept(File current, String name) { + File file = new File(current, name); + if (foldersOnly) + return file.isDirectory(); + if (fileExtensions!=null && file.isFile()) + return fileExtensions.contains(FilenameUtils.getExtension(name)); + return true; + } + }); + + // Sort files by name, folder has priority + Arrays.sort(filesListed, new Comparator() { + @Override + public int compare(File file1, File file2) { + if (file1.isDirectory() && !file2.isDirectory()) + return -1; + if (!file1.isDirectory() && file2.isDirectory()) + return 1; + return file1.getName().compareTo(file2.getName()); + } + }); + + Collections.addAll(ITEMS,filesListed); + + mAdapter = new FileChooserAdapter(getActivity(), ITEMS, rootFile, mListener); + + setHasOptionsMenu(true); + } + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + if (foldersOnly) + inflater.inflate(R.menu.file_chooser,menu); + super.onCreateOptionsMenu(menu, inflater); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()){ + case R.id.action_ok: + mListener.onFileSelected(rootFile,true); + return true; + case R.id.action_add_folder: + final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity(),R.style.AppCompatAlertDialog); + View view = getActivity().getLayoutInflater().inflate(R.layout.dialog_single_edit_text,null); + final EditText editText = (EditText) view.findViewById(R.id.editText1); + editText.setHint(R.string.Chooser__new_folder_name_hint); + builder.setTitle(R.string.Chooser__add_folder); + builder.setView(view); + builder.setCancelable(true); + builder.setPositiveButton(R.string.OK, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + File subDirectory = new File(rootFile,editText.getText().toString()); + if (subDirectory.mkdir()) + mListener.onFileSelected(subDirectory,false); + } + }); + builder.create().show(); + return true; + } + return super.onOptionsItemSelected(item); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.fragment_filechooser, container, false); + mRecyclerView = (RecyclerView) view.findViewById(R.id.file_chooser_recyclerView); + + mRecyclerView.setLayoutManager + (new LinearLayoutManager( + container.getContext(), + LinearLayoutManager.VERTICAL, + false)); + mRecyclerView.setHasFixedSize(true); + + // Set the adapter + mRecyclerView.setAdapter(mAdapter); + + // Set the toolbar to have location name + getActivity().setTitle(rootFile.getAbsolutePath()); + + return view; + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + try { + mListener = (OnFileChosen) activity; + } catch (ClassCastException e) { + throw new ClassCastException(activity.toString() + + " must implement OnFileChosen"); + } + } + + @Override + public void onDetach() { + super.onDetach(); + mListener = null; + } + + /** + * This interface must be implemented by activities that contain this + * fragment to allow an interaction in this fragment to be communicated + * to the activity and potentially other fragments contained in that + * activity. + *

+ * See the Android Training lesson Communicating with Other Fragments for more information. + */ + public interface OnFileChosen { + void onFileSelected(File path, Boolean confirmed); + } +} diff --git a/app/src/main/java/com/doplgangr/secrecy/fragments/FilesListFragment.java b/app/src/main/java/com/doplgangr/secrecy/fragments/FilesListFragment.java index b7eb6d9..0b0d51b 100644 --- a/app/src/main/java/com/doplgangr/secrecy/fragments/FilesListFragment.java +++ b/app/src/main/java/com/doplgangr/secrecy/fragments/FilesListFragment.java @@ -27,6 +27,7 @@ import android.content.Context; import android.content.DialogInterface; import android.content.Intent; +import android.net.Uri; import android.os.Bundle; import android.os.Environment; import android.support.v4.app.NotificationCompat; @@ -51,6 +52,7 @@ import com.doplgangr.secrecy.Config; import com.doplgangr.secrecy.CustomApp; +import com.doplgangr.secrecy.activities.FileChooserActivity; import com.doplgangr.secrecy.activities.FilePhotoActivity; import com.doplgangr.secrecy.activities.FilesActivity; import com.doplgangr.secrecy.events.AddingFileDoneEvent; @@ -67,7 +69,6 @@ import com.doplgangr.secrecy.R; import com.doplgangr.secrecy.utils.Util; import com.doplgangr.secrecy.adapters.FilesListAdapter; -import com.ipaulpro.afilechooser.FileChooserActivity; import java.io.File; import java.io.FileNotFoundException; @@ -534,10 +535,6 @@ void addFile() { FilesActivity.onPauseDecision.startActivity(); } catch (ActivityNotFoundException e) { intent = new Intent(context, FileChooserActivity.class); - intent.putStringArrayListExtra( - FileChooserActivity.EXTRA_FILTER_INCLUDE_EXTENSIONS, - INCLUDE_EXTENSIONS_LIST); - intent.putExtra(FileChooserActivity.EXTRA_SELECT_FOLDER, false); startActivityForResult(intent, REQUEST_CODE); FilesActivity.onPauseDecision.startActivity(); } @@ -622,7 +619,10 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) { .setOngoing(true); mBuilder.setProgress(0, 0, true); mNotifyManager.notify(NotificationID, mBuilder.build()); - + //if the result is from our internal file chooser + Object fileFromChooser = data.getSerializableExtra(com.doplgangr.secrecy.activities.FileChooserActivity.FILE_SELECTED); + if (fileFromChooser !=null) + addFileInBackground(secret, Uri.fromFile((File) fileFromChooser)); addFileInBackground(secret, data.getData()); super.onActivityResult(requestCode, resultCode, data); } else { diff --git a/app/src/main/java/com/doplgangr/secrecy/fragments/SettingsFragment.java b/app/src/main/java/com/doplgangr/secrecy/fragments/SettingsFragment.java index bf9b5ff..ed788a7 100644 --- a/app/src/main/java/com/doplgangr/secrecy/fragments/SettingsFragment.java +++ b/app/src/main/java/com/doplgangr/secrecy/fragments/SettingsFragment.java @@ -41,7 +41,6 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.ArrayAdapter; import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; @@ -49,20 +48,18 @@ import com.doplgangr.secrecy.Config; import com.doplgangr.secrecy.CustomApp; import com.doplgangr.secrecy.R; +import com.doplgangr.secrecy.activities.FileChooserActivity; import com.doplgangr.secrecy.utils.Util; import com.doplgangr.secrecy.filesystem.Storage; import com.doplgangr.secrecy.premium.PremiumStateHelper; import com.doplgangr.secrecy.premium.StealthMode; import com.doplgangr.secrecy.adapters.VaultsListFragment; -import com.ipaulpro.afilechooser.FileChooserActivity; -import com.ipaulpro.afilechooser.utils.FileUtils; import java.io.File; import java.io.IOException; import java.util.ArrayList; -import java.util.Map; -public class SettingsFragment extends PreferenceFragment { +public class SettingsFragment extends PreferenceFragment{ private static final int REQUEST_CODE_SET_VAULT_ROOT = 6384; private static final int REQUEST_CODE_MOVE_VAULT = 2058; private Context context; @@ -210,18 +207,7 @@ private void preparePreferenceVaultRoot(){ vault_root.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { @Override public boolean onPreferenceClick(Preference preference) { - choosePath(new getFileListener() { - @Override - public void get(File file) { - Intent intent = new Intent(context, FileChooserActivity.class); - intent.putStringArrayListExtra( - FileChooserActivity.EXTRA_FILTER_INCLUDE_EXTENSIONS, - INCLUDE_EXTENSIONS_LIST); - intent.putExtra(FileChooserActivity.PATH, file.getAbsolutePath()); - intent.putExtra(FileChooserActivity.EXTRA_SELECT_FOLDER, true); - startActivityForResult(intent, REQUEST_CODE_SET_VAULT_ROOT); - } - }); + choosePath(); return true; } }); @@ -232,18 +218,7 @@ private void preparePreferenceVaultMove(){ vault_move.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { @Override public boolean onPreferenceClick(Preference preference) { - choosePath(new getFileListener() { - @Override - public void get(File file) { - Intent intent = new Intent(context, FileChooserActivity.class); - intent.putStringArrayListExtra( - FileChooserActivity.EXTRA_FILTER_INCLUDE_EXTENSIONS, - INCLUDE_EXTENSIONS_LIST); - intent.putExtra(FileChooserActivity.PATH, file.getAbsolutePath()); - intent.putExtra(FileChooserActivity.EXTRA_SELECT_FOLDER, true); - startActivityForResult(intent, REQUEST_CODE_MOVE_VAULT); - } - }); + movePath(); return true; } }); @@ -359,12 +334,10 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) { // If the file selection was successful if (resultCode == Activity.RESULT_OK) { if (data != null) { - // Get the URI of the selected file - final Uri uri = data.getData(); + // Get the selected file + final File file = (File) data.getSerializableExtra(FileChooserActivity.FILE_SELECTED); try { - // Get the file path from the URI - final String path = FileUtils.getPath(context, uri); - Storage.setRoot(path); + Storage.setRoot(file.getAbsolutePath()); Preference vault_root = findPreference(Config.VAULT_ROOT); vault_root.setSummary(Storage.getRoot().getAbsolutePath()); } catch (Exception e) { @@ -376,11 +349,10 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) { case REQUEST_CODE_MOVE_VAULT: if (resultCode == Activity.RESULT_OK) { if (data != null) { - // Get the URI of the selected file - final Uri uri = data.getData(); + // Get the selected file + final File file = (File) data.getSerializableExtra(FileChooserActivity.FILE_SELECTED); try { - // Get the file path from the URI - final String path = FileUtils.getPath(context, uri); + final String path = file.getAbsolutePath(); if (path.contains(Storage.getRoot().getAbsolutePath())) { Util.alert(context, getString(R.string.Settings__cannot_move_vault), @@ -450,40 +422,17 @@ void moveStorageRoot(String path, ProgressDialog progressDialog) { progressDialog.dismiss(); } - void choosePath(final getFileListener listener) { - AlertDialog.Builder builderSingle = new AlertDialog.Builder(context); - builderSingle.setTitle(context.getString(R.string.Settings__select_storage_title)); - final ArrayAdapter arrayAdapter = new ArrayAdapter( - context, - R.layout.select_dialog_singlechoice); - final Map storages = Util.getAllStorageLocations(); - for (String key : storages.keySet()) { - arrayAdapter.add(key); - } - builderSingle.setNegativeButton(R.string.CANCEL, - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - dialog.dismiss(); - } - } - ); - - builderSingle.setAdapter(arrayAdapter, - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - String strName = arrayAdapter.getItem(which); - File file = storages.get(strName); - listener.get(file); - } - } - ); - builderSingle.show(); + void choosePath() { + Intent intent = new Intent(getActivity(), FileChooserActivity.class); + intent.putExtra(FileChooserActivity.FOLDERS_ONLY, true); + startActivityForResult(intent, REQUEST_CODE_SET_VAULT_ROOT); } - public interface getFileListener { - void get(File file); + void movePath() { + Intent intent = new Intent(getActivity(), FileChooserActivity.class); + intent.putExtra(FileChooserActivity.FOLDERS_ONLY, true); + startActivityForResult(intent, REQUEST_CODE_MOVE_VAULT); } + } \ No newline at end of file diff --git a/app/src/main/java/com/doplgangr/secrecy/utils/Util.java b/app/src/main/java/com/doplgangr/secrecy/utils/Util.java index 144573a..f55feca 100644 --- a/app/src/main/java/com/doplgangr/secrecy/utils/Util.java +++ b/app/src/main/java/com/doplgangr/secrecy/utils/Util.java @@ -209,6 +209,25 @@ public static Boolean canWrite(java.io.File root) { } + /** Checks whether a directory is truly readable. Since File.canRead() + * only checks for file security, it is necessary to try doing a File.listFiles() + * to test for real directory access. + * @param root Directory root to be checked against + * @return True if directory can be read, False if any exception occurs + * e.g. the folder is not readable, devices not mounted etc. + */ + public static Boolean canReadDir(java.io.File root) { + if (root == null) + return false; + if (!root.exists()) + return false; + try { + return root.canRead() && root.listFiles()!=null; + } catch (Exception e) { + return false; + } + } + public static void openURI(String uri) { Intent i = new Intent(Intent.ACTION_VIEW); i.setData(Uri.parse(uri)); diff --git a/app/src/main/res/drawable-hdpi/ic_action_done.png b/app/src/main/res/drawable-hdpi/ic_action_done.png new file mode 100644 index 0000000..f073fc1 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_action_done.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_action_folder.png b/app/src/main/res/drawable-hdpi/ic_action_folder.png new file mode 100644 index 0000000..ef162d8 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_action_folder.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_action_folder_add.png b/app/src/main/res/drawable-hdpi/ic_action_folder_add.png new file mode 100644 index 0000000..601f883 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_action_folder_add.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_file.png b/app/src/main/res/drawable-hdpi/ic_file.png new file mode 100644 index 0000000..410be49 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_file.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_action_done.png b/app/src/main/res/drawable-mdpi/ic_action_done.png new file mode 100644 index 0000000..c372052 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_action_done.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_action_folder.png b/app/src/main/res/drawable-mdpi/ic_action_folder.png new file mode 100644 index 0000000..66314e9 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_action_folder.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_action_folder_add.png b/app/src/main/res/drawable-mdpi/ic_action_folder_add.png new file mode 100644 index 0000000..f6d42f6 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_action_folder_add.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_file.png b/app/src/main/res/drawable-mdpi/ic_file.png new file mode 100644 index 0000000..15aa037 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_file.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_action_done.png b/app/src/main/res/drawable-xhdpi/ic_action_done.png new file mode 100644 index 0000000..446c536 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_action_done.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_action_folder.png b/app/src/main/res/drawable-xhdpi/ic_action_folder.png new file mode 100644 index 0000000..c1da4ab Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_action_folder.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_action_folder_add.png b/app/src/main/res/drawable-xhdpi/ic_action_folder_add.png new file mode 100644 index 0000000..fd23e94 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_action_folder_add.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_file.png b/app/src/main/res/drawable-xhdpi/ic_file.png new file mode 100644 index 0000000..622d113 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_file.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_action_done.png b/app/src/main/res/drawable-xxhdpi/ic_action_done.png new file mode 100644 index 0000000..444b568 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_action_done.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_action_folder.png b/app/src/main/res/drawable-xxhdpi/ic_action_folder.png new file mode 100644 index 0000000..c25bb36 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_action_folder.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_action_folder_add.png b/app/src/main/res/drawable-xxhdpi/ic_action_folder_add.png new file mode 100644 index 0000000..c9b3d4e Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_action_folder_add.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_file.png b/app/src/main/res/drawable-xxhdpi/ic_file.png new file mode 100644 index 0000000..8b20e7c Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_file.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_action_done.png b/app/src/main/res/drawable-xxxhdpi/ic_action_done.png new file mode 100644 index 0000000..e359a2f Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_action_done.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_action_folder.png b/app/src/main/res/drawable-xxxhdpi/ic_action_folder.png new file mode 100644 index 0000000..b9e8694 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_action_folder.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_action_folder_add.png b/app/src/main/res/drawable-xxxhdpi/ic_action_folder_add.png new file mode 100644 index 0000000..a8cce8e Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_action_folder_add.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_file.png b/app/src/main/res/drawable-xxxhdpi/ic_file.png new file mode 100644 index 0000000..445ad41 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_file.png differ diff --git a/app/src/main/res/layout/activity_file_chooser.xml b/app/src/main/res/layout/activity_file_chooser.xml new file mode 100644 index 0000000..05a2c0a --- /dev/null +++ b/app/src/main/res/layout/activity_file_chooser.xml @@ -0,0 +1,18 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_single_edit_text.xml b/app/src/main/res/layout/dialog_single_edit_text.xml new file mode 100644 index 0000000..9de0ec2 --- /dev/null +++ b/app/src/main/res/layout/dialog_single_edit_text.xml @@ -0,0 +1,16 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_filechooser.xml b/app/src/main/res/layout/fragment_filechooser.xml new file mode 100644 index 0000000..a01aa3a --- /dev/null +++ b/app/src/main/res/layout/fragment_filechooser.xml @@ -0,0 +1,8 @@ + + \ No newline at end of file diff --git a/app/src/main/res/layout/listitem_single_line_text.xml b/app/src/main/res/layout/listitem_single_line_text.xml new file mode 100644 index 0000000..72cacff --- /dev/null +++ b/app/src/main/res/layout/listitem_single_line_text.xml @@ -0,0 +1,24 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/file_chooser.xml b/app/src/main/res/menu/file_chooser.xml new file mode 100644 index 0000000..6067c94 --- /dev/null +++ b/app/src/main/res/menu/file_chooser.xml @@ -0,0 +1,20 @@ + +

+ + + + \ No newline at end of file diff --git a/app/src/main/res/values/color.xml b/app/src/main/res/values/color.xml index 9d602aa..4fdd3d2 100644 --- a/app/src/main/res/values/color.xml +++ b/app/src/main/res/values/color.xml @@ -20,6 +20,8 @@ @color/quantum_deeporange_A200 @color/quantum_deeporange_A100 @color/quantum_deeporange_A400 + @color/button_material_light + @color/primary_text_default_material_light #727272 \ No newline at end of file diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index 8036a75..601ad42 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -26,6 +26,12 @@ 20sp 56dp + + 24dp + + 48dp + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3ed477e..583e0d7 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -75,6 +75,7 @@ Maximal image size Performance Sort files by + New Folder Name Small Medium diff --git a/app/src/main/res/values/strings_file_handling.xml b/app/src/main/res/values/strings_file_handling.xml index 2a40cd4..217f7a8 100644 --- a/app/src/main/res/values/strings_file_handling.xml +++ b/app/src/main/res/values/strings_file_handling.xml @@ -54,4 +54,5 @@ Restore in Progress Restore Finished. %s has been restored. New File Name + Add Folder \ No newline at end of file diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 403f4b1..ee8a4da 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -11,6 +11,8 @@ @style/ButtonBarButton + \ No newline at end of file