Hide UI elements about public share when this is disabled in the server
[pub/Android/ownCloud.git] / src / com / owncloud / android / ui / fragment / ShareFileFragment.java
1 /**
2 * ownCloud Android client application
3 *
4 * @author masensio
5 * @author David A. Velasco
6 * Copyright (C) 2015 ownCloud Inc.
7 *
8 * This program is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2,
10 * as published by the Free Software Foundation.
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 General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 *
20 */
21
22 package com.owncloud.android.ui.fragment;
23
24 import android.accounts.Account;
25 import android.app.Activity;
26 import android.graphics.Bitmap;
27 import android.os.Bundle;
28 import android.support.v4.app.Fragment;
29 import android.support.v7.widget.AppCompatButton;
30 import android.view.LayoutInflater;
31 import android.view.View;
32 import android.view.ViewGroup;
33 import android.widget.Button;
34 import android.widget.CompoundButton;
35 import android.widget.ImageView;
36 import android.widget.ListAdapter;
37 import android.widget.ListView;
38 import android.widget.ScrollView;
39 import android.widget.Switch;
40 import android.widget.TextView;
41 import android.widget.Toast;
42
43 import com.owncloud.android.R;
44 import com.owncloud.android.authentication.AccountUtils;
45 import com.owncloud.android.datamodel.OCFile;
46 import com.owncloud.android.datamodel.ThumbnailsCacheManager;
47 import com.owncloud.android.lib.common.utils.Log_OC;
48 import com.owncloud.android.lib.resources.shares.OCShare;
49 import com.owncloud.android.lib.resources.shares.ShareType;
50 import com.owncloud.android.lib.resources.status.OCCapability;
51 import com.owncloud.android.ui.activity.FileActivity;
52 import com.owncloud.android.ui.adapter.ShareUserListAdapter;
53 import com.owncloud.android.ui.dialog.ExpirationDatePickerDialogFragment;
54 import com.owncloud.android.utils.DisplayUtils;
55 import com.owncloud.android.utils.MimetypeIconUtil;
56
57 import java.text.SimpleDateFormat;
58
59 import java.util.ArrayList;
60 import java.util.Date;
61
62 /**
63 * Fragment for Sharing a file with sharees (users or groups) or creating
64 * a public link.
65 *
66 * A simple {@link Fragment} subclass.
67 *
68 * Activities that contain this fragment must implement the
69 * {@link ShareFileFragment.OnShareFragmentInteractionListener} interface
70 * to handle interaction events.
71 *
72 * Use the {@link ShareFileFragment#newInstance} factory method to
73 * create an instance of this fragment.
74 */
75 public class ShareFileFragment extends Fragment
76 implements ShareUserListAdapter.ShareUserAdapterListener{
77
78 private static final String TAG = ShareFileFragment.class.getSimpleName();
79
80 /** The fragment initialization parameters */
81 private static final String ARG_FILE = "FILE";
82 private static final String ARG_ACCOUNT = "ACCOUNT";
83
84 // /** Tag for dialog */
85 // private static final String FTAG_CHOOSER_DIALOG = "CHOOSER_DIALOG";
86
87 /** File to share, received as a parameter in construction time */
88 private OCFile mFile;
89
90 /** OC account holding the file to share, received as a parameter in construction time */
91 private Account mAccount;
92
93 /** Reference to parent listener */
94 private OnShareFragmentInteractionListener mListener;
95
96 /** List of private shares bound to the file */
97 private ArrayList<OCShare> mPrivateShares;
98
99 /** Capabilities of the server */
100 private OCCapability mCapabilities;
101
102 /** Adapter to show private shares */
103 private ShareUserListAdapter mUserGroupsAdapter = null;
104
105 /** Public share bound to the file */
106 private OCShare mPublicShare;
107
108 /** Listener for changes on switch to share / unshare publicly */
109 private CompoundButton.OnCheckedChangeListener mOnShareViaLinkSwitchCheckedChangeListener;
110
111 /**
112 * Listener for user actions to set, update or clear password on public link
113 */
114 private OnPasswordInteractionListener mOnPasswordInteractionListener = null;
115
116 /**
117 * Listener for user actions to set, update or clear expiration date on public link
118 */
119 private OnExpirationDateInteractionListener mOnExpirationDateInteractionListener = null;
120
121
122 /**
123 * Public factory method to create new ShareFileFragment instances.
124 *
125 * @param fileToShare An {@link OCFile} to show in the fragment
126 * @param account An ownCloud account
127 * @return A new instance of fragment ShareFileFragment.
128 */
129 public static ShareFileFragment newInstance(OCFile fileToShare, Account account) {
130 ShareFileFragment fragment = new ShareFileFragment();
131 Bundle args = new Bundle();
132 args.putParcelable(ARG_FILE, fileToShare);
133 args.putParcelable(ARG_ACCOUNT, account);
134 fragment.setArguments(args);
135 return fragment;
136 }
137
138 public ShareFileFragment() {
139 // Required empty public constructor
140 }
141
142 /**
143 * {@inheritDoc}
144 */
145 @Override
146 public void onCreate(Bundle savedInstanceState) {
147 super.onCreate(savedInstanceState);
148 if (getArguments() != null) {
149 mFile = getArguments().getParcelable(ARG_FILE);
150 mAccount = getArguments().getParcelable(ARG_ACCOUNT);
151 }
152 }
153
154
155 /**
156 * {@inheritDoc}
157 */
158 @Override
159 public View onCreateView(LayoutInflater inflater, ViewGroup container,
160 Bundle savedInstanceState) {
161 // Inflate the layout for this fragment
162 View view = inflater.inflate(R.layout.share_file_layout, container, false);
163
164 // Setup layout
165 // Image
166 ImageView icon = (ImageView) view.findViewById(R.id.shareFileIcon);
167 icon.setImageResource(MimetypeIconUtil.getFileTypeIconId(mFile.getMimetype(),
168 mFile.getFileName()));
169 if (mFile.isImage()) {
170 String remoteId = String.valueOf(mFile.getRemoteId());
171 Bitmap thumbnail = ThumbnailsCacheManager.getBitmapFromDiskCache(remoteId);
172 if (thumbnail != null) {
173 icon.setImageBitmap(thumbnail);
174 }
175 }
176 // Name
177 TextView filename = (TextView) view.findViewById(R.id.shareFileName);
178 filename.setText(mFile.getFileName());
179 // Size
180 TextView size = (TextView) view.findViewById(R.id.shareFileSize);
181 if (mFile.isFolder()) {
182 size.setVisibility(View.GONE);
183 } else {
184 size.setText(DisplayUtils.bytesToHumanReadable(mFile.getFileLength()));
185 }
186
187 // Add User Button
188 Button addUserGroupButton = (Button)
189 view.findViewById(R.id.addUserButton);
190 addUserGroupButton.setOnClickListener(new View.OnClickListener() {
191 @Override
192 public void onClick(View view) {
193 boolean shareWithUsersEnable = AccountUtils.hasSearchUsersSupport(mAccount);
194 if (shareWithUsersEnable) {
195 // Show Search Fragment
196 mListener.showSearchUsersAndGroups();
197 } else {
198 String message = getString(R.string.share_sharee_unavailable);
199 Toast.makeText(getActivity(), message, Toast.LENGTH_LONG).show();
200 }
201 }
202 });
203
204 // Switch to create public share
205 mOnShareViaLinkSwitchCheckedChangeListener = new CompoundButton.OnCheckedChangeListener() {
206 @Override
207 public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
208 if (!isResumed()) {
209 // very important, setCheched(...) is called automatically during
210 // Fragment recreation on device rotations
211 return;
212 }
213 if (isChecked) {
214 ((FileActivity) getActivity()).getFileOperationsHelper().
215 shareFileViaLink(mFile);
216
217 } else {
218 ((FileActivity) getActivity()).getFileOperationsHelper().
219 unshareFileViaLink(mFile);
220 }
221 }
222 };
223 Switch shareViaLinkSwitch = (Switch) view.findViewById(R.id.shareViaLinkSectionSwitch);
224 shareViaLinkSwitch.setOnCheckedChangeListener(mOnShareViaLinkSwitchCheckedChangeListener);
225
226 // Set listener for user actions on expiration date
227 initExpirationListener(view);
228
229 // Set listener for user actions on password
230 initPasswordListener(view);
231
232 return view;
233 }
234
235 /**
236 * Binds listener for user actions that start any update on a expiration date
237 * for the public link to the views receiving the user events.
238 *
239 * @param shareView Root view in the fragment.
240 */
241 private void initExpirationListener(View shareView) {
242 mOnExpirationDateInteractionListener = new OnExpirationDateInteractionListener();
243
244 ((Switch) shareView.findViewById(R.id.shareViaLinkExpirationSwitch)).
245 setOnCheckedChangeListener(mOnExpirationDateInteractionListener);
246
247 shareView.findViewById(R.id.shareViaLinkExpirationLabel).
248 setOnClickListener(mOnExpirationDateInteractionListener);
249
250 shareView.findViewById(R.id.shareViaLinkExpirationValue).
251 setOnClickListener(mOnExpirationDateInteractionListener);
252 }
253
254 /**
255 * Listener for user actions that start any update on the expiration date for the public link.
256 */
257 private class OnExpirationDateInteractionListener
258 implements CompoundButton.OnCheckedChangeListener, View.OnClickListener {
259
260 /**
261 * Called by R.id.shareViaLinkExpirationSwitch to set or clear the expiration date.
262 *
263 * @param switchView {@link Switch} toggled by the user, R.id.shareViaLinkExpirationSwitch
264 * @param isChecked New switch state.
265 */
266 @Override
267 public void onCheckedChanged(CompoundButton switchView, boolean isChecked) {
268 if (!isResumed()) {
269 // very important, setCheched(...) is called automatically during
270 // Fragment recreation on device rotations
271 return;
272 }
273 if (isChecked) {
274 ExpirationDatePickerDialogFragment dialog =
275 ExpirationDatePickerDialogFragment.newInstance(mFile, -1);
276 dialog.show(
277 getActivity().getSupportFragmentManager(),
278 ExpirationDatePickerDialogFragment.DATE_PICKER_DIALOG
279 );
280
281 } else {
282 ((FileActivity) getActivity()).getFileOperationsHelper().
283 setExpirationDateToShareViaLink(mFile, -1);
284 }
285
286 // undo the toggle to grant the view will be correct if the dialog is cancelled
287 switchView.setOnCheckedChangeListener(null);
288 switchView.toggle();
289 switchView.setOnCheckedChangeListener(mOnExpirationDateInteractionListener);
290 }
291
292 /**
293 * Called by R.id.shareViaLinkExpirationLabel or R.id.shareViaLinkExpirationValue
294 * to change the current expiration date.
295 *
296 * @param expirationView Label or value view touched by the user.
297 */
298 @Override
299 public void onClick(View expirationView) {
300 if (mPublicShare != null && mPublicShare.getExpirationDate() > 0) {
301 long chosenDateInMillis = -1;
302 if (mPublicShare != null) {
303 chosenDateInMillis = mPublicShare.getExpirationDate();
304 }
305 ExpirationDatePickerDialogFragment dialog =
306 ExpirationDatePickerDialogFragment.newInstance(
307 mFile,
308 chosenDateInMillis
309 );
310 dialog.show(
311 getActivity().getSupportFragmentManager(),
312 ExpirationDatePickerDialogFragment.DATE_PICKER_DIALOG
313 );
314 }
315 }
316 }
317
318
319 /**
320 * Binds listener for user actions that start any update on a password for the public link
321 * to the views receiving the user events.
322 *
323 * @param shareView Root view in the fragment.
324 */
325 private void initPasswordListener(View shareView) {
326 mOnPasswordInteractionListener = new OnPasswordInteractionListener();
327
328 ((Switch) shareView.findViewById(R.id.shareViaLinkPasswordSwitch)).
329 setOnCheckedChangeListener(mOnPasswordInteractionListener);
330
331 shareView.findViewById(R.id.shareViaLinkPasswordLabel).
332 setOnClickListener(mOnPasswordInteractionListener);
333
334 shareView.findViewById(R.id.shareViaLinkPasswordValue).
335 setOnClickListener(mOnPasswordInteractionListener);
336 }
337
338
339 /**
340 * Listener for user actions that start any update on a password for the public link.
341 */
342 private class OnPasswordInteractionListener
343 implements CompoundButton.OnCheckedChangeListener, View.OnClickListener {
344
345 /**
346 * Called by R.id.shareViaLinkPasswordSwitch to set or clear the password.
347 *
348 * @param switchView {@link Switch} toggled by the user, R.id.shareViaLinkPasswordSwitch
349 * @param isChecked New switch state.
350 */
351 @Override
352 public void onCheckedChanged(CompoundButton switchView, boolean isChecked) {
353 if (!isResumed()) {
354 // very important, setCheched(...) is called automatically during
355 // Fragment recreation on device rotations
356 return;
357 }
358 if (isChecked) {
359 ((FileActivity) getActivity()).getFileOperationsHelper().
360 requestPasswordForShareViaLink(mFile);
361 } else {
362 ((FileActivity) getActivity()).getFileOperationsHelper().
363 setPasswordToShareViaLink(mFile, ""); // "" clears
364 }
365
366 // undo the toggle to grant the view will be correct if the dialog is cancelled
367 switchView.setOnCheckedChangeListener(null);
368 switchView.toggle();
369 switchView.setOnCheckedChangeListener(mOnPasswordInteractionListener);
370 }
371
372 /**
373 * Called by R.id.shareViaLinkPasswordLabel or R.id.shareViaLinkPasswordValue
374 * to change the current password.
375 *
376 * @param passwordView Label or value view touched by the user.
377 */
378 @Override
379 public void onClick(View passwordView) {
380 if (mPublicShare != null && mPublicShare.isPasswordProtected()) {
381 ((FileActivity) getActivity()).getFileOperationsHelper().
382 requestPasswordForShareViaLink(mFile);
383 }
384 }
385 }
386
387
388 @Override
389 public void onActivityCreated(Bundle savedInstanceState) {
390 super.onActivityCreated(savedInstanceState);
391
392 // Load known capabilities of the server from DB
393 refreshCapabilitiesFromDB();
394
395 // Load data into the list of private shares
396 refreshUsersOrGroupsListFromDB();
397
398 // Load data of public share, if exists
399 refreshPublicShareFromDB();
400 }
401
402 @Override
403 public void onAttach(Activity activity) {
404 super.onAttach(activity);
405 try {
406 mListener = (OnShareFragmentInteractionListener) activity;
407 } catch (ClassCastException e) {
408 throw new ClassCastException(activity.toString()
409 + " must implement OnShareFragmentInteractionListener");
410 }
411 }
412
413 @Override
414 public void onDetach() {
415 super.onDetach();
416 mListener = null;
417 }
418
419
420 /**
421 * Get known server capabilities from DB
422 *
423 * Depends on the parent Activity provides a {@link com.owncloud.android.datamodel.FileDataStorageManager}
424 * instance ready to use. If not ready, does nothing.
425 */
426 public void refreshCapabilitiesFromDB() {
427 if (((FileActivity)mListener).getStorageManager() != null) {
428 mCapabilities = ((FileActivity)mListener).getStorageManager().
429 getCapability(mAccount.name);
430 }
431 }
432
433
434 /**
435 * Get users and groups from the DB to fill in the "share with" list.
436 *
437 * Depends on the parent Activity provides a {@link com.owncloud.android.datamodel.FileDataStorageManager}
438 * instance ready to use. If not ready, does nothing.
439 */
440 public void refreshUsersOrGroupsListFromDB (){
441 if (((FileActivity) mListener).getStorageManager() != null) {
442 // Get Users and Groups
443 mPrivateShares = ((FileActivity) mListener).getStorageManager().getSharesWithForAFile(
444 mFile.getRemotePath(),
445 mAccount.name
446 );
447
448 // Update list of users/groups
449 updateListOfUserGroups();
450 }
451 }
452
453 private void updateListOfUserGroups() {
454 // Update list of users/groups
455 // TODO Refactoring: create a new {@link ShareUserListAdapter} instance with every call should not be needed
456 mUserGroupsAdapter = new ShareUserListAdapter(
457 getActivity(),
458 R.layout.share_user_item,
459 mPrivateShares,
460 this
461 );
462
463 // Show data
464 TextView noShares = (TextView) getView().findViewById(R.id.shareNoUsers);
465 ListView usersList = (ListView) getView().findViewById(R.id.shareUsersList);
466
467 if (mPrivateShares.size() > 0) {
468 noShares.setVisibility(View.GONE);
469 usersList.setVisibility(View.VISIBLE);
470 usersList.setAdapter(mUserGroupsAdapter);
471 setListViewHeightBasedOnChildren(usersList);
472 } else {
473 noShares.setVisibility(View.VISIBLE);
474 usersList.setVisibility(View.GONE);
475 }
476
477 // Set Scroll to initial position
478 ScrollView scrollView = (ScrollView) getView().findViewById(R.id.shareScroll);
479 scrollView.scrollTo(0, 0);
480 }
481
482 @Override
483 public void unshareButtonPressed(OCShare share) {
484 // Unshare
485 mListener.unshareWith(share);
486 Log_OC.d(TAG, "Unshare - " + share.getSharedWithDisplayName());
487 }
488
489
490
491 /**
492 * Get public link from the DB to fill in the "Share link" section in the UI.
493 *
494 * Takes into account server capabilities before reading database.
495 *
496 * Depends on the parent Activity provides a {@link com.owncloud.android.datamodel.FileDataStorageManager}
497 * instance ready to use. If not ready, does nothing.
498 */
499 public void refreshPublicShareFromDB() {
500 if (isPublicShareDisabled()) {
501 hidePublicShare();
502
503 } else if (((FileActivity) mListener).getStorageManager() != null) {
504 // Get public share
505 mPublicShare = ((FileActivity) mListener).getStorageManager().getFirstShareByPathAndType(
506 mFile.getRemotePath(),
507 ShareType.PUBLIC_LINK,
508 ""
509 );
510
511 // Update public share section
512 updatePublicShareSection();
513 }
514 }
515
516 /**
517 * @return 'True' when public share is disabled in the server
518 */
519 private boolean isPublicShareDisabled() {
520 return (mCapabilities != null &&
521 mCapabilities.getFilesSharingPublicEnabled().isFalse()
522 );
523 }
524
525 /**
526 * Updates in the UI the section about public share with the information in the current
527 * public share bound to mFile, if any
528 */
529 private void updatePublicShareSection() {
530 if (mPublicShare != null && ShareType.PUBLIC_LINK.equals(mPublicShare.getShareType())) {
531 /// public share bound -> expand section
532 Switch shareViaLinkSwitch = getShareViaLinkSwitch();
533 if (!shareViaLinkSwitch.isChecked()) {
534 // set null listener before setChecked() to prevent infinite loop of calls
535 shareViaLinkSwitch.setOnCheckedChangeListener(null);
536 shareViaLinkSwitch.setChecked(true);
537 shareViaLinkSwitch.setOnCheckedChangeListener(
538 mOnShareViaLinkSwitchCheckedChangeListener
539 );
540 }
541 getExpirationDateSection().setVisibility(View.VISIBLE);
542 getPasswordSection().setVisibility(View.VISIBLE);
543 // GetLink button
544 AppCompatButton getLinkButton = getGetLinkButton();
545 getLinkButton.setVisibility(View.VISIBLE);
546 getLinkButton.setOnClickListener(new View.OnClickListener() {
547 @Override
548 public void onClick(View v) {
549 //GetLink from the server and show ShareLinkToDialog
550 ((FileActivity) getActivity()).getFileOperationsHelper().
551 getFileWithLink(mFile);
552
553 }
554 });
555
556 /// update state of expiration date switch and message depending on expiration date
557 Switch expirationDateSwitch = getExpirationDateSwitch();
558 // set null listener before setChecked() to prevent infinite loop of calls
559 expirationDateSwitch.setOnCheckedChangeListener(null);
560 long expirationDate = mPublicShare.getExpirationDate();
561 if (expirationDate > 0) {
562 if (!expirationDateSwitch.isChecked()) {
563 expirationDateSwitch.toggle();
564 }
565 String formattedDate =
566 SimpleDateFormat.getDateInstance().format(
567 new Date(expirationDate)
568 );
569 getExpirationDateValue().setText(formattedDate);
570 } else {
571 if (expirationDateSwitch.isChecked()) {
572 expirationDateSwitch.toggle();
573 }
574 getExpirationDateValue().setText(R.string.empty);
575 }
576 // recover listener
577 expirationDateSwitch.setOnCheckedChangeListener(
578 mOnExpirationDateInteractionListener
579 );
580
581 /// update state of password switch and message depending on password protection
582 Switch passwordSwitch = getPasswordSwitch();
583 // set null listener before setChecked() to prevent infinite loop of calls
584 passwordSwitch.setOnCheckedChangeListener(null);
585 if (mPublicShare.isPasswordProtected()) {
586 if (!passwordSwitch.isChecked()) {
587 passwordSwitch.toggle();
588 }
589 getPasswordValue().setVisibility(View.VISIBLE);
590 } else {
591 if (passwordSwitch.isChecked()) {
592 passwordSwitch.toggle();
593 }
594 getPasswordValue().setVisibility(View.INVISIBLE);
595 }
596 // recover listener
597 passwordSwitch.setOnCheckedChangeListener(
598 mOnPasswordInteractionListener
599 );
600
601
602 } else {
603 /// no public share -> collapse section
604 Switch shareViaLinkSwitch = getShareViaLinkSwitch();
605 if (shareViaLinkSwitch.isChecked()) {
606 shareViaLinkSwitch.setOnCheckedChangeListener(null);
607 getShareViaLinkSwitch().setChecked(false);
608 shareViaLinkSwitch.setOnCheckedChangeListener(
609 mOnShareViaLinkSwitchCheckedChangeListener
610 );
611 }
612 getExpirationDateSection().setVisibility(View.GONE);
613 getPasswordSection().setVisibility(View.GONE);
614 getGetLinkButton().setVisibility(View.GONE);
615 }
616 }
617
618
619 /// BEWARE: next methods will failed with NullPointerException if called before onCreateView() finishes
620
621 private Switch getShareViaLinkSwitch() {
622 return (Switch) getView().findViewById(R.id.shareViaLinkSectionSwitch);
623 }
624
625 private View getExpirationDateSection() {
626 return getView().findViewById(R.id.shareViaLinkExpirationSection);
627 }
628
629 private Switch getExpirationDateSwitch() {
630 return (Switch) getView().findViewById(R.id.shareViaLinkExpirationSwitch);
631 }
632
633 private TextView getExpirationDateValue() {
634 return (TextView) getView().findViewById(R.id.shareViaLinkExpirationValue);
635 }
636
637 private View getPasswordSection() {
638 return getView().findViewById(R.id.shareViaLinkPasswordSection);
639 }
640
641 private Switch getPasswordSwitch() {
642 return (Switch) getView().findViewById(R.id.shareViaLinkPasswordSwitch);
643 }
644
645 private TextView getPasswordValue() {
646 return (TextView) getView().findViewById(R.id.shareViaLinkPasswordValue);
647 }
648
649 private AppCompatButton getGetLinkButton() {
650 return (AppCompatButton) getView().findViewById(R.id.shareViaLinkGetLinkButton);
651 }
652
653 /**
654 * Hides all the UI elements related to public share
655 */
656 private void hidePublicShare() {
657 getShareViaLinkSwitch().setVisibility(View.GONE);
658 getExpirationDateSection().setVisibility(View.GONE);
659 getPasswordSection().setVisibility(View.GONE);
660 getGetLinkButton().setVisibility(View.GONE);
661 }
662
663 public static void setListViewHeightBasedOnChildren(ListView listView) {
664 ListAdapter listAdapter = listView.getAdapter();
665 if (listAdapter == null) {
666 return;
667 }
668 int desiredWidth = View.MeasureSpec.makeMeasureSpec(listView.getWidth(), View.MeasureSpec.AT_MOST);
669 int totalHeight = 0;
670 View view = null;
671 for (int i = 0; i < listAdapter.getCount(); i++) {
672 view = listAdapter.getView(i, view, listView);
673 if (i == 0) {
674 view.setLayoutParams(new ViewGroup.LayoutParams(desiredWidth, ViewGroup.LayoutParams.WRAP_CONTENT));
675 }
676 view.measure(desiredWidth, View.MeasureSpec.UNSPECIFIED);
677 totalHeight += view.getMeasuredHeight();
678 }
679 ViewGroup.LayoutParams params = listView.getLayoutParams();
680 params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
681 listView.setLayoutParams(params);
682 listView.requestLayout();
683 }
684
685 /**
686 * This interface must be implemented by activities that contain this
687 * fragment to allow an interaction in this fragment to be communicated
688 * to the activity and potentially other fragments contained in that
689 * activity.
690 * <p/>
691 * See the Android Training lesson <a href=
692 * "http://developer.android.com/training/basics/fragments/communicating.html"
693 * >Communicating with Other Fragments</a> for more information.
694 */
695 public interface OnShareFragmentInteractionListener {
696 void showSearchUsersAndGroups();
697 void refreshUsersOrGroupsListFromServer();
698 void unshareWith(OCShare share);
699 }
700
701 }