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