• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.settings;
18 
19 import android.app.Activity;
20 import android.app.Dialog;
21 import android.app.DialogFragment;
22 import android.app.Fragment;
23 import android.content.ContentResolver;
24 import android.content.Context;
25 import android.content.DialogInterface;
26 import android.content.Intent;
27 import android.content.pm.PackageManager;
28 import android.os.Bundle;
29 import android.support.annotation.VisibleForTesting;
30 import android.support.annotation.XmlRes;
31 import android.support.v7.preference.Preference;
32 import android.support.v7.preference.PreferenceGroup;
33 import android.support.v7.preference.PreferenceScreen;
34 import android.support.v7.widget.LinearLayoutManager;
35 import android.support.v7.widget.RecyclerView;
36 import android.text.TextUtils;
37 import android.util.ArrayMap;
38 import android.util.Log;
39 import android.view.LayoutInflater;
40 import android.view.View;
41 import android.view.ViewGroup;
42 import android.widget.Button;
43 
44 import com.android.settings.applications.LayoutPreference;
45 import com.android.settings.core.InstrumentedPreferenceFragment;
46 import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
47 import com.android.settings.search.actionbar.SearchMenuController;
48 import com.android.settings.support.actionbar.HelpMenuController;
49 import com.android.settings.support.actionbar.HelpResourceProvider;
50 import com.android.settings.widget.HighlightablePreferenceGroupAdapter;
51 import com.android.settings.widget.LoadingViewController;
52 import com.android.settingslib.CustomDialogPreference;
53 import com.android.settingslib.CustomEditTextPreference;
54 import com.android.settingslib.core.instrumentation.Instrumentable;
55 import com.android.settingslib.widget.FooterPreferenceMixin;
56 
57 import java.util.UUID;
58 
59 /**
60  * Base class for Settings fragments, with some helper functions and dialog management.
61  */
62 public abstract class SettingsPreferenceFragment extends InstrumentedPreferenceFragment
63         implements DialogCreatable, HelpResourceProvider {
64 
65     private static final String TAG = "SettingsPreference";
66 
67     private static final String SAVE_HIGHLIGHTED_KEY = "android:preference_highlighted";
68 
69     protected final FooterPreferenceMixin mFooterPreferenceMixin =
70             new FooterPreferenceMixin(this, getLifecycle());
71 
72 
73     private static final int ORDER_FIRST = -1;
74 
75     private SettingsDialogFragment mDialogFragment;
76     // Cache the content resolver for async callbacks
77     private ContentResolver mContentResolver;
78 
79     private RecyclerView.Adapter mCurrentRootAdapter;
80     private boolean mIsDataSetObserverRegistered = false;
81     private RecyclerView.AdapterDataObserver mDataSetObserver =
82             new RecyclerView.AdapterDataObserver() {
83                 @Override
84                 public void onChanged() {
85                     onDataSetChanged();
86                 }
87 
88                 @Override
89                 public void onItemRangeChanged(int positionStart, int itemCount) {
90                     onDataSetChanged();
91                 }
92 
93                 @Override
94                 public void onItemRangeChanged(int positionStart, int itemCount, Object payload) {
95                     onDataSetChanged();
96                 }
97 
98                 @Override
99                 public void onItemRangeInserted(int positionStart, int itemCount) {
100                     onDataSetChanged();
101                 }
102 
103                 @Override
104                 public void onItemRangeRemoved(int positionStart, int itemCount) {
105                     onDataSetChanged();
106                 }
107 
108                 @Override
109                 public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
110                     onDataSetChanged();
111                 }
112             };
113 
114     private ViewGroup mPinnedHeaderFrameLayout;
115     private ViewGroup mButtonBar;
116 
117     private LayoutPreference mHeader;
118 
119     private View mEmptyView;
120     private LinearLayoutManager mLayoutManager;
121     private ArrayMap<String, Preference> mPreferenceCache;
122     private boolean mAnimationAllowed;
123 
124     @VisibleForTesting
125     public HighlightablePreferenceGroupAdapter mAdapter;
126     @VisibleForTesting
127     public boolean mPreferenceHighlighted = false;
128 
129     @Override
onCreate(Bundle icicle)130     public void onCreate(Bundle icicle) {
131         super.onCreate(icicle);
132         SearchMenuController.init(this /* host */);
133         HelpMenuController.init(this /* host */);
134 
135         if (icicle != null) {
136             mPreferenceHighlighted = icicle.getBoolean(SAVE_HIGHLIGHTED_KEY);
137         }
138         HighlightablePreferenceGroupAdapter.adjustInitialExpandedChildCount(this /* host */);
139     }
140 
141     @Override
onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)142     public View onCreateView(LayoutInflater inflater, ViewGroup container,
143             Bundle savedInstanceState) {
144         final View root = super.onCreateView(inflater, container, savedInstanceState);
145         mPinnedHeaderFrameLayout = root.findViewById(R.id.pinned_header);
146         mButtonBar = root.findViewById(R.id.button_bar);
147         return root;
148     }
149 
150     @Override
addPreferencesFromResource(@mlRes int preferencesResId)151     public void addPreferencesFromResource(@XmlRes int preferencesResId) {
152         super.addPreferencesFromResource(preferencesResId);
153         checkAvailablePrefs(getPreferenceScreen());
154     }
155 
checkAvailablePrefs(PreferenceGroup preferenceGroup)156     private void checkAvailablePrefs(PreferenceGroup preferenceGroup) {
157         if (preferenceGroup == null) return;
158         for (int i = 0; i < preferenceGroup.getPreferenceCount(); i++) {
159             Preference pref = preferenceGroup.getPreference(i);
160             if (pref instanceof SelfAvailablePreference
161                     && !((SelfAvailablePreference) pref).isAvailable(getContext())) {
162                 preferenceGroup.removePreference(pref);
163             } else if (pref instanceof PreferenceGroup) {
164                 checkAvailablePrefs((PreferenceGroup) pref);
165             }
166         }
167     }
168 
getButtonBar()169     public ViewGroup getButtonBar() {
170         return mButtonBar;
171     }
172 
setPinnedHeaderView(int layoutResId)173     public View setPinnedHeaderView(int layoutResId) {
174         final LayoutInflater inflater = getActivity().getLayoutInflater();
175         final View pinnedHeader =
176                 inflater.inflate(layoutResId, mPinnedHeaderFrameLayout, false);
177         setPinnedHeaderView(pinnedHeader);
178         return pinnedHeader;
179     }
180 
setPinnedHeaderView(View pinnedHeader)181     public void setPinnedHeaderView(View pinnedHeader) {
182         mPinnedHeaderFrameLayout.addView(pinnedHeader);
183         mPinnedHeaderFrameLayout.setVisibility(View.VISIBLE);
184     }
185 
186     @Override
onSaveInstanceState(Bundle outState)187     public void onSaveInstanceState(Bundle outState) {
188         super.onSaveInstanceState(outState);
189 
190         if (mAdapter != null) {
191             outState.putBoolean(SAVE_HIGHLIGHTED_KEY, mAdapter.isHighlightRequested());
192         }
193     }
194 
195     @Override
onActivityCreated(Bundle savedInstanceState)196     public void onActivityCreated(Bundle savedInstanceState) {
197         super.onActivityCreated(savedInstanceState);
198         setHasOptionsMenu(true);
199     }
200 
201     @Override
onResume()202     public void onResume() {
203         super.onResume();
204         highlightPreferenceIfNeeded();
205     }
206 
207     @Override
onBindPreferences()208     protected void onBindPreferences() {
209         registerObserverIfNeeded();
210     }
211 
212     @Override
onUnbindPreferences()213     protected void onUnbindPreferences() {
214         unregisterObserverIfNeeded();
215     }
216 
setLoading(boolean loading, boolean animate)217     public void setLoading(boolean loading, boolean animate) {
218         View loadingContainer = getView().findViewById(R.id.loading_container);
219         LoadingViewController.handleLoadingContainer(loadingContainer, getListView(),
220                 !loading /* done */,
221                 animate);
222     }
223 
registerObserverIfNeeded()224     public void registerObserverIfNeeded() {
225         if (!mIsDataSetObserverRegistered) {
226             if (mCurrentRootAdapter != null) {
227                 mCurrentRootAdapter.unregisterAdapterDataObserver(mDataSetObserver);
228             }
229             mCurrentRootAdapter = getListView().getAdapter();
230             mCurrentRootAdapter.registerAdapterDataObserver(mDataSetObserver);
231             mIsDataSetObserverRegistered = true;
232             onDataSetChanged();
233         }
234     }
235 
unregisterObserverIfNeeded()236     public void unregisterObserverIfNeeded() {
237         if (mIsDataSetObserverRegistered) {
238             if (mCurrentRootAdapter != null) {
239                 mCurrentRootAdapter.unregisterAdapterDataObserver(mDataSetObserver);
240                 mCurrentRootAdapter = null;
241             }
242             mIsDataSetObserverRegistered = false;
243         }
244     }
245 
highlightPreferenceIfNeeded()246     public void highlightPreferenceIfNeeded() {
247         if (!isAdded()) {
248             return;
249         }
250         if (mAdapter != null) {
251             mAdapter.requestHighlight(getView(), getListView());
252         }
253     }
254 
255     /**
256      * Returns initial expanded child count.
257      * <p/>
258      * Only override this method if the initial expanded child must be determined at run time.
259      */
getInitialExpandedChildCount()260     public int getInitialExpandedChildCount() {
261         return 0;
262     }
263 
onDataSetChanged()264     protected void onDataSetChanged() {
265         highlightPreferenceIfNeeded();
266         updateEmptyView();
267     }
268 
getHeaderView()269     public LayoutPreference getHeaderView() {
270         return mHeader;
271     }
272 
setHeaderView(int resource)273     protected void setHeaderView(int resource) {
274         mHeader = new LayoutPreference(getPrefContext(), resource);
275         addPreferenceToTop(mHeader);
276     }
277 
setHeaderView(View view)278     protected void setHeaderView(View view) {
279         mHeader = new LayoutPreference(getPrefContext(), view);
280         addPreferenceToTop(mHeader);
281     }
282 
addPreferenceToTop(LayoutPreference preference)283     private void addPreferenceToTop(LayoutPreference preference) {
284         preference.setOrder(ORDER_FIRST);
285         if (getPreferenceScreen() != null) {
286             getPreferenceScreen().addPreference(preference);
287         }
288     }
289 
290     @Override
setPreferenceScreen(PreferenceScreen preferenceScreen)291     public void setPreferenceScreen(PreferenceScreen preferenceScreen) {
292         if (preferenceScreen != null && !preferenceScreen.isAttached()) {
293             // Without ids generated, the RecyclerView won't animate changes to the preferences.
294             preferenceScreen.setShouldUseGeneratedIds(mAnimationAllowed);
295         }
296         super.setPreferenceScreen(preferenceScreen);
297         if (preferenceScreen != null) {
298             if (mHeader != null) {
299                 preferenceScreen.addPreference(mHeader);
300             }
301         }
302     }
303 
304     @VisibleForTesting
updateEmptyView()305     void updateEmptyView() {
306         if (mEmptyView == null) return;
307         if (getPreferenceScreen() != null) {
308             final View listContainer = getActivity().findViewById(android.R.id.list_container);
309             boolean show = (getPreferenceScreen().getPreferenceCount()
310                     - (mHeader != null ? 1 : 0)
311                     - (mFooterPreferenceMixin.hasFooter() ? 1 : 0)) <= 0
312                     || (listContainer != null && listContainer.getVisibility() != View.VISIBLE);
313             mEmptyView.setVisibility(show ? View.VISIBLE : View.GONE);
314         } else {
315             mEmptyView.setVisibility(View.VISIBLE);
316         }
317     }
318 
setEmptyView(View v)319     public void setEmptyView(View v) {
320         if (mEmptyView != null) {
321             mEmptyView.setVisibility(View.GONE);
322         }
323         mEmptyView = v;
324         updateEmptyView();
325     }
326 
getEmptyView()327     public View getEmptyView() {
328         return mEmptyView;
329     }
330 
331     @Override
onCreateLayoutManager()332     public RecyclerView.LayoutManager onCreateLayoutManager() {
333         mLayoutManager = new LinearLayoutManager(getContext());
334         return mLayoutManager;
335     }
336 
337     @Override
onCreateAdapter(PreferenceScreen preferenceScreen)338     protected RecyclerView.Adapter onCreateAdapter(PreferenceScreen preferenceScreen) {
339         final Bundle arguments = getArguments();
340         mAdapter = new HighlightablePreferenceGroupAdapter(preferenceScreen,
341                 arguments == null
342                         ? null : arguments.getString(SettingsActivity.EXTRA_FRAGMENT_ARG_KEY),
343                 mPreferenceHighlighted);
344         return mAdapter;
345     }
346 
setAnimationAllowed(boolean animationAllowed)347     protected void setAnimationAllowed(boolean animationAllowed) {
348         mAnimationAllowed = animationAllowed;
349     }
350 
cacheRemoveAllPrefs(PreferenceGroup group)351     protected void cacheRemoveAllPrefs(PreferenceGroup group) {
352         mPreferenceCache = new ArrayMap<>();
353         final int N = group.getPreferenceCount();
354         for (int i = 0; i < N; i++) {
355             Preference p = group.getPreference(i);
356             if (TextUtils.isEmpty(p.getKey())) {
357                 continue;
358             }
359             mPreferenceCache.put(p.getKey(), p);
360         }
361     }
362 
getCachedPreference(String key)363     protected Preference getCachedPreference(String key) {
364         return mPreferenceCache != null ? mPreferenceCache.remove(key) : null;
365     }
366 
removeCachedPrefs(PreferenceGroup group)367     protected void removeCachedPrefs(PreferenceGroup group) {
368         for (Preference p : mPreferenceCache.values()) {
369             group.removePreference(p);
370         }
371         mPreferenceCache = null;
372     }
373 
getCachedCount()374     protected int getCachedCount() {
375         return mPreferenceCache != null ? mPreferenceCache.size() : 0;
376     }
377 
378     @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
removePreference(String key)379     public boolean removePreference(String key) {
380         return removePreference(getPreferenceScreen(), key);
381     }
382 
383     @VisibleForTesting
removePreference(PreferenceGroup group, String key)384     boolean removePreference(PreferenceGroup group, String key) {
385         final int preferenceCount = group.getPreferenceCount();
386         for (int i = 0; i < preferenceCount; i++) {
387             final Preference preference = group.getPreference(i);
388             final String curKey = preference.getKey();
389 
390             if (TextUtils.equals(curKey, key)) {
391                 return group.removePreference(preference);
392             }
393 
394             if (preference instanceof PreferenceGroup) {
395                 if (removePreference((PreferenceGroup) preference, key)) {
396                     return true;
397                 }
398             }
399         }
400         return false;
401     }
402 
403     /*
404      * The name is intentionally made different from Activity#finish(), so that
405      * users won't misunderstand its meaning.
406      */
finishFragment()407     public final void finishFragment() {
408         getActivity().onBackPressed();
409     }
410 
411     // Some helpers for functions used by the settings fragments when they were activities
412 
413     /**
414      * Returns the ContentResolver from the owning Activity.
415      */
getContentResolver()416     protected ContentResolver getContentResolver() {
417         Context context = getActivity();
418         if (context != null) {
419             mContentResolver = context.getContentResolver();
420         }
421         return mContentResolver;
422     }
423 
424     /**
425      * Returns the specified system service from the owning Activity.
426      */
getSystemService(final String name)427     protected Object getSystemService(final String name) {
428         return getActivity().getSystemService(name);
429     }
430 
431     /**
432      * Returns the PackageManager from the owning Activity.
433      */
getPackageManager()434     protected PackageManager getPackageManager() {
435         return getActivity().getPackageManager();
436     }
437 
438     @Override
onDetach()439     public void onDetach() {
440         if (isRemoving()) {
441             if (mDialogFragment != null) {
442                 mDialogFragment.dismiss();
443                 mDialogFragment = null;
444             }
445         }
446         super.onDetach();
447     }
448 
449     // Dialog management
450 
showDialog(int dialogId)451     protected void showDialog(int dialogId) {
452         if (mDialogFragment != null) {
453             Log.e(TAG, "Old dialog fragment not null!");
454         }
455         mDialogFragment = new SettingsDialogFragment(this, dialogId);
456         mDialogFragment.show(getChildFragmentManager(), Integer.toString(dialogId));
457     }
458 
459     @Override
onCreateDialog(int dialogId)460     public Dialog onCreateDialog(int dialogId) {
461         return null;
462     }
463 
464     @Override
getDialogMetricsCategory(int dialogId)465     public int getDialogMetricsCategory(int dialogId) {
466         return 0;
467     }
468 
removeDialog(int dialogId)469     protected void removeDialog(int dialogId) {
470         // mDialogFragment may not be visible yet in parent fragment's onResume().
471         // To be able to dismiss dialog at that time, don't check
472         // mDialogFragment.isVisible().
473         if (mDialogFragment != null && mDialogFragment.getDialogId() == dialogId) {
474             mDialogFragment.dismissAllowingStateLoss();
475         }
476         mDialogFragment = null;
477     }
478 
479     /**
480      * Sets the OnCancelListener of the dialog shown. This method can only be
481      * called after showDialog(int) and before removeDialog(int). The method
482      * does nothing otherwise.
483      */
setOnCancelListener(DialogInterface.OnCancelListener listener)484     protected void setOnCancelListener(DialogInterface.OnCancelListener listener) {
485         if (mDialogFragment != null) {
486             mDialogFragment.mOnCancelListener = listener;
487         }
488     }
489 
490     /**
491      * Sets the OnDismissListener of the dialog shown. This method can only be
492      * called after showDialog(int) and before removeDialog(int). The method
493      * does nothing otherwise.
494      */
setOnDismissListener(DialogInterface.OnDismissListener listener)495     protected void setOnDismissListener(DialogInterface.OnDismissListener listener) {
496         if (mDialogFragment != null) {
497             mDialogFragment.mOnDismissListener = listener;
498         }
499     }
500 
onDialogShowing()501     public void onDialogShowing() {
502         // override in subclass to attach a dismiss listener, for instance
503     }
504 
505     @Override
onDisplayPreferenceDialog(Preference preference)506     public void onDisplayPreferenceDialog(Preference preference) {
507         if (preference.getKey() == null) {
508             // Auto-key preferences that don't have a key, so the dialog can find them.
509             preference.setKey(UUID.randomUUID().toString());
510         }
511         DialogFragment f = null;
512         if (preference instanceof RestrictedListPreference) {
513             f = RestrictedListPreference.RestrictedListPreferenceDialogFragment
514                     .newInstance(preference.getKey());
515         } else if (preference instanceof CustomListPreference) {
516             f = CustomListPreference.CustomListPreferenceDialogFragment
517                     .newInstance(preference.getKey());
518         } else if (preference instanceof CustomDialogPreference) {
519             f = CustomDialogPreference.CustomPreferenceDialogFragment
520                     .newInstance(preference.getKey());
521         } else if (preference instanceof CustomEditTextPreference) {
522             f = CustomEditTextPreference.CustomPreferenceDialogFragment
523                     .newInstance(preference.getKey());
524         } else {
525             super.onDisplayPreferenceDialog(preference);
526             return;
527         }
528         f.setTargetFragment(this, 0);
529         f.show(getFragmentManager(), "dialog_preference");
530         onDialogShowing();
531     }
532 
533     public static class SettingsDialogFragment extends InstrumentedDialogFragment {
534         private static final String KEY_DIALOG_ID = "key_dialog_id";
535         private static final String KEY_PARENT_FRAGMENT_ID = "key_parent_fragment_id";
536 
537         private Fragment mParentFragment;
538 
539         private DialogInterface.OnCancelListener mOnCancelListener;
540         private DialogInterface.OnDismissListener mOnDismissListener;
541 
SettingsDialogFragment()542         public SettingsDialogFragment() {
543             /* do nothing */
544         }
545 
SettingsDialogFragment(DialogCreatable fragment, int dialogId)546         public SettingsDialogFragment(DialogCreatable fragment, int dialogId) {
547             super(fragment, dialogId);
548             if (!(fragment instanceof Fragment)) {
549                 throw new IllegalArgumentException("fragment argument must be an instance of "
550                         + Fragment.class.getName());
551             }
552             mParentFragment = (Fragment) fragment;
553         }
554 
555 
556         @Override
getMetricsCategory()557         public int getMetricsCategory() {
558             if (mDialogCreatable == null) {
559                 return Instrumentable.METRICS_CATEGORY_UNKNOWN;
560             }
561             final int metricsCategory = mDialogCreatable.getDialogMetricsCategory(mDialogId);
562             if (metricsCategory <= 0) {
563                 throw new IllegalStateException("Dialog must provide a metrics category");
564             }
565             return metricsCategory;
566         }
567 
568         @Override
onSaveInstanceState(Bundle outState)569         public void onSaveInstanceState(Bundle outState) {
570             super.onSaveInstanceState(outState);
571             if (mParentFragment != null) {
572                 outState.putInt(KEY_DIALOG_ID, mDialogId);
573                 outState.putInt(KEY_PARENT_FRAGMENT_ID, mParentFragment.getId());
574             }
575         }
576 
577         @Override
onStart()578         public void onStart() {
579             super.onStart();
580 
581             if (mParentFragment != null && mParentFragment instanceof SettingsPreferenceFragment) {
582                 ((SettingsPreferenceFragment) mParentFragment).onDialogShowing();
583             }
584         }
585 
586         @Override
onCreateDialog(Bundle savedInstanceState)587         public Dialog onCreateDialog(Bundle savedInstanceState) {
588             if (savedInstanceState != null) {
589                 mDialogId = savedInstanceState.getInt(KEY_DIALOG_ID, 0);
590                 mParentFragment = getParentFragment();
591                 int mParentFragmentId = savedInstanceState.getInt(KEY_PARENT_FRAGMENT_ID, -1);
592                 if (mParentFragment == null) {
593                     mParentFragment = getFragmentManager().findFragmentById(mParentFragmentId);
594                 }
595                 if (!(mParentFragment instanceof DialogCreatable)) {
596                     throw new IllegalArgumentException(
597                             (mParentFragment != null
598                                     ? mParentFragment.getClass().getName()
599                                     : mParentFragmentId)
600                                     + " must implement "
601                                     + DialogCreatable.class.getName());
602                 }
603                 // This dialog fragment could be created from non-SettingsPreferenceFragment
604                 if (mParentFragment instanceof SettingsPreferenceFragment) {
605                     // restore mDialogFragment in mParentFragment
606                     ((SettingsPreferenceFragment) mParentFragment).mDialogFragment = this;
607                 }
608             }
609             return ((DialogCreatable) mParentFragment).onCreateDialog(mDialogId);
610         }
611 
612         @Override
onCancel(DialogInterface dialog)613         public void onCancel(DialogInterface dialog) {
614             super.onCancel(dialog);
615             if (mOnCancelListener != null) {
616                 mOnCancelListener.onCancel(dialog);
617             }
618         }
619 
620         @Override
onDismiss(DialogInterface dialog)621         public void onDismiss(DialogInterface dialog) {
622             super.onDismiss(dialog);
623             if (mOnDismissListener != null) {
624                 mOnDismissListener.onDismiss(dialog);
625             }
626         }
627 
getDialogId()628         public int getDialogId() {
629             return mDialogId;
630         }
631 
632         @Override
onDetach()633         public void onDetach() {
634             super.onDetach();
635 
636             // This dialog fragment could be created from non-SettingsPreferenceFragment
637             if (mParentFragment instanceof SettingsPreferenceFragment) {
638                 // in case the dialog is not explicitly removed by removeDialog()
639                 if (((SettingsPreferenceFragment) mParentFragment).mDialogFragment == this) {
640                     ((SettingsPreferenceFragment) mParentFragment).mDialogFragment = null;
641                 }
642             }
643         }
644     }
645 
hasNextButton()646     protected boolean hasNextButton() {
647         return ((ButtonBarHandler) getActivity()).hasNextButton();
648     }
649 
getNextButton()650     protected Button getNextButton() {
651         return ((ButtonBarHandler) getActivity()).getNextButton();
652     }
653 
finish()654     public void finish() {
655         Activity activity = getActivity();
656         if (activity == null) return;
657         if (getFragmentManager().getBackStackEntryCount() > 0) {
658             getFragmentManager().popBackStack();
659         } else {
660             activity.finish();
661         }
662     }
663 
getIntent()664     protected Intent getIntent() {
665         if (getActivity() == null) {
666             return null;
667         }
668         return getActivity().getIntent();
669     }
670 
setResult(int result, Intent intent)671     protected void setResult(int result, Intent intent) {
672         if (getActivity() == null) {
673             return;
674         }
675         getActivity().setResult(result, intent);
676     }
677 
setResult(int result)678     protected void setResult(int result) {
679         if (getActivity() == null) {
680             return;
681         }
682         getActivity().setResult(result);
683     }
684 }
685