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