1 /* 2 * Copyright (C) 2019 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.tv.twopanelsettings.slices; 18 19 import static androidx.lifecycle.Lifecycle.Event.ON_CREATE; 20 import static androidx.lifecycle.Lifecycle.Event.ON_DESTROY; 21 import static androidx.lifecycle.Lifecycle.Event.ON_PAUSE; 22 import static androidx.lifecycle.Lifecycle.Event.ON_RESUME; 23 import static androidx.lifecycle.Lifecycle.Event.ON_START; 24 import static androidx.lifecycle.Lifecycle.Event.ON_STOP; 25 26 import static com.android.tv.twopanelsettings.slices.InstrumentationUtils.logPageFocused; 27 28 import android.animation.AnimatorInflater; 29 import android.app.tvsettings.TvSettingsEnums; 30 import android.content.Context; 31 import android.os.Bundle; 32 import android.view.Gravity; 33 import android.view.Menu; 34 import android.view.MenuInflater; 35 import android.view.MenuItem; 36 import android.view.View; 37 import android.view.ViewGroup; 38 import android.widget.TextView; 39 40 import androidx.annotation.CallSuper; 41 import androidx.annotation.NonNull; 42 import androidx.lifecycle.LifecycleOwner; 43 import androidx.preference.PreferenceGroupAdapter; 44 import androidx.preference.PreferenceScreen; 45 import androidx.preference.PreferenceViewHolder; 46 import androidx.recyclerview.widget.RecyclerView; 47 48 import com.android.settingslib.core.lifecycle.Lifecycle; 49 import com.android.tv.twopanelsettings.R; 50 import com.android.tv.twopanelsettings.SettingsPreferenceFragmentBase; 51 import com.android.tv.twopanelsettings.TwoPanelSettingsFragment; 52 53 /** 54 * A copy of SettingsPreferenceFragment in Settings. 55 */ 56 public abstract class SettingsPreferenceFragment extends SettingsPreferenceFragmentBase 57 implements LifecycleOwner, 58 TwoPanelSettingsFragment.PreviewableComponentCallback { 59 private final Lifecycle mLifecycle = new Lifecycle(this); 60 61 // Rename getLifecycle() to getSettingsLifecycle() as androidx Fragment has already implemented 62 // getLifecycle(), overriding here would cause unexpected crash in framework. 63 @NonNull getSettingsLifecycle()64 public Lifecycle getSettingsLifecycle() { 65 return mLifecycle; 66 } 67 SettingsPreferenceFragment()68 public SettingsPreferenceFragment() { 69 } 70 71 @CallSuper 72 @Override onAttach(Context context)73 public void onAttach(Context context) { 74 super.onAttach(context); 75 mLifecycle.onAttach(context); 76 } 77 78 @CallSuper 79 @Override onCreate(Bundle savedInstanceState)80 public void onCreate(Bundle savedInstanceState) { 81 mLifecycle.onCreate(savedInstanceState); 82 mLifecycle.handleLifecycleEvent(ON_CREATE); 83 super.onCreate(savedInstanceState); 84 if (getCallbackFragment() != null 85 && !(getCallbackFragment() instanceof TwoPanelSettingsFragment)) { 86 logPageFocused(getPageId(), true); 87 } 88 } 89 90 // We explicitly set the title gravity to RIGHT in RTL cases to remedy some complicated gravity 91 // issues. For more details, please read the comment of onViewCreated() in 92 // com.android.tv.settings.SettingsPreferenceFragment. 93 @Override onViewCreated(View view, Bundle savedInstanceState)94 public void onViewCreated(View view, Bundle savedInstanceState) { 95 super.onViewCreated(view, savedInstanceState); 96 if (view != null) { 97 TextView titleView = view.findViewById(R.id.decor_title); 98 // We rely on getResources().getConfiguration().getLayoutDirection() instead of 99 // view.isLayoutRtl() as the latter could return false in some complex scenarios even if 100 // it is RTL. 101 if (titleView != null 102 && getResources().getConfiguration().getLayoutDirection() 103 == View.LAYOUT_DIRECTION_RTL) { 104 titleView.setGravity(Gravity.RIGHT); 105 } 106 } 107 } 108 109 @Override onCreateAdapter(PreferenceScreen preferenceScreen)110 protected RecyclerView.Adapter onCreateAdapter(PreferenceScreen preferenceScreen) { 111 return new PreferenceGroupAdapter(preferenceScreen) { 112 @Override 113 @NonNull 114 public PreferenceViewHolder onCreateViewHolder(@NonNull ViewGroup parent, 115 int viewType) { 116 PreferenceViewHolder vh = super.onCreateViewHolder(parent, viewType); 117 vh.itemView.setStateListAnimator(AnimatorInflater.loadStateListAnimator( 118 getContext(), R.animator.preference)); 119 return vh; 120 } 121 }; 122 } 123 124 @Override 125 public void setPreferenceScreen(PreferenceScreen preferenceScreen) { 126 mLifecycle.setPreferenceScreen(preferenceScreen); 127 super.setPreferenceScreen(preferenceScreen); 128 } 129 130 @CallSuper 131 @Override 132 public void onSaveInstanceState(Bundle outState) { 133 super.onSaveInstanceState(outState); 134 mLifecycle.onSaveInstanceState(outState); 135 } 136 137 @CallSuper 138 @Override 139 public void onStart() { 140 mLifecycle.handleLifecycleEvent(ON_START); 141 super.onStart(); 142 } 143 144 @CallSuper 145 @Override 146 public void onResume() { 147 super.onResume(); 148 mLifecycle.handleLifecycleEvent(ON_RESUME); 149 } 150 151 // This should only be invoked if the parent Fragment is TwoPanelSettingsFragment. 152 @CallSuper 153 @Override 154 public void onArriveAtMainPanel(boolean forward) { 155 logPageFocused(getPageId(), forward); 156 } 157 158 @CallSuper 159 @Override 160 public void onPause() { 161 mLifecycle.handleLifecycleEvent(ON_PAUSE); 162 super.onPause(); 163 } 164 165 @CallSuper 166 @Override 167 public void onStop() { 168 mLifecycle.handleLifecycleEvent(ON_STOP); 169 super.onStop(); 170 } 171 172 @CallSuper 173 @Override 174 public void onDestroy() { 175 mLifecycle.handleLifecycleEvent(ON_DESTROY); 176 super.onDestroy(); 177 } 178 179 @CallSuper 180 @Override 181 public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) { 182 mLifecycle.onCreateOptionsMenu(menu, inflater); 183 super.onCreateOptionsMenu(menu, inflater); 184 } 185 186 @CallSuper 187 @Override 188 public void onPrepareOptionsMenu(final Menu menu) { 189 mLifecycle.onPrepareOptionsMenu(menu); 190 super.onPrepareOptionsMenu(menu); 191 } 192 193 @CallSuper 194 @Override 195 public boolean onOptionsItemSelected(final MenuItem menuItem) { 196 boolean lifecycleHandled = mLifecycle.onOptionsItemSelected(menuItem); 197 if (!lifecycleHandled) { 198 return super.onOptionsItemSelected(menuItem); 199 } 200 return lifecycleHandled; 201 } 202 203 /** Subclasses should override this to use their own PageId for statsd logging. */ 204 protected int getPageId() { 205 return TvSettingsEnums.PAGE_CLASSIC_DEFAULT; 206 } 207 } 208