New user model

New non-nullable user model abstracts away all complexities of Nextcloud
user account and provides.

- backported java.util.Optional
- extended UserAccountManager with User getters
- deprecated CurrentAccountProvider.getCurrentAccount() method
- migrated connectivity service to new user model
- migrated UploadsStorageManager to new user model
- migrated OCFileListAdapter

Signed-off-by: Chris Narkiewicz <hello@ezaquarii.com>
This commit is contained in:
Chris Narkiewicz 2019-11-16 22:17:22 +00:00
parent b9ff6cecfc
commit 609b99666f
No known key found for this signature in database
GPG key ID: 30D28CA4CCC665C6
16 changed files with 994 additions and 158 deletions

View file

@ -0,0 +1,57 @@
/*
* Nextcloud Android client application
*
* @author Chris Narkiewicz <hello@ezaquarii.com>
* Copyright (C) 2019 Chris Narkiewicz
* Copyright (C) 2019 Nextcloud GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.nextcloud.client.account
import android.accounts.Account
import android.content.Context
import android.net.Uri
import com.owncloud.android.MainApp
import com.owncloud.android.R
import com.owncloud.android.lib.common.OwnCloudAccount
import com.owncloud.android.lib.common.OwnCloudBasicCredentials
import java.net.URI
/**
* This object represents anonymous user, ie. user that did not log in the Nextcloud server.
* It serves as a semantically correct "empty value", allowing simplification of logic
* in various components requiring user data, such as DB queries.
*/
internal class AnonymousUser(private val accountType: String) : User {
companion object {
@JvmStatic
fun fromContext(context: Context): AnonymousUser {
val type = context.getString(R.string.account_type)
return AnonymousUser(type)
}
}
override val accountName: String = "anonymous"
override val server = Server(URI.create(""), MainApp.MINIMUM_SUPPORTED_SERVER_VERSION)
override fun toPlatformAccount(): Account {
return Account(accountName, accountType)
}
override fun toOwnCloudAccount(): OwnCloudAccount {
return OwnCloudAccount(Uri.EMPTY, OwnCloudBasicCredentials("", ""))
}
}

View file

@ -2,19 +2,31 @@ package com.nextcloud.client.account;
import android.accounts.Account;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
/**
* This interface provides access to currently selected user Account.
* This interface provides access to currently selected user.
*
* @see UserAccountManager
*/
@FunctionalInterface
public interface CurrentAccountProvider {
/**
* Get currently active account.
* Get currently active account.
*
* @return Currently selected {@link Account} or first valid {@link Account} registered in OS or null, if not available at all.
*/
@Deprecated
@Nullable
Account getCurrentAccount();
/**
* Get currently active user profile. If there is no actice user, anonymous user is returned.
*
* @return User profile. Profile is never null.
*/
@NonNull
default User getUser() {
return new AnonymousUser("dummy");
}
}

View file

@ -0,0 +1,46 @@
/*
* Nextcloud Android client application
*
* @author Chris Narkiewicz <hello@ezaquarii.com>
* Copyright (C) 2019 Chris Narkiewicz
* Copyright (C) 2019 Nextcloud GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.nextcloud.client.account
import android.accounts.Account
import com.owncloud.android.lib.common.OwnCloudAccount
/**
* This class represents normal user logged into the Nextcloud server.
*/
internal class RegisteredUser(
private val account: Account,
private val ownCloudAccount: OwnCloudAccount,
override val server: Server
) : User {
override val accountName: String get() {
return account.name
}
override fun toPlatformAccount(): Account {
return account
}
override fun toOwnCloudAccount(): OwnCloudAccount {
return ownCloudAccount
}
}

View file

@ -0,0 +1,30 @@
/*
* Nextcloud Android client application
*
* @author Chris Narkiewicz <hello@ezaquarii.com>
* Copyright (C) 2019 Chris Narkiewicz
* Copyright (C) 2019 Nextcloud GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.nextcloud.client.account
import com.owncloud.android.lib.resources.status.OwnCloudVersion
import java.net.URI
/**
* This object provides all information necessary to interact
* with backend server.
*/
data class Server(val uri: URI, val version: OwnCloudVersion)

View file

@ -0,0 +1,53 @@
/*
* Nextcloud Android client application
*
* @author Chris Narkiewicz <hello@ezaquarii.com>
* Copyright (C) 2019 Chris Narkiewicz
* Copyright (C) 2019 Nextcloud GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.nextcloud.client.account
import android.accounts.Account
import com.owncloud.android.lib.common.OwnCloudAccount
interface User {
val accountName: String
val server: Server
/**
* This is temporary helper method created to facilitate incremental refactoring.
* Code using legacy platform Account can be partially converted to instantiate User
* object and use account instance when required.
*
* This method calls will allow tracing code awaiting further refactoring.
*
* @return Account instance that is associated with this User object.
*/
@Deprecated("Temporary workaround")
fun toPlatformAccount(): Account
/**
* This is temporary helper method created to facilitate incremental refactoring.
* Code using legacy ownCloud account can be partially converted to instantiate User
* object and use account instance when required.
*
* This method calls will allow tracing code awaiting further refactoring.
*
* @return OwnCloudAccount instance that is associated with this User object.
*/
@Deprecated("Temporary workaround")
fun toOwnCloudAccount(): OwnCloudAccount
}

View file

@ -21,10 +21,13 @@ package com.nextcloud.client.account;
import android.accounts.Account;
import com.nextcloud.java.util.Optional;
import com.owncloud.android.datamodel.OCFile;
import com.owncloud.android.lib.common.OwnCloudAccount;
import com.owncloud.android.lib.resources.status.OwnCloudVersion;
import java.util.List;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@ -51,6 +54,22 @@ public interface UserAccountManager extends CurrentAccountProvider {
@NonNull
Account[] getAccounts();
/**
* Get configured nextcloud user accounts
* @return List of users or empty list, if users are not registered.
*/
@NonNull
List<User> getAllUsers();
/**
* Get user with a specific account name.
*
* @param accountName Account name of the requested user
* @return User or empty optional if user does not exist.
*/
@NonNull
Optional<User> getUser(CharSequence accountName);
/**
* Check if Nextcloud account is registered in {@link android.accounts.AccountManager}
*

View file

@ -27,6 +27,7 @@ import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.text.TextUtils;
import com.nextcloud.java.util.Optional;
import com.owncloud.android.MainApp;
import com.owncloud.android.R;
import com.owncloud.android.datamodel.ArbitraryDataProvider;
@ -35,11 +36,18 @@ import com.owncloud.android.lib.common.OwnCloudAccount;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.OwnCloudClientManagerFactory;
import com.owncloud.android.lib.common.UserInfo;
import com.owncloud.android.lib.common.accounts.AccountUtils;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.utils.Log_OC;
import com.owncloud.android.lib.resources.status.OwnCloudVersion;
import com.owncloud.android.lib.resources.users.GetUserInfoRemoteOperation;
import org.jetbrains.annotations.NotNull;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
import androidx.annotation.NonNull;
@ -80,6 +88,20 @@ public class UserAccountManagerImpl implements UserAccountManager {
return accountManager.getAccountsByType(getAccountType());
}
@Override
@NonNull
public List<User> getAllUsers() {
Account[] accounts = getAccounts();
List<User> users = new ArrayList<>(accounts.length);
for (Account account : accounts) {
User user = createUserFromAccount(account);
if (user != null) {
users.add(user);
}
}
return users;
}
@Override
public boolean exists(Account account) {
Account[] nextcloudAccounts = getAccounts();
@ -103,6 +125,7 @@ public class UserAccountManagerImpl implements UserAccountManager {
return false;
}
@Override
@Nullable
public Account getCurrentAccount() {
Account[] ocAccounts = getAccounts();
@ -139,6 +162,76 @@ public class UserAccountManagerImpl implements UserAccountManager {
return defaultAccount;
}
/**
* Temporary solution to convert platform account to user instance.
* It takes null and returns null on error to ease error handling
* in legacy code.
*
* @param account Account instance
* @return User instance or null, if conversion failed
*/
@Nullable
private User createUserFromAccount(@Nullable Account account) {
if (account == null) {
return null;
}
OwnCloudAccount ownCloudAccount = null;
try {
ownCloudAccount = new OwnCloudAccount(account, context);
} catch (AccountUtils.AccountNotFoundException ex) {
return null;
}
/*
* Server version
*/
String serverVersionStr = accountManager.getUserData(account, AccountUtils.Constants.KEY_OC_VERSION);
OwnCloudVersion serverVersion;
if (serverVersionStr != null) {
serverVersion = new OwnCloudVersion(serverVersionStr);
} else {
serverVersion = MainApp.MINIMUM_SUPPORTED_SERVER_VERSION;
}
/*
* Server address
*/
String serverAddressStr = accountManager.getUserData(account, AccountUtils.Constants.KEY_OC_BASE_URL);
if (serverAddressStr == null || serverAddressStr.isEmpty()) {
return AnonymousUser.fromContext(context);
}
URI serverUri = URI.create(serverAddressStr); // TODO: validate
return new RegisteredUser(
account,
ownCloudAccount,
new Server(serverUri, serverVersion)
);
}
/**
* Get user. If user cannot be retrieved due to data error, anonymous user is returned instead.
*
*
* @return User instance
*/
@NotNull
@Override
public User getUser() {
Account account = getCurrentAccount();
User user = createUserFromAccount(account);
return user != null ? user : AnonymousUser.fromContext(context);
}
@Override
@NonNull
public Optional<User> getUser(CharSequence accountName) {
Account account = getAccountByName(accountName.toString());
User user = createUserFromAccount(account);
return Optional.of(user);
}
@Override
@Nullable
public OwnCloudAccount getCurrentOwnCloudAccount() {
@ -197,6 +290,7 @@ public class UserAccountManagerImpl implements UserAccountManager {
return result;
}
@Deprecated
@Override
@NonNull
public OwnCloudVersion getServerVersion(Account account) {

View file

@ -20,14 +20,13 @@
package com.nextcloud.client.network;
import android.accounts.Account;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import com.evernote.android.job.JobRequest;
import com.nextcloud.client.account.Server;
import com.nextcloud.client.account.UserAccountManager;
import com.owncloud.android.lib.common.OwnCloudAccount;
import com.owncloud.android.lib.common.utils.Log_OC;
import com.nextcloud.client.logger.Logger;
import com.owncloud.android.lib.resources.status.OwnCloudVersion;
import org.apache.commons.httpclient.HttpClient;
@ -44,10 +43,11 @@ class ConnectivityServiceImpl implements ConnectivityService {
private final static String TAG = ConnectivityServiceImpl.class.getName();
private ConnectivityManager connectivityManager;
private UserAccountManager accountManager;
private ClientFactory clientFactory;
private GetRequestBuilder requestBuilder;
private final ConnectivityManager connectivityManager;
private final UserAccountManager accountManager;
private final ClientFactory clientFactory;
private final GetRequestBuilder requestBuilder;
private final Logger logger;
static class GetRequestBuilder implements Function1<String, GetMethod> {
@Override
@ -59,55 +59,55 @@ class ConnectivityServiceImpl implements ConnectivityService {
ConnectivityServiceImpl(ConnectivityManager connectivityManager,
UserAccountManager accountManager,
ClientFactory clientFactory,
GetRequestBuilder requestBuilder) {
GetRequestBuilder requestBuilder,
Logger logger) {
this.connectivityManager = connectivityManager;
this.accountManager = accountManager;
this.clientFactory = clientFactory;
this.requestBuilder = requestBuilder;
this.logger = logger;
}
@Override
public boolean isInternetWalled() {
if (isOnlineWithWifi()) {
try {
Account account = accountManager.getCurrentAccount();
OwnCloudAccount ocAccount = accountManager.getCurrentOwnCloudAccount();
if (account != null && ocAccount != null) {
OwnCloudVersion serverVersion = accountManager.getServerVersion(account);
Server server = accountManager.getUser().getServer();
String baseServerAddress = server.getUri().toString();
if (baseServerAddress.isEmpty()) {
return true;
}
String url;
if (server.getVersion().compareTo(OwnCloudVersion.nextcloud_13) > 0) {
url = baseServerAddress + "/index.php/204";
} else {
url = baseServerAddress + "/status.php";
}
String url;
if (serverVersion.compareTo(OwnCloudVersion.nextcloud_13) > 0) {
url = ocAccount.getBaseUri() + "/index.php/204";
} else {
url = ocAccount.getBaseUri() + "/status.php";
}
GetMethod get = requestBuilder.invoke(url);
HttpClient client = clientFactory.createPlainClient();
GetMethod get = requestBuilder.invoke(url);
HttpClient client = clientFactory.createPlainClient();
int status = client.executeMethod(get);
int status = client.executeMethod(get);
if (serverVersion.compareTo(OwnCloudVersion.nextcloud_13) > 0) {
return !(status == HttpStatus.SC_NO_CONTENT &&
(get.getResponseContentLength() == -1 || get.getResponseContentLength() == 0));
} else {
if (status == HttpStatus.SC_OK) {
try {
// try parsing json to verify response
// check if json contains maintenance and it should be false
String json = get.getResponseBodyAsString();
return new JSONObject(json).getBoolean("maintenance");
} catch (Exception e) {
return true;
}
} else {
if (server.getVersion().compareTo(OwnCloudVersion.nextcloud_13) > 0) {
return !(status == HttpStatus.SC_NO_CONTENT &&
(get.getResponseContentLength() == -1 || get.getResponseContentLength() == 0));
} else {
if (status == HttpStatus.SC_OK) {
try {
// try parsing json to verify response
// check if json contains maintenance and it should be false
String json = get.getResponseBodyAsString();
return new JSONObject(json).getBoolean("maintenance");
} catch (Exception e) {
return true;
}
} else {
return true;
}
}
} catch (IOException e) {
Log_OC.e(TAG, "Error checking internet connection", e);
logger.e(TAG, "Error checking internet connection", e);
}
} else {
return getActiveNetworkType() == JobRequest.NetworkType.ANY;

View file

@ -24,6 +24,7 @@ import android.content.Context;
import android.net.ConnectivityManager;
import com.nextcloud.client.account.UserAccountManager;
import com.nextcloud.client.logger.Logger;
import javax.inject.Singleton;
@ -36,11 +37,13 @@ public class NetworkModule {
@Provides
ConnectivityService connectivityService(ConnectivityManager connectivityManager,
UserAccountManager accountManager,
ClientFactory clientFactory) {
ClientFactory clientFactory,
Logger logger) {
return new ConnectivityServiceImpl(connectivityManager,
accountManager,
clientFactory,
new ConnectivityServiceImpl.GetRequestBuilder());
new ConnectivityServiceImpl.GetRequestBuilder(),
logger);
}
@Provides

View file

@ -0,0 +1,366 @@
/*
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.nextcloud.java.util;
import com.nextcloud.java.util.function.Predicate;
import java.util.NoSuchElementException;
import androidx.core.util.Consumer;
import androidx.core.util.ObjectsCompat;
import androidx.core.util.Supplier;
import kotlin.jvm.functions.Function1;
/**
* This class is backported from Java 8 to be used on older Android API levels.
* It uses available interfaces from Kotlin and androidx. It is semantically
* identical with Java 8 API, allowing smooth migration when those APIs become
* available.
*
* A container object which may or may not contain a non-null value.
* If a value is present, {@code isPresent()} will return {@code true} and
* {@code get()} will return the value.
*
* <p>Additional methods that depend on the presence or absence of a contained
* value are provided, such as {@link #orElse(java.lang.Object) orElse()}
* (return a default value if value not present) and
* {@link #ifPresent(Consumer) ifPresent()} (execute a block
* of code if the value is present).
*/
public final class Optional<T> {
/**
* Common instance for {@code empty()}.
*/
private static final Optional<?> EMPTY = new Optional<>();
/**
* If non-null, the value; if null, indicates no value is present
*/
private final T value;
/**
* Constructs an empty instance.
*
* @implNote Generally only one empty instance, {@link Optional#EMPTY},
* should exist per VM.
*/
private Optional() {
this.value = null;
}
/**
* Returns an empty {@code Optional} instance. No value is present for this
* Optional.
*
* @apiNote Though it may be tempting to do so, avoid testing if an object
* is empty by comparing with {@code ==} against instances returned by
* {@code Option.empty()}. There is no guarantee that it is a singleton.
* Instead, use {@link #isPresent()}.
*
* @param <T> Type of the non-existent value
* @return an empty {@code Optional}
*/
public static<T> Optional<T> empty() {
@SuppressWarnings("unchecked")
Optional<T> t = (Optional<T>) EMPTY;
return t;
}
/**
* Constructs an instance with the value present.
*
* @param value the non-null value to be present
* @throws NullPointerException if value is null
*/
private Optional(T value) {
if (value == null) {
throw new NullPointerException();
}
this.value = value;
}
/**
* Returns an {@code Optional} with the specified present non-null value.
*
* @param <T> the class of the value
* @param value the value to be present, which must be non-null
* @return an {@code Optional} with the value present
* @throws NullPointerException if value is null
*/
public static <T> Optional<T> of(T value) {
return new Optional<>(value);
}
/**
* Returns an {@code Optional} describing the specified value, if non-null,
* otherwise returns an empty {@code Optional}.
*
* @param <T> the class of the value
* @param value the possibly-null value to describe
* @return an {@code Optional} with a present value if the specified value
* is non-null, otherwise an empty {@code Optional}
*/
public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}
/**
* If a value is present in this {@code Optional}, returns the value,
* otherwise throws {@code NoSuchElementException}.
*
* @return the non-null value held by this {@code Optional}
* @throws NoSuchElementException if there is no value present
*
* @see Optional#isPresent()
*/
public T get() {
if (value == null) {
throw new NoSuchElementException("No value present");
}
return value;
}
/**
* Return {@code true} if there is a value present, otherwise {@code false}.
*
* @return {@code true} if there is a value present, otherwise {@code false}
*/
public boolean isPresent() {
return value != null;
}
/**
* If a value is present, invoke the specified consumer with the value,
* otherwise do nothing.
*
* @param consumer block to be executed if a value is present
* @throws NullPointerException if value is present and {@code consumer} is
* null
*/
public void ifPresent(Consumer<? super T> consumer) {
if (value != null) {
consumer.accept(value);
}
}
/**
* If a value is present, and the value matches the given predicate,
* return an {@code Optional} describing the value, otherwise return an
* empty {@code Optional}.
*
* @param predicate a predicate to apply to the value, if present
* @return an {@code Optional} describing the value of this {@code Optional}
* if a value is present and the value matches the given predicate,
* otherwise an empty {@code Optional}
* @throws NullPointerException if the predicate is null
*/
public Optional<T> filter(Predicate<? super T> predicate) {
if (predicate == null) {
throw new NullPointerException();
}
if (!isPresent()) {
return this;
} else {
return predicate.test(value) ? this : empty();
}
}
/**
* If a value is present, apply the provided mapping function to it,
* and if the result is non-null, return an {@code Optional} describing the
* result. Otherwise return an empty {@code Optional}.
*
* @apiNote This method supports post-processing on optional values, without
* the need to explicitly check for a return status. For example, the
* following code traverses a stream of file names, selects one that has
* not yet been processed, and then opens that file, returning an
* {@code Optional<FileInputStream>}:
*
* <pre>{@code
* Optional<FileInputStream> fis =
* names.stream().filter(name -> !isProcessedYet(name))
* .findFirst()
* .map(name -> new FileInputStream(name));
* }</pre>
*
* Here, {@code findFirst} returns an {@code Optional<String>}, and then
* {@code map} returns an {@code Optional<FileInputStream>} for the desired
* file if one exists.
*
* @param <U> The type of the result of the mapping function
* @param mapper a mapping function to apply to the value, if present
* @return an {@code Optional} describing the result of applying a mapping
* function to the value of this {@code Optional}, if a value is present,
* otherwise an empty {@code Optional}
* @throws NullPointerException if the mapping function is null
*/
public<U> Optional<U> map(Function1<? super T, ? extends U> mapper) {
if (mapper == null) {
throw new NullPointerException();
}
if (!isPresent()) {
return empty();
} else {
return Optional.ofNullable(mapper.invoke(value));
}
}
/**
* If a value is present, apply the provided {@code Optional}-bearing
* mapping function to it, return that result, otherwise return an empty
* {@code Optional}. This method is similar to {@link #map(Function1)},
* but the provided mapper is one whose result is already an {@code Optional},
* and if invoked, {@code flatMap} does not wrap it with an additional
* {@code Optional}.
*
* @param <U> The type parameter to the {@code Optional} returned by
* @param mapper a mapping function to apply to the value, if present
* the mapping function
* @return the result of applying an {@code Optional}-bearing mapping
* function to the value of this {@code Optional}, if a value is present,
* otherwise an empty {@code Optional}
* @throws NullPointerException if the mapping function is null or returns
* a null result
*/
public<U> Optional<U> flatMap(Function1<? super T, Optional<U>> mapper) {
if(mapper == null) {
throw new NullPointerException();
}
if (!isPresent()) {
return empty();
} else {
Optional<U> u = mapper.invoke(value);
if (u == null) {
throw new NullPointerException();
}
return u;
}
}
/**
* Return the value if present, otherwise return {@code other}.
*
* @param other the value to be returned if there is no value present, may
* be null
* @return the value, if present, otherwise {@code other}
*/
public T orElse(T other) {
return value != null ? value : other;
}
/**
* Return the value if present, otherwise invoke {@code other} and return
* the result of that invocation.
*
* @param other a {@code Supplier} whose result is returned if no value
* is present
* @return the value if present otherwise the result of {@code other.get()}
* @throws NullPointerException if value is not present and {@code other} is
* null
*/
public T orElseGet(Supplier<? extends T> other) {
return value != null ? value : other.get();
}
/**
* Return the contained value, if present, otherwise throw an exception
* to be created by the provided supplier.
*
* @apiNote A method reference to the exception constructor with an empty
* argument list can be used as the supplier. For example,
* {@code IllegalStateException::new}
*
* @param <X> Type of the exception to be thrown
* @param exceptionSupplier The supplier which will return the exception to
* be thrown
* @return the present value
* @throws X if there is no value present
* @throws NullPointerException if no value is present and
* {@code exceptionSupplier} is null
*/
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
if (value != null) {
return value;
} else {
throw exceptionSupplier.get();
}
}
/**
* Indicates whether some other object is "equal to" this Optional. The
* other object is considered equal if:
* <ul>
* <li>it is also an {@code Optional} and;
* <li>both instances have no value present or;
* <li>the present values are "equal to" each other via {@code equals()}.
* </ul>
*
* @param obj an object to be tested for equality
* @return {code true} if the other object is "equal to" this object
* otherwise {@code false}
*/
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof Optional)) {
return false;
}
Optional<?> other = (Optional<?>) obj;
return ObjectsCompat.equals(value, other.value);
}
/**
* Returns the hash code value of the present value, if any, or 0 (zero) if
* no value is present.
*
* @return hash code value of the present value or 0 if no value is present
*/
@Override
public int hashCode() {
return ObjectsCompat.hashCode(value);
}
/**
* Returns a non-empty string representation of this Optional suitable for
* debugging. The exact presentation format is unspecified and may vary
* between implementations and versions.
*
* @implSpec If a value is present the result must include its string
* representation in the result. Empty and present Optionals must be
* unambiguously differentiable.
*
* @return the string representation of this instance
*/
@Override
public String toString() {
return value != null
? String.format("Optional[%s]", value)
: "Optional.empty";
}
}

View file

@ -0,0 +1,121 @@
/*
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.nextcloud.java.util.function;
/**
* This class is backported from Java 8 to be used on older Android API levels.
*
* Represents a predicate (boolean-valued function) of one argument.
*
* <p>This is a <a href="package-summary.html">functional interface</a>
* whose functional method is {@link #test(Object)}.
*
* @param <T> the type of the input to the predicate
*/
@FunctionalInterface
public interface Predicate<T> {
/**
* Evaluates this predicate on the given argument.
*
* @param t the input argument
* @return {@code true} if the input argument matches the predicate,
* otherwise {@code false}
*/
boolean test(T t);
/**
* Returns a composed predicate that represents a short-circuiting logical
* AND of this predicate and another. When evaluating the composed
* predicate, if this predicate is {@code false}, then the {@code other}
* predicate is not evaluated.
*
* <p>Any exceptions thrown during evaluation of either predicate are relayed
* to the caller; if evaluation of this predicate throws an exception, the
* {@code other} predicate will not be evaluated.
*
* @param other a predicate that will be logically-ANDed with this
* predicate
* @return a composed predicate that represents the short-circuiting logical
* AND of this predicate and the {@code other} predicate
* @throws NullPointerException if other is null
*/
default Predicate<T> and(Predicate<? super T> other) {
if (other == null) {
throw new NullPointerException();
}
return (t) -> test(t) && other.test(t);
}
/**
* Returns a predicate that represents the logical negation of this
* predicate.
*
* @return a predicate that represents the logical negation of this
* predicate
*/
default Predicate<T> negate() {
return (t) -> !test(t);
}
/**
* Returns a composed predicate that represents a short-circuiting logical
* OR of this predicate and another. When evaluating the composed
* predicate, if this predicate is {@code true}, then the {@code other}
* predicate is not evaluated.
*
* <p>Any exceptions thrown during evaluation of either predicate are relayed
* to the caller; if evaluation of this predicate throws an exception, the
* {@code other} predicate will not be evaluated.
*
* @param other a predicate that will be logically-ORed with this
* predicate
* @return a composed predicate that represents the short-circuiting logical
* OR of this predicate and the {@code other} predicate
* @throws NullPointerException if other is null
*/
default Predicate<T> or(Predicate<? super T> other) {
if (other == null) {
throw new NullPointerException();
}
return (t) -> test(t) || other.test(t);
}
/**
* Returns a predicate that tests if two arguments are equal according
* to {@link androidx.core.util.ObjectsCompat#equals(Object, Object)}.
*
* @param <T> the type of arguments to the predicate
* @param targetRef the object reference with which to compare for equality,
* which may be {@code null}
* @return a predicate that tests if two arguments are equal according
* to {@link androidx.core.util.ObjectsCompat#equals(Object, Object)}
*/
static <T> Predicate<T> isEqual(Object targetRef) {
return (null == targetRef)
? object -> object == null
: object -> targetRef.equals(object);
}
}

View file

@ -0,0 +1,26 @@
/*
* Nextcloud Android client application
*
* @author Chris Narkiewicz <hello@ezaquarii.com>
* Copyright (C) 2019 Chris Narkiewicz
* Copyright (C) 2019 Nextcloud GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
/**
* This is a compatibility package providing some backported Java 8 classes
* not available in some older Android runtimes.
*/
package com.nextcloud.java.util;

View file

@ -30,6 +30,7 @@ import android.database.Cursor;
import android.net.Uri;
import com.nextcloud.client.account.CurrentAccountProvider;
import com.nextcloud.client.account.User;
import com.owncloud.android.db.OCUpload;
import com.owncloud.android.db.ProviderMeta.ProviderTableMeta;
import com.owncloud.android.db.UploadResult;
@ -345,24 +346,19 @@ public class UploadsStorageManager extends Observable {
}
public OCUpload[] getCurrentAndPendingUploadsForCurrentAccount() {
Account account = currentAccountProvider.getCurrentAccount();
User user = currentAccountProvider.getUser();
if (account != null) {
return getUploads(
ProviderTableMeta.UPLOADS_STATUS + "==" + UploadStatus.UPLOAD_IN_PROGRESS.value +
" OR " + ProviderTableMeta.UPLOADS_LAST_RESULT +
"==" + UploadResult.DELAYED_FOR_WIFI.getValue() +
" OR " + ProviderTableMeta.UPLOADS_LAST_RESULT +
"==" + UploadResult.LOCK_FAILED.getValue() +
" OR " + ProviderTableMeta.UPLOADS_LAST_RESULT +
"==" + UploadResult.DELAYED_FOR_CHARGING.getValue() +
" OR " + ProviderTableMeta.UPLOADS_LAST_RESULT +
"==" + UploadResult.DELAYED_IN_POWER_SAVE_MODE.getValue() +
" AND " + ProviderTableMeta.UPLOADS_ACCOUNT_NAME + "== ?",
account.name);
} else {
return new OCUpload[0];
}
return getUploads(ProviderTableMeta.UPLOADS_STATUS + "==" + UploadStatus.UPLOAD_IN_PROGRESS.value +
" OR " + ProviderTableMeta.UPLOADS_LAST_RESULT +
"==" + UploadResult.DELAYED_FOR_WIFI.getValue() +
" OR " + ProviderTableMeta.UPLOADS_LAST_RESULT +
"==" + UploadResult.LOCK_FAILED.getValue() +
" OR " + ProviderTableMeta.UPLOADS_LAST_RESULT +
"==" + UploadResult.DELAYED_FOR_CHARGING.getValue() +
" OR " + ProviderTableMeta.UPLOADS_LAST_RESULT +
"==" + UploadResult.DELAYED_IN_POWER_SAVE_MODE.getValue() +
" AND " + ProviderTableMeta.UPLOADS_ACCOUNT_NAME + "== ?",
user.getAccountName());
}
/**
@ -384,14 +380,10 @@ public class UploadsStorageManager extends Observable {
}
public OCUpload[] getFinishedUploadsForCurrentAccount() {
Account account = currentAccountProvider.getCurrentAccount();
User user = currentAccountProvider.getUser();
if (account != null) {
return getUploads(ProviderTableMeta.UPLOADS_STATUS + "==" + UploadStatus.UPLOAD_SUCCEEDED.value + AND +
ProviderTableMeta.UPLOADS_ACCOUNT_NAME + "== ?", account.name);
} else {
return new OCUpload[0];
}
return getUploads(ProviderTableMeta.UPLOADS_STATUS + "==" + UploadStatus.UPLOAD_SUCCEEDED.value + AND +
ProviderTableMeta.UPLOADS_ACCOUNT_NAME + "== ?", user.getAccountName());
}
/**
@ -403,23 +395,19 @@ public class UploadsStorageManager extends Observable {
}
public OCUpload[] getFailedButNotDelayedUploadsForCurrentAccount() {
Account account = currentAccountProvider.getCurrentAccount();
User user = currentAccountProvider.getUser();
if (account != null) {
return getUploads(ProviderTableMeta.UPLOADS_STATUS + "==" + UploadStatus.UPLOAD_FAILED.value +
AND + ProviderTableMeta.UPLOADS_LAST_RESULT +
"<>" + UploadResult.DELAYED_FOR_WIFI.getValue() +
AND + ProviderTableMeta.UPLOADS_LAST_RESULT +
"<>" + UploadResult.LOCK_FAILED.getValue() +
AND + ProviderTableMeta.UPLOADS_LAST_RESULT +
"<>" + UploadResult.DELAYED_FOR_CHARGING.getValue() +
AND + ProviderTableMeta.UPLOADS_LAST_RESULT +
"<>" + UploadResult.DELAYED_IN_POWER_SAVE_MODE.getValue() +
AND + ProviderTableMeta.UPLOADS_ACCOUNT_NAME + "== ?",
account.name);
} else {
return new OCUpload[0];
}
return getUploads(ProviderTableMeta.UPLOADS_STATUS + "==" + UploadStatus.UPLOAD_FAILED.value +
AND + ProviderTableMeta.UPLOADS_LAST_RESULT +
"<>" + UploadResult.DELAYED_FOR_WIFI.getValue() +
AND + ProviderTableMeta.UPLOADS_LAST_RESULT +
"<>" + UploadResult.LOCK_FAILED.getValue() +
AND + ProviderTableMeta.UPLOADS_LAST_RESULT +
"<>" + UploadResult.DELAYED_FOR_CHARGING.getValue() +
AND + ProviderTableMeta.UPLOADS_LAST_RESULT +
"<>" + UploadResult.DELAYED_IN_POWER_SAVE_MODE.getValue() +
AND + ProviderTableMeta.UPLOADS_ACCOUNT_NAME + "== ?",
user.getAccountName());
}
/**
@ -446,50 +434,41 @@ public class UploadsStorageManager extends Observable {
}
public long clearFailedButNotDelayedUploads() {
Account account = currentAccountProvider.getCurrentAccount();
long result = 0;
if (account != null) {
result = getDB().delete(
ProviderTableMeta.CONTENT_URI_UPLOADS,
ProviderTableMeta.UPLOADS_STATUS + "==" + UploadStatus.UPLOAD_FAILED.value +
AND + ProviderTableMeta.UPLOADS_LAST_RESULT +
"<>" + UploadResult.LOCK_FAILED.getValue() +
AND + ProviderTableMeta.UPLOADS_LAST_RESULT +
"<>" + UploadResult.DELAYED_FOR_WIFI.getValue() +
AND + ProviderTableMeta.UPLOADS_LAST_RESULT +
"<>" + UploadResult.DELAYED_FOR_CHARGING.getValue() +
AND + ProviderTableMeta.UPLOADS_LAST_RESULT +
"<>" + UploadResult.DELAYED_IN_POWER_SAVE_MODE.getValue() +
AND + ProviderTableMeta.UPLOADS_ACCOUNT_NAME + "== ?",
new String[]{account.name}
);
}
User user = currentAccountProvider.getUser();
final long deleted = getDB().delete(
ProviderTableMeta.CONTENT_URI_UPLOADS,
ProviderTableMeta.UPLOADS_STATUS + "==" + UploadStatus.UPLOAD_FAILED.value +
AND + ProviderTableMeta.UPLOADS_LAST_RESULT +
"<>" + UploadResult.LOCK_FAILED.getValue() +
AND + ProviderTableMeta.UPLOADS_LAST_RESULT +
"<>" + UploadResult.DELAYED_FOR_WIFI.getValue() +
AND + ProviderTableMeta.UPLOADS_LAST_RESULT +
"<>" + UploadResult.DELAYED_FOR_CHARGING.getValue() +
AND + ProviderTableMeta.UPLOADS_LAST_RESULT +
"<>" + UploadResult.DELAYED_IN_POWER_SAVE_MODE.getValue() +
AND + ProviderTableMeta.UPLOADS_ACCOUNT_NAME + "== ?",
new String[]{user.getAccountName()}
);
Log_OC.d(TAG, "delete all failed uploads but those delayed for Wifi");
if (result > 0) {
if (deleted > 0) {
notifyObserversNow();
}
return result;
return deleted;
}
public long clearSuccessfulUploads() {
Account account = currentAccountProvider.getCurrentAccount();
long result = 0;
if (account != null) {
result = getDB().delete(
ProviderTableMeta.CONTENT_URI_UPLOADS,
ProviderTableMeta.UPLOADS_STATUS + "==" + UploadStatus.UPLOAD_SUCCEEDED.value + AND +
ProviderTableMeta.UPLOADS_ACCOUNT_NAME + "== ?", new String[]{account.name}
);
}
User user = currentAccountProvider.getUser();
final long deleted = getDB().delete(
ProviderTableMeta.CONTENT_URI_UPLOADS,
ProviderTableMeta.UPLOADS_STATUS + "==" + UploadStatus.UPLOAD_SUCCEEDED.value + AND +
ProviderTableMeta.UPLOADS_ACCOUNT_NAME + "== ?", new String[]{user.getAccountName()}
);
Log_OC.d(TAG, "delete all successful uploads");
if (result > 0) {
if (deleted > 0) {
notifyObserversNow();
}
return result;
return deleted;
}
/**

View file

@ -47,6 +47,7 @@ import android.widget.TextView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.target.BitmapImageViewTarget;
import com.nextcloud.client.account.User;
import com.nextcloud.client.account.UserAccountManager;
import com.nextcloud.client.preferences.AppPreferences;
import com.owncloud.android.R;
@ -117,7 +118,7 @@ public class OCFileListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
private Set<OCFile> checkedFiles;
private FileDataStorageManager mStorageManager;
private Account account;
private User user;
private OCFileListFragmentInterface ocFileListFragmentInterface;
private FilesFilter mFilesFilter;
@ -135,7 +136,7 @@ public class OCFileListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
public OCFileListAdapter(
Context context,
Account account,
User user,
AppPreferences preferences,
UserAccountManager accountManager,
ComponentsGetter transferServiceGetter,
@ -147,16 +148,16 @@ public class OCFileListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
mContext = context;
this.preferences = preferences;
this.accountManager = accountManager;
this.account = account;
this.user = user;
mHideItemOptions = argHideItemOptions;
this.gridView = gridView;
checkedFiles = new HashSet<>();
this.transferServiceGetter = transferServiceGetter;
if (account != null) {
if (this.user != null) {
AccountManager platformAccountManager = AccountManager.get(mContext);
userId = platformAccountManager.getUserData(account,
userId = platformAccountManager.getUserData(this.user.toPlatformAccount(),
com.owncloud.android.lib.common.accounts.AccountUtils.Constants.KEY_USER_ID);
} else {
userId = "";
@ -399,7 +400,7 @@ public class OCFileListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
showFederatedShareAvatar(sharee.getUserId(), avatarRadius, resources, avatar);
} else {
avatar.setTag(sharee);
DisplayUtils.setAvatar(account,
DisplayUtils.setAvatar(user.toPlatformAccount(),
sharee.getUserId(),
sharee.getDisplayName(),
this,
@ -460,17 +461,17 @@ public class OCFileListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
OperationsService.OperationsServiceBinder operationsServiceBinder = transferServiceGetter.getOperationsServiceBinder();
FileDownloader.FileDownloaderBinder fileDownloaderBinder = transferServiceGetter.getFileDownloaderBinder();
FileUploader.FileUploaderBinder fileUploaderBinder = transferServiceGetter.getFileUploaderBinder();
if (operationsServiceBinder != null && operationsServiceBinder.isSynchronizing(account, file)) {
if (operationsServiceBinder != null && operationsServiceBinder.isSynchronizing(user.toPlatformAccount(), file)) {
//synchronizing
gridViewHolder.localFileIndicator.setImageResource(R.drawable.ic_synchronizing);
gridViewHolder.localFileIndicator.setVisibility(View.VISIBLE);
} else if (fileDownloaderBinder != null && fileDownloaderBinder.isDownloading(account, file)) {
} else if (fileDownloaderBinder != null && fileDownloaderBinder.isDownloading(user.toPlatformAccount(), file)) {
// downloading
gridViewHolder.localFileIndicator.setImageResource(R.drawable.ic_synchronizing);
gridViewHolder.localFileIndicator.setVisibility(View.VISIBLE);
} else if (fileUploaderBinder != null && fileUploaderBinder.isUploading(account, file)) {
} else if (fileUploaderBinder != null && fileUploaderBinder.isUploading(user.toPlatformAccount(), file)) {
//uploading
gridViewHolder.localFileIndicator.setImageResource(R.drawable.ic_synchronizing);
gridViewHolder.localFileIndicator.setVisibility(View.VISIBLE);
@ -575,13 +576,17 @@ public class OCFileListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
if (ThumbnailsCacheManager.cancelPotentialThumbnailWork(file, thumbnailView)) {
try {
final ThumbnailsCacheManager.ThumbnailGenerationTask task =
new ThumbnailsCacheManager.ThumbnailGenerationTask(thumbnailView, mStorageManager,
account, asyncTasks);
new ThumbnailsCacheManager.ThumbnailGenerationTask(thumbnailView,
mStorageManager,
user.toPlatformAccount(),
asyncTasks);
if (thumbnail == null) {
thumbnail = BitmapUtils.drawableToBitmap(
MimeTypeUtil.getFileTypeIcon(file.getMimeType(), file.getFileName(),
account, mContext));
MimeTypeUtil.getFileTypeIcon(file.getMimeType(),
file.getFileName(),
user.toPlatformAccount(),
mContext));
}
final ThumbnailsCacheManager.AsyncThumbnailDrawable asyncDrawable =
new ThumbnailsCacheManager.AsyncThumbnailDrawable(mContext.getResources(),
@ -602,7 +607,7 @@ public class OCFileListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
} else {
thumbnailView.setImageDrawable(MimeTypeUtil.getFileTypeIcon(file.getMimeType(),
file.getFileName(),
account,
user.toPlatformAccount(),
mContext));
}
}
@ -685,7 +690,7 @@ public class OCFileListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
sharedIconView.setImageResource(R.drawable.ic_unshared);
sharedIconView.setContentDescription(mContext.getString(R.string.shared_icon_share));
}
if (accountManager.accountOwnsFile(file, account)) {
if (accountManager.accountOwnsFile(file, user.toPlatformAccount())) {
sharedIconView.setOnClickListener(view -> ocFileListFragmentInterface.onShareIconClick(file));
} else {
sharedIconView.setOnClickListener(view -> ocFileListFragmentInterface.showShareDetailView(file));
@ -703,7 +708,7 @@ public class OCFileListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
* @param limitToMimeType show only files of this mimeType
*/
public void swapDirectory(
Account account,
User account,
OCFile directory,
FileDataStorageManager updatedStorageManager,
boolean onlyOnDevice, String limitToMimeType
@ -712,8 +717,8 @@ public class OCFileListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
if (updatedStorageManager != null && !updatedStorageManager.equals(mStorageManager)) {
mStorageManager = updatedStorageManager;
showShareAvatar = mStorageManager.getCapability(account.name).getVersion().isShareesOnDavSupported();
this.account = account;
showShareAvatar = mStorageManager.getCapability(account.getAccountName()).getVersion().isShareesOnDavSupported();
this.user = account;
}
if (mStorageManager != null) {
mFiles = mStorageManager.getFolderContent(directory, onlyOnDevice);
@ -744,11 +749,11 @@ public class OCFileListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
FileDataStorageManager storageManager, OCFile folder, boolean clear) {
if (storageManager != null && mStorageManager == null) {
mStorageManager = storageManager;
showShareAvatar = mStorageManager.getCapability(account.name).getVersion().isShareesOnDavSupported();
showShareAvatar = mStorageManager.getCapability(user.getAccountName()).getVersion().isShareesOnDavSupported();
}
if (mStorageManager == null) {
mStorageManager = new FileDataStorageManager(account, mContext.getContentResolver());
mStorageManager = new FileDataStorageManager(user.toPlatformAccount(), mContext.getContentResolver());
}
if (clear) {
@ -808,12 +813,12 @@ public class OCFileListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
shares.add(ocShare);
// get ocFile from Server to have an up-to-date copy
RemoteOperationResult result = new ReadFileRemoteOperation(ocShare.getPath()).execute(account,
RemoteOperationResult result = new ReadFileRemoteOperation(ocShare.getPath()).execute(user.toPlatformAccount(),
mContext);
if (result.isSuccess()) {
OCFile file = FileStorageUtils.fillOCFile((RemoteFile) result.getData().get(0));
FileStorageUtils.searchForLocalFileInDefaultPath(file, account);
FileStorageUtils.searchForLocalFileInDefaultPath(file, user.toPlatformAccount());
file = mStorageManager.saveFileWithParent(file, mContext);
ShareType newShareType = ocShare.getShareType();
@ -868,7 +873,7 @@ public class OCFileListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
for (Object remoteFile : objects) {
OCFile ocFile = FileStorageUtils.fillOCFile((RemoteFile) remoteFile);
FileStorageUtils.searchForLocalFileInDefaultPath(ocFile, account);
FileStorageUtils.searchForLocalFileInDefaultPath(ocFile, user.toPlatformAccount());
try {
if (ExtendedListFragment.SearchType.PHOTO_SEARCH == searchType) {
@ -885,9 +890,9 @@ public class OCFileListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
true,
false,
mStorageManager,
account,
user.toPlatformAccount(),
mContext);
refreshFolderOperation.execute(account, mContext);
refreshFolderOperation.execute(user.toPlatformAccount(), mContext);
}
}

View file

@ -332,7 +332,7 @@ public class OCFileListFragment extends ExtendedListFragment implements
mAdapter = new OCFileListAdapter(
getActivity(),
accountManager.getCurrentAccount(),
accountManager.getUser(),
preferences,
accountManager,
mContainerActivity,
@ -1180,7 +1180,7 @@ public class OCFileListFragment extends ExtendedListFragment implements
}
mAdapter.swapDirectory(
accountManager.getCurrentAccount(),
accountManager.getUser(),
directory,
storageManager,
onlyOnDevice,

View file

@ -19,16 +19,17 @@
*/
package com.nextcloud.client.network
import android.accounts.Account
import android.net.ConnectivityManager
import android.net.NetworkInfo
import android.net.Uri
import com.nextcloud.client.account.Server
import com.nextcloud.client.account.User
import com.nextcloud.client.account.UserAccountManager
import com.nextcloud.client.logger.Logger
import com.nhaarman.mockitokotlin2.any
import com.nhaarman.mockitokotlin2.mock
import com.nhaarman.mockitokotlin2.never
import com.nhaarman.mockitokotlin2.verify
import com.nhaarman.mockitokotlin2.whenever
import com.owncloud.android.lib.common.OwnCloudAccount
import com.owncloud.android.lib.resources.status.OwnCloudVersion
import org.apache.commons.httpclient.HttpClient
import org.apache.commons.httpclient.HttpStatus
@ -42,6 +43,7 @@ import org.junit.runners.Suite
import org.mockito.ArgumentCaptor
import org.mockito.Mock
import org.mockito.MockitoAnnotations
import java.net.URI
@RunWith(Suite::class)
@Suite.SuiteClasses(
@ -86,13 +88,14 @@ class ConnectivityServiceTest {
lateinit var requestBuilder: ConnectivityServiceImpl.GetRequestBuilder
@Mock
lateinit var platformAccount: Account
lateinit var logger: Logger
val baseServerUri = URI.create(SERVER_BASE_URL)
val newServer = Server(baseServerUri, OwnCloudVersion.nextcloud_14)
val legacyServer = Server(baseServerUri, OwnCloudVersion.nextcloud_13)
@Mock
lateinit var ownCloudAccount: OwnCloudAccount
@Mock
lateinit var baseServerUri: Uri
lateinit var user: User
lateinit var connectivityService: ConnectivityServiceImpl
@ -103,15 +106,15 @@ class ConnectivityServiceTest {
platformConnectivityManager,
accountManager,
clientFactory,
requestBuilder
requestBuilder,
logger
)
whenever(platformConnectivityManager.activeNetworkInfo).thenReturn(networkInfo)
whenever(requestBuilder.invoke(any())).thenReturn(getRequest)
whenever(clientFactory.createPlainClient()).thenReturn(client)
whenever(accountManager.currentOwnCloudAccount).thenReturn(ownCloudAccount)
whenever(accountManager.currentAccount).thenReturn(platformAccount)
whenever(baseServerUri.toString()).thenReturn(SERVER_BASE_URL)
whenever(ownCloudAccount.baseUri).thenReturn(baseServerUri)
whenever(user.server).thenReturn(newServer)
whenever(accountManager.user).thenReturn(user)
}
}
@ -158,7 +161,7 @@ class ConnectivityServiceTest {
fun setUp() {
whenever(networkInfo.isConnectedOrConnecting).thenReturn(true)
whenever(networkInfo.type).thenReturn(ConnectivityManager.TYPE_WIFI)
whenever(accountManager.getServerVersion(any())).thenReturn(OwnCloudVersion.nextcloud_13)
whenever(user.server).thenReturn(legacyServer)
assertTrue("Precondition failed", connectivityService.isOnlineWithWifi)
}
@ -207,6 +210,28 @@ class ConnectivityServiceTest {
assertTrue("Precondition failed", connectivityService.isOnlineWithWifi)
}
@Test
fun `check request is not sent when server uri is not set`() {
// GIVEN
// network connectivity is present
// user has no server URI (empty)
val serverWithoutUri = Server(URI(""), OwnCloudVersion.nextcloud_14)
whenever(user.server).thenReturn(serverWithoutUri)
// WHEN
// connectivity is checked
val result = connectivityService.isInternetWalled
// THEN
// connection is walled
// request is not sent
assertTrue("Server should not be accessible", result)
verify(requestBuilder, never()).invoke(any())
verify(client, never()).executeMethod(any())
verify(client, never()).executeMethod(any(), any())
verify(client, never()).executeMethod(any(), any(), any())
}
fun mockResponse(contentLength: Long = 0, status: Int = HttpStatus.SC_OK) {
whenever(client.executeMethod(any())).thenReturn(status)
whenever(getRequest.statusCode).thenReturn(status)