UserAccountManagerImpl.java 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. /*
  2. * Nextcloud Android client application
  3. *
  4. * @author Chris Narkiewicz
  5. * Copyright (C) 2019 Chris Narkiewicz
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
  9. * License as published by the Free Software Foundation; either
  10. * version 3 of the License, or any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
  16. *
  17. * You should have received a copy of the GNU Affero General Public
  18. * License along with this program. If not, see <http://www.gnu.org/licenses/>.
  19. */
  20. package com.nextcloud.client.account;
  21. import android.accounts.Account;
  22. import android.accounts.AccountManager;
  23. import android.app.Activity;
  24. import android.content.Context;
  25. import android.content.SharedPreferences;
  26. import android.preference.PreferenceManager;
  27. import android.text.TextUtils;
  28. import com.nextcloud.java.util.Optional;
  29. import com.owncloud.android.MainApp;
  30. import com.owncloud.android.R;
  31. import com.owncloud.android.datamodel.ArbitraryDataProvider;
  32. import com.owncloud.android.datamodel.OCFile;
  33. import com.owncloud.android.lib.common.OwnCloudAccount;
  34. import com.owncloud.android.lib.common.OwnCloudClient;
  35. import com.owncloud.android.lib.common.OwnCloudClientManagerFactory;
  36. import com.owncloud.android.lib.common.UserInfo;
  37. import com.owncloud.android.lib.common.accounts.AccountUtils;
  38. import com.owncloud.android.lib.common.operations.RemoteOperationResult;
  39. import com.owncloud.android.lib.common.utils.Log_OC;
  40. import com.owncloud.android.lib.resources.status.OwnCloudVersion;
  41. import com.owncloud.android.lib.resources.users.GetUserInfoRemoteOperation;
  42. import java.net.URI;
  43. import java.util.ArrayList;
  44. import java.util.List;
  45. import javax.inject.Inject;
  46. import androidx.annotation.NonNull;
  47. import androidx.annotation.Nullable;
  48. public class UserAccountManagerImpl implements UserAccountManager {
  49. private static final String TAG = UserAccountManagerImpl.class.getSimpleName();
  50. private static final String PREF_SELECT_OC_ACCOUNT = "select_oc_account";
  51. private Context context;
  52. private AccountManager accountManager;
  53. public static UserAccountManagerImpl fromContext(Context context) {
  54. AccountManager am = (AccountManager)context.getSystemService(Context.ACCOUNT_SERVICE);
  55. return new UserAccountManagerImpl(context, am);
  56. }
  57. @Inject
  58. public UserAccountManagerImpl(
  59. Context context,
  60. AccountManager accountManager
  61. ) {
  62. this.context = context;
  63. this.accountManager = accountManager;
  64. }
  65. @Override
  66. public void removeAllAccounts() {
  67. for (Account account : getAccounts()) {
  68. accountManager.removeAccount(account, null, null);
  69. }
  70. }
  71. @Override
  72. @NonNull
  73. public Account[] getAccounts() {
  74. return accountManager.getAccountsByType(getAccountType());
  75. }
  76. @Override
  77. @NonNull
  78. public List<User> getAllUsers() {
  79. Account[] accounts = getAccounts();
  80. List<User> users = new ArrayList<>(accounts.length);
  81. for (Account account : accounts) {
  82. User user = createUserFromAccount(account);
  83. if (user != null) {
  84. users.add(user);
  85. }
  86. }
  87. return users;
  88. }
  89. @Override
  90. public boolean exists(Account account) {
  91. Account[] nextcloudAccounts = getAccounts();
  92. if (account != null && account.name != null) {
  93. int lastAtPos = account.name.lastIndexOf('@');
  94. String hostAndPort = account.name.substring(lastAtPos + 1);
  95. String username = account.name.substring(0, lastAtPos);
  96. String otherHostAndPort;
  97. String otherUsername;
  98. for (Account otherAccount : nextcloudAccounts) {
  99. lastAtPos = otherAccount.name.lastIndexOf('@');
  100. otherHostAndPort = otherAccount.name.substring(lastAtPos + 1);
  101. otherUsername = otherAccount.name.substring(0, lastAtPos);
  102. if (otherHostAndPort.equals(hostAndPort) &&
  103. otherUsername.equalsIgnoreCase(username)) {
  104. return true;
  105. }
  106. }
  107. }
  108. return false;
  109. }
  110. @Override
  111. @Nullable
  112. public Account getCurrentAccount() {
  113. Account[] ocAccounts = getAccounts();
  114. Account defaultAccount = null;
  115. ArbitraryDataProvider arbitraryDataProvider = new ArbitraryDataProvider(context.getContentResolver());
  116. SharedPreferences appPreferences = PreferenceManager.getDefaultSharedPreferences(context);
  117. String accountName = appPreferences.getString(PREF_SELECT_OC_ACCOUNT, null);
  118. // account validation: the saved account MUST be in the list of ownCloud Accounts known by the AccountManager
  119. if (accountName != null) {
  120. for (Account account : ocAccounts) {
  121. if (account.name.equals(accountName)) {
  122. defaultAccount = account;
  123. break;
  124. }
  125. }
  126. }
  127. if (defaultAccount == null && ocAccounts.length > 0) {
  128. // take first which is not pending for removal account as fallback
  129. for (Account account: ocAccounts) {
  130. boolean pendingForRemoval = arbitraryDataProvider.getBooleanValue(account,
  131. PENDING_FOR_REMOVAL);
  132. if (!pendingForRemoval) {
  133. defaultAccount = account;
  134. break;
  135. }
  136. }
  137. }
  138. return defaultAccount;
  139. }
  140. /**
  141. * Temporary solution to convert platform account to user instance.
  142. * It takes null and returns null on error to ease error handling
  143. * in legacy code.
  144. *
  145. * @param account Account instance
  146. * @return User instance or null, if conversion failed
  147. */
  148. @Nullable
  149. private User createUserFromAccount(@Nullable Account account) {
  150. if (account == null) {
  151. return null;
  152. }
  153. OwnCloudAccount ownCloudAccount = null;
  154. try {
  155. ownCloudAccount = new OwnCloudAccount(account, context);
  156. } catch (AccountUtils.AccountNotFoundException ex) {
  157. return null;
  158. }
  159. /*
  160. * Server version
  161. */
  162. String serverVersionStr = accountManager.getUserData(account, AccountUtils.Constants.KEY_OC_VERSION);
  163. OwnCloudVersion serverVersion;
  164. if (serverVersionStr != null) {
  165. serverVersion = new OwnCloudVersion(serverVersionStr);
  166. } else {
  167. serverVersion = MainApp.MINIMUM_SUPPORTED_SERVER_VERSION;
  168. }
  169. /*
  170. * Server address
  171. */
  172. String serverAddressStr = accountManager.getUserData(account, AccountUtils.Constants.KEY_OC_BASE_URL);
  173. if (serverAddressStr == null || serverAddressStr.isEmpty()) {
  174. return AnonymousUser.fromContext(context);
  175. }
  176. URI serverUri = URI.create(serverAddressStr); // TODO: validate
  177. return new RegisteredUser(
  178. account,
  179. ownCloudAccount,
  180. new Server(serverUri, serverVersion)
  181. );
  182. }
  183. /**
  184. * Get user. If user cannot be retrieved due to data error, anonymous user is returned instead.
  185. *
  186. *
  187. * @return User instance
  188. */
  189. @NonNull
  190. @Override
  191. public User getUser() {
  192. Account account = getCurrentAccount();
  193. User user = createUserFromAccount(account);
  194. return user != null ? user : AnonymousUser.fromContext(context);
  195. }
  196. @Override
  197. @NonNull
  198. public Optional<User> getUser(CharSequence accountName) {
  199. Account account = getAccountByName(accountName.toString());
  200. User user = createUserFromAccount(account);
  201. return Optional.ofNullable(user);
  202. }
  203. @Override
  204. @Nullable
  205. public OwnCloudAccount getCurrentOwnCloudAccount() {
  206. try {
  207. Account currentPlatformAccount = getCurrentAccount();
  208. return new OwnCloudAccount(currentPlatformAccount, context);
  209. } catch (com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException |
  210. IllegalArgumentException ex) {
  211. return null;
  212. }
  213. }
  214. @Override
  215. @Nullable
  216. public Account getAccountByName(String name) {
  217. for (Account account : getAccounts()) {
  218. if (account.name.equals(name)) {
  219. return account;
  220. }
  221. }
  222. return null;
  223. }
  224. @Override
  225. public boolean setCurrentOwnCloudAccount(String accountName) {
  226. boolean result = false;
  227. if (accountName != null) {
  228. for (final Account account : getAccounts()) {
  229. if (accountName.equals(account.name)) {
  230. SharedPreferences.Editor appPrefs = PreferenceManager.getDefaultSharedPreferences(context).edit();
  231. appPrefs.putString(PREF_SELECT_OC_ACCOUNT, accountName);
  232. appPrefs.apply();
  233. result = true;
  234. break;
  235. }
  236. }
  237. }
  238. return result;
  239. }
  240. @Override
  241. public boolean setCurrentOwnCloudAccount(int hashCode) {
  242. boolean result = false;
  243. if (hashCode != 0) {
  244. for (final Account account : getAccounts()) {
  245. if (hashCode == account.hashCode()) {
  246. SharedPreferences.Editor appPrefs = PreferenceManager.getDefaultSharedPreferences(context).edit();
  247. appPrefs.putString(PREF_SELECT_OC_ACCOUNT, account.name);
  248. appPrefs.apply();
  249. result = true;
  250. break;
  251. }
  252. }
  253. }
  254. return result;
  255. }
  256. @Deprecated
  257. @Override
  258. @NonNull
  259. public OwnCloudVersion getServerVersion(Account account) {
  260. OwnCloudVersion serverVersion = MainApp.MINIMUM_SUPPORTED_SERVER_VERSION;
  261. if (account != null) {
  262. AccountManager accountMgr = AccountManager.get(MainApp.getAppContext());
  263. String serverVersionStr = accountMgr.getUserData(account, com.owncloud.android.lib.common.accounts.AccountUtils.Constants.KEY_OC_VERSION);
  264. if (serverVersionStr != null) {
  265. serverVersion = new OwnCloudVersion(serverVersionStr);
  266. }
  267. }
  268. return serverVersion;
  269. }
  270. @Override
  271. public boolean isMediaStreamingSupported(Account account) {
  272. return account != null && getServerVersion(account).isMediaStreamingSupported();
  273. }
  274. @Override
  275. public void resetOwnCloudAccount() {
  276. SharedPreferences.Editor appPrefs = PreferenceManager.getDefaultSharedPreferences(context).edit();
  277. appPrefs.putString(PREF_SELECT_OC_ACCOUNT, null);
  278. appPrefs.apply();
  279. }
  280. @Override
  281. public boolean accountOwnsFile(OCFile file, Account account) {
  282. final String ownerId = file.getOwnerId();
  283. return TextUtils.isEmpty(ownerId) || account.name.split("@")[0].equals(ownerId);
  284. }
  285. public boolean migrateUserId() {
  286. boolean success = false;
  287. Account[] ocAccounts = accountManager.getAccountsByType(MainApp.getAccountType(context));
  288. String userId;
  289. String displayName;
  290. GetUserInfoRemoteOperation remoteUserNameOperation = new GetUserInfoRemoteOperation();
  291. for (Account account : ocAccounts) {
  292. String storedUserId = accountManager.getUserData(account, com.owncloud.android.lib.common.accounts.AccountUtils.Constants.KEY_USER_ID);
  293. if (!TextUtils.isEmpty(storedUserId)) {
  294. continue;
  295. }
  296. // add userId
  297. try {
  298. OwnCloudAccount ocAccount = new OwnCloudAccount(account, context);
  299. OwnCloudClient client = OwnCloudClientManagerFactory.getDefaultSingleton()
  300. .getClientFor(ocAccount, context);
  301. RemoteOperationResult result = remoteUserNameOperation.execute(client);
  302. if (result.isSuccess()) {
  303. UserInfo userInfo = (UserInfo) result.getData().get(0);
  304. userId = userInfo.id;
  305. displayName = userInfo.displayName;
  306. } else {
  307. // skip account, try it next time
  308. Log_OC.e(TAG, "Error while getting username for account: " + account.name);
  309. continue;
  310. }
  311. } catch (Exception e) {
  312. Log_OC.e(TAG, "Error while getting username: " + e.getMessage());
  313. continue;
  314. }
  315. accountManager.setUserData(account,
  316. com.owncloud.android.lib.common.accounts.AccountUtils.Constants.KEY_DISPLAY_NAME,
  317. displayName);
  318. accountManager.setUserData(account,
  319. com.owncloud.android.lib.common.accounts.AccountUtils.Constants.KEY_USER_ID,
  320. userId);
  321. success = true;
  322. }
  323. return success;
  324. }
  325. private String getAccountType() {
  326. return context.getString(R.string.account_type);
  327. }
  328. @Override
  329. public void startAccountCreation(final Activity activity) {
  330. accountManager.addAccount(getAccountType(),
  331. null,
  332. null,
  333. null,
  334. activity,
  335. null,
  336. null);
  337. }
  338. }