diff --git a/Source/Android/app/build.gradle b/Source/Android/app/build.gradle index 857eef27f6..db2d89db8e 100644 --- a/Source/Android/app/build.gradle +++ b/Source/Android/app/build.gradle @@ -96,6 +96,8 @@ dependencies { // Allows FRP-style asynchronous operations in Android. api 'io.reactivex:rxandroid:1.2.1' + + compile 'com.nononsenseapps:filepicker:4.1.0' } def getVersion() { diff --git a/Source/Android/app/src/main/AndroidManifest.xml b/Source/Android/app/src/main/AndroidManifest.xml index d445f5d822..6e854150b9 100644 --- a/Source/Android/app/src/main/AndroidManifest.xml +++ b/Source/Android/app/src/main/AndroidManifest.xml @@ -50,11 +50,6 @@ - - + + + + + + @@ -74,6 +78,16 @@ android:exported="false"> + + + + diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/AddDirectoryActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/AddDirectoryActivity.java deleted file mode 100644 index 84080854d6..0000000000 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/AddDirectoryActivity.java +++ /dev/null @@ -1,141 +0,0 @@ -package org.dolphinemu.dolphinemu.activities; - -import android.content.AsyncQueryHandler; -import android.content.ContentValues; -import android.content.Intent; -import android.net.Uri; -import android.os.Bundle; -import android.os.Environment; -import android.support.v4.app.FragmentActivity; -import android.support.v7.app.AppCompatActivity; -import android.support.v7.widget.LinearLayoutManager; -import android.support.v7.widget.RecyclerView; -import android.support.v7.widget.Toolbar; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; - -import org.dolphinemu.dolphinemu.R; -import org.dolphinemu.dolphinemu.adapters.FileAdapter; -import org.dolphinemu.dolphinemu.model.GameDatabase; -import org.dolphinemu.dolphinemu.model.GameProvider; -import org.dolphinemu.dolphinemu.ui.main.MainPresenter; - -/** - * An Activity that shows a list of files and folders, allowing the user to tell the app which folder(s) - * contains the user's games. - */ -public class AddDirectoryActivity extends AppCompatActivity implements FileAdapter.FileClickListener -{ - private static final String KEY_CURRENT_PATH = "path"; - - private FileAdapter mAdapter; - private Toolbar mToolbar; - - @Override - protected void onCreate(Bundle savedInstanceState) - { - super.onCreate(savedInstanceState); - - setContentView(R.layout.activity_add_directory); - - mToolbar = (Toolbar) findViewById(R.id.toolbar_folder_list); - setSupportActionBar(mToolbar); - - RecyclerView recyclerView = (RecyclerView) findViewById(R.id.list_files); - - // Specifying the LayoutManager determines how the RecyclerView arranges views. - RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false); - recyclerView.setLayoutManager(layoutManager); - - String path; - // Stuff in this block only happens when this activity is newly created (i.e. not a rotation) - if (savedInstanceState == null) - { - path = Environment.getExternalStorageDirectory().getPath(); - } - else - { - // Get the path we were looking at before we rotated. - path = savedInstanceState.getString(KEY_CURRENT_PATH); - } - - mAdapter = new FileAdapter(path, this); - recyclerView.setAdapter(mAdapter); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) - { - MenuInflater inflater = getMenuInflater(); - inflater.inflate(R.menu.menu_add_directory, menu); - - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) - { - switch (item.getItemId()) - { - case R.id.menu_up_one_level: - mAdapter.upOneLevel(); - break; - } - - return super.onOptionsItemSelected(item); - } - - - @Override - protected void onSaveInstanceState(Bundle outState) - { - super.onSaveInstanceState(outState); - - // Save the path we're looking at so when rotation is done, we start from same folder. - outState.putString(KEY_CURRENT_PATH, mAdapter.getPath()); - } - - /** - * Add a directory to the library, and if successful, end the activity. - */ - @Override - public void addDirectory() - { - // Set up a callback for when the addition is complete - // TODO This has a nasty warning on it; find a cleaner way to do this Insert asynchronously - AsyncQueryHandler handler = new AsyncQueryHandler(getContentResolver()) - { - @Override - protected void onInsertComplete(int token, Object cookie, Uri uri) - { - Intent resultData = new Intent(); - - resultData.putExtra(KEY_CURRENT_PATH, mAdapter.getPath()); - setResult(RESULT_OK, resultData); - - finish(); - } - }; - - ContentValues file = new ContentValues(); - file.put(GameDatabase.KEY_FOLDER_PATH, mAdapter.getPath()); - - handler.startInsert(0, // We don't need to identify this call to the handler - null, // We don't need to pass additional data to the handler - GameProvider.URI_FOLDER, // Tell the GameProvider we are adding a folder - file); // Tell the GameProvider what folder we are adding - } - - @Override - public void updateSubtitle(String path) - { - mToolbar.setSubtitle(path); - } - - public static void launch(FragmentActivity activity) - { - Intent fileChooser = new Intent(activity, AddDirectoryActivity.class); - activity.startActivityForResult(fileChooser, MainPresenter.REQUEST_ADD_DIRECTORY); - } -} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/CustomFilePickerActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/CustomFilePickerActivity.java new file mode 100644 index 0000000000..d14b92e38d --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/CustomFilePickerActivity.java @@ -0,0 +1,28 @@ +package org.dolphinemu.dolphinemu.activities; + +import android.os.Environment; +import android.support.annotation.Nullable; + +import com.nononsenseapps.filepicker.AbstractFilePickerFragment; +import com.nononsenseapps.filepicker.FilePickerActivity; + +import org.dolphinemu.dolphinemu.fragments.CustomFilePickerFragment; + +import java.io.File; + +public class CustomFilePickerActivity extends FilePickerActivity + +{ + @Override + protected AbstractFilePickerFragment getFragment( + @Nullable final String startPath, final int mode, final boolean allowMultiple, + final boolean allowCreateDir, final boolean allowExistingFile, + final boolean singleClick) + { + AbstractFilePickerFragment fragment = new CustomFilePickerFragment(); + // startPath is allowed to be null. In that case, default folder should be SD-card and not "/" + fragment.setArgs(startPath != null ? startPath : Environment.getExternalStorageDirectory().getPath(), + mode, allowMultiple, allowCreateDir, allowExistingFile, singleClick); + return fragment; + } +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/FileAdapter.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/FileAdapter.java deleted file mode 100644 index 3e1048ffa5..0000000000 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/FileAdapter.java +++ /dev/null @@ -1,217 +0,0 @@ -package org.dolphinemu.dolphinemu.adapters; - -import android.os.Environment; -import android.support.v7.widget.RecyclerView; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.Toast; - -import org.dolphinemu.dolphinemu.R; -import org.dolphinemu.dolphinemu.model.FileListItem; -import org.dolphinemu.dolphinemu.viewholders.FileViewHolder; - -import java.io.File; -import java.util.ArrayList; -import java.util.Collections; - -public final class FileAdapter extends RecyclerView.Adapter implements View.OnClickListener -{ - private ArrayList mFileList; - - private String mPath; - - private FileClickListener mListener; - - /** - * Initializes the dataset to be displayed, and associates the Adapter with the - * Activity as an event listener. - * - * @param path A String containing the path to the directory to be shown by this Adapter. - * @param listener An Activity that can respond to callbacks from this Adapter. - */ - public FileAdapter(String path, FileClickListener listener) - { - mFileList = generateFileList(new File(path)); - mListener = listener; - mListener.updateSubtitle(path); - } - - /** - * Called by the LayoutManager when it is necessary to create a new view. - * - * @param parent The RecyclerView (I think?) the created view will be thrown into. - * @param viewType Not used here, but useful when more than one type of child will be used in the RecyclerView. - * @return The created ViewHolder with references to all the child view's members. - */ - @Override - public FileViewHolder onCreateViewHolder(ViewGroup parent, int viewType) - { - // Create a new view. - View listItem = LayoutInflater.from(parent.getContext()) - .inflate(R.layout.list_item_file, parent, false); - - listItem.setOnClickListener(this); - - // Use that view to create a ViewHolder. - return new FileViewHolder(listItem); - } - - /** - * Called by the LayoutManager when a new view is not necessary because we can recycle - * an existing one (for example, if a view just scrolled onto the screen from the bottom, we - * can use the view that just scrolled off the top instead of inflating a new one.) - * - * @param holder A ViewHolder representing the view we're recycling. - * @param position The position of the 'new' view in the dataset. - */ - @Override - public void onBindViewHolder(FileViewHolder holder, int position) - { - // Get a reference to the item from the dataset; we'll use this to fill in the view contents. - final FileListItem file = mFileList.get(position); - - // Fill in the view contents. - switch (file.getType()) - { - case FileListItem.TYPE_FOLDER: - holder.imageType.setImageResource(R.drawable.ic_folder); - break; - - case FileListItem.TYPE_GC: - holder.imageType.setImageResource(R.drawable.ic_gamecube); - break; - - case FileListItem.TYPE_WII: - holder.imageType.setImageResource(R.drawable.ic_wii); - break; - - case FileListItem.TYPE_OTHER: - holder.imageType.setImageResource(android.R.color.transparent); - break; - } - - holder.textFileName.setText(file.getFilename()); - holder.itemView.setTag(file.getPath()); - } - - /** - * Called by the LayoutManager to find out how much data we have. - * - * @return Size of the dataset. - */ - @Override - public int getItemCount() - { - return mFileList.size(); - } - - /** - * When a file is clicked, determine if it is a directory; if it is, show that new directory's - * contents. If it is not, end the activity successfully. - * - * @param view The View representing the file the user clicked on. - */ - @Override - public void onClick(final View view) - { - final String path = (String) view.getTag(); - - File clickedFile = new File(path); - - if (clickedFile.isDirectory()) - { - final ArrayList fileList = generateFileList(clickedFile); - - if (fileList.isEmpty()) - { - Toast.makeText(view.getContext(), R.string.add_directory_empty_folder, Toast.LENGTH_SHORT).show(); - } - else - { - // Delay the loading of the new directory to give a little bit of time for UI feedback - // to happen. Hacky, but good enough for now; this is necessary because we're modifying - // the RecyclerView's contents, rather than constructing a new one. - view.getHandler().postDelayed(() -> - { - mFileList = fileList; - notifyDataSetChanged(); - mListener.updateSubtitle(path); - }, 200); - } - } - else - { - // Pass the activity the path of the parent directory of the clicked file. - mListener.addDirectory(); - } - } - - /** - * For a given directory, return a list of Files it contains. - * - * @param directory A File representing the directory that should have its contents displayed. - * @return The list of files contained in the directory. - */ - private ArrayList generateFileList(File directory) - { - File[] children = directory.listFiles(); - mPath = directory.getAbsolutePath(); - ArrayList fileList = new ArrayList(0); - - if (children != null) - { - - fileList = new ArrayList(children.length); - - for (File child : children) - { - if (!child.isHidden()) - { - FileListItem item = new FileListItem(child); - fileList.add(item); - } - } - - Collections.sort(fileList); - } - return fileList; - } - - public String getPath() - { - return mPath; - } - - public void setPath(String path) - { - File directory = new File(path); - - mFileList = generateFileList(directory); - notifyDataSetChanged(); - mListener.updateSubtitle(path); - } - - public void upOneLevel() - { - if (!mPath.equals("/")) - { - File currentDirectory = new File(mPath); - File parentDirectory = currentDirectory.getParentFile(); - - mFileList = generateFileList(parentDirectory); - notifyDataSetChanged(); - mListener.updateSubtitle(mPath); - } - } - - /** - * Callback to the containing Activity. - */ - public interface FileClickListener - { - void addDirectory(); - - void updateSubtitle(String path); - } -} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/GameAdapter.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/GameAdapter.java index 7c5a6ea415..1ba972d841 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/GameAdapter.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/adapters/GameAdapter.java @@ -18,9 +18,9 @@ import org.dolphinemu.dolphinemu.utils.PicassoUtils; import org.dolphinemu.dolphinemu.viewholders.GameViewHolder; /** - * This adapter, unlike {@link FileAdapter} which is backed by an ArrayList, gets its - * information from a database Cursor. This fact, paired with the usage of ContentProviders - * and Loaders, allows for efficient display of a limited view into a (possibly) large dataset. + * This adapter gets its information from a database Cursor. This fact, paired with the usage of + * ContentProviders and Loaders, allows for efficient display of a limited view into a (possibly) + * large dataset. */ public final class GameAdapter extends RecyclerView.Adapter implements View.OnClickListener, diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/CustomFilePickerFragment.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/CustomFilePickerFragment.java new file mode 100644 index 0000000000..9d15d0fe1a --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/CustomFilePickerFragment.java @@ -0,0 +1,22 @@ +package org.dolphinemu.dolphinemu.fragments; + +import android.net.Uri; +import android.support.annotation.NonNull; +import android.support.v4.content.FileProvider; + +import com.nononsenseapps.filepicker.FilePickerFragment; + +import java.io.File; + +public class CustomFilePickerFragment extends FilePickerFragment +{ + @NonNull + @Override + public Uri toUri(@NonNull final File file) + { + return FileProvider + .getUriForFile(getContext(), + getContext().getApplicationContext().getPackageName() + ".filesprovider", + file); + } +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainActivity.java index 1f46f8eecb..9b584201a7 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainActivity.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainActivity.java @@ -17,13 +17,14 @@ import android.view.View; import android.widget.Toast; import org.dolphinemu.dolphinemu.R; -import org.dolphinemu.dolphinemu.activities.AddDirectoryActivity; import org.dolphinemu.dolphinemu.adapters.PlatformPagerAdapter; import org.dolphinemu.dolphinemu.model.GameProvider; import org.dolphinemu.dolphinemu.services.DirectoryInitializationService; import org.dolphinemu.dolphinemu.ui.platform.Platform; import org.dolphinemu.dolphinemu.ui.platform.PlatformGamesView; import org.dolphinemu.dolphinemu.ui.settings.SettingsActivity; +import org.dolphinemu.dolphinemu.utils.AddDirectoryHelper; +import org.dolphinemu.dolphinemu.utils.FileBrowserHelper; import org.dolphinemu.dolphinemu.utils.PermissionsHandler; import org.dolphinemu.dolphinemu.utils.StartupHandler; @@ -71,6 +72,13 @@ public final class MainActivity extends AppCompatActivity implements MainView } } + @Override + protected void onResume() + { + super.onResume(); + mPresenter.addDirIfNeeded(new AddDirectoryHelper(this)); + } + // TODO: Replace with a ButterKnife injection. private void findViews() { @@ -127,7 +135,7 @@ public final class MainActivity extends AppCompatActivity implements MainView @Override public void launchFileListActivity() { - AddDirectoryActivity.launch(this); + FileBrowserHelper.openDirectoryPicker(this); } @Override @@ -137,8 +145,6 @@ public final class MainActivity extends AppCompatActivity implements MainView } /** - * Callback from AddDirectoryActivity. Applies any changes necessary to the GameGridActivity. - * * @param requestCode An int describing whether the Activity that is returning did so successfully. * @param resultCode An int describing what Activity is giving us this callback. * @param result The information the returning Activity is providing us. @@ -146,7 +152,20 @@ public final class MainActivity extends AppCompatActivity implements MainView @Override protected void onActivityResult(int requestCode, int resultCode, Intent result) { - mPresenter.handleActivityResult(requestCode, resultCode); + switch (requestCode) + { + case MainPresenter.REQUEST_ADD_DIRECTORY: + // If the user picked a file, as opposed to just backing out. + if (resultCode == MainActivity.RESULT_OK) + { + mPresenter.onDirectorySelected(FileBrowserHelper.getSelectedDirectory(result)); + } + break; + + case MainPresenter.REQUEST_EMULATE_GAME: + mPresenter.refreshFragmentScreenshot(resultCode); + break; + } } @Override @@ -198,7 +217,7 @@ public final class MainActivity extends AppCompatActivity implements MainView @Nullable private PlatformGamesView getPlatformGamesView(Platform platform) { - String fragmentTag = "android:switcher:" + mViewPager.getId() + ":" + platform; + String fragmentTag = "android:switcher:" + mViewPager.getId() + ":" + platform.toInt(); return (PlatformGamesView) getSupportFragmentManager().findFragmentByTag(fragmentTag); } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainPresenter.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainPresenter.java index 57ee61baef..4ed97b6ecb 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainPresenter.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainPresenter.java @@ -1,17 +1,15 @@ package org.dolphinemu.dolphinemu.ui.main; -import android.database.Cursor; - import org.dolphinemu.dolphinemu.BuildConfig; import org.dolphinemu.dolphinemu.DolphinApplication; import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.model.GameDatabase; import org.dolphinemu.dolphinemu.ui.platform.Platform; +import org.dolphinemu.dolphinemu.utils.AddDirectoryHelper; import org.dolphinemu.dolphinemu.utils.SettingsFile; import rx.android.schedulers.AndroidSchedulers; -import rx.functions.Action1; import rx.schedulers.Schedulers; public final class MainPresenter @@ -20,6 +18,7 @@ public final class MainPresenter public static final int REQUEST_EMULATE_GAME = 2; private final MainView mView; + private String mDirToAdd; public MainPresenter(MainView view) { @@ -71,24 +70,27 @@ public final class MainPresenter return false; } - public void handleActivityResult(int requestCode, int resultCode) + public void addDirIfNeeded(AddDirectoryHelper helper) { - switch (requestCode) + if (mDirToAdd != null) { - case REQUEST_ADD_DIRECTORY: - // If the user picked a file, as opposed to just backing out. - if (resultCode == MainActivity.RESULT_OK) - { - mView.refresh(); - } - break; + helper.addDirectory(mDirToAdd, mView::refresh); - case REQUEST_EMULATE_GAME: - mView.refreshFragmentScreenshot(resultCode); - break; + mDirToAdd = null; } } + public void onDirectorySelected(String dir) + { + mDirToAdd = dir; + } + + public void refreshFragmentScreenshot(int resultCode) + { + mView.refreshFragmentScreenshot(resultCode); + } + + public void loadGames(final Platform platform) { GameDatabase databaseHelper = DolphinApplication.databaseHelper; diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/TvMainActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/TvMainActivity.java index cb72c34a3e..46de94b2d6 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/TvMainActivity.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/TvMainActivity.java @@ -12,17 +12,12 @@ import android.support.v17.leanback.widget.CursorObjectAdapter; import android.support.v17.leanback.widget.HeaderItem; import android.support.v17.leanback.widget.ListRow; import android.support.v17.leanback.widget.ListRowPresenter; -import android.support.v17.leanback.widget.OnItemViewClickedListener; -import android.support.v17.leanback.widget.Presenter; -import android.support.v17.leanback.widget.Row; -import android.support.v17.leanback.widget.RowPresenter; import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentManager; import android.support.v4.content.ContextCompat; import android.widget.Toast; import org.dolphinemu.dolphinemu.R; -import org.dolphinemu.dolphinemu.activities.AddDirectoryActivity; import org.dolphinemu.dolphinemu.activities.EmulationActivity; import org.dolphinemu.dolphinemu.adapters.GameRowPresenter; import org.dolphinemu.dolphinemu.adapters.SettingsRowPresenter; @@ -31,6 +26,8 @@ import org.dolphinemu.dolphinemu.model.TvSettingsItem; import org.dolphinemu.dolphinemu.services.DirectoryInitializationService; import org.dolphinemu.dolphinemu.ui.platform.Platform; import org.dolphinemu.dolphinemu.ui.settings.SettingsActivity; +import org.dolphinemu.dolphinemu.utils.AddDirectoryHelper; +import org.dolphinemu.dolphinemu.utils.FileBrowserHelper; import org.dolphinemu.dolphinemu.utils.PermissionsHandler; import org.dolphinemu.dolphinemu.utils.StartupHandler; import org.dolphinemu.dolphinemu.viewholders.TvGameViewHolder; @@ -58,6 +55,13 @@ public final class TvMainActivity extends FragmentActivity implements MainView StartupHandler.HandleInit(this); } + @Override + protected void onResume() + { + super.onResume(); + mPresenter.addDirIfNeeded(new AddDirectoryHelper(this)); + } + void setupUI() { final FragmentManager fragmentManager = getSupportFragmentManager(); mBrowseFragment = new BrowseSupportFragment(); @@ -125,7 +129,7 @@ public final class TvMainActivity extends FragmentActivity implements MainView @Override public void launchFileListActivity() { - AddDirectoryActivity.launch(this); + FileBrowserHelper.openDirectoryPicker(this); } @Override @@ -150,7 +154,20 @@ public final class TvMainActivity extends FragmentActivity implements MainView @Override protected void onActivityResult(int requestCode, int resultCode, Intent result) { - mPresenter.handleActivityResult(requestCode, resultCode); + switch (requestCode) + { + case MainPresenter.REQUEST_ADD_DIRECTORY: + // If the user picked a file, as opposed to just backing out. + if (resultCode == MainActivity.RESULT_OK) + { + mPresenter.onDirectorySelected(FileBrowserHelper.getSelectedDirectory(result)); + } + break; + + case MainPresenter.REQUEST_EMULATE_GAME: + mPresenter.refreshFragmentScreenshot(resultCode); + break; + } } @Override diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/AddDirectoryHelper.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/AddDirectoryHelper.java new file mode 100644 index 0000000000..55feddb957 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/AddDirectoryHelper.java @@ -0,0 +1,44 @@ +package org.dolphinemu.dolphinemu.utils; + +import android.content.AsyncQueryHandler; +import android.content.ContentValues; +import android.content.Context; +import android.net.Uri; + +import org.dolphinemu.dolphinemu.model.GameDatabase; +import org.dolphinemu.dolphinemu.model.GameProvider; + +public class AddDirectoryHelper +{ + private Context mContext; + + public interface AddDirectoryListener + { + void onDirectoryAdded(); + } + + public AddDirectoryHelper(Context context) + { + this.mContext = context; + } + + public void addDirectory(String dir, AddDirectoryListener addDirectoryListener) + { + AsyncQueryHandler handler = new AsyncQueryHandler(mContext.getContentResolver()) + { + @Override + protected void onInsertComplete(int token, Object cookie, Uri uri) + { + addDirectoryListener.onDirectoryAdded(); + } + }; + + ContentValues file = new ContentValues(); + file.put(GameDatabase.KEY_FOLDER_PATH, dir); + + handler.startInsert(0, // We don't need to identify this call to the handler + null, // We don't need to pass additional data to the handler + GameProvider.URI_FOLDER, // Tell the GameProvider we are adding a folder + file); + } +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/FileBrowserHelper.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/FileBrowserHelper.java new file mode 100644 index 0000000000..e2fe1cf818 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/FileBrowserHelper.java @@ -0,0 +1,43 @@ +package org.dolphinemu.dolphinemu.utils; + +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.os.Environment; +import android.support.annotation.Nullable; +import android.support.v4.app.FragmentActivity; + +import com.nononsenseapps.filepicker.FilePickerActivity; +import com.nononsenseapps.filepicker.Utils; + +import org.dolphinemu.dolphinemu.activities.CustomFilePickerActivity; +import org.dolphinemu.dolphinemu.ui.main.MainPresenter; + +import java.io.File; +import java.util.List; + +public final class FileBrowserHelper +{ + public static void openDirectoryPicker(FragmentActivity activity) { + Intent i = new Intent(activity, CustomFilePickerActivity.class); + + i.putExtra(FilePickerActivity.EXTRA_ALLOW_MULTIPLE, false); + i.putExtra(FilePickerActivity.EXTRA_ALLOW_CREATE_DIR, false); + i.putExtra(FilePickerActivity.EXTRA_MODE, FilePickerActivity.MODE_DIR); + i.putExtra(FilePickerActivity.EXTRA_START_PATH, Environment.getExternalStorageDirectory().getPath()); + + activity.startActivityForResult(i, MainPresenter.REQUEST_ADD_DIRECTORY); + } + + @Nullable + public static String getSelectedDirectory(Intent result) { + // Use the provided utility method to parse the result + List files = Utils.getSelectedFilesFromResult(result); + if(!files.isEmpty()) { + File file = Utils.getFileForUri(files.get(0)); + return file.getAbsolutePath(); + } + + return null; + } +} diff --git a/Source/Android/app/src/main/res/values/styles.xml b/Source/Android/app/src/main/res/values/styles.xml index eb8cf73dcb..a211077fee 100644 --- a/Source/Android/app/src/main/res/values/styles.xml +++ b/Source/Android/app/src/main/res/values/styles.xml @@ -145,4 +145,27 @@ @color/button_text_color - \ No newline at end of file + + + + + +