Home | History | Annotate | Download | only in preference
      1 /*
      2  * Copyright (C) 2015 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 androidx.leanback.preference;
     18 
     19 import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
     20 
     21 import android.app.Fragment;
     22 import android.app.FragmentTransaction;
     23 import android.os.Build;
     24 import android.os.Bundle;
     25 import android.view.KeyEvent;
     26 import android.view.LayoutInflater;
     27 import android.view.View;
     28 import android.view.ViewGroup;
     29 import android.widget.Space;
     30 
     31 import androidx.annotation.NonNull;
     32 import androidx.annotation.Nullable;
     33 import androidx.annotation.RestrictTo;
     34 import androidx.preference.ListPreference;
     35 import androidx.preference.MultiSelectListPreference;
     36 import androidx.preference.Preference;
     37 import androidx.preference.PreferenceFragment;
     38 import androidx.preference.PreferenceScreen;
     39 
     40 /**
     41  * This fragment provides a container for displaying a {@link LeanbackPreferenceFragment}
     42  *
     43  * <p>The following sample code shows a simple leanback preference fragment that is
     44  * populated from a resource.  The resource it loads is:</p>
     45  *
     46  * {@sample frameworks/support/samples/SupportPreferenceDemos/src/main/res/xml/preferences.xml preferences}
     47  *
     48  * <p>The sample implements
     49  * {@link PreferenceFragment.OnPreferenceStartFragmentCallback#onPreferenceStartFragment(PreferenceFragment, Preference)},
     50  * {@link PreferenceFragment.OnPreferenceStartScreenCallback#onPreferenceStartScreen(PreferenceFragment, PreferenceScreen)},
     51  * and {@link #onPreferenceStartInitialScreen()}:</p>
     52  *
     53  * {@sample frameworks/support/samples/SupportPreferenceDemos/src/main/java/com/example/android/supportpreference/FragmentSupportPreferencesLeanback.java
     54  *      support_fragment_leanback}
     55  */
     56 public abstract class LeanbackSettingsFragment extends Fragment
     57         implements PreferenceFragment.OnPreferenceStartFragmentCallback,
     58         PreferenceFragment.OnPreferenceStartScreenCallback,
     59         PreferenceFragment.OnPreferenceDisplayDialogCallback {
     60 
     61     private static final String PREFERENCE_FRAGMENT_TAG =
     62             "androidx.leanback.preference.LeanbackSettingsFragment.PREFERENCE_FRAGMENT";
     63 
     64     private final RootViewOnKeyListener mRootViewOnKeyListener = new RootViewOnKeyListener();
     65 
     66     @Override
     67     public View onCreateView(LayoutInflater inflater, ViewGroup container,
     68             Bundle savedInstanceState) {
     69         final View v = inflater.inflate(R.layout.leanback_settings_fragment, container, false);
     70 
     71         return v;
     72     }
     73 
     74     @Override
     75     public void onViewCreated(View view, Bundle savedInstanceState) {
     76         super.onViewCreated(view, savedInstanceState);
     77         if (savedInstanceState == null) {
     78             onPreferenceStartInitialScreen();
     79         }
     80     }
     81 
     82     @Override
     83     public void onResume() {
     84         super.onResume();
     85         // Trap back button presses
     86         final LeanbackSettingsRootView rootView = (LeanbackSettingsRootView) getView();
     87         if (rootView != null) {
     88             rootView.setOnBackKeyListener(mRootViewOnKeyListener);
     89         }
     90     }
     91 
     92     @Override
     93     public void onPause() {
     94         super.onPause();
     95         final LeanbackSettingsRootView rootView = (LeanbackSettingsRootView) getView();
     96         if (rootView != null) {
     97             rootView.setOnBackKeyListener(null);
     98         }
     99     }
    100 
    101     @Override
    102     public boolean onPreferenceDisplayDialog(@NonNull PreferenceFragment caller, Preference pref) {
    103         if (caller == null) {
    104             throw new IllegalArgumentException("Cannot display dialog for preference " + pref
    105                     + ", Caller must not be null!");
    106         }
    107         final Fragment f;
    108         if (pref instanceof ListPreference) {
    109             final ListPreference listPreference = (ListPreference) pref;
    110             f = LeanbackListPreferenceDialogFragment.newInstanceSingle(listPreference.getKey());
    111             f.setTargetFragment(caller, 0);
    112             startPreferenceFragment(f);
    113         } else if (pref instanceof MultiSelectListPreference) {
    114             MultiSelectListPreference listPreference = (MultiSelectListPreference) pref;
    115             f = LeanbackListPreferenceDialogFragment.newInstanceMulti(listPreference.getKey());
    116             f.setTargetFragment(caller, 0);
    117             startPreferenceFragment(f);
    118         }
    119         // TODO
    120 //        else if (pref instanceof EditTextPreference) {
    121 //
    122 //        }
    123         else {
    124             return false;
    125         }
    126         return true;
    127     }
    128 
    129     /**
    130      * Called to instantiate the initial {@link androidx.preference.PreferenceFragment}
    131      * to be shown in this fragment. Implementations are expected to call
    132      * {@link #startPreferenceFragment(android.app.Fragment)}.
    133      */
    134     public abstract void onPreferenceStartInitialScreen();
    135 
    136     /**
    137      * Displays a preference fragment to the user. This method can also be used to display
    138      * list-style fragments on top of the stack of preference fragments.
    139      *
    140      * @param fragment Fragment instance to be added.
    141      */
    142     public void startPreferenceFragment(@NonNull Fragment fragment) {
    143         final FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
    144         final Fragment prevFragment =
    145                 getChildFragmentManager().findFragmentByTag(PREFERENCE_FRAGMENT_TAG);
    146         if (prevFragment != null) {
    147             transaction
    148                     .addToBackStack(null)
    149                     .replace(R.id.settings_preference_fragment_container, fragment,
    150                             PREFERENCE_FRAGMENT_TAG);
    151         } else {
    152             transaction
    153                     .add(R.id.settings_preference_fragment_container, fragment,
    154                             PREFERENCE_FRAGMENT_TAG);
    155         }
    156         transaction.commit();
    157     }
    158 
    159     /**
    160      * Displays a fragment to the user, temporarily replacing the contents of this fragment.
    161      *
    162      * @param fragment Fragment instance to be added.
    163      */
    164     public void startImmersiveFragment(@NonNull Fragment fragment) {
    165         final FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
    166         final Fragment preferenceFragment =
    167                 getChildFragmentManager().findFragmentByTag(PREFERENCE_FRAGMENT_TAG);
    168         if (preferenceFragment != null && !preferenceFragment.isHidden()) {
    169             if (Build.VERSION.SDK_INT < 23) {
    170                 // b/22631964
    171                 transaction.add(R.id.settings_preference_fragment_container, new DummyFragment());
    172             }
    173             transaction.remove(preferenceFragment);
    174         }
    175         transaction
    176                 .add(R.id.settings_dialog_container, fragment)
    177                 .addToBackStack(null)
    178                 .commit();
    179     }
    180 
    181     private class RootViewOnKeyListener implements View.OnKeyListener {
    182 
    183         @Override
    184         public boolean onKey(View v, int keyCode, KeyEvent event) {
    185             if (keyCode == KeyEvent.KEYCODE_BACK) {
    186                 return getChildFragmentManager().popBackStackImmediate();
    187             } else {
    188                 return false;
    189             }
    190         }
    191     }
    192 
    193     /**
    194      * @hide
    195      */
    196     @RestrictTo(LIBRARY_GROUP)
    197     public static class DummyFragment extends Fragment {
    198 
    199         @Override
    200         public @Nullable View onCreateView(LayoutInflater inflater, ViewGroup container,
    201                 Bundle savedInstanceState) {
    202             final View v = new Space(inflater.getContext());
    203             v.setVisibility(View.GONE);
    204             return v;
    205         }
    206     }
    207 }
    208