ShareActivity.java 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  1. /**
  2. * ownCloud Android client application
  3. *
  4. * @author masensio
  5. * @author David A. Velasco
  6. * @author Juan Carlos González Cabrero
  7. * Copyright (C) 2015 ownCloud Inc.
  8. * <p/>
  9. * This program is free software: you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License version 2,
  11. * as published by the Free Software Foundation.
  12. * <p/>
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. * <p/>
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  20. */
  21. package com.owncloud.android.ui.activity;
  22. import android.app.SearchManager;
  23. import android.content.Intent;
  24. import android.net.Uri;
  25. import android.os.Bundle;
  26. import android.support.v4.app.DialogFragment;
  27. import android.support.v4.app.Fragment;
  28. import android.support.v4.app.FragmentTransaction;
  29. import android.widget.Toast;
  30. import com.owncloud.android.R;
  31. import com.owncloud.android.datamodel.OCFile;
  32. import com.owncloud.android.lib.common.accounts.AccountUtils;
  33. import com.owncloud.android.lib.common.operations.RemoteOperation;
  34. import com.owncloud.android.lib.common.operations.RemoteOperationResult;
  35. import com.owncloud.android.lib.common.utils.Log_OC;
  36. import com.owncloud.android.lib.resources.shares.OCShare;
  37. import com.owncloud.android.lib.resources.shares.ShareType;
  38. import com.owncloud.android.lib.resources.status.OwnCloudVersion;
  39. import com.owncloud.android.operations.CreateShareViaLinkOperation;
  40. import com.owncloud.android.operations.GetSharesForFileOperation;
  41. import com.owncloud.android.operations.UnshareOperation;
  42. import com.owncloud.android.operations.UpdateSharePermissionsOperation;
  43. import com.owncloud.android.ui.dialog.ShareLinkToDialog;
  44. import com.owncloud.android.ui.fragment.EditShareFragment;
  45. import com.owncloud.android.ui.fragment.SearchShareesFragment;
  46. import com.owncloud.android.ui.fragment.ShareFileFragment;
  47. import com.owncloud.android.ui.fragment.ShareFragmentListener;
  48. import com.owncloud.android.utils.ErrorMessageAdapter;
  49. import com.owncloud.android.utils.GetShareWithUsersAsyncTask;
  50. import org.nextcloud.providers.UsersAndGroupsSearchProvider;
  51. import java.util.ArrayList;
  52. /**
  53. * Activity for sharing files
  54. */
  55. public class ShareActivity extends FileActivity
  56. implements ShareFragmentListener {
  57. private static final String TAG = ShareActivity.class.getSimpleName();
  58. private static final String TAG_SHARE_FRAGMENT = "SHARE_FRAGMENT";
  59. private static final String TAG_SEARCH_FRAGMENT = "SEARCH_USER_AND_GROUPS_FRAGMENT";
  60. private static final String TAG_EDIT_SHARE_FRAGMENT = "EDIT_SHARE_FRAGMENT";
  61. private static final String TAG_PUBLIC_LINK = "PUBLIC_LINK";
  62. /// Tags for dialog fragments
  63. private static final String FTAG_CHOOSER_DIALOG = "CHOOSER_DIALOG";
  64. private static final String FTAG_SHARE_PASSWORD_DIALOG = "SHARE_PASSWORD_DIALOG";
  65. @Override
  66. protected void onCreate(Bundle savedInstanceState) {
  67. super.onCreate(savedInstanceState);
  68. setContentView(R.layout.share_activity);
  69. FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
  70. if (savedInstanceState == null) {
  71. // Add Share fragment on first creation
  72. Fragment fragment = ShareFileFragment.newInstance(getFile(), getAccount());
  73. ft.replace(R.id.share_fragment_container, fragment, TAG_SHARE_FRAGMENT);
  74. ft.commit();
  75. }
  76. }
  77. protected void onAccountSet(boolean stateWasRecovered) {
  78. super.onAccountSet(stateWasRecovered);
  79. // Load data into the list
  80. Log_OC.d(TAG, "Refreshing lists on account set");
  81. refreshSharesFromStorageManager();
  82. // Request for a refresh of the data through the server (starts an Async Task)
  83. refreshUsersOrGroupsListFromServer();
  84. }
  85. @Override
  86. protected void onNewIntent(Intent intent) {
  87. // Verify the action and get the query
  88. if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
  89. String query = intent.getStringExtra(SearchManager.QUERY);
  90. Log_OC.w(TAG, "Ignored Intent requesting to query for " + query);
  91. } else if (UsersAndGroupsSearchProvider.ACTION_SHARE_WITH.equals(intent.getAction())) {
  92. Uri data = intent.getData();
  93. String dataString = intent.getDataString();
  94. String shareWith = dataString.substring(dataString.lastIndexOf('/') + 1);
  95. ArrayList<String> shareeNames = new ArrayList<>();
  96. for (OCShare share : getStorageManager().getSharesWithForAFile(getFile().getRemotePath(), getAccount().name)) {
  97. shareeNames.add(share.getShareWith());
  98. }
  99. if (!shareeNames.contains(shareWith)) {
  100. doShareWith(
  101. shareWith,
  102. data.getAuthority()
  103. );
  104. }
  105. } else {
  106. Log_OC.e(TAG, "Unexpected intent " + intent.toString());
  107. }
  108. }
  109. private void doShareWith(String shareeName, String dataAuthority) {
  110. ShareType shareType = UsersAndGroupsSearchProvider.getShareType(dataAuthority);
  111. getFileOperationsHelper().shareFileWithSharee(
  112. getFile(),
  113. shareeName,
  114. shareType,
  115. getAppropiatePermissions(shareType)
  116. );
  117. }
  118. private int getAppropiatePermissions(ShareType shareType) {
  119. // check if the Share is FERERATED
  120. boolean isFederated = ShareType.FEDERATED.equals(shareType);
  121. if (getFile().isSharedWithMe()) {
  122. return OCShare.READ_PERMISSION_FLAG; // minimum permissions
  123. } else if (isFederated) {
  124. OwnCloudVersion serverVersion =
  125. com.owncloud.android.authentication.AccountUtils.getServerVersion(getAccount());
  126. if (serverVersion != null && serverVersion.isNotReshareableFederatedSupported()) {
  127. return (
  128. getFile().isFolder() ?
  129. OCShare.FEDERATED_PERMISSIONS_FOR_FOLDER_AFTER_OC9 :
  130. OCShare.FEDERATED_PERMISSIONS_FOR_FILE_AFTER_OC9
  131. );
  132. } else {
  133. return (
  134. getFile().isFolder() ?
  135. OCShare.FEDERATED_PERMISSIONS_FOR_FOLDER_UP_TO_OC9 :
  136. OCShare.FEDERATED_PERMISSIONS_FOR_FILE_UP_TO_OC9
  137. );
  138. }
  139. } else {
  140. return (
  141. getFile().isFolder() ?
  142. OCShare.MAXIMUM_PERMISSIONS_FOR_FOLDER :
  143. OCShare.MAXIMUM_PERMISSIONS_FOR_FILE
  144. );
  145. }
  146. }
  147. @Override
  148. public void showSearchUsersAndGroups() {
  149. // replace ShareFragment with SearchFragment on demand
  150. FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
  151. Fragment searchFragment = SearchShareesFragment.newInstance(getFile(), getAccount());
  152. ft.replace(R.id.share_fragment_container, searchFragment, TAG_SEARCH_FRAGMENT);
  153. ft.addToBackStack(null); // BACK button will recover the ShareFragment
  154. ft.commit();
  155. }
  156. @Override
  157. public void showEditShare(OCShare share) {
  158. // replace current fragment with EditShareFragment on demand
  159. FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
  160. Fragment editShareFragment = EditShareFragment.newInstance(share, getFile(), getAccount());
  161. ft.replace(R.id.share_fragment_container, editShareFragment, TAG_EDIT_SHARE_FRAGMENT);
  162. ft.addToBackStack(null); // BACK button will recover the previous fragment
  163. ft.commit();
  164. }
  165. @Override
  166. // Call to Unshare operation
  167. public void unshareWith(OCShare share) {
  168. OCFile file = getFile();
  169. getFileOperationsHelper().unshareFileWithUserOrGroup(file, share.getShareType(), share.getShareWith());
  170. }
  171. /**
  172. * Get users and groups from the server to fill in the "share with" list
  173. */
  174. @Override
  175. public void refreshUsersOrGroupsListFromServer() {
  176. // Show loading
  177. showLoadingDialog(getString(R.string.common_loading));
  178. // Get Users and Groups
  179. GetShareWithUsersAsyncTask getTask = new GetShareWithUsersAsyncTask(this);
  180. Object[] params = {getFile(), getAccount(), getStorageManager()};
  181. getTask.execute(params);
  182. }
  183. /**
  184. * Updates the view associated to the activity after the finish of some operation over files
  185. * in the current account.
  186. *
  187. * @param operation Removal operation performed.
  188. * @param result Result of the removal.
  189. */
  190. @Override
  191. public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {
  192. super.onRemoteOperationFinish(operation, result);
  193. if (result.isSuccess() ||
  194. (operation instanceof GetSharesForFileOperation &&
  195. result.getCode() == RemoteOperationResult.ResultCode.SHARE_NOT_FOUND
  196. )
  197. ) {
  198. Log_OC.d(TAG, "Refreshing view on successful operation or finished refresh");
  199. refreshSharesFromStorageManager();
  200. }
  201. if (operation instanceof CreateShareViaLinkOperation) {
  202. onCreateShareViaLinkOperationFinish((CreateShareViaLinkOperation) operation, result);
  203. }
  204. if (operation instanceof UnshareOperation && result.isSuccess() && getEditShareFragment() != null) {
  205. getSupportFragmentManager().popBackStack();
  206. }
  207. if (operation instanceof UpdateSharePermissionsOperation
  208. && getEditShareFragment() != null && getEditShareFragment().isAdded()) {
  209. getEditShareFragment().onUpdateSharePermissionsFinished(result);
  210. }
  211. }
  212. /**
  213. * Updates the view, reading data from {@link com.owncloud.android.datamodel.FileDataStorageManager}
  214. */
  215. private void refreshSharesFromStorageManager() {
  216. ShareFileFragment shareFileFragment = getShareFileFragment();
  217. if (shareFileFragment != null
  218. && shareFileFragment.isAdded()) { // only if added to the view hierarchy!!
  219. shareFileFragment.refreshCapabilitiesFromDB();
  220. shareFileFragment.refreshUsersOrGroupsListFromDB();
  221. shareFileFragment.refreshPublicShareFromDB();
  222. }
  223. SearchShareesFragment searchShareesFragment = getSearchFragment();
  224. if (searchShareesFragment != null &&
  225. searchShareesFragment.isAdded()) { // only if added to the view hierarchy!!
  226. searchShareesFragment.refreshUsersOrGroupsListFromDB();
  227. }
  228. EditShareFragment editShareFragment = getEditShareFragment();
  229. if (editShareFragment != null &&
  230. editShareFragment.isAdded()) {
  231. editShareFragment.refreshUiFromDB();
  232. }
  233. }
  234. /**
  235. * Shortcut to get access to the {@link ShareFileFragment} instance, if any
  236. *
  237. * @return A {@link ShareFileFragment} instance, or null
  238. */
  239. private ShareFileFragment getShareFileFragment() {
  240. return (ShareFileFragment) getSupportFragmentManager().findFragmentByTag(TAG_SHARE_FRAGMENT);
  241. }
  242. /**
  243. * Shortcut to get access to the {@link SearchShareesFragment} instance, if any
  244. *
  245. * @return A {@link SearchShareesFragment} instance, or null
  246. */
  247. private SearchShareesFragment getSearchFragment() {
  248. return (SearchShareesFragment) getSupportFragmentManager().findFragmentByTag(TAG_SEARCH_FRAGMENT);
  249. }
  250. /**
  251. * Shortcut to get access to the {@link EditShareFragment} instance, if any
  252. *
  253. * @return A {@link EditShareFragment} instance, or null
  254. */
  255. private EditShareFragment getEditShareFragment() {
  256. return (EditShareFragment) getSupportFragmentManager().findFragmentByTag(TAG_EDIT_SHARE_FRAGMENT);
  257. }
  258. private void onCreateShareViaLinkOperationFinish(CreateShareViaLinkOperation operation,
  259. RemoteOperationResult result) {
  260. if (result.isSuccess()) {
  261. updateFileFromDB();
  262. // Create dialog to allow the user choose an app to send the link
  263. Intent intentToShareLink = new Intent(Intent.ACTION_SEND);
  264. // if share to user and share via link multiple ocshares are returned,
  265. // therefore filtering for public_link
  266. String link = "";
  267. for (Object object : result.getData()) {
  268. OCShare shareLink = (OCShare) object;
  269. if (TAG_PUBLIC_LINK.equalsIgnoreCase(shareLink.getShareType().name())) {
  270. link = shareLink.getShareLink();
  271. break;
  272. }
  273. }
  274. intentToShareLink.putExtra(Intent.EXTRA_TEXT, link);
  275. intentToShareLink.setType("text/plain");
  276. String username = AccountUtils.getUsernameForAccount(getAccount());
  277. if (username != null) {
  278. intentToShareLink.putExtra(
  279. Intent.EXTRA_SUBJECT,
  280. getString(
  281. R.string.subject_user_shared_with_you,
  282. username,
  283. getFile().getFileName()
  284. )
  285. );
  286. } else {
  287. intentToShareLink.putExtra(
  288. Intent.EXTRA_SUBJECT,
  289. getString(
  290. R.string.subject_shared_with_you,
  291. getFile().getFileName()
  292. )
  293. );
  294. }
  295. String[] packagesToExclude = new String[]{getPackageName()};
  296. DialogFragment chooserDialog = ShareLinkToDialog.newInstance(intentToShareLink, packagesToExclude);
  297. chooserDialog.show(getSupportFragmentManager(), FTAG_CHOOSER_DIALOG);
  298. } else {
  299. // Detect Failure (403) --> maybe needs password
  300. String password = operation.getPassword();
  301. if (result.getCode() == RemoteOperationResult.ResultCode.SHARE_FORBIDDEN &&
  302. (password == null || password.length() == 0) &&
  303. getCapabilities().getFilesSharingPublicEnabled().isUnknown()) {
  304. // Was tried without password, but not sure that it's optional.
  305. // Try with password before giving up; see also ShareFileFragment#OnShareViaLinkListener
  306. ShareFileFragment shareFileFragment = getShareFileFragment();
  307. if (shareFileFragment != null
  308. && shareFileFragment.isAdded()) { // only if added to the view hierarchy!!
  309. shareFileFragment.requestPasswordForShareViaLink(true);
  310. }
  311. } else {
  312. Toast t = Toast.makeText(this,
  313. ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()),
  314. Toast.LENGTH_LONG);
  315. t.show();
  316. }
  317. }
  318. }
  319. }