• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 com.android.traceur;
18 
19 import android.annotation.Nullable;
20 import android.app.AlertDialog;
21 import android.content.ActivityNotFoundException;
22 import android.content.BroadcastReceiver;
23 import android.content.Context;
24 import android.content.DialogInterface;
25 import android.content.Intent;
26 import android.content.IntentFilter;
27 import android.content.pm.PackageManager;
28 import android.content.SharedPreferences;
29 import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
30 import android.icu.text.MessageFormat;
31 import android.net.Uri;
32 import android.os.Bundle;
33 import androidx.preference.MultiSelectListPreference;
34 import androidx.preference.ListPreference;
35 import androidx.preference.Preference;
36 import androidx.preference.PreferenceFragment;
37 import androidx.preference.PreferenceManager;
38 import androidx.preference.SwitchPreference;
39 import android.view.LayoutInflater;
40 import android.view.View;
41 import android.view.ViewGroup;
42 import android.view.Menu;
43 import android.view.MenuInflater;
44 import android.widget.Toast;
45 
46 import com.android.settingslib.HelpUtils;
47 
48 import java.util.ArrayList;
49 import java.util.HashMap;
50 import java.util.Locale;
51 import java.util.Map;
52 import java.util.Map.Entry;
53 import java.util.Set;
54 import java.util.TreeMap;
55 
56 public class MainFragment extends PreferenceFragment {
57 
58     static final String TAG = TraceUtils.TAG;
59 
60     public static final String ACTION_REFRESH_TAGS = "com.android.traceur.REFRESH_TAGS";
61 
62     private static final String BETTERBUG_PACKAGE_NAME =
63             "com.google.android.apps.internal.betterbug";
64 
65     private static final String ROOT_MIME_TYPE = "vnd.android.document/root";
66     private static final String STORAGE_URI = "content://com.android.traceur.documents/root";
67 
68     private SwitchPreference mTracingOn;
69 
70     private AlertDialog mAlertDialog;
71     private SharedPreferences mPrefs;
72 
73     private MultiSelectListPreference mTags;
74 
75     private boolean mRefreshing;
76 
77     private BroadcastReceiver mRefreshReceiver;
78 
79     OnSharedPreferenceChangeListener mSharedPreferenceChangeListener =
80         new OnSharedPreferenceChangeListener () {
81               public void onSharedPreferenceChanged(
82                       SharedPreferences sharedPreferences, String key) {
83                   refreshUi();
84               }
85         };
86 
87     @Override
onCreate(@ullable Bundle savedInstanceState)88     public void onCreate(@Nullable Bundle savedInstanceState) {
89         super.onCreate(savedInstanceState);
90 
91         Receiver.updateDeveloperOptionsWatcher(getContext());
92 
93         mPrefs = PreferenceManager.getDefaultSharedPreferences(
94                 getActivity().getApplicationContext());
95 
96         mTracingOn = (SwitchPreference) findPreference(getActivity().getString(R.string.pref_key_tracing_on));
97         mTracingOn.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
98             @Override
99             public boolean onPreferenceClick(Preference preference) {
100               Receiver.updateTracing(getContext());
101               return true;
102             }
103         });
104 
105         mTags = (MultiSelectListPreference) findPreference(getContext().getString(R.string.pref_key_tags));
106         mTags.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
107             @Override
108             public boolean onPreferenceChange(Preference preference, Object newValue) {
109                 if (mRefreshing) {
110                     return true;
111                 }
112                 Set<String> set = (Set<String>) newValue;
113                 TreeMap<String, String> available = TraceUtils.listCategories();
114                 ArrayList<String> clean = new ArrayList<>(set.size());
115 
116                 for (String s : set) {
117                     if (available.containsKey(s)) {
118                         clean.add(s);
119                     }
120                 }
121                 set.clear();
122                 set.addAll(clean);
123                 return true;
124             }
125         });
126 
127         findPreference("restore_default_tags").setOnPreferenceClickListener(
128                 new Preference.OnPreferenceClickListener() {
129                     @Override
130                     public boolean onPreferenceClick(Preference preference) {
131                         refreshUi(/* restoreDefaultTags =*/ true);
132                         Toast.makeText(getContext(),
133                             getContext().getString(R.string.default_categories_restored),
134                                 Toast.LENGTH_SHORT).show();
135                         return true;
136                     }
137                 });
138 
139         findPreference(getString(R.string.pref_key_quick_setting))
140             .setOnPreferenceClickListener(
141                 new Preference.OnPreferenceClickListener() {
142                     @Override
143                     public boolean onPreferenceClick(Preference preference) {
144                         Receiver.updateQuickSettings(getContext());
145                         return true;
146                     }
147                 });
148 
149         findPreference("clear_saved_traces").setOnPreferenceClickListener(
150                 new Preference.OnPreferenceClickListener() {
151                     @Override
152                     public boolean onPreferenceClick(Preference preference) {
153                         new AlertDialog.Builder(getContext())
154                             .setTitle(R.string.clear_saved_traces_question)
155                             .setMessage(R.string.all_traces_will_be_deleted)
156                             .setPositiveButton(R.string.clear,
157                                 new DialogInterface.OnClickListener() {
158                                     public void onClick(DialogInterface dialog, int which) {
159                                         TraceUtils.clearSavedTraces();
160                                     }
161                                 })
162                             .setNegativeButton(android.R.string.no,
163                                 new DialogInterface.OnClickListener() {
164                                     public void onClick(DialogInterface dialog, int which) {
165                                         dialog.dismiss();
166                                     }
167                                 })
168                             .create()
169                             .show();
170                         return true;
171                     }
172                 });
173 
174         findPreference("trace_link_button")
175             .setOnPreferenceClickListener(
176                 new Preference.OnPreferenceClickListener() {
177                     @Override
178                     public boolean onPreferenceClick(Preference preference) {
179                         Intent intent = buildTraceFileViewIntent();
180                         try {
181                             startActivity(intent);
182                         } catch (ActivityNotFoundException e) {
183                             return false;
184                         }
185                         return true;
186                     }
187                 });
188 
189         // This disables "Attach to bugreports" when long traces are enabled. This cannot be done in
190         // main.xml because there are some other settings there that are enabled with long traces.
191         SwitchPreference attachToBugreport = findPreference(
192             getString(R.string.pref_key_attach_to_bugreport));
193         findPreference(getString(R.string.pref_key_long_traces))
194             .setOnPreferenceClickListener(
195                 new Preference.OnPreferenceClickListener() {
196                     @Override
197                     public boolean onPreferenceClick(Preference preference) {
198                         if (((SwitchPreference) preference).isChecked()) {
199                             attachToBugreport.setEnabled(false);
200                         } else {
201                             attachToBugreport.setEnabled(true);
202                         }
203                         return true;
204                     }
205                 });
206 
207         refreshUi();
208 
209         mRefreshReceiver = new BroadcastReceiver() {
210             @Override
211             public void onReceive(Context context, Intent intent) {
212                 refreshUi();
213             }
214         };
215 
216     }
217 
218     @Override
onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)219     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
220         setHasOptionsMenu(true);
221         return super.onCreateView(inflater, container, savedInstanceState);
222     }
223 
224     @Override
onStart()225     public void onStart() {
226         super.onStart();
227         getPreferenceScreen().getSharedPreferences()
228             .registerOnSharedPreferenceChangeListener(mSharedPreferenceChangeListener);
229         getActivity().registerReceiver(mRefreshReceiver, new IntentFilter(ACTION_REFRESH_TAGS));
230         Receiver.updateTracing(getContext());
231     }
232 
233     @Override
onStop()234     public void onStop() {
235         getPreferenceScreen().getSharedPreferences()
236             .unregisterOnSharedPreferenceChangeListener(mSharedPreferenceChangeListener);
237         getActivity().unregisterReceiver(mRefreshReceiver);
238 
239         if (mAlertDialog != null) {
240             mAlertDialog.cancel();
241             mAlertDialog = null;
242         }
243 
244         super.onStop();
245     }
246 
247     @Override
onCreatePreferences(Bundle savedInstanceState, String rootKey)248     public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
249         addPreferencesFromResource(R.xml.main);
250     }
251 
252     @Override
onCreateOptionsMenu(Menu menu, MenuInflater inflater)253     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
254         HelpUtils.prepareHelpMenuItem(getActivity(), menu, R.string.help_url,
255             this.getClass().getName());
256     }
257 
buildTraceFileViewIntent()258     private Intent buildTraceFileViewIntent() {
259         Intent intent = new Intent(Intent.ACTION_VIEW);
260         intent.setDataAndType(Uri.parse(STORAGE_URI), ROOT_MIME_TYPE);
261         return intent;
262     }
263 
refreshUi()264     private void refreshUi() {
265         refreshUi(/* restoreDefaultTags =*/ false);
266     }
267 
268     /*
269      * Refresh the preferences UI to make sure it reflects the current state of the preferences and
270      * system.
271      */
refreshUi(boolean restoreDefaultTags)272     private void refreshUi(boolean restoreDefaultTags) {
273         Context context = getContext();
274 
275         // Make sure the Record Trace toggle matches the preference value.
276         mTracingOn.setChecked(mTracingOn.getPreferenceManager().getSharedPreferences().getBoolean(
277                 mTracingOn.getKey(), false));
278 
279         SwitchPreference stopOnReport =
280                 (SwitchPreference) findPreference(getString(R.string.pref_key_stop_on_bugreport));
281         stopOnReport.setChecked(mPrefs.getBoolean(stopOnReport.getKey(), false));
282 
283         // Update category list to match the categories available on the system.
284         Set<Entry<String, String>> availableTags = TraceUtils.listCategories().entrySet();
285         ArrayList<String> entries = new ArrayList<String>(availableTags.size());
286         ArrayList<String> values = new ArrayList<String>(availableTags.size());
287         for (Entry<String, String> entry : availableTags) {
288             entries.add(entry.getKey() + ": " + entry.getValue());
289             values.add(entry.getKey());
290         }
291 
292         mRefreshing = true;
293         try {
294             mTags.setEntries(entries.toArray(new String[0]));
295             mTags.setEntryValues(values.toArray(new String[0]));
296             if (restoreDefaultTags || !mPrefs.contains(context.getString(R.string.pref_key_tags))) {
297                 mTags.setValues(Receiver.getDefaultTagList());
298             }
299         } finally {
300             mRefreshing = false;
301         }
302 
303         // Update subtitles on this screen.
304         Set<String> categories = mTags.getValues();
305         MessageFormat msgFormat = new MessageFormat(
306                 getResources().getString(R.string.num_categories_selected),
307                 Locale.getDefault());
308         Map<String, Object> arguments = new HashMap<>();
309         arguments.put("count", categories.size());
310         mTags.setSummary(Receiver.getDefaultTagList().equals(categories)
311                          ? context.getString(R.string.default_categories)
312                          : msgFormat.format(arguments));
313 
314         ListPreference bufferSize = (ListPreference)findPreference(
315                 context.getString(R.string.pref_key_buffer_size));
316         bufferSize.setSummary(bufferSize.getEntry());
317 
318         // If we are not using the Perfetto trace backend,
319         // hide the unsupported preferences.
320         if (TraceUtils.currentTraceEngine().equals(PerfettoUtils.NAME)) {
321             ListPreference maxLongTraceSize = (ListPreference)findPreference(
322                     context.getString(R.string.pref_key_max_long_trace_size));
323             maxLongTraceSize.setSummary(maxLongTraceSize.getEntry());
324 
325             ListPreference maxLongTraceDuration = (ListPreference)findPreference(
326                     context.getString(R.string.pref_key_max_long_trace_duration));
327             maxLongTraceDuration.setSummary(maxLongTraceDuration.getEntry());
328         } else {
329             Preference longTraceCategory = findPreference("long_trace_category");
330             if (longTraceCategory != null) {
331                 getPreferenceScreen().removePreference(longTraceCategory);
332             }
333         }
334 
335         // Check if BetterBug is installed to see if Traceur should display either the toggle for
336         // 'attach_to_bugreport' or 'stop_on_bugreport'.
337         try {
338             context.getPackageManager().getPackageInfo(BETTERBUG_PACKAGE_NAME,
339                     PackageManager.MATCH_SYSTEM_ONLY);
340             findPreference(getString(R.string.pref_key_attach_to_bugreport)).setVisible(true);
341             findPreference(getString(R.string.pref_key_stop_on_bugreport)).setVisible(false);
342             // Changes the long traces summary to add that they cannot be attached to bugreports.
343             findPreference(getString(R.string.pref_key_long_traces))
344                     .setSummary(getString(R.string.long_traces_summary_betterbug));
345         } catch (PackageManager.NameNotFoundException e) {
346             // attach_to_bugreport must be disabled here because it's true by default.
347             mPrefs.edit().putBoolean(
348                     getString(R.string.pref_key_attach_to_bugreport), false).commit();
349             findPreference(getString(R.string.pref_key_attach_to_bugreport)).setVisible(false);
350             findPreference(getString(R.string.pref_key_stop_on_bugreport)).setVisible(true);
351             // Sets long traces summary to the default in case Betterbug was removed.
352             findPreference(getString(R.string.pref_key_long_traces))
353                     .setSummary(getString(R.string.long_traces_summary));
354         }
355 
356         // Check if an activity exists to handle the trace_link_button intent. If not, hide the UI
357         // element
358         PackageManager packageManager = context.getPackageManager();
359         Intent intent = buildTraceFileViewIntent();
360         if (intent.resolveActivity(packageManager) == null) {
361             findPreference("trace_link_button").setVisible(false);
362         }
363     }
364 }
365