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