From: David A. Velasco Date: Fri, 20 Nov 2015 15:31:17 +0000 (+0100) Subject: Updated handling of enforced password for public shares depending on server capabilities X-Git-Tag: oc-android-1.9^2~10^2~4 X-Git-Url: http://git.linex4red.de/pub/Android/ownCloud.git/commitdiff_plain/9b4d153e90cebad0458585fd77d4235d3f44615e?ds=inline;hp=--cc Updated handling of enforced password for public shares depending on server capabilities --- 9b4d153e90cebad0458585fd77d4235d3f44615e diff --git a/src/com/owncloud/android/datamodel/FileDataStorageManager.java b/src/com/owncloud/android/datamodel/FileDataStorageManager.java index 5b5daa72..6c88116f 100644 --- a/src/com/owncloud/android/datamodel/FileDataStorageManager.java +++ b/src/com/owncloud/android/datamodel/FileDataStorageManager.java @@ -1884,6 +1884,8 @@ public class FileDataStorageManager { if (c.moveToFirst()) { capability = createCapabilityInstance(c); + } else { + capability = new OCCapability(); // return default with all UNKNOWN } c.close(); return capability; diff --git a/src/com/owncloud/android/files/FileOperationsHelper.java b/src/com/owncloud/android/files/FileOperationsHelper.java index 013fed91..5ce6cc30 100644 --- a/src/com/owncloud/android/files/FileOperationsHelper.java +++ b/src/com/owncloud/android/files/FileOperationsHelper.java @@ -143,18 +143,22 @@ public class FileOperationsHelper { /** * Helper method to share a file via a public link. Starts a request to do it in {@link OperationsService} * - * @param file The file to share. + * @param file The file to share. + * @param password Optional password to protect the public share. */ - public void shareFileViaLink(OCFile file) { + public void shareFileViaLink(OCFile file, String password) { if (isSharedSupported()) { if (file != null) { mFileActivity.showLoadingDialog( mFileActivity.getApplicationContext(). - getString(R.string.wait_a_moment) + getString(R.string.wait_a_moment) ); Intent service = new Intent(mFileActivity, OperationsService.class); service.setAction(OperationsService.ACTION_CREATE_SHARE_VIA_LINK); service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount()); + if (password != null && password.length() > 0) { + service.putExtra(OperationsService.EXTRA_SHARE_PASSWORD, password); + } service.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath()); mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(service); @@ -325,11 +329,14 @@ public class FileOperationsHelper { /** * Starts a dialog that requests a password to the user to protect a share link. * - * @param file File which public share will be protected by the requested password + * @param file File which public share will be protected by the requested password + * @param createShare When 'true', the request for password will be followed by the creation of a new + * public link; when 'false', a public share is assumed to exist, and the password + * is bound to it. */ - public void requestPasswordForShareViaLink(OCFile file) { + public void requestPasswordForShareViaLink(OCFile file, boolean createShare) { SharePasswordDialogFragment dialog = - SharePasswordDialogFragment.newInstance(file); + SharePasswordDialogFragment.newInstance(file, createShare); dialog.show( mFileActivity.getSupportFragmentManager(), SharePasswordDialogFragment.PASSWORD_FRAGMENT diff --git a/src/com/owncloud/android/operations/CreateShareViaLinkOperation.java b/src/com/owncloud/android/operations/CreateShareViaLinkOperation.java index 83ec1b64..e9cb7d2d 100644 --- a/src/com/owncloud/android/operations/CreateShareViaLinkOperation.java +++ b/src/com/owncloud/android/operations/CreateShareViaLinkOperation.java @@ -89,7 +89,7 @@ public class CreateShareViaLinkOperation extends SyncOperation { } if (!result.isSuccess() || !shareByLink) { - operation = new CreateRemoteShareOperation( + CreateRemoteShareOperation createOp = new CreateRemoteShareOperation( mPath, ShareType.PUBLIC_LINK, "", @@ -97,7 +97,8 @@ public class CreateShareViaLinkOperation extends SyncOperation { mPassword, OCShare.DEFAULT_PERMISSION ); - result = operation.execute(client); + createOp.setGetShareDetails(true); + result = createOp.execute(client); } if (result.isSuccess()) { diff --git a/src/com/owncloud/android/operations/RefreshFolderOperation.java b/src/com/owncloud/android/operations/RefreshFolderOperation.java index 71baf23d..368833e5 100644 --- a/src/com/owncloud/android/operations/RefreshFolderOperation.java +++ b/src/com/owncloud/android/operations/RefreshFolderOperation.java @@ -246,7 +246,7 @@ public class RefreshFolderOperation extends RemoteOperation { GetCapabilitiesOperarion getCapabilities = new GetCapabilitiesOperarion(); RemoteOperationResult result = getCapabilities.execute(mStorageManager,mContext); if (!result.isSuccess()){ - Log_OC.d(TAG, "Update Capabilities unsuccessfully"); + Log_OC.w(TAG, "Update Capabilities unsuccessfully"); } } diff --git a/src/com/owncloud/android/ui/activity/FileActivity.java b/src/com/owncloud/android/ui/activity/FileActivity.java index 563dbb1d..3fba453d 100644 --- a/src/com/owncloud/android/ui/activity/FileActivity.java +++ b/src/com/owncloud/android/ui/activity/FileActivity.java @@ -67,6 +67,7 @@ import com.owncloud.android.lib.common.operations.RemoteOperation; import com.owncloud.android.lib.common.operations.RemoteOperationResult; import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode; import com.owncloud.android.lib.common.utils.Log_OC; +import com.owncloud.android.lib.resources.status.OCCapability; import com.owncloud.android.operations.CreateShareViaLinkOperation; import com.owncloud.android.operations.CreateShareWithShareeOperation; import com.owncloud.android.operations.GetSharesForFileOperation; @@ -94,8 +95,6 @@ public class FileActivity extends AppCompatActivity public static final String EXTRA_FILE = "com.owncloud.android.ui.activity.FILE"; public static final String EXTRA_ACCOUNT = "com.owncloud.android.ui.activity.ACCOUNT"; - public static final String EXTRA_WAITING_TO_PREVIEW = - "com.owncloud.android.ui.activity.WAITING_TO_PREVIEW"; public static final String EXTRA_FROM_NOTIFICATION = "com.owncloud.android.ui.activity.FROM_NOTIFICATION"; @@ -114,9 +113,13 @@ public class FileActivity extends AppCompatActivity /** OwnCloud {@link Account} where the main {@link OCFile} handled by the activity is located.*/ private Account mAccount; - /** Main {@link OCFile} handled by the activity.*/ + /** Capabilites of the server where {@link #mAccount} lives */ + private OCCapability mCapabilities; + + /** Main {@link OCFile} handled by the activity.*/ private OCFile mFile; + /** Flag to signal that the activity will is finishing to enforce the creation of an ownCloud * {@link Account} */ private boolean mRedirectingToSetupAccount = false; @@ -146,8 +149,6 @@ public class FileActivity extends AppCompatActivity protected FileUploaderBinder mUploaderBinder = null; private ServiceConnection mDownloadServiceConnection, mUploadServiceConnection = null; - private boolean mTryShareAgain = false; - // Navigation Drawer protected DrawerLayout mDrawerLayout; protected ActionBarDrawerToggle mDrawerToggle; @@ -162,6 +163,7 @@ public class FileActivity extends AppCompatActivity protected NavigationDrawerListAdapter mNavigationDrawerAdapter = null; + // TODO re-enable when "Accounts" is available in Navigation Drawer // protected boolean mShowAccounts = false; @@ -184,7 +186,6 @@ public class FileActivity extends AppCompatActivity mFileOperationsHelper.setOpIdWaitingFor( savedInstanceState.getLong(KEY_WAITING_FOR_OP_ID, Long.MAX_VALUE) ); - mTryShareAgain = savedInstanceState.getBoolean(KEY_TRY_SHARE_AGAIN); if (getSupportActionBar() != null) { getSupportActionBar().setTitle(savedInstanceState.getString(KEY_ACTION_BAR_TITLE)); } @@ -555,7 +556,6 @@ public class FileActivity extends AppCompatActivity outState.putParcelable(FileActivity.EXTRA_FILE, mFile); outState.putBoolean(FileActivity.EXTRA_FROM_NOTIFICATION, mFromNotification); outState.putLong(KEY_WAITING_FOR_OP_ID, mFileOperationsHelper.getOpIdWaitingFor()); - outState.putBoolean(KEY_TRY_SHARE_AGAIN, mTryShareAgain); if(getSupportActionBar() != null && getSupportActionBar().getTitle() != null) { // Null check in case the actionbar is used in ActionBar.NAVIGATION_MODE_LIST // since it doesn't have a title then @@ -599,6 +599,18 @@ public class FileActivity extends AppCompatActivity mAccount = account; } + + /** + * Getter for the capabilities of the server where the current OC account lives. + * + * @return Capabilities of the server where the current OC account lives. Null if the account is not + * set yet. + */ + public OCCapability getCapabilities() { + return mCapabilities; + } + + /** * @return Value of mFromNotification: True if the Activity is launched by a notification */ @@ -613,14 +625,6 @@ public class FileActivity extends AppCompatActivity return mRedirectingToSetupAccount; } - public boolean isTryShareAgain(){ - return mTryShareAgain; - } - - public void setTryShareAgain(boolean tryShareAgain) { - mTryShareAgain = tryShareAgain; - } - public OperationsServiceBinder getOperationsServiceBinder() { return mOperationsServiceBinder; } @@ -677,6 +681,7 @@ public class FileActivity extends AppCompatActivity protected void onAccountSet(boolean stateWasRecovered) { if (getAccount() != null) { mStorageManager = new FileDataStorageManager(getAccount(), getContentResolver()); + mCapabilities = mStorageManager.getCapability(mAccount.name); } else { Log_OC.wtf(TAG, "onAccountChanged was called with NULL account associated!"); @@ -731,7 +736,6 @@ public class FileActivity extends AppCompatActivity Toast.LENGTH_LONG); t.show(); } - mTryShareAgain = false; } else if (operation == null || operation instanceof CreateShareWithShareeOperation || @@ -783,7 +787,6 @@ public class FileActivity extends AppCompatActivity private void onCreateShareViaLinkOperationFinish(CreateShareViaLinkOperation operation, RemoteOperationResult result) { if (result.isSuccess()) { - mTryShareAgain = false; updateFileFromDB(); Intent sendIntent = operation.getSendIntentWithSubject(this); @@ -794,16 +797,21 @@ public class FileActivity extends AppCompatActivity } else { // Detect Failure (403) --> needs Password if (result.getCode() == ResultCode.SHARE_FORBIDDEN) { - if (!isTryShareAgain()) { + String password = operation.getPassword(); + if ((password == null || password.length() == 0) && + !getCapabilities().getFilesSharingPublicEnabled().isFalse()) + { + // Was tried without password, but not sure that it's optional. Try with password. + // Try with password before giving up. + // See also ShareFileFragment#OnShareViaLinkListener SharePasswordDialogFragment dialog = - SharePasswordDialogFragment.newInstance(new OCFile(operation.getPath())); + SharePasswordDialogFragment.newInstance(new OCFile(operation.getPath()), true); dialog.show(getSupportFragmentManager(), DIALOG_SHARE_PASSWORD); } else { Toast t = Toast.makeText(this, ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()), Toast.LENGTH_LONG); t.show(); - mTryShareAgain = false; } } else { Toast t = Toast.makeText(this, diff --git a/src/com/owncloud/android/ui/dialog/SharePasswordDialogFragment.java b/src/com/owncloud/android/ui/dialog/SharePasswordDialogFragment.java index 51dbf486..1b7def27 100644 --- a/src/com/owncloud/android/ui/dialog/SharePasswordDialogFragment.java +++ b/src/com/owncloud/android/ui/dialog/SharePasswordDialogFragment.java @@ -44,21 +44,26 @@ public class SharePasswordDialogFragment extends DialogFragment implements DialogInterface.OnClickListener { private static final String ARG_FILE = "FILE"; + private static final String ARG_CREATE_SHARE = "CREATE_SHARE"; public static final String PASSWORD_FRAGMENT = "PASSWORD_FRAGMENT"; private OCFile mFile; + private boolean mCreateShare; /** * Public factory method to create new SharePasswordDialogFragment instances. * - * @param file - * @return Dialog ready to show. + * @param file OCFile bound to the public share that which password will be set or updated + * @param createShare When 'true', the public share will be created; when 'false', will be assumed + * that the public share already exists, and its state will be directly updated. + * @return Dialog ready to show. */ - public static SharePasswordDialogFragment newInstance(OCFile file) { + public static SharePasswordDialogFragment newInstance(OCFile file, boolean createShare) { SharePasswordDialogFragment frag = new SharePasswordDialogFragment(); Bundle args = new Bundle(); args.putParcelable(ARG_FILE, file); + args.putBoolean(ARG_CREATE_SHARE, createShare); frag.setArguments(args); return frag; } @@ -66,6 +71,7 @@ public class SharePasswordDialogFragment extends DialogFragment @Override public Dialog onCreateDialog(Bundle savedInstanceState) { mFile = getArguments().getParcelable(ARG_FILE); + mCreateShare = getArguments().getBoolean(ARG_CREATE_SHARE, false); // Inflate the layout for the dialog LayoutInflater inflater = getActivity().getLayoutInflater(); @@ -91,9 +97,6 @@ public class SharePasswordDialogFragment extends DialogFragment @Override public void onClick(DialogInterface dialog, int which) { if (which == AlertDialog.BUTTON_POSITIVE) { - // Enable the flag "Share again" - ((FileActivity) getActivity()).setTryShareAgain(true); - String password = ((TextView)(getDialog().findViewById(R.id.share_password))) .getText().toString(); @@ -106,13 +109,16 @@ public class SharePasswordDialogFragment extends DialogFragment return; } - // Share the file - ((FileActivity) getActivity()).getFileOperationsHelper(). - setPasswordToShareViaLink(mFile, password); + if (mCreateShare) { + // Share the file + ((FileActivity) getActivity()).getFileOperationsHelper(). + shareFileViaLink(mFile, password); - } else { - // Disable the flag "Share again" - ((FileActivity) getActivity()).setTryShareAgain(false); + } else { + // updat existing link + ((FileActivity) getActivity()).getFileOperationsHelper(). + setPasswordToShareViaLink(mFile, password); + } } } } diff --git a/src/com/owncloud/android/ui/fragment/ShareFileFragment.java b/src/com/owncloud/android/ui/fragment/ShareFileFragment.java index 18c8d08c..46382a65 100644 --- a/src/com/owncloud/android/ui/fragment/ShareFileFragment.java +++ b/src/com/owncloud/android/ui/fragment/ShareFileFragment.java @@ -145,6 +145,7 @@ public class ShareFileFragment extends Fragment @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + Log_OC.d(TAG, "onCreate"); if (getArguments() != null) { mFile = getArguments().getParcelable(ARG_FILE); mAccount = getArguments().getParcelable(ARG_ACCOUNT); @@ -158,6 +159,8 @@ public class ShareFileFragment extends Fragment @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + Log_OC.d(TAG, "onCreateView"); + // Inflate the layout for this fragment View view = inflater.inflate(R.layout.share_file_layout, container, false); @@ -204,24 +207,12 @@ public class ShareFileFragment extends Fragment // Switch to create public share mOnShareViaLinkSwitchCheckedChangeListener = new CompoundButton.OnCheckedChangeListener() { @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - if (!isResumed()) { - // very important, setCheched(...) is called automatically during - // Fragment recreation on device rotations - return; - } - if (isChecked) { - ((FileActivity) getActivity()).getFileOperationsHelper(). - shareFileViaLink(mFile); - - } else { - ((FileActivity) getActivity()).getFileOperationsHelper(). - unshareFileViaLink(mFile); - } + public void onCheckedChanged(CompoundButton switchView, boolean isChecked) { } }; - Switch shareViaLinkSwitch = (Switch) view.findViewById(R.id.shareViaLinkSectionSwitch); - shareViaLinkSwitch.setOnCheckedChangeListener(mOnShareViaLinkSwitchCheckedChangeListener); + + // Set listener for user actions on switch for sharing/unsharing via link + initShareViaLinkListener(view); // Set listener for user actions on expiration date initExpirationListener(view); @@ -232,6 +223,68 @@ public class ShareFileFragment extends Fragment return view; } + + /** + * Binds listener for user actions to create or delete a public share + * to the views receiving the user events. + * + * @param shareView Root view in the fragment. + */ + private void initShareViaLinkListener(View shareView) { + mOnShareViaLinkSwitchCheckedChangeListener = new OnShareViaLinkListener(); + Switch shareViaLinkSwitch = (Switch) shareView.findViewById(R.id.shareViaLinkSectionSwitch); + shareViaLinkSwitch.setOnCheckedChangeListener(mOnShareViaLinkSwitchCheckedChangeListener); + } + + /** + * Listener for user actions that create or delete a public share. + */ + private class OnShareViaLinkListener + implements CompoundButton.OnCheckedChangeListener { + + /** + * Called by R.id.shareViaLinkSectionSwitch to create or delete a public link. + * + * @param switchView {@link Switch} toggled by the user, R.id.shareViaLinkSectionSwitch + * @param isChecked New switch state. + */ + @Override + public void onCheckedChanged(CompoundButton switchView, boolean isChecked) { + if (!isResumed()) { + // very important, setCheched(...) is called automatically during + // Fragment recreation on device rotations + return; + } + if (isChecked) { + if (mCapabilities != null && + mCapabilities.getFilesSharingPublicPasswordEnforced().isTrue()) { + // password enforced by server, request to the user before trying to create + ((FileActivity) getActivity()).getFileOperationsHelper(). + requestPasswordForShareViaLink(mFile, true); + + } else { + // create without password if not enforced by server or we don't know if enforced; + ((FileActivity) getActivity()).getFileOperationsHelper(). + shareFileViaLink(mFile, null); + + // FileActivtiy#onCreateShareViaLinkOperationFinish still handles the guess of enforcement + // for server in versions previous to OwnCloudVersion#MINIMUM_VERSION_CAPABILITIES_API + } + + } else { + ((FileActivity) getActivity()).getFileOperationsHelper(). + unshareFileViaLink(mFile); + } + + // undo the toggle to grant the view will be correct if any intermediate dialog is cancelled or + // the create/delete operation fails + switchView.setOnCheckedChangeListener(null); + switchView.toggle(); + switchView.setOnCheckedChangeListener(mOnShareViaLinkSwitchCheckedChangeListener); + } + } + + /** * Binds listener for user actions that start any update on a expiration date * for the public link to the views receiving the user events. @@ -357,7 +410,7 @@ public class ShareFileFragment extends Fragment } if (isChecked) { ((FileActivity) getActivity()).getFileOperationsHelper(). - requestPasswordForShareViaLink(mFile); + requestPasswordForShareViaLink(mFile, false); } else { ((FileActivity) getActivity()).getFileOperationsHelper(). setPasswordToShareViaLink(mFile, ""); // "" clears @@ -379,7 +432,7 @@ public class ShareFileFragment extends Fragment public void onClick(View passwordView) { if (mPublicShare != null && mPublicShare.isPasswordProtected()) { ((FileActivity) getActivity()).getFileOperationsHelper(). - requestPasswordForShareViaLink(mFile); + requestPasswordForShareViaLink(mFile, false); } } } @@ -388,6 +441,7 @@ public class ShareFileFragment extends Fragment @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); + Log_OC.d(TAG, "onActivityCreated"); // Load known capabilities of the server from DB refreshCapabilitiesFromDB();