ErrorMessageAdapter.java 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504
  1. /**
  2. * ownCloud Android client application
  3. *
  4. * @author masensio
  5. * Copyright (C) 2016 ownCloud GmbH.
  6. *
  7. * This program is free software: you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License version 2,
  9. * as published by the Free Software Foundation.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. *
  19. */
  20. package com.owncloud.android.utils;
  21. import android.content.res.Resources;
  22. import android.support.annotation.NonNull;
  23. import android.support.annotation.Nullable;
  24. import com.owncloud.android.R;
  25. import com.owncloud.android.lib.common.operations.RemoteOperation;
  26. import com.owncloud.android.lib.common.operations.RemoteOperationResult;
  27. import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
  28. import com.owncloud.android.operations.CopyFileOperation;
  29. import com.owncloud.android.operations.CreateFolderOperation;
  30. import com.owncloud.android.operations.CreateShareViaLinkOperation;
  31. import com.owncloud.android.operations.CreateShareWithShareeOperation;
  32. import com.owncloud.android.operations.DownloadFileOperation;
  33. import com.owncloud.android.operations.MoveFileOperation;
  34. import com.owncloud.android.operations.RemoveFileOperation;
  35. import com.owncloud.android.operations.RenameFileOperation;
  36. import com.owncloud.android.operations.SynchronizeFileOperation;
  37. import com.owncloud.android.operations.SynchronizeFolderOperation;
  38. import com.owncloud.android.operations.UnshareOperation;
  39. import com.owncloud.android.operations.UpdateSharePermissionsOperation;
  40. import com.owncloud.android.operations.UpdateShareViaLinkOperation;
  41. import com.owncloud.android.operations.UploadFileOperation;
  42. import org.apache.commons.httpclient.ConnectTimeoutException;
  43. import java.io.File;
  44. import java.net.SocketTimeoutException;
  45. /**
  46. * Class to choose proper error messages to show to the user depending on the results of operations,
  47. * always following the same policy
  48. */
  49. public final class ErrorMessageAdapter {
  50. private ErrorMessageAdapter() {
  51. // utility class -> private constructor
  52. }
  53. /**
  54. * Return an internationalized user message corresponding to an operation result
  55. * and the operation performed.
  56. *
  57. * @param result Result of a {@link RemoteOperation} performed.
  58. * @param operation Operation performed.
  59. * @param res Reference to app resources, for i18n.
  60. * @return User message corresponding to 'result' and 'operation'.
  61. */
  62. @NonNull
  63. public static String getErrorCauseMessage(
  64. RemoteOperationResult result,
  65. RemoteOperation operation,
  66. Resources res
  67. ) {
  68. String message = getSpecificMessageForResultAndOperation(result, operation, res);
  69. if (message == null || message.length() <= 0) {
  70. message = getCommonMessageForResult(result, res);
  71. }
  72. if (message == null || message.length() <= 0) {
  73. message = getGenericErrorMessageForOperation(operation, res);
  74. }
  75. if (message == null) {
  76. if (result.isSuccess()) {
  77. message = res.getString(R.string.common_ok);
  78. } else {
  79. message = res.getString(R.string.common_error_unknown);
  80. }
  81. }
  82. return message;
  83. }
  84. /**
  85. * Return a user message corresponding to an operation result and specific for the operation
  86. * performed.
  87. *
  88. * @param result Result of a {@link RemoteOperation} performed.
  89. * @param operation Operation performed.
  90. * @param res Reference to app resources, for i18n.
  91. * @return User message corresponding to 'result' and 'operation', or NULL if there is no
  92. * specific message for both.
  93. */
  94. @Nullable
  95. private static String getSpecificMessageForResultAndOperation(
  96. RemoteOperationResult result,
  97. RemoteOperation operation,
  98. Resources res
  99. ) {
  100. String message = null;
  101. if (operation instanceof UploadFileOperation) {
  102. message = getMessageForUploadFileOperation(result, (UploadFileOperation) operation, res);
  103. } else if (operation instanceof DownloadFileOperation) {
  104. message = getMessageForDownloadFileOperation(result, (DownloadFileOperation) operation, res);
  105. } else if (operation instanceof RemoveFileOperation) {
  106. message = getMessageForRemoveFileOperation(result, res);
  107. } else if (operation instanceof RenameFileOperation) {
  108. message = getMessageForRenameFileOperation(result, res);
  109. } else if (operation instanceof SynchronizeFileOperation) {
  110. if (!((SynchronizeFileOperation) operation).transferWasRequested()) {
  111. message = res.getString(R.string.sync_file_nothing_to_do_msg);
  112. }
  113. } else if (operation instanceof CreateFolderOperation) {
  114. message = getMessageForCreateFolderOperation(result, res);
  115. } else if (operation instanceof CreateShareViaLinkOperation ||
  116. operation instanceof CreateShareWithShareeOperation) {
  117. message = getMessageForCreateShareOperations(result, res);
  118. } else if (operation instanceof UnshareOperation) {
  119. message = getMessageForUnshareOperation(result, res);
  120. } else if (operation instanceof UpdateShareViaLinkOperation ||
  121. operation instanceof UpdateSharePermissionsOperation) {
  122. message = getMessageForUpdateShareOperations(result, res);
  123. } else if (operation instanceof MoveFileOperation) {
  124. message = getMessageForMoveFileOperation(result, res);
  125. } else if (operation instanceof SynchronizeFolderOperation) {
  126. message = getMessageForSynchronizeFolderOperation(result, (SynchronizeFolderOperation) operation, res);
  127. } else if (operation instanceof CopyFileOperation) {
  128. message = getMessageForCopyFileOperation(result, res);
  129. }
  130. return message;
  131. }
  132. private static String getMessageForSynchronizeFolderOperation(
  133. RemoteOperationResult result,
  134. SynchronizeFolderOperation operation,
  135. Resources res
  136. ) {
  137. if (!result.isSuccess() && result.getCode() == ResultCode.FILE_NOT_FOUND) {
  138. return String.format(
  139. res.getString(R.string.sync_current_folder_was_removed),
  140. new File(operation.getFolderPath()).getName()
  141. );
  142. }
  143. return
  144. null;
  145. }
  146. private static String getMessageForMoveFileOperation(RemoteOperationResult result, Resources res) {
  147. if (result.getCode() == ResultCode.FILE_NOT_FOUND) {
  148. return res.getString(R.string.move_file_not_found);
  149. } else if (result.getCode() == ResultCode.INVALID_MOVE_INTO_DESCENDANT) {
  150. return res.getString(R.string.move_file_invalid_into_descendent);
  151. } else if (result.getCode() == ResultCode.INVALID_OVERWRITE) {
  152. return res.getString(R.string.move_file_invalid_overwrite);
  153. } else if (result.getCode() == ResultCode.FORBIDDEN) {
  154. return String.format(res.getString(R.string.forbidden_permissions),
  155. res.getString(R.string.forbidden_permissions_move));
  156. } else if (result.getCode() == ResultCode.INVALID_CHARACTER_DETECT_IN_SERVER) {
  157. return res.getString(R.string.filename_forbidden_charaters_from_server);
  158. }
  159. return null;
  160. }
  161. private static String getMessageForUpdateShareOperations(RemoteOperationResult result, Resources res) {
  162. if (result.getData() != null && result.getData().size() > 0) {
  163. return (String) result.getData().get(0); // share API sends its own error messages
  164. } else if (result.getCode() == ResultCode.SHARE_NOT_FOUND) {
  165. return res.getString(R.string.update_link_file_no_exist);
  166. } else if (result.getCode() == ResultCode.SHARE_FORBIDDEN) {
  167. // Error --> No permissions
  168. return String.format(res.getString(R.string.forbidden_permissions),
  169. res.getString(R.string.update_link_forbidden_permissions));
  170. }
  171. return null;
  172. }
  173. private static String getMessageForUnshareOperation(RemoteOperationResult result, Resources res) {
  174. if (result.getData() != null && result.getData().size() > 0) {
  175. return (String) result.getData().get(0); // share API sends its own error messages
  176. } else if (result.getCode() == ResultCode.SHARE_NOT_FOUND) {
  177. return res.getString(R.string.unshare_link_file_no_exist);
  178. } else if (result.getCode() == ResultCode.SHARE_FORBIDDEN) {
  179. // Error --> No permissions
  180. return String.format(res.getString(R.string.forbidden_permissions),
  181. res.getString(R.string.unshare_link_forbidden_permissions));
  182. }
  183. return null;
  184. }
  185. private static String getMessageForCopyFileOperation(RemoteOperationResult result, Resources res) {
  186. if (result.getCode() == ResultCode.FILE_NOT_FOUND) {
  187. return res.getString(R.string.copy_file_not_found);
  188. } else if (result.getCode() == ResultCode.INVALID_COPY_INTO_DESCENDANT) {
  189. return res.getString(R.string.copy_file_invalid_into_descendent);
  190. } else if (result.getCode() == ResultCode.INVALID_OVERWRITE) {
  191. return res.getString(R.string.copy_file_invalid_overwrite);
  192. } else if (result.getCode() == ResultCode.FORBIDDEN) {
  193. return String.format(res.getString(R.string.forbidden_permissions),
  194. res.getString(R.string.forbidden_permissions_copy));
  195. }
  196. return null;
  197. }
  198. private static String getMessageForCreateShareOperations(RemoteOperationResult result, Resources res) {
  199. if (result.getData() != null && result.getData().size() > 0) {
  200. return (String) result.getData().get(0); // share API sends its own error messages
  201. } else if (result.getCode() == ResultCode.SHARE_NOT_FOUND) {
  202. return res.getString(R.string.share_link_file_no_exist);
  203. } else if (result.getCode() == ResultCode.SHARE_FORBIDDEN) {
  204. // Error --> No permissions
  205. return String.format(res.getString(R.string.forbidden_permissions),
  206. res.getString(R.string.share_link_forbidden_permissions));
  207. }
  208. return null;
  209. }
  210. private static String getMessageForCreateFolderOperation(RemoteOperationResult result, Resources res) {
  211. if (result.getCode() == ResultCode.INVALID_CHARACTER_IN_NAME) {
  212. return res.getString(R.string.filename_forbidden_characters);
  213. } else if (result.getCode().equals(ResultCode.FORBIDDEN)) {
  214. return String.format(res.getString(R.string.forbidden_permissions),
  215. res.getString(R.string.forbidden_permissions_create));
  216. } else if (result.getCode() == ResultCode.INVALID_CHARACTER_DETECT_IN_SERVER) {
  217. return res.getString(R.string.filename_forbidden_charaters_from_server);
  218. }
  219. return null;
  220. }
  221. private static String getMessageForRenameFileOperation(RemoteOperationResult result, Resources res) {
  222. if (result.getCode().equals(ResultCode.INVALID_LOCAL_FILE_NAME)) {
  223. return res.getString(R.string.rename_local_fail_msg);
  224. } else if (result.getCode().equals(ResultCode.FORBIDDEN)) {
  225. // Error --> No permissions
  226. return String.format(res.getString(R.string.forbidden_permissions),
  227. res.getString(R.string.forbidden_permissions_rename));
  228. } else if (result.getCode().equals(ResultCode.INVALID_CHARACTER_IN_NAME)) {
  229. return res.getString(R.string.filename_forbidden_characters);
  230. } else if (result.getCode() == ResultCode.INVALID_CHARACTER_DETECT_IN_SERVER) {
  231. return res.getString(R.string.filename_forbidden_charaters_from_server);
  232. }
  233. return null;
  234. }
  235. private static String getMessageForRemoveFileOperation(RemoteOperationResult result, Resources res) {
  236. if (result.isSuccess()) {
  237. return res.getString(R.string.remove_success_msg);
  238. } else {
  239. if (result.getCode().equals(ResultCode.FORBIDDEN)) {
  240. // Error --> No permissions
  241. return String.format(res.getString(R.string.forbidden_permissions),
  242. res.getString(R.string.forbidden_permissions_delete));
  243. }
  244. }
  245. return null;
  246. }
  247. private static String getMessageForDownloadFileOperation(
  248. RemoteOperationResult result,
  249. DownloadFileOperation operation,
  250. Resources res
  251. ) {
  252. if (result.isSuccess()) {
  253. return String.format(
  254. res.getString(R.string.downloader_download_succeeded_content),
  255. new File(operation.getSavePath()).getName());
  256. } else {
  257. if (result.getCode() == ResultCode.FILE_NOT_FOUND) {
  258. return res.getString(R.string.downloader_download_file_not_found);
  259. }
  260. }
  261. return null;
  262. }
  263. private static String getMessageForUploadFileOperation(
  264. RemoteOperationResult result,
  265. UploadFileOperation operation,
  266. Resources res
  267. ) {
  268. if (result.isSuccess()) {
  269. return String.format(
  270. res.getString(R.string.uploader_upload_succeeded_content_single),
  271. operation.getFileName());
  272. } else {
  273. if (result.getCode() == ResultCode.LOCAL_STORAGE_FULL
  274. || result.getCode() == ResultCode.LOCAL_STORAGE_NOT_COPIED) {
  275. return String.format(
  276. res.getString(R.string.error__upload__local_file_not_copied),
  277. operation.getFileName(),
  278. res.getString(R.string.app_name));
  279. } else if (result.getCode() == ResultCode.FORBIDDEN) {
  280. return String.format(res.getString(R.string.forbidden_permissions),
  281. res.getString(R.string.uploader_upload_forbidden_permissions));
  282. } else if (result.getCode() == ResultCode.INVALID_CHARACTER_DETECT_IN_SERVER) {
  283. return res.getString(R.string.filename_forbidden_charaters_from_server);
  284. }
  285. }
  286. return null;
  287. }
  288. /**
  289. * Return a user message corresponding to an operation result with no knowledge about the operation
  290. * performed.
  291. *
  292. * @param result Result of a {@link RemoteOperation} performed.
  293. * @param res Reference to app resources, for i18n.
  294. * @return User message corresponding to 'result'.
  295. */
  296. @Nullable
  297. private static String getCommonMessageForResult(RemoteOperationResult result, Resources res) {
  298. String message = null;
  299. if (!result.isSuccess()) {
  300. if (result.getCode() == ResultCode.WRONG_CONNECTION) {
  301. message = res.getString(R.string.network_error_socket_exception);
  302. } else if (result.getCode() == ResultCode.TIMEOUT) {
  303. message = res.getString(R.string.network_error_socket_exception);
  304. if (result.getException() instanceof SocketTimeoutException) {
  305. message = res.getString(R.string.network_error_socket_timeout_exception);
  306. } else if (result.getException() instanceof ConnectTimeoutException) {
  307. message = res.getString(R.string.network_error_connect_timeout_exception);
  308. }
  309. } else if (result.getCode() == ResultCode.HOST_NOT_AVAILABLE) {
  310. message = res.getString(R.string.network_host_not_available);
  311. } else if (result.getCode() == ResultCode.MAINTENANCE_MODE) {
  312. message = res.getString(R.string.maintenance_mode);
  313. } else if (result.getCode() == ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED) {
  314. message = res.getString(R.string.uploads_view_upload_status_failed_ssl_certificate_not_trusted);
  315. } else if (result.getCode() == ResultCode.BAD_OC_VERSION) {
  316. message = res.getString(R.string.auth_bad_oc_version_title);
  317. } else if (result.getCode() == ResultCode.INCORRECT_ADDRESS) {
  318. message = res.getString(R.string.auth_incorrect_address_title);
  319. } else if (result.getCode() == ResultCode.SSL_ERROR) {
  320. message = res.getString(R.string.auth_ssl_general_error_title);
  321. } else if (result.getCode() == ResultCode.UNAUTHORIZED) {
  322. message = res.getString(R.string.auth_unauthorized);
  323. } else if (result.getCode() == ResultCode.INSTANCE_NOT_CONFIGURED) {
  324. message = res.getString(R.string.auth_not_configured_title);
  325. } else if (result.getCode() == ResultCode.FILE_NOT_FOUND) {
  326. message = res.getString(R.string.auth_incorrect_path_title);
  327. } else if (result.getCode() == ResultCode.OAUTH2_ERROR) {
  328. message = res.getString(R.string.auth_oauth_error);
  329. } else if (result.getCode() == ResultCode.OAUTH2_ERROR_ACCESS_DENIED) {
  330. message = res.getString(R.string.auth_oauth_error_access_denied);
  331. } else if (result.getCode() == ResultCode.ACCOUNT_NOT_NEW) {
  332. message = res.getString(R.string.auth_account_not_new);
  333. } else if (result.getCode() == ResultCode.ACCOUNT_NOT_THE_SAME) {
  334. message = res.getString(R.string.auth_account_not_the_same);
  335. }
  336. else if (result.getHttpPhrase() != null && result.getHttpPhrase().length() > 0) {
  337. // last chance: error message from server
  338. message = result.getHttpPhrase();
  339. }
  340. }
  341. return message;
  342. }
  343. /**
  344. * Return a user message corresponding to a generic error for a given operation.
  345. *
  346. * @param operation Operation performed.
  347. * @param res Reference to app resources, for i18n.
  348. * @return User message corresponding to a generic error of 'operation'.
  349. */
  350. @Nullable
  351. private static String getGenericErrorMessageForOperation(RemoteOperation operation, Resources res) {
  352. String message = null;
  353. if (operation instanceof UploadFileOperation) {
  354. message = String.format(
  355. res.getString(R.string.uploader_upload_failed_content_single),
  356. ((UploadFileOperation) operation).getFileName());
  357. } else if (operation instanceof DownloadFileOperation) {
  358. message = String.format(
  359. res.getString(R.string.downloader_download_failed_content),
  360. new File(((DownloadFileOperation) operation).getSavePath()).getName()
  361. );
  362. } else if (operation instanceof RemoveFileOperation) {
  363. message = res.getString(R.string.remove_fail_msg);
  364. } else if (operation instanceof RenameFileOperation) {
  365. message = res.getString(R.string.rename_server_fail_msg);
  366. } else if (operation instanceof CreateFolderOperation) {
  367. message = res.getString(R.string.create_dir_fail_msg);
  368. } else if (operation instanceof CreateShareViaLinkOperation ||
  369. operation instanceof CreateShareWithShareeOperation
  370. ) {
  371. message = res.getString(R.string.share_link_file_error);
  372. } else if (operation instanceof UnshareOperation) {
  373. message = res.getString(R.string.unshare_link_file_error);
  374. } else if (operation instanceof UpdateShareViaLinkOperation ||
  375. operation instanceof UpdateSharePermissionsOperation
  376. ) {
  377. message = res.getString(R.string.update_link_file_error);
  378. } else if (operation instanceof MoveFileOperation) {
  379. message = res.getString(R.string.move_file_error);
  380. } else if (operation instanceof SynchronizeFolderOperation) {
  381. String folderPathName = new File(
  382. ((SynchronizeFolderOperation) operation).getFolderPath()
  383. ).getName();
  384. message = String.format(res.getString(R.string.sync_folder_failed_content), folderPathName);
  385. } else if (operation instanceof CopyFileOperation) {
  386. message = res.getString(R.string.copy_file_error);
  387. }
  388. return message;
  389. }
  390. }