• 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.XmlRes;
30 import android.support.v7.preference.Preference;
31 import android.support.v7.preference.PreferenceGroup;
32 import android.support.v7.preference.PreferenceGroupAdapter;
33 import android.support.v7.preference.PreferenceScreen;
34 import android.support.v7.preference.PreferenceViewHolder;
35 import android.support.v7.widget.LinearLayoutManager;
36 import android.support.v7.widget.RecyclerView;
37 import android.text.TextUtils;
38 import android.util.ArrayMap;
39 import android.util.Log;
40 import android.view.LayoutInflater;
41 import android.view.Menu;
42 import android.view.MenuInflater;
43 import android.view.View;
44 import android.view.ViewGroup;
45 import android.widget.Button;
46 
47 import com.android.settings.applications.LayoutPreference;
48 import com.android.settings.widget.FloatingActionButton;
49 import com.android.settingslib.HelpUtils;
50 
51 import java.util.UUID;
52 
53 /**
54  * Base class for Settings fragments, with some helper functions and dialog management.
55  */
56 public abstract class SettingsPreferenceFragment extends InstrumentedPreferenceFragment
57         implements DialogCreatable {
58 
59     /**
60      * The Help Uri Resource key. This can be passed as an extra argument when creating the
61      * Fragment.
62      **/
63     public static final String HELP_URI_RESOURCE_KEY = "help_uri_resource";
64 
65     private static final String TAG = "SettingsPreference";
66 
67     private static final int DELAY_HIGHLIGHT_DURATION_MILLIS = 600;
68 
69     private static final String SAVE_HIGHLIGHTED_KEY = "android:preference_highlighted";
70 
71     private SettingsDialogFragment mDialogFragment;
72 
73     private String mHelpUri;
74 
75     private static final int ORDER_FIRST = -1;
76     private static final int ORDER_LAST = Integer.MAX_VALUE -1;
77 
78     // Cache the content resolver for async callbacks
79     private ContentResolver mContentResolver;
80 
81     private String mPreferenceKey;
82     private boolean mPreferenceHighlighted = false;
83 
84     private RecyclerView.Adapter mCurrentRootAdapter;
85     private boolean mIsDataSetObserverRegistered = false;
86     private RecyclerView.AdapterDataObserver mDataSetObserver =
87             new RecyclerView.AdapterDataObserver() {
88         @Override
89         public void onChanged() {
90             onDataSetChanged();
91         }
92     };
93 
94     private ViewGroup mPinnedHeaderFrameLayout;
95     private FloatingActionButton mFloatingActionButton;
96     private ViewGroup mButtonBar;
97 
98     private LayoutPreference mHeader;
99 
100     private LayoutPreference mFooter;
101     private View mEmptyView;
102     private LinearLayoutManager mLayoutManager;
103     private HighlightablePreferenceGroupAdapter mAdapter;
104     private ArrayMap<String, Preference> mPreferenceCache;
105     private boolean mAnimationAllowed;
106 
107     @Override
onCreate(Bundle icicle)108     public void onCreate(Bundle icicle) {
109         super.onCreate(icicle);
110 
111         if (icicle != null) {
112             mPreferenceHighlighted = icicle.getBoolean(SAVE_HIGHLIGHTED_KEY);
113         }
114 
115         // Prepare help url and enable menu if necessary
116         Bundle arguments = getArguments();
117         int helpResource;
118         if (arguments != null && arguments.containsKey(HELP_URI_RESOURCE_KEY)) {
119             helpResource = arguments.getInt(HELP_URI_RESOURCE_KEY);
120         } else {
121             helpResource = getHelpResource();
122         }
123         if (helpResource != 0) {
124             mHelpUri = getResources().getString(helpResource);
125         }
126     }
127 
128     @Override
onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)129     public View onCreateView(LayoutInflater inflater, ViewGroup container,
130             Bundle savedInstanceState) {
131         final View root = super.onCreateView(inflater, container, savedInstanceState);
132         mPinnedHeaderFrameLayout = (ViewGroup) root.findViewById(R.id.pinned_header);
133         mFloatingActionButton = (FloatingActionButton) root.findViewById(R.id.fab);
134         mButtonBar = (ViewGroup) root.findViewById(R.id.button_bar);
135         return root;
136     }
137 
138     @Override
onCreatePreferences(Bundle savedInstanceState, String rootKey)139     public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
140     }
141 
142     @Override
addPreferencesFromResource(@mlRes int preferencesResId)143     public void addPreferencesFromResource(@XmlRes int preferencesResId) {
144         super.addPreferencesFromResource(preferencesResId);
145         checkAvailablePrefs(getPreferenceScreen());
146     }
147 
checkAvailablePrefs(PreferenceGroup preferenceGroup)148     private void checkAvailablePrefs(PreferenceGroup preferenceGroup) {
149         if (preferenceGroup == null) return;
150         for (int i = 0; i < preferenceGroup.getPreferenceCount(); i++) {
151             Preference pref = preferenceGroup.getPreference(i);
152             if (pref instanceof SelfAvailablePreference
153                     && !((SelfAvailablePreference) pref).isAvailable(getContext())) {
154                 preferenceGroup.removePreference(pref);
155             } else if (pref instanceof PreferenceGroup) {
156                 checkAvailablePrefs((PreferenceGroup) pref);
157             }
158         }
159     }
160 
getFloatingActionButton()161     public FloatingActionButton getFloatingActionButton() {
162         return mFloatingActionButton;
163     }
164 
getButtonBar()165     public ViewGroup getButtonBar() {
166         return mButtonBar;
167     }
168 
setPinnedHeaderView(int layoutResId)169     public View setPinnedHeaderView(int layoutResId) {
170         final LayoutInflater inflater = getActivity().getLayoutInflater();
171         final View pinnedHeader =
172                 inflater.inflate(layoutResId, mPinnedHeaderFrameLayout, false);
173         setPinnedHeaderView(pinnedHeader);
174         return pinnedHeader;
175     }
176 
setPinnedHeaderView(View pinnedHeader)177     public void setPinnedHeaderView(View pinnedHeader) {
178         mPinnedHeaderFrameLayout.addView(pinnedHeader);
179         mPinnedHeaderFrameLayout.setVisibility(View.VISIBLE);
180     }
181 
182     @Override
onSaveInstanceState(Bundle outState)183     public void onSaveInstanceState(Bundle outState) {
184         super.onSaveInstanceState(outState);
185 
186         outState.putBoolean(SAVE_HIGHLIGHTED_KEY, mPreferenceHighlighted);
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 
199         final Bundle args = getArguments();
200         if (args != null) {
201             mPreferenceKey = args.getString(SettingsActivity.EXTRA_FRAGMENT_ARG_KEY);
202             highlightPreferenceIfNeeded();
203         }
204     }
205 
206     @Override
onBindPreferences()207     protected void onBindPreferences() {
208         registerObserverIfNeeded();
209     }
210 
211     @Override
onUnbindPreferences()212     protected void onUnbindPreferences() {
213         unregisterObserverIfNeeded();
214     }
215 
showLoadingWhenEmpty()216     public void showLoadingWhenEmpty() {
217         View loading = getView().findViewById(R.id.loading_container);
218         setEmptyView(loading);
219     }
220 
setLoading(boolean loading, boolean animate)221     public void setLoading(boolean loading, boolean animate) {
222         View loading_container = getView().findViewById(R.id.loading_container);
223         Utils.handleLoadingContainer(loading_container, getListView(), !loading, animate);
224     }
225 
registerObserverIfNeeded()226     public void registerObserverIfNeeded() {
227         if (!mIsDataSetObserverRegistered) {
228             if (mCurrentRootAdapter != null) {
229                 mCurrentRootAdapter.unregisterAdapterDataObserver(mDataSetObserver);
230             }
231             mCurrentRootAdapter = getListView().getAdapter();
232             mCurrentRootAdapter.registerAdapterDataObserver(mDataSetObserver);
233             mIsDataSetObserverRegistered = true;
234             onDataSetChanged();
235         }
236     }
237 
unregisterObserverIfNeeded()238     public void unregisterObserverIfNeeded() {
239         if (mIsDataSetObserverRegistered) {
240             if (mCurrentRootAdapter != null) {
241                 mCurrentRootAdapter.unregisterAdapterDataObserver(mDataSetObserver);
242                 mCurrentRootAdapter = null;
243             }
244             mIsDataSetObserverRegistered = false;
245         }
246     }
247 
highlightPreferenceIfNeeded()248     public void highlightPreferenceIfNeeded() {
249         if (isAdded() && !mPreferenceHighlighted &&!TextUtils.isEmpty(mPreferenceKey)) {
250             highlightPreference(mPreferenceKey);
251         }
252     }
253 
onDataSetChanged()254     protected void onDataSetChanged() {
255         highlightPreferenceIfNeeded();
256         updateEmptyView();
257     }
258 
getHeaderView()259     public LayoutPreference getHeaderView() {
260         return mHeader;
261     }
262 
getFooterView()263     public LayoutPreference getFooterView() {
264         return mFooter;
265     }
266 
setHeaderView(int resource)267     protected void setHeaderView(int resource) {
268         mHeader = new LayoutPreference(getPrefContext(), resource);
269         addPreferenceToTop(mHeader);
270     }
271 
setHeaderView(View view)272     protected void setHeaderView(View view) {
273         mHeader = new LayoutPreference(getPrefContext(), view);
274         addPreferenceToTop(mHeader);
275     }
276 
addPreferenceToTop(LayoutPreference preference)277     private void addPreferenceToTop(LayoutPreference preference) {
278         preference.setOrder(ORDER_FIRST);
279         if (getPreferenceScreen() != null) {
280             getPreferenceScreen().addPreference(preference);
281         }
282     }
283 
setFooterView(int resource)284     protected void setFooterView(int resource) {
285         setFooterView(resource != 0 ? new LayoutPreference(getPrefContext(), resource) : null);
286     }
287 
setFooterView(View v)288     protected void setFooterView(View v) {
289         setFooterView(v != null ? new LayoutPreference(getPrefContext(), v) : null);
290     }
291 
setFooterView(LayoutPreference footer)292     private void setFooterView(LayoutPreference footer) {
293         if (getPreferenceScreen() != null && mFooter != null) {
294             getPreferenceScreen().removePreference(mFooter);
295         }
296         if (footer != null) {
297             mFooter = footer;
298             mFooter.setOrder(ORDER_LAST);
299             if (getPreferenceScreen() != null) {
300                 getPreferenceScreen().addPreference(mFooter);
301             }
302         } else {
303             mFooter = null;
304         }
305     }
306 
307     @Override
setPreferenceScreen(PreferenceScreen preferenceScreen)308     public void setPreferenceScreen(PreferenceScreen preferenceScreen) {
309         if (preferenceScreen != null && !preferenceScreen.isAttached()) {
310             // Without ids generated, the RecyclerView won't animate changes to the preferences.
311             preferenceScreen.setShouldUseGeneratedIds(mAnimationAllowed);
312         }
313         super.setPreferenceScreen(preferenceScreen);
314         if (preferenceScreen != null) {
315             if (mHeader != null) {
316                 preferenceScreen.addPreference(mHeader);
317             }
318             if (mFooter != null) {
319                 preferenceScreen.addPreference(mFooter);
320             }
321         }
322     }
323 
updateEmptyView()324     private void updateEmptyView() {
325         if (mEmptyView == null) return;
326         if (getPreferenceScreen() != null) {
327             boolean show = (getPreferenceScreen().getPreferenceCount()
328                     - (mHeader != null ? 1 : 0)
329                     - (mFooter != null ? 1 : 0)) <= 0;
330             mEmptyView.setVisibility(show ? View.VISIBLE : View.GONE);
331         } else {
332             mEmptyView.setVisibility(View.VISIBLE);
333         }
334     }
335 
setEmptyView(View v)336     public void setEmptyView(View v) {
337         if (mEmptyView != null) {
338             mEmptyView.setVisibility(View.GONE);
339         }
340         mEmptyView = v;
341         updateEmptyView();
342     }
343 
getEmptyView()344     public View getEmptyView() {
345         return mEmptyView;
346     }
347 
348     /**
349      * Return a valid ListView position or -1 if none is found
350      */
canUseListViewForHighLighting(String key)351     private int canUseListViewForHighLighting(String key) {
352         if (getListView() == null) {
353             return -1;
354         }
355 
356         RecyclerView listView = getListView();
357         RecyclerView.Adapter adapter = listView.getAdapter();
358 
359         if (adapter != null && adapter instanceof PreferenceGroupAdapter) {
360             return findListPositionFromKey((PreferenceGroupAdapter) adapter, key);
361         }
362 
363         return -1;
364     }
365 
366     @Override
onCreateLayoutManager()367     public RecyclerView.LayoutManager onCreateLayoutManager() {
368         mLayoutManager = new LinearLayoutManager(getContext());
369         return mLayoutManager;
370     }
371 
372     @Override
onCreateAdapter(PreferenceScreen preferenceScreen)373     protected RecyclerView.Adapter onCreateAdapter(PreferenceScreen preferenceScreen) {
374         mAdapter = new HighlightablePreferenceGroupAdapter(preferenceScreen);
375         return mAdapter;
376     }
377 
setAnimationAllowed(boolean animationAllowed)378     protected void setAnimationAllowed(boolean animationAllowed) {
379         mAnimationAllowed = animationAllowed;
380     }
381 
cacheRemoveAllPrefs(PreferenceGroup group)382     protected void cacheRemoveAllPrefs(PreferenceGroup group) {
383         mPreferenceCache = new ArrayMap<String, Preference>();
384         final int N = group.getPreferenceCount();
385         for (int i = 0; i < N; i++) {
386             Preference p = group.getPreference(i);
387             if (TextUtils.isEmpty(p.getKey())) {
388                 continue;
389             }
390             mPreferenceCache.put(p.getKey(), p);
391         }
392     }
393 
getCachedPreference(String key)394     protected Preference getCachedPreference(String key) {
395         return mPreferenceCache != null ? mPreferenceCache.remove(key) : null;
396     }
397 
removeCachedPrefs(PreferenceGroup group)398     protected void removeCachedPrefs(PreferenceGroup group) {
399         for (Preference p : mPreferenceCache.values()) {
400             group.removePreference(p);
401         }
402         mPreferenceCache = null;
403     }
404 
getCachedCount()405     protected int getCachedCount() {
406         return mPreferenceCache != null ? mPreferenceCache.size() : 0;
407     }
408 
highlightPreference(String key)409     private void highlightPreference(String key) {
410         final int position = canUseListViewForHighLighting(key);
411         if (position >= 0) {
412             mPreferenceHighlighted = true;
413             mLayoutManager.scrollToPosition(position);
414 
415             getView().postDelayed(new Runnable() {
416                 @Override
417                 public void run() {
418                     mAdapter.highlight(position);
419                 }
420             }, DELAY_HIGHLIGHT_DURATION_MILLIS);
421         }
422     }
423 
findListPositionFromKey(PreferenceGroupAdapter adapter, String key)424     private int findListPositionFromKey(PreferenceGroupAdapter adapter, String key) {
425         final int count = adapter.getItemCount();
426         for (int n = 0; n < count; n++) {
427             final Preference preference = adapter.getItem(n);
428             final String preferenceKey = preference.getKey();
429             if (preferenceKey != null && preferenceKey.equals(key)) {
430                 return n;
431             }
432         }
433         return -1;
434     }
435 
removePreference(String key)436     protected void removePreference(String key) {
437         Preference pref = findPreference(key);
438         if (pref != null) {
439             getPreferenceScreen().removePreference(pref);
440         }
441     }
442 
443     /**
444      * Override this if you want to show a help item in the menu, by returning the resource id.
445      * @return the resource id for the help url
446      */
getHelpResource()447     protected int getHelpResource() {
448         return R.string.help_uri_default;
449     }
450 
451     @Override
onCreateOptionsMenu(Menu menu, MenuInflater inflater)452     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
453         if (mHelpUri != null && getActivity() != null) {
454             HelpUtils.prepareHelpMenuItem(getActivity(), menu, mHelpUri, getClass().getName());
455         }
456     }
457 
458     /*
459      * The name is intentionally made different from Activity#finish(), so that
460      * users won't misunderstand its meaning.
461      */
finishFragment()462     public final void finishFragment() {
463         getActivity().onBackPressed();
464     }
465 
466     // Some helpers for functions used by the settings fragments when they were activities
467 
468     /**
469      * Returns the ContentResolver from the owning Activity.
470      */
getContentResolver()471     protected ContentResolver getContentResolver() {
472         Context context = getActivity();
473         if (context != null) {
474             mContentResolver = context.getContentResolver();
475         }
476         return mContentResolver;
477     }
478 
479     /**
480      * Returns the specified system service from the owning Activity.
481      */
getSystemService(final String name)482     protected Object getSystemService(final String name) {
483         return getActivity().getSystemService(name);
484     }
485 
486     /**
487      * Returns the PackageManager from the owning Activity.
488      */
getPackageManager()489     protected PackageManager getPackageManager() {
490         return getActivity().getPackageManager();
491     }
492 
493     @Override
onDetach()494     public void onDetach() {
495         if (isRemoving()) {
496             if (mDialogFragment != null) {
497                 mDialogFragment.dismiss();
498                 mDialogFragment = null;
499             }
500         }
501         super.onDetach();
502     }
503 
504     // Dialog management
505 
showDialog(int dialogId)506     protected void showDialog(int dialogId) {
507         if (mDialogFragment != null) {
508             Log.e(TAG, "Old dialog fragment not null!");
509         }
510         mDialogFragment = new SettingsDialogFragment(this, dialogId);
511         mDialogFragment.show(getChildFragmentManager(), Integer.toString(dialogId));
512     }
513 
onCreateDialog(int dialogId)514     public Dialog onCreateDialog(int dialogId) {
515         return null;
516     }
517 
removeDialog(int dialogId)518     protected void removeDialog(int dialogId) {
519         // mDialogFragment may not be visible yet in parent fragment's onResume().
520         // To be able to dismiss dialog at that time, don't check
521         // mDialogFragment.isVisible().
522         if (mDialogFragment != null && mDialogFragment.getDialogId() == dialogId) {
523             mDialogFragment.dismissAllowingStateLoss();
524         }
525         mDialogFragment = null;
526     }
527 
528     /**
529      * Sets the OnCancelListener of the dialog shown. This method can only be
530      * called after showDialog(int) and before removeDialog(int). The method
531      * does nothing otherwise.
532      */
setOnCancelListener(DialogInterface.OnCancelListener listener)533     protected void setOnCancelListener(DialogInterface.OnCancelListener listener) {
534         if (mDialogFragment != null) {
535             mDialogFragment.mOnCancelListener = listener;
536         }
537     }
538 
539     /**
540      * Sets the OnDismissListener of the dialog shown. This method can only be
541      * called after showDialog(int) and before removeDialog(int). The method
542      * does nothing otherwise.
543      */
setOnDismissListener(DialogInterface.OnDismissListener listener)544     protected void setOnDismissListener(DialogInterface.OnDismissListener listener) {
545         if (mDialogFragment != null) {
546             mDialogFragment.mOnDismissListener = listener;
547         }
548     }
549 
onDialogShowing()550     public void onDialogShowing() {
551         // override in subclass to attach a dismiss listener, for instance
552     }
553 
554     @Override
onDisplayPreferenceDialog(Preference preference)555     public void onDisplayPreferenceDialog(Preference preference) {
556         if (preference.getKey() == null) {
557             // Auto-key preferences that don't have a key, so the dialog can find them.
558             preference.setKey(UUID.randomUUID().toString());
559         }
560         DialogFragment f = null;
561         if (preference instanceof RestrictedListPreference) {
562             f = RestrictedListPreference.RestrictedListPreferenceDialogFragment
563                     .newInstance(preference.getKey());
564         } else if (preference instanceof CustomListPreference) {
565             f = CustomListPreference.CustomListPreferenceDialogFragment
566                     .newInstance(preference.getKey());
567         } else if (preference instanceof CustomDialogPreference) {
568             f = CustomDialogPreference.CustomPreferenceDialogFragment
569                     .newInstance(preference.getKey());
570         } else if (preference instanceof CustomEditTextPreference) {
571             f = CustomEditTextPreference.CustomPreferenceDialogFragment
572                     .newInstance(preference.getKey());
573         } else {
574             super.onDisplayPreferenceDialog(preference);
575             return;
576         }
577         f.setTargetFragment(this, 0);
578         f.show(getFragmentManager(), "dialog_preference");
579         onDialogShowing();
580     }
581 
582     public static class SettingsDialogFragment extends DialogFragment {
583         private static final String KEY_DIALOG_ID = "key_dialog_id";
584         private static final String KEY_PARENT_FRAGMENT_ID = "key_parent_fragment_id";
585 
586         private int mDialogId;
587 
588         private Fragment mParentFragment;
589 
590         private DialogInterface.OnCancelListener mOnCancelListener;
591         private DialogInterface.OnDismissListener mOnDismissListener;
592 
SettingsDialogFragment()593         public SettingsDialogFragment() {
594             /* do nothing */
595         }
596 
SettingsDialogFragment(DialogCreatable fragment, int dialogId)597         public SettingsDialogFragment(DialogCreatable fragment, int dialogId) {
598             mDialogId = dialogId;
599             if (!(fragment instanceof Fragment)) {
600                 throw new IllegalArgumentException("fragment argument must be an instance of "
601                         + Fragment.class.getName());
602             }
603             mParentFragment = (Fragment) fragment;
604         }
605 
606         @Override
onSaveInstanceState(Bundle outState)607         public void onSaveInstanceState(Bundle outState) {
608             super.onSaveInstanceState(outState);
609             if (mParentFragment != null) {
610                 outState.putInt(KEY_DIALOG_ID, mDialogId);
611                 outState.putInt(KEY_PARENT_FRAGMENT_ID, mParentFragment.getId());
612             }
613         }
614 
615         @Override
onStart()616         public void onStart() {
617             super.onStart();
618 
619             if (mParentFragment != null && mParentFragment instanceof SettingsPreferenceFragment) {
620                 ((SettingsPreferenceFragment) mParentFragment).onDialogShowing();
621             }
622         }
623 
624         @Override
onCreateDialog(Bundle savedInstanceState)625         public Dialog onCreateDialog(Bundle savedInstanceState) {
626             if (savedInstanceState != null) {
627                 mDialogId = savedInstanceState.getInt(KEY_DIALOG_ID, 0);
628                 mParentFragment = getParentFragment();
629                 int mParentFragmentId = savedInstanceState.getInt(KEY_PARENT_FRAGMENT_ID, -1);
630                 if (mParentFragment == null) {
631                     mParentFragment = getFragmentManager().findFragmentById(mParentFragmentId);
632                 }
633                 if (!(mParentFragment instanceof DialogCreatable)) {
634                     throw new IllegalArgumentException(
635                             (mParentFragment != null
636                                     ? mParentFragment.getClass().getName()
637                                     : mParentFragmentId)
638                                     + " must implement "
639                                     + DialogCreatable.class.getName());
640                 }
641                 // This dialog fragment could be created from non-SettingsPreferenceFragment
642                 if (mParentFragment instanceof SettingsPreferenceFragment) {
643                     // restore mDialogFragment in mParentFragment
644                     ((SettingsPreferenceFragment) mParentFragment).mDialogFragment = this;
645                 }
646             }
647             return ((DialogCreatable) mParentFragment).onCreateDialog(mDialogId);
648         }
649 
650         @Override
onCancel(DialogInterface dialog)651         public void onCancel(DialogInterface dialog) {
652             super.onCancel(dialog);
653             if (mOnCancelListener != null) {
654                 mOnCancelListener.onCancel(dialog);
655             }
656         }
657 
658         @Override
onDismiss(DialogInterface dialog)659         public void onDismiss(DialogInterface dialog) {
660             super.onDismiss(dialog);
661             if (mOnDismissListener != null) {
662                 mOnDismissListener.onDismiss(dialog);
663             }
664         }
665 
getDialogId()666         public int getDialogId() {
667             return mDialogId;
668         }
669 
670         @Override
onDetach()671         public void onDetach() {
672             super.onDetach();
673 
674             // This dialog fragment could be created from non-SettingsPreferenceFragment
675             if (mParentFragment instanceof SettingsPreferenceFragment) {
676                 // in case the dialog is not explicitly removed by removeDialog()
677                 if (((SettingsPreferenceFragment) mParentFragment).mDialogFragment == this) {
678                     ((SettingsPreferenceFragment) mParentFragment).mDialogFragment = null;
679                 }
680             }
681         }
682     }
683 
hasNextButton()684     protected boolean hasNextButton() {
685         return ((ButtonBarHandler)getActivity()).hasNextButton();
686     }
687 
getNextButton()688     protected Button getNextButton() {
689         return ((ButtonBarHandler)getActivity()).getNextButton();
690     }
691 
finish()692     public void finish() {
693         Activity activity = getActivity();
694         if (activity == null) return;
695         if (getFragmentManager().getBackStackEntryCount() > 0) {
696             getFragmentManager().popBackStack();
697         } else {
698             activity.finish();
699         }
700     }
701 
getIntent()702     protected Intent getIntent() {
703         if (getActivity() == null) {
704             return null;
705         }
706         return getActivity().getIntent();
707     }
708 
setResult(int result, Intent intent)709     protected void setResult(int result, Intent intent) {
710         if (getActivity() == null) {
711             return;
712         }
713         getActivity().setResult(result, intent);
714     }
715 
setResult(int result)716     protected void setResult(int result) {
717         if (getActivity() == null) {
718             return;
719         }
720         getActivity().setResult(result);
721     }
722 
getPrefContext()723     protected final Context getPrefContext() {
724         return getPreferenceManager().getContext();
725     }
726 
startFragment(Fragment caller, String fragmentClass, int titleRes, int requestCode, Bundle extras)727     public boolean startFragment(Fragment caller, String fragmentClass, int titleRes,
728             int requestCode, Bundle extras) {
729         final Activity activity = getActivity();
730         if (activity instanceof SettingsActivity) {
731             SettingsActivity sa = (SettingsActivity) activity;
732             sa.startPreferencePanel(fragmentClass, extras, titleRes, null, caller, requestCode);
733             return true;
734         } else {
735             Log.w(TAG,
736                     "Parent isn't SettingsActivity nor PreferenceActivity, thus there's no way to "
737                     + "launch the given Fragment (name: " + fragmentClass
738                     + ", requestCode: " + requestCode + ")");
739             return false;
740         }
741     }
742 
743     public static class HighlightablePreferenceGroupAdapter extends PreferenceGroupAdapter {
744 
745         private int mHighlightPosition = -1;
746 
HighlightablePreferenceGroupAdapter(PreferenceGroup preferenceGroup)747         public HighlightablePreferenceGroupAdapter(PreferenceGroup preferenceGroup) {
748             super(preferenceGroup);
749         }
750 
highlight(int position)751         public void highlight(int position) {
752             mHighlightPosition = position;
753             notifyDataSetChanged();
754         }
755 
756         @Override
onBindViewHolder(PreferenceViewHolder holder, int position)757         public void onBindViewHolder(PreferenceViewHolder holder, int position) {
758             super.onBindViewHolder(holder, position);
759             if (position == mHighlightPosition) {
760                 View v = holder.itemView;
761                 if (v.getBackground() != null) {
762                     final int centerX = v.getWidth() / 2;
763                     final int centerY = v.getHeight() / 2;
764                     v.getBackground().setHotspot(centerX, centerY);
765                 }
766                 v.setPressed(true);
767                 v.setPressed(false);
768                 mHighlightPosition = -1;
769             }
770         }
771     }
772 }
773