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