From f5fc69d1c2e14ab43fdde8e8a81a0a0f2e4067f9 Mon Sep 17 00:00:00 2001 From: Ruslan Tkhakokhov Date: Tue, 25 Jul 2017 18:04:54 -0700 Subject: [PATCH] Network browsing (#25) Add basic network browsing support. The embedded "master browser" functionality embedded in libsmbclient is the only way to browse as of now, but the code is structured to be extendable for other mechanisms of browsing. This fixes #5. --- .../SambaProviderApplication.java | 8 ++ .../sambadocumentsprovider/TaskManager.java | 2 - .../base/DirectoryEntry.java | 2 +- .../browsing/BrowsingException.java | 24 ++++ .../browsing/MasterBrowsingProvider.java | 74 ++++++++++ .../browsing/NetworkBrowser.java | 96 +++++++++++++ .../browsing/NetworkBrowsingProvider.java | 27 ++++ .../document/DocumentMetadata.java | 29 +++- .../mount/MountServerActivity.java | 1 + .../provider/SambaDocumentsProvider.java | 127 +++++++++++++++++- app/src/main/res/drawable/ic_cloud.xml | 28 ++++ app/src/main/res/drawable/ic_server.xml | 31 +++++ app/src/main/res/values/strings.xml | 2 + 13 files changed, 441 insertions(+), 10 deletions(-) create mode 100644 app/src/main/java/com/google/android/sambadocumentsprovider/browsing/BrowsingException.java create mode 100644 app/src/main/java/com/google/android/sambadocumentsprovider/browsing/MasterBrowsingProvider.java create mode 100644 app/src/main/java/com/google/android/sambadocumentsprovider/browsing/NetworkBrowser.java create mode 100644 app/src/main/java/com/google/android/sambadocumentsprovider/browsing/NetworkBrowsingProvider.java create mode 100644 app/src/main/res/drawable/ic_cloud.xml create mode 100644 app/src/main/res/drawable/ic_server.xml diff --git a/app/src/main/java/com/google/android/sambadocumentsprovider/SambaProviderApplication.java b/app/src/main/java/com/google/android/sambadocumentsprovider/SambaProviderApplication.java index 74294fe..3ad1a44 100644 --- a/app/src/main/java/com/google/android/sambadocumentsprovider/SambaProviderApplication.java +++ b/app/src/main/java/com/google/android/sambadocumentsprovider/SambaProviderApplication.java @@ -27,6 +27,7 @@ import android.net.NetworkRequest; import android.util.Log; import com.google.android.sambadocumentsprovider.SambaConfiguration.OnConfigurationChangedListener; +import com.google.android.sambadocumentsprovider.browsing.NetworkBrowser; import com.google.android.sambadocumentsprovider.cache.DocumentCache; import com.google.android.sambadocumentsprovider.nativefacade.CredentialCache; import com.google.android.sambadocumentsprovider.nativefacade.SambaMessageLooper; @@ -42,6 +43,7 @@ public class SambaProviderApplication extends Application { private SmbFacade mSambaClient; private ShareManager mShareManager; + private NetworkBrowser mNetworkBrowser; @Override public void onCreate() { @@ -64,6 +66,8 @@ public class SambaProviderApplication extends Application { mShareManager = new ShareManager(context, credentialCache); + mNetworkBrowser = new NetworkBrowser(mSambaClient, mTaskManager); + registerNetworkCallback(context); } @@ -129,6 +133,10 @@ public class SambaProviderApplication extends Application { return getApplication(context).mTaskManager; } + public static NetworkBrowser getNetworkBrowser(Context context) { + return getApplication(context).mNetworkBrowser; + } + private static SambaProviderApplication getApplication(Context context) { return ((SambaProviderApplication) context.getApplicationContext()); } diff --git a/app/src/main/java/com/google/android/sambadocumentsprovider/TaskManager.java b/app/src/main/java/com/google/android/sambadocumentsprovider/TaskManager.java index e53176e..4963627 100644 --- a/app/src/main/java/com/google/android/sambadocumentsprovider/TaskManager.java +++ b/app/src/main/java/com/google/android/sambadocumentsprovider/TaskManager.java @@ -21,8 +21,6 @@ import android.net.Uri; import android.os.AsyncTask; import android.os.AsyncTask.Status; import android.util.Log; -import com.google.android.sambadocumentsprovider.provider.ReadFileTask; -import com.google.android.sambadocumentsprovider.provider.WriteFileTask; import java.util.HashMap; import java.util.Map; import java.util.concurrent.Executor; diff --git a/app/src/main/java/com/google/android/sambadocumentsprovider/base/DirectoryEntry.java b/app/src/main/java/com/google/android/sambadocumentsprovider/base/DirectoryEntry.java index 5c0b03a..f30ea6d 100644 --- a/app/src/main/java/com/google/android/sambadocumentsprovider/base/DirectoryEntry.java +++ b/app/src/main/java/com/google/android/sambadocumentsprovider/base/DirectoryEntry.java @@ -29,7 +29,7 @@ public class DirectoryEntry { @IntDef({WORKGROUP, SERVER, FILE_SHARE, PRINTER_SHARE, COMMS_SHARE, IPC_SHARE, DIR, FILE, LINK}) @Retention(RetentionPolicy.SOURCE) - @interface Type {} + public @interface Type {} public static final int WORKGROUP = 1; public static final int SERVER = 2; public static final int FILE_SHARE = 3; diff --git a/app/src/main/java/com/google/android/sambadocumentsprovider/browsing/BrowsingException.java b/app/src/main/java/com/google/android/sambadocumentsprovider/browsing/BrowsingException.java new file mode 100644 index 0000000..8fb304b --- /dev/null +++ b/app/src/main/java/com/google/android/sambadocumentsprovider/browsing/BrowsingException.java @@ -0,0 +1,24 @@ +/* + * Copyright 2017 Google Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.google.android.sambadocumentsprovider.browsing; + +class BrowsingException extends Exception { + BrowsingException(String message) { + super("Browsing failed: " + message); + } +} diff --git a/app/src/main/java/com/google/android/sambadocumentsprovider/browsing/MasterBrowsingProvider.java b/app/src/main/java/com/google/android/sambadocumentsprovider/browsing/MasterBrowsingProvider.java new file mode 100644 index 0000000..d6cc630 --- /dev/null +++ b/app/src/main/java/com/google/android/sambadocumentsprovider/browsing/MasterBrowsingProvider.java @@ -0,0 +1,74 @@ +/* + * Copyright 2017 Google Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.google.android.sambadocumentsprovider.browsing; + +import com.google.android.sambadocumentsprovider.base.DirectoryEntry; +import com.google.android.sambadocumentsprovider.nativefacade.SmbClient; +import com.google.android.sambadocumentsprovider.nativefacade.SmbDir; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +class MasterBrowsingProvider implements NetworkBrowsingProvider { + private static final String MASTER_BROWSING_DIR = "smb://"; + + private final SmbClient mClient; + + MasterBrowsingProvider(SmbClient client) { + mClient = client; + } + + @Override + public List getServers() throws BrowsingException { + List serversList = new ArrayList<>(); + + try { + SmbDir rootDir = mClient.openDir(MASTER_BROWSING_DIR); + + List workgroups = getDirectoryChildren(rootDir); + for (DirectoryEntry workgroup : workgroups) { + if (workgroup.getType() == DirectoryEntry.WORKGROUP) { + List servers = getDirectoryChildren + (mClient.openDir(MASTER_BROWSING_DIR + workgroup.getName())); + + for (DirectoryEntry server : servers) { + if (server.getType() == DirectoryEntry.SERVER) { + serversList.add(server.getName()); + } + } + } + } + } catch (IOException e) { + throw new BrowsingException(e.getMessage()); + } + + return serversList; + } + + private static List getDirectoryChildren(SmbDir dir) throws IOException { + List children = new ArrayList<>(); + + DirectoryEntry currentEntry; + while ((currentEntry = dir.readDir()) != null) { + children.add(currentEntry); + } + + return children; + } +} diff --git a/app/src/main/java/com/google/android/sambadocumentsprovider/browsing/NetworkBrowser.java b/app/src/main/java/com/google/android/sambadocumentsprovider/browsing/NetworkBrowser.java new file mode 100644 index 0000000..0083eeb --- /dev/null +++ b/app/src/main/java/com/google/android/sambadocumentsprovider/browsing/NetworkBrowser.java @@ -0,0 +1,96 @@ +/* + * Copyright 2017 Google Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.google.android.sambadocumentsprovider.browsing; + +import android.net.Uri; +import android.os.AsyncTask; +import android.util.Log; + +import com.google.android.sambadocumentsprovider.TaskManager; +import com.google.android.sambadocumentsprovider.base.DirectoryEntry; +import com.google.android.sambadocumentsprovider.base.OnTaskFinishedCallback; +import com.google.android.sambadocumentsprovider.nativefacade.SmbClient; +import com.google.android.sambadocumentsprovider.nativefacade.SmbDir; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Future; + +public class NetworkBrowser { + public static final Uri SMB_BROWSING_URI = Uri.parse("smb://"); + + private static final String TAG = "NetworkBrowser"; + + private final NetworkBrowsingProvider mMasterProvider; + private final TaskManager mTaskManager; + + private final Map mTasks = new HashMap<>(); + + public NetworkBrowser(SmbClient client, TaskManager taskManager) { + mMasterProvider = new MasterBrowsingProvider(client); + mTaskManager = taskManager; + } + + public AsyncTask getServersAsync(OnTaskFinishedCallback> callback) { + AsyncTask> loadServersTask = new LoadServersTask(callback); + + mTaskManager.runTask(SMB_BROWSING_URI, loadServersTask); + + return loadServersTask; + } + + private List getServers() throws BrowsingException { + return mMasterProvider.getServers(); + } + + private class LoadServersTask extends AsyncTask> { + final OnTaskFinishedCallback> mCallback; + + private BrowsingException mException; + + LoadServersTask(OnTaskFinishedCallback> callback) { + mCallback = callback; + } + + List loadData() throws BrowsingException { + return getServers(); + } + + @Override + protected List doInBackground(Void... voids) { + try { + return loadData(); + } catch (BrowsingException e) { + Log.e(TAG, "Failed to load data for network browsing: ", e); + mException = e; + return null; + } + } + + protected void onPostExecute(List servers) { + if (servers != null) { + mCallback.onTaskFinished(OnTaskFinishedCallback.SUCCEEDED, servers, null); + } else { + mCallback.onTaskFinished(OnTaskFinishedCallback.FAILED, null, mException); + } + } + } +} diff --git a/app/src/main/java/com/google/android/sambadocumentsprovider/browsing/NetworkBrowsingProvider.java b/app/src/main/java/com/google/android/sambadocumentsprovider/browsing/NetworkBrowsingProvider.java new file mode 100644 index 0000000..9aee90a --- /dev/null +++ b/app/src/main/java/com/google/android/sambadocumentsprovider/browsing/NetworkBrowsingProvider.java @@ -0,0 +1,27 @@ +/* + * Copyright 2017 Google Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.google.android.sambadocumentsprovider.browsing; + +import java.util.List; + +interface NetworkBrowsingProvider { + /** + * Returns unresolved host names. + */ + List getServers() throws BrowsingException; +} diff --git a/app/src/main/java/com/google/android/sambadocumentsprovider/document/DocumentMetadata.java b/app/src/main/java/com/google/android/sambadocumentsprovider/document/DocumentMetadata.java index 81c6f39..5ee55f3 100644 --- a/app/src/main/java/com/google/android/sambadocumentsprovider/document/DocumentMetadata.java +++ b/app/src/main/java/com/google/android/sambadocumentsprovider/document/DocumentMetadata.java @@ -25,6 +25,8 @@ import android.system.StructStat; import android.text.TextUtils; import android.util.Log; import android.webkit.MimeTypeMap; + +import com.google.android.sambadocumentsprovider.R; import com.google.android.sambadocumentsprovider.base.DirectoryEntry; import com.google.android.sambadocumentsprovider.nativefacade.SmbClient; import com.google.android.sambadocumentsprovider.nativefacade.SmbDir; @@ -32,7 +34,6 @@ import java.io.IOException; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; @@ -74,6 +75,18 @@ public class DocumentMetadata { return mEntry.getType() == DirectoryEntry.FILE_SHARE; } + public Integer getIconResourceId() { + switch (mEntry.getType()) { + case DirectoryEntry.SERVER: + return R.drawable.ic_server; + case DirectoryEntry.FILE_SHARE: + return R.drawable.ic_folder_shared; + default: + // Tells SAF to use the default icon. + return null; + } + } + public Long getLastModified() { final StructStat stat = mStat.get(); return (stat == null) ? null : TimeUnit.MILLISECONDS.convert(stat.st_mtime, TimeUnit.SECONDS); @@ -293,6 +306,10 @@ public class DocumentMetadata { return builder.build(); } + public static boolean isServerUri(Uri uri) { + return uri.getPathSegments().isEmpty() && !uri.getAuthority().isEmpty(); + } + public static DocumentMetadata fromUri(Uri uri, SmbClient client) throws IOException { final List pathSegments = uri.getPathSegments(); if (pathSegments.isEmpty()) { @@ -315,9 +332,17 @@ public class DocumentMetadata { return createShare(uri); } + public static DocumentMetadata createServer(Uri uri) { + return create(uri, DirectoryEntry.SERVER); + } + public static DocumentMetadata createShare(Uri uri) { + return create(uri, DirectoryEntry.FILE_SHARE); + } + + private static DocumentMetadata create(Uri uri, @DirectoryEntry.Type int type) { final DirectoryEntry entry = - new DirectoryEntry(DirectoryEntry.FILE_SHARE, "", uri.getLastPathSegment()); + new DirectoryEntry(type, "", uri.getLastPathSegment()); return new DocumentMetadata(uri, entry); } } diff --git a/app/src/main/java/com/google/android/sambadocumentsprovider/mount/MountServerActivity.java b/app/src/main/java/com/google/android/sambadocumentsprovider/mount/MountServerActivity.java index 1b692f6..bf0ae0e 100644 --- a/app/src/main/java/com/google/android/sambadocumentsprovider/mount/MountServerActivity.java +++ b/app/src/main/java/com/google/android/sambadocumentsprovider/mount/MountServerActivity.java @@ -56,6 +56,7 @@ import com.google.android.sambadocumentsprovider.cache.DocumentCache; import com.google.android.sambadocumentsprovider.document.DocumentMetadata; import com.google.android.sambadocumentsprovider.nativefacade.SmbClient; import com.google.android.sambadocumentsprovider.provider.SambaDocumentsProvider; + import java.util.List; public class MountServerActivity extends AppCompatActivity { diff --git a/app/src/main/java/com/google/android/sambadocumentsprovider/provider/SambaDocumentsProvider.java b/app/src/main/java/com/google/android/sambadocumentsprovider/provider/SambaDocumentsProvider.java index 3713690..787b143 100644 --- a/app/src/main/java/com/google/android/sambadocumentsprovider/provider/SambaDocumentsProvider.java +++ b/app/src/main/java/com/google/android/sambadocumentsprovider/provider/SambaDocumentsProvider.java @@ -27,6 +27,7 @@ import android.content.Context; import android.database.Cursor; import android.database.MatrixCursor; import android.net.Uri; +import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; import android.os.CancellationSignal; @@ -48,6 +49,7 @@ import com.google.android.sambadocumentsprovider.TaskManager; import com.google.android.sambadocumentsprovider.base.AuthFailedException; import com.google.android.sambadocumentsprovider.base.DirectoryEntry; import com.google.android.sambadocumentsprovider.base.DocumentCursor; +import com.google.android.sambadocumentsprovider.browsing.NetworkBrowser; import com.google.android.sambadocumentsprovider.cache.CacheResult; import com.google.android.sambadocumentsprovider.cache.DocumentCache; import com.google.android.sambadocumentsprovider.document.DocumentMetadata; @@ -55,12 +57,11 @@ import com.google.android.sambadocumentsprovider.document.LoadChildrenTask; import com.google.android.sambadocumentsprovider.base.OnTaskFinishedCallback; import com.google.android.sambadocumentsprovider.document.LoadDocumentTask; import com.google.android.sambadocumentsprovider.document.LoadStatTask; -import com.google.android.sambadocumentsprovider.nativefacade.SmbClient; import com.google.android.sambadocumentsprovider.nativefacade.SmbFacade; -import com.google.android.sambadocumentsprovider.nativefacade.SmbFile; import java.io.FileNotFoundException; import java.io.IOException; +import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; @@ -87,7 +88,8 @@ public class SambaDocumentsProvider extends DocumentsProvider { Document.COLUMN_FLAGS, Document.COLUMN_MIME_TYPE, Document.COLUMN_SIZE, - Document.COLUMN_LAST_MODIFIED + Document.COLUMN_LAST_MODIFIED, + Document.COLUMN_ICON }; private final OnTaskFinishedCallback mLoadDocumentCallback = @@ -127,6 +129,22 @@ public class SambaDocumentsProvider extends DocumentsProvider { } }; + private final OnTaskFinishedCallback> mLoadSharesFinishedCallback = + new OnTaskFinishedCallback>() { + @Override + public void onTaskFinished( + @OnTaskFinishedCallback.Status int status, + @Nullable List item, + @Nullable Exception exception) { + if (BuildConfig.DEBUG) Log.d(TAG, "Browsing callback"); + + mBrowsingStorage = item; + + getContext().getContentResolver().notifyChange( + toNotifyUri(toUri(NetworkBrowser.SMB_BROWSING_URI.toString())), null, false); + } + }; + private final MountedShareChangeListener mShareChangeListener = new MountedShareChangeListener() { @Override public void onMountedServerChange() { @@ -142,6 +160,9 @@ public class SambaDocumentsProvider extends DocumentsProvider { private DocumentCache mCache; private TaskManager mTaskManager; private StorageManager mStorageManager; + private NetworkBrowser mNetworkBrowser; + + private List mBrowsingStorage = new ArrayList<>(); @Override public boolean onCreate() { @@ -155,6 +176,7 @@ public class SambaDocumentsProvider extends DocumentsProvider { mShareManager = SambaProviderApplication.getServerManager(context); mShareManager.addListener(mShareChangeListener); mStorageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE); + mNetworkBrowser = SambaProviderApplication.getNetworkBrowser(context); return mClient != null; } @@ -165,6 +187,15 @@ public class SambaDocumentsProvider extends DocumentsProvider { projection = (projection == null) ? DEFAULT_ROOT_PROJECTION : projection; MatrixCursor cursor = new MatrixCursor(projection, mShareManager.size()); + + cursor.addRow(new Object[] { + NetworkBrowser.SMB_BROWSING_URI.toString(), + NetworkBrowser.SMB_BROWSING_URI.toString(), + getContext().getResources().getString(R.string.browsing_root_name), + 0, + R.drawable.ic_cloud, + }); + for (String uri : mShareManager) { final String name; final Uri parsedUri = Uri.parse(uri); @@ -204,7 +235,15 @@ public class SambaDocumentsProvider extends DocumentsProvider { if (BuildConfig.DEBUG) Log.d(TAG, "Querying document: " + documentId); projection = (projection == null) ? DEFAULT_DOCUMENT_PROJECTION : projection; + final MatrixCursor cursor = new MatrixCursor(projection); final Uri uri = toUri(documentId); + + if (documentId.equals(NetworkBrowser.SMB_BROWSING_URI.toString())) { + cursor.addRow(getCursorRowForBrowsingRoot(projection)); + + return cursor; + } + try { try (CacheResult result = mCache.get(uri)) { @@ -221,7 +260,6 @@ public class SambaDocumentsProvider extends DocumentsProvider { metadata = result.getItem(); } - final MatrixCursor cursor = new MatrixCursor(projection); cursor.addRow(getDocumentValues(projection, metadata)); return cursor; @@ -239,13 +277,27 @@ public class SambaDocumentsProvider extends DocumentsProvider { if (BuildConfig.DEBUG) Log.d(TAG, "Querying children documents under " + documentId); projection = (projection == null) ? DEFAULT_DOCUMENT_PROJECTION : projection; + if (documentId.equals(NetworkBrowser.SMB_BROWSING_URI.toString())) { + return getFilesSharesCursor(projection); + } + final Uri uri = toUri(documentId); + try { + if (DocumentMetadata.isServerUri(uri)) { + try (final CacheResult result = mCache.get(uri)) { + if (result.getState() == CacheResult.CACHE_MISS) { + DocumentMetadata metadata = DocumentMetadata.createServer(uri); + mCache.put(metadata); + } + } + } + try (final CacheResult result = mCache.get(uri)) { boolean isLoading = false; - final DocumentCursor cursor = new DocumentCursor(projection); final Bundle extra = new Bundle(); final Uri notifyUri = toNotifyUri(uri); + final DocumentCursor cursor = new DocumentCursor(projection); if (result.getState() == CacheResult.CACHE_MISS) { // Last loading failed... Just feed the bitter fruit. @@ -359,11 +411,76 @@ public class SambaDocumentsProvider extends DocumentsProvider { case Document.COLUMN_LAST_MODIFIED: row[i] = metadata.getLastModified(); break; + case Document.COLUMN_ICON: + row[i] = metadata.getIconResourceId(); + break; } } return row; } + private Object[] getCursorRowForServer( + String[] projection, + String server) { + Object[] row = new Object[projection.length]; + + for (int i = 0; i < projection.length; ++i) { + switch (projection[i]) { + case Document.COLUMN_DOCUMENT_ID: + row[i] = NetworkBrowser.SMB_BROWSING_URI.toString() + server; + break; + case Document.COLUMN_DISPLAY_NAME: + row[i] = server.isEmpty() + ? getContext().getResources().getString(R.string.browsing_root_name) : server; + break; + case Document.COLUMN_FLAGS: + row[i] = 0; + break; + case Document.COLUMN_MIME_TYPE: + row[i] = Document.MIME_TYPE_DIR; + break; + case Document.COLUMN_SIZE: + case Document.COLUMN_LAST_MODIFIED: + row[i] = null; + break; + case Document.COLUMN_ICON: + row[i] = R.drawable.ic_server; + break; + } + } + + return row; + } + + private Object[] getCursorRowForBrowsingRoot(String[] projection) { + return getCursorRowForServer(projection, ""); + } + + private Cursor getFilesSharesCursor(String[] projection) { + final DocumentCursor cursor = new DocumentCursor(projection); + + final Uri uri = toUri(NetworkBrowser.SMB_BROWSING_URI.toString()); + + if (mBrowsingStorage.isEmpty()) { + AsyncTask serversTask = mNetworkBrowser.getServersAsync(mLoadSharesFinishedCallback); + + Bundle extra = new Bundle(); + extra.putBoolean(DocumentsContract.EXTRA_LOADING, true); + + cursor.setNotificationUri(getContext().getContentResolver(), toNotifyUri(uri)); + cursor.setExtras(extra); + cursor.setLoadingTask(serversTask); + } else { + for (String server : mBrowsingStorage) { + cursor.addRow(getCursorRowForServer(projection, server)); + } + + mBrowsingStorage.clear(); + } + + return cursor; + } + @Override public String createDocument(String parentDocumentId, String mimeType, String displayName) throws FileNotFoundException { diff --git a/app/src/main/res/drawable/ic_cloud.xml b/app/src/main/res/drawable/ic_cloud.xml new file mode 100644 index 0000000..e7a8fed --- /dev/null +++ b/app/src/main/res/drawable/ic_cloud.xml @@ -0,0 +1,28 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_server.xml b/app/src/main/res/drawable/ic_server.xml new file mode 100644 index 0000000..19c8638 --- /dev/null +++ b/app/src/main/res/drawable/ic_server.xml @@ -0,0 +1,31 @@ + + + + + + + \ 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 8ff2367..df3fedd 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -47,4 +47,6 @@ Send feedback It needs a web browser to send feedback. + + Samba Shares