|
@@ -24,6 +24,7 @@ import android.accounts.Account;
|
|
|
import android.app.SearchManager;
|
|
|
import android.content.ContentProvider;
|
|
|
import android.content.ContentValues;
|
|
|
+import android.content.Context;
|
|
|
import android.content.UriMatcher;
|
|
|
import android.database.Cursor;
|
|
|
import android.database.MatrixCursor;
|
|
@@ -57,17 +58,18 @@ import androidx.annotation.Nullable;
|
|
|
|
|
|
|
|
|
/**
|
|
|
- * Content provider for search suggestions, to search for users and groups existing in an ownCloud server.
|
|
|
+ * Content provider for search suggestions, to search for users and groups existing in an ownCloud
|
|
|
+ * server.
|
|
|
*/
|
|
|
public class UsersAndGroupsSearchProvider extends ContentProvider {
|
|
|
|
|
|
private static final String TAG = UsersAndGroupsSearchProvider.class.getSimpleName();
|
|
|
|
|
|
private static final String[] COLUMNS = {
|
|
|
- BaseColumns._ID,
|
|
|
- SearchManager.SUGGEST_COLUMN_TEXT_1,
|
|
|
- SearchManager.SUGGEST_COLUMN_ICON_1,
|
|
|
- SearchManager.SUGGEST_COLUMN_INTENT_DATA
|
|
|
+ BaseColumns._ID,
|
|
|
+ SearchManager.SUGGEST_COLUMN_TEXT_1,
|
|
|
+ SearchManager.SUGGEST_COLUMN_ICON_1,
|
|
|
+ SearchManager.SUGGEST_COLUMN_INTENT_DATA
|
|
|
};
|
|
|
|
|
|
private static final int SEARCH = 1;
|
|
@@ -75,15 +77,15 @@ public class UsersAndGroupsSearchProvider extends ContentProvider {
|
|
|
private static final int RESULTS_PER_PAGE = 50;
|
|
|
private static final int REQUESTED_PAGE = 1;
|
|
|
|
|
|
- static String AUTHORITY;
|
|
|
public static String ACTION_SHARE_WITH;
|
|
|
|
|
|
public static final String CONTENT = "content";
|
|
|
|
|
|
- static String DATA_USER;
|
|
|
- static String DATA_GROUP;
|
|
|
- static String DATA_ROOM;
|
|
|
- static String DATA_REMOTE;
|
|
|
+ private String DATA_USER;
|
|
|
+ private String DATA_GROUP;
|
|
|
+ private String DATA_ROOM;
|
|
|
+ private String DATA_REMOTE;
|
|
|
+ private String DATA_EMAIL;
|
|
|
|
|
|
private UriMatcher mUriMatcher;
|
|
|
|
|
@@ -107,21 +109,23 @@ public class UsersAndGroupsSearchProvider extends ContentProvider {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
- AUTHORITY = getContext().getResources().getString(R.string.users_and_groups_search_authority);
|
|
|
+ String AUTHORITY = getContext().getResources().getString(R.string.users_and_groups_search_authority);
|
|
|
ACTION_SHARE_WITH = getContext().getResources().getString(R.string.users_and_groups_share_with);
|
|
|
DATA_USER = AUTHORITY + ".data.user";
|
|
|
DATA_GROUP = AUTHORITY + ".data.group";
|
|
|
DATA_ROOM = AUTHORITY + ".data.room";
|
|
|
DATA_REMOTE = AUTHORITY + ".data.remote";
|
|
|
+ DATA_EMAIL = AUTHORITY + ".data.email";
|
|
|
|
|
|
sShareTypes.put(DATA_USER, ShareType.USER);
|
|
|
sShareTypes.put(DATA_GROUP, ShareType.GROUP);
|
|
|
sShareTypes.put(DATA_ROOM, ShareType.ROOM);
|
|
|
sShareTypes.put(DATA_REMOTE, ShareType.FEDERATED);
|
|
|
- sShareTypes.put(DATA_REMOTE, ShareType.EMAIL);
|
|
|
+ sShareTypes.put(DATA_EMAIL, ShareType.EMAIL);
|
|
|
|
|
|
mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
|
|
|
mUriMatcher.addURI(AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY + "/*", SEARCH);
|
|
|
+
|
|
|
return true;
|
|
|
}
|
|
|
|
|
@@ -130,9 +134,9 @@ public class UsersAndGroupsSearchProvider extends ContentProvider {
|
|
|
*
|
|
|
* Reference: http://developer.android.com/guide/topics/search/adding-custom-suggestions.html#CustomContentProvider
|
|
|
*
|
|
|
- * @param uri Content {@link Uri}, formatted as
|
|
|
- * "content://com.nextcloud.android.providers.UsersAndGroupsSearchProvider/" +
|
|
|
- * {@link android.app.SearchManager#SUGGEST_URI_PATH_QUERY} + "/" + 'userQuery'
|
|
|
+ * @param uri Content {@link Uri}, formatted as "content://com.nextcloud.android.providers.UsersAndGroupsSearchProvider/"
|
|
|
+ * + {@link android.app.SearchManager#SUGGEST_URI_PATH_QUERY} + "/" +
|
|
|
+ * 'userQuery'
|
|
|
* @param projection Expected to be NULL.
|
|
|
* @param selection Expected to be NULL.
|
|
|
* @param selectionArgs Expected to be NULL.
|
|
@@ -158,16 +162,25 @@ public class UsersAndGroupsSearchProvider extends ContentProvider {
|
|
|
private Cursor searchForUsersOrGroups(Uri uri) {
|
|
|
MatrixCursor response = null;
|
|
|
|
|
|
- String userQuery = uri.getLastPathSegment().toLowerCase(Locale.ROOT);
|
|
|
+ String lastPathSegment = uri.getLastPathSegment();
|
|
|
+
|
|
|
+ if (lastPathSegment == null) {
|
|
|
+ throw new IllegalArgumentException("Wrong URI passed!");
|
|
|
+ }
|
|
|
|
|
|
// need to trust on the AccountUtils to get the current account since the query in the client side is not
|
|
|
// directly started by our code, but from SearchView implementation
|
|
|
Account account = AccountUtils.getCurrentOwnCloudAccount(getContext());
|
|
|
|
|
|
+ if (account == null) {
|
|
|
+ throw new IllegalArgumentException("Account may not be null!");
|
|
|
+ }
|
|
|
+
|
|
|
+ String userQuery = lastPathSegment.toLowerCase(Locale.ROOT);
|
|
|
+
|
|
|
// request to the OC server about users and groups matching userQuery
|
|
|
- GetRemoteShareesOperation searchRequest = new GetRemoteShareesOperation(
|
|
|
- userQuery, REQUESTED_PAGE, RESULTS_PER_PAGE
|
|
|
- );
|
|
|
+ GetRemoteShareesOperation searchRequest = new GetRemoteShareesOperation(userQuery, REQUESTED_PAGE,
|
|
|
+ RESULTS_PER_PAGE);
|
|
|
RemoteOperationResult result = searchRequest.execute(account, getContext());
|
|
|
List<JSONObject> names = new ArrayList<>();
|
|
|
|
|
@@ -189,14 +202,19 @@ public class UsersAndGroupsSearchProvider extends ContentProvider {
|
|
|
Uri dataUri;
|
|
|
int count = 0;
|
|
|
|
|
|
+ if (getContext() == null) {
|
|
|
+ throw new IllegalArgumentException("Context may not be null!");
|
|
|
+ }
|
|
|
+
|
|
|
Uri userBaseUri = new Uri.Builder().scheme(CONTENT).authority(DATA_USER).build();
|
|
|
Uri groupBaseUri = new Uri.Builder().scheme(CONTENT).authority(DATA_GROUP).build();
|
|
|
Uri roomBaseUri = new Uri.Builder().scheme(CONTENT).authority(DATA_ROOM).build();
|
|
|
Uri remoteBaseUri = new Uri.Builder().scheme(CONTENT).authority(DATA_REMOTE).build();
|
|
|
+ Uri emailBaseUri = new Uri.Builder().scheme(CONTENT).authority(DATA_EMAIL).build();
|
|
|
|
|
|
FileDataStorageManager manager = new FileDataStorageManager(account, getContext().getContentResolver());
|
|
|
boolean federatedShareAllowed = manager.getCapability(account.name).getFilesSharingFederationOutgoing()
|
|
|
- .isTrue();
|
|
|
+ .isTrue();
|
|
|
|
|
|
try {
|
|
|
while (namesIt.hasNext()) {
|
|
@@ -225,7 +243,7 @@ public class UsersAndGroupsSearchProvider extends ContentProvider {
|
|
|
} else {
|
|
|
String[] uriSplitted = shareWith.split("@");
|
|
|
displayName = getContext().getString(R.string.share_known_remote_clarification,
|
|
|
- userName, uriSplitted[uriSplitted.length - 1]);
|
|
|
+ userName, uriSplitted[uriSplitted.length - 1]);
|
|
|
}
|
|
|
}
|
|
|
break;
|
|
@@ -239,7 +257,7 @@ public class UsersAndGroupsSearchProvider extends ContentProvider {
|
|
|
case EMAIL:
|
|
|
icon = R.drawable.ic_email;
|
|
|
displayName = getContext().getString(R.string.share_email_clarification, userName);
|
|
|
- dataUri = Uri.withAppendedPath(remoteBaseUri, shareWith);
|
|
|
+ dataUri = Uri.withAppendedPath(emailBaseUri, shareWith);
|
|
|
break;
|
|
|
|
|
|
case ROOM:
|
|
@@ -292,17 +310,20 @@ public class UsersAndGroupsSearchProvider extends ContentProvider {
|
|
|
*/
|
|
|
private void showErrorMessage(final RemoteOperationResult result) {
|
|
|
Handler handler = new Handler(Looper.getMainLooper());
|
|
|
- handler.post(new Runnable() {
|
|
|
- @Override
|
|
|
- public void run() {
|
|
|
- // The Toast must be shown in the main thread to grant that will be hidden correctly; otherwise
|
|
|
- // the thread may die before, an exception will occur, and the message will be left on the screen
|
|
|
- // until the app dies
|
|
|
-
|
|
|
- Toast.makeText(getContext().getApplicationContext(),
|
|
|
- ErrorMessageAdapter.getErrorCauseMessage(result, null, getContext().getResources()),
|
|
|
- Toast.LENGTH_SHORT).show();
|
|
|
+ handler.post(() -> {
|
|
|
+ // The Toast must be shown in the main thread to grant that will be hidden correctly; otherwise
|
|
|
+ // the thread may die before, an exception will occur, and the message will be left on the screen
|
|
|
+ // until the app dies
|
|
|
+
|
|
|
+ Context context = getContext();
|
|
|
+
|
|
|
+ if (context == null) {
|
|
|
+ throw new IllegalArgumentException("Context may not be null!");
|
|
|
}
|
|
|
+
|
|
|
+ Toast.makeText(getContext().getApplicationContext(),
|
|
|
+ ErrorMessageAdapter.getErrorCauseMessage(result, null, getContext().getResources()),
|
|
|
+ Toast.LENGTH_SHORT).show();
|
|
|
});
|
|
|
}
|
|
|
}
|