• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 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.core;
18 
19 import static com.android.internal.jank.InteractionJankMonitor.CUJ_SETTINGS_PAGE_SCROLL;
20 import static com.android.internal.jank.InteractionJankMonitor.Configuration;
21 
22 import android.content.Context;
23 import android.os.Bundle;
24 import android.text.TextUtils;
25 import android.util.Log;
26 
27 import androidx.annotation.XmlRes;
28 import androidx.preference.Preference;
29 import androidx.preference.PreferenceScreen;
30 import androidx.recyclerview.widget.RecyclerView;
31 
32 import com.android.internal.jank.InteractionJankMonitor;
33 import com.android.settings.overlay.FeatureFactory;
34 import com.android.settings.survey.SurveyMixin;
35 import com.android.settingslib.core.instrumentation.Instrumentable;
36 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
37 import com.android.settingslib.core.instrumentation.VisibilityLoggerMixin;
38 import com.android.settingslib.core.lifecycle.ObservablePreferenceFragment;
39 
40 /**
41  * Instrumented fragment that logs visibility state.
42  */
43 public abstract class InstrumentedPreferenceFragment extends ObservablePreferenceFragment
44         implements Instrumentable {
45 
46     private static final String TAG = "InstrumentedPrefFrag";
47 
48 
49     protected MetricsFeatureProvider mMetricsFeatureProvider;
50 
51     // metrics placeholder value. Only use this for development.
52     protected final int PLACEHOLDER_METRIC = 10000;
53 
54     private VisibilityLoggerMixin mVisibilityLoggerMixin;
55     private RecyclerView.OnScrollListener mOnScrollListener;
56 
57     @Override
onAttach(Context context)58     public void onAttach(Context context) {
59         mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider();
60         // Mixin that logs visibility change for activity.
61         mVisibilityLoggerMixin = new VisibilityLoggerMixin(getMetricsCategory(),
62                 mMetricsFeatureProvider);
63         getSettingsLifecycle().addObserver(mVisibilityLoggerMixin);
64         getSettingsLifecycle().addObserver(new SurveyMixin(this, getClass().getSimpleName()));
65         super.onAttach(context);
66     }
67 
68     @Override
onResume()69     public void onResume() {
70         mVisibilityLoggerMixin.setSourceMetricsCategory(getActivity());
71         // Add scroll listener to trace interaction jank.
72         final RecyclerView recyclerView = getListView();
73         if (recyclerView != null) {
74             mOnScrollListener = new OnScrollListener(getClass().getName());
75             recyclerView.addOnScrollListener(mOnScrollListener);
76         }
77         super.onResume();
78     }
79 
80     @Override
onPause()81     public void onPause() {
82         final RecyclerView recyclerView = getListView();
83         if (mOnScrollListener != null) {
84             recyclerView.removeOnScrollListener(mOnScrollListener);
85             mOnScrollListener = null;
86         }
87         super.onPause();
88     }
89 
90     @Override
onCreatePreferences(Bundle savedInstanceState, String rootKey)91     public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
92         final int resId = getPreferenceScreenResId();
93         if (resId > 0) {
94             addPreferencesFromResource(resId);
95         }
96     }
97 
98     @Override
addPreferencesFromResource(@mlRes int preferencesResId)99     public void addPreferencesFromResource(@XmlRes int preferencesResId) {
100         super.addPreferencesFromResource(preferencesResId);
101         updateActivityTitleWithScreenTitle(getPreferenceScreen());
102     }
103 
104     @Override
findPreference(CharSequence key)105     public <T extends Preference> T findPreference(CharSequence key) {
106         if (key == null) {
107             return null;
108         }
109         return super.findPreference(key);
110     }
111 
112     @Override
onPreferenceTreeClick(Preference preference)113     public boolean onPreferenceTreeClick(Preference preference) {
114         writePreferenceClickMetric(preference);
115         return super.onPreferenceTreeClick(preference);
116     }
117 
getPrefContext()118     protected final Context getPrefContext() {
119         return getPreferenceManager().getContext();
120     }
121 
122     /**
123      * Get the res id for static preference xml for this fragment.
124      */
getPreferenceScreenResId()125     protected int getPreferenceScreenResId() {
126         return -1;
127     }
128 
writeElapsedTimeMetric(int action, String key)129     protected void writeElapsedTimeMetric(int action, String key) {
130         mVisibilityLoggerMixin.writeElapsedTimeMetric(action, key);
131     }
132 
writePreferenceClickMetric(Preference preference)133     protected void writePreferenceClickMetric(Preference preference) {
134         mMetricsFeatureProvider.logClickedPreference(preference, getMetricsCategory());
135     }
136 
updateActivityTitleWithScreenTitle(PreferenceScreen screen)137     private void updateActivityTitleWithScreenTitle(PreferenceScreen screen) {
138         if (screen != null) {
139             final CharSequence title = screen.getTitle();
140             if (!TextUtils.isEmpty(title)) {
141                 getActivity().setTitle(title);
142             } else {
143                 Log.w(TAG, "Screen title missing for fragment " + this.getClass().getName());
144             }
145         }
146     }
147 
148     private static final class OnScrollListener extends RecyclerView.OnScrollListener {
149         private final InteractionJankMonitor mMonitor = InteractionJankMonitor.getInstance();
150         private final String mClassName;
151 
OnScrollListener(String className)152         private OnScrollListener(String className) {
153             mClassName = className;
154         }
155 
156         @Override
onScrollStateChanged(RecyclerView recyclerView, int newState)157         public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
158             switch (newState) {
159                 case RecyclerView.SCROLL_STATE_DRAGGING:
160                     final Configuration.Builder builder =
161                             new Configuration.Builder(CUJ_SETTINGS_PAGE_SCROLL)
162                                     .setView(recyclerView)
163                                     .setTag(mClassName);
164                     mMonitor.begin(builder);
165                     break;
166                 case RecyclerView.SCROLL_STATE_IDLE:
167                     mMonitor.end(CUJ_SETTINGS_PAGE_SCROLL);
168                     break;
169                 default:
170             }
171         }
172     }
173 }
174