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