• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
5  * except in compliance with the License. You may obtain a copy of the License at
6  *
7  *      http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software distributed under the
10  * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
11  * KIND, either express or implied. See the License for the specific language governing
12  * permissions and limitations under the License.
13  */
14 
15 package com.android.settings.datausage;
16 
17 import static android.app.usage.NetworkStats.Bucket.UID_REMOVED;
18 import static android.app.usage.NetworkStats.Bucket.UID_TETHERING;
19 import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
20 
21 import android.app.Activity;
22 import android.app.ActivityManager;
23 import android.app.settings.SettingsEnums;
24 import android.app.usage.NetworkStats;
25 import android.app.usage.NetworkStats.Bucket;
26 import android.content.Context;
27 import android.content.Intent;
28 import android.content.pm.UserInfo;
29 import android.graphics.Color;
30 import android.net.ConnectivityManager;
31 import android.net.NetworkPolicy;
32 import android.net.NetworkTemplate;
33 import android.os.Bundle;
34 import android.os.Process;
35 import android.os.UserHandle;
36 import android.os.UserManager;
37 import android.provider.Settings;
38 import android.telephony.SubscriptionInfo;
39 import android.telephony.SubscriptionManager;
40 import android.util.EventLog;
41 import android.util.Log;
42 import android.util.SparseArray;
43 import android.view.View;
44 import android.view.View.AccessibilityDelegate;
45 import android.view.accessibility.AccessibilityEvent;
46 import android.widget.AdapterView;
47 import android.widget.AdapterView.OnItemSelectedListener;
48 import android.widget.ImageView;
49 import android.widget.Spinner;
50 
51 import androidx.annotation.VisibleForTesting;
52 import androidx.lifecycle.Lifecycle;
53 import androidx.loader.app.LoaderManager.LoaderCallbacks;
54 import androidx.loader.content.Loader;
55 import androidx.preference.Preference;
56 import androidx.preference.PreferenceGroup;
57 
58 import com.android.settings.R;
59 import com.android.settings.core.SubSettingLauncher;
60 import com.android.settings.datausage.CycleAdapter.SpinnerInterface;
61 import com.android.settings.network.MobileDataEnabledListener;
62 import com.android.settings.network.ProxySubscriptionManager;
63 import com.android.settings.widget.LoadingViewController;
64 import com.android.settingslib.AppItem;
65 import com.android.settingslib.net.NetworkCycleChartData;
66 import com.android.settingslib.net.NetworkCycleChartDataLoader;
67 import com.android.settingslib.net.NetworkStatsSummaryLoader;
68 import com.android.settingslib.net.UidDetailProvider;
69 
70 import java.util.ArrayList;
71 import java.util.Collections;
72 import java.util.List;
73 import java.util.Objects;
74 
75 /**
76  * Panel showing data usage history across various networks, including options
77  * to inspect based on usage cycle and control through {@link NetworkPolicy}.
78  */
79 public class DataUsageList extends DataUsageBaseFragment
80         implements MobileDataEnabledListener.Client {
81 
82     static final String EXTRA_SUB_ID = "sub_id";
83     static final String EXTRA_NETWORK_TEMPLATE = "network_template";
84     static final String EXTRA_NETWORK_TYPE = "network_type";
85 
86     private static final String TAG = "DataUsageList";
87     private static final boolean LOGD = false;
88 
89     private static final String KEY_USAGE_AMOUNT = "usage_amount";
90     private static final String KEY_CHART_DATA = "chart_data";
91     private static final String KEY_APPS_GROUP = "apps_group";
92     private static final String KEY_TEMPLATE = "template";
93     private static final String KEY_APP = "app";
94 
95     @VisibleForTesting
96     static final int LOADER_CHART_DATA = 2;
97     @VisibleForTesting
98     static final int LOADER_SUMMARY = 3;
99 
100     @VisibleForTesting
101     MobileDataEnabledListener mDataStateListener;
102 
103     @VisibleForTesting
104     NetworkTemplate mTemplate;
105     @VisibleForTesting
106     int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
107     @VisibleForTesting
108     int mNetworkType;
109     @VisibleForTesting
110     Spinner mCycleSpinner;
111     @VisibleForTesting
112     LoadingViewController mLoadingViewController;
113 
114     private ChartDataUsagePreference mChart;
115     private List<NetworkCycleChartData> mCycleData;
116     // Caches the cycles for startAppDataUsage usage, which need be cleared when resumed.
117     private ArrayList<Long> mCycles;
118     // Spinner will keep the selected cycle even after paused, this only keeps the displayed cycle,
119     // which need be cleared when resumed.
120     private CycleAdapter.CycleItem mLastDisplayedCycle;
121     private UidDetailProvider mUidDetailProvider;
122     private CycleAdapter mCycleAdapter;
123     private Preference mUsageAmount;
124     private PreferenceGroup mApps;
125     private View mHeader;
126 
127     @Override
getMetricsCategory()128     public int getMetricsCategory() {
129         return SettingsEnums.DATA_USAGE_LIST;
130     }
131 
132     @Override
onCreate(Bundle savedInstanceState)133     public void onCreate(Bundle savedInstanceState) {
134         super.onCreate(savedInstanceState);
135         if (isGuestUser(getContext())) {
136             Log.e(TAG, "This setting isn't available for guest user");
137             EventLog.writeEvent(0x534e4554, "262741858", -1 /* UID */, "Guest user");
138             finish();
139             return;
140         }
141 
142         final Activity activity = getActivity();
143         if (!isBandwidthControlEnabled()) {
144             Log.w(TAG, "No bandwidth control; leaving");
145             activity.finish();
146             return;
147         }
148 
149         mUidDetailProvider = new UidDetailProvider(activity);
150         mUsageAmount = findPreference(KEY_USAGE_AMOUNT);
151         mChart = findPreference(KEY_CHART_DATA);
152         mApps = findPreference(KEY_APPS_GROUP);
153 
154         final Preference unnecessaryWarningPreference = findPreference("operator_warning");
155         if (unnecessaryWarningPreference != null) {
156             unnecessaryWarningPreference.setVisible(false);
157         }
158 
159         processArgument();
160         mDataStateListener = new MobileDataEnabledListener(activity, this);
161     }
162 
163     @Override
onViewCreated(View v, Bundle savedInstanceState)164     public void onViewCreated(View v, Bundle savedInstanceState) {
165         super.onViewCreated(v, savedInstanceState);
166 
167         mHeader = setPinnedHeaderView(R.layout.apps_filter_spinner);
168         mHeader.findViewById(R.id.filter_settings).setOnClickListener(btn -> {
169             final Bundle args = new Bundle();
170             args.putParcelable(DataUsageList.EXTRA_NETWORK_TEMPLATE, mTemplate);
171             new SubSettingLauncher(getContext())
172                     .setDestination(BillingCycleSettings.class.getName())
173                     .setTitleRes(R.string.billing_cycle)
174                     .setSourceMetricsCategory(getMetricsCategory())
175                     .setArguments(args)
176                     .launch();
177         });
178         mCycleSpinner = mHeader.findViewById(R.id.filter_spinner);
179         mCycleSpinner.setVisibility(View.GONE);
180         mCycleAdapter = new CycleAdapter(mCycleSpinner.getContext(), new SpinnerInterface() {
181             @Override
182             public void setAdapter(CycleAdapter cycleAdapter) {
183                 mCycleSpinner.setAdapter(cycleAdapter);
184             }
185 
186             @Override
187             public void setOnItemSelectedListener(OnItemSelectedListener listener) {
188                 mCycleSpinner.setOnItemSelectedListener(listener);
189             }
190 
191             @Override
192             public Object getSelectedItem() {
193                 return mCycleSpinner.getSelectedItem();
194             }
195 
196             @Override
197             public void setSelection(int position) {
198                 mCycleSpinner.setSelection(position);
199             }
200         }, mCycleListener);
201         mCycleSpinner.setAccessibilityDelegate(new AccessibilityDelegate() {
202             @Override
203             public void sendAccessibilityEvent(View host, int eventType) {
204                 if (eventType == AccessibilityEvent.TYPE_VIEW_SELECTED) {
205                     // Ignore TYPE_VIEW_SELECTED or TalkBack will speak for it at onResume.
206                     return;
207                 }
208                 super.sendAccessibilityEvent(host, eventType);
209             }
210         });
211 
212         mLoadingViewController = new LoadingViewController(
213                 getView().findViewById(R.id.loading_container), getListView());
214     }
215 
216     @Override
onResume()217     public void onResume() {
218         super.onResume();
219         mLoadingViewController.showLoadingViewDelayed();
220         mDataStateListener.start(mSubId);
221         mCycles = null;
222         mLastDisplayedCycle = null;
223 
224         // kick off loader for network history
225         // TODO: consider chaining two loaders together instead of reloading
226         // network history when showing app detail.
227         getLoaderManager().restartLoader(LOADER_CHART_DATA,
228                 buildArgs(mTemplate), mNetworkCycleDataCallbacks);
229 
230         updateBody();
231     }
232 
233     @Override
onPause()234     public void onPause() {
235         super.onPause();
236         mDataStateListener.stop();
237 
238         getLoaderManager().destroyLoader(LOADER_CHART_DATA);
239         getLoaderManager().destroyLoader(LOADER_SUMMARY);
240     }
241 
242     @Override
onDestroy()243     public void onDestroy() {
244         if (mUidDetailProvider != null) {
245             mUidDetailProvider.clearCache();
246             mUidDetailProvider = null;
247         }
248         super.onDestroy();
249     }
250 
251     @Override
getPreferenceScreenResId()252     protected int getPreferenceScreenResId() {
253         return R.xml.data_usage_list;
254     }
255 
256     @Override
getLogTag()257     protected String getLogTag() {
258         return TAG;
259     }
260 
processArgument()261     void processArgument() {
262         final Bundle args = getArguments();
263         if (args != null) {
264             mSubId = args.getInt(EXTRA_SUB_ID, SubscriptionManager.INVALID_SUBSCRIPTION_ID);
265             mTemplate = args.getParcelable(EXTRA_NETWORK_TEMPLATE);
266             mNetworkType = args.getInt(EXTRA_NETWORK_TYPE, ConnectivityManager.TYPE_MOBILE);
267         }
268         if (mTemplate == null && mSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
269             final Intent intent = getIntent();
270             mSubId = intent.getIntExtra(Settings.EXTRA_SUB_ID,
271                     SubscriptionManager.INVALID_SUBSCRIPTION_ID);
272             mTemplate = intent.getParcelableExtra(Settings.EXTRA_NETWORK_TEMPLATE);
273         }
274     }
275 
276     /**
277      * Implementation of {@code MobileDataEnabledListener.Client}
278      */
onMobileDataEnabledChange()279     public void onMobileDataEnabledChange() {
280         updatePolicy();
281     }
282 
283     /**
284      * Update body content based on current tab. Loads network cycle data from system, and
285      * binds them to visible controls.
286      */
updateBody()287     private void updateBody() {
288         if (!isAdded()) return;
289 
290         final Context context = getActivity();
291 
292         // detail mode can change visible menus, invalidate
293         getActivity().invalidateOptionsMenu();
294 
295         int seriesColor = context.getColor(R.color.sim_noitification);
296         if (mSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
297             final SubscriptionInfo sir = ProxySubscriptionManager.getInstance(context)
298                     .getActiveSubscriptionInfo(mSubId);
299 
300             if (sir != null) {
301                 seriesColor = sir.getIconTint();
302             }
303         }
304 
305         final int secondaryColor = Color.argb(127, Color.red(seriesColor), Color.green(seriesColor),
306                 Color.blue(seriesColor));
307         mChart.setColors(seriesColor, secondaryColor);
308     }
309 
buildArgs(NetworkTemplate template)310     private Bundle buildArgs(NetworkTemplate template) {
311         final Bundle args = new Bundle();
312         args.putParcelable(KEY_TEMPLATE, template);
313         args.putParcelable(KEY_APP, null);
314         return args;
315     }
316 
317     /**
318      * Update chart sweeps and cycle list to reflect {@link NetworkPolicy} for
319      * current {@link #mTemplate}.
320      */
321     @VisibleForTesting
updatePolicy()322     void updatePolicy() {
323         final NetworkPolicy policy = services.mPolicyEditor.getPolicy(mTemplate);
324         final View configureButton = mHeader.findViewById(R.id.filter_settings);
325         //SUB SELECT
326         if (isNetworkPolicyModifiable(policy, mSubId) && isMobileDataAvailable(mSubId)) {
327             mChart.setNetworkPolicy(policy);
328             configureButton.setVisibility(View.VISIBLE);
329             ((ImageView) configureButton).setColorFilter(android.R.color.white);
330         } else {
331             // controls are disabled; don't bind warning/limit sweeps
332             mChart.setNetworkPolicy(null);
333             configureButton.setVisibility(View.GONE);
334         }
335 
336         // generate cycle list based on policy and available history
337         mCycleAdapter.updateCycleList(mCycleData);
338         updateSelectedCycle();
339     }
340 
341     /**
342      * Updates the chart and detail data when initial loaded or selected cycle changed.
343      */
updateSelectedCycle()344     private void updateSelectedCycle() {
345         // Avoid from updating UI after #onStop.
346         if (!getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED)) {
347             return;
348         }
349 
350         // Avoid from updating UI when async query still on-going.
351         // This could happen when a request from #onMobileDataEnabledChange.
352         if (mCycleData == null) {
353             return;
354         }
355 
356         final int position = mCycleSpinner.getSelectedItemPosition();
357         if (mCycleAdapter.getCount() == 0 || position < 0) {
358             return;
359         }
360         final CycleAdapter.CycleItem cycle = mCycleAdapter.getItem(position);
361         if (Objects.equals(cycle, mLastDisplayedCycle)) {
362             // Avoid duplicate update to avoid page flash.
363             return;
364         }
365         mLastDisplayedCycle = cycle;
366 
367         if (LOGD) {
368             Log.d(TAG, "showing cycle " + cycle + ", [start=" + cycle.start + ", end="
369                     + cycle.end + "]");
370         }
371 
372         // update chart to show selected cycle, and update detail data
373         // to match updated sweep bounds.
374         mChart.setNetworkCycleData(mCycleData.get(position));
375 
376         updateDetailData();
377     }
378 
379     /**
380      * Update details based on {@link #mChart} inspection range depending on
381      * current mode. Updates {@link #mAdapter} with sorted list
382      * of applications data usage.
383      */
updateDetailData()384     private void updateDetailData() {
385         if (LOGD) Log.d(TAG, "updateDetailData()");
386 
387         // kick off loader for detailed stats
388         getLoaderManager().restartLoader(LOADER_SUMMARY, null /* args */,
389                 mNetworkStatsDetailCallbacks);
390 
391         final long totalBytes = mCycleData != null && !mCycleData.isEmpty()
392             ? mCycleData.get(mCycleSpinner.getSelectedItemPosition()).getTotalUsage() : 0;
393         final CharSequence totalPhrase = DataUsageUtils.formatDataUsage(getActivity(), totalBytes);
394         mUsageAmount.setTitle(getString(R.string.data_used_template, totalPhrase));
395     }
396 
397     /**
398      * Bind the given {@link NetworkStats}, or {@code null} to clear list.
399      */
bindStats(NetworkStats stats, int[] restrictedUids)400     private void bindStats(NetworkStats stats, int[] restrictedUids) {
401         mApps.removeAll();
402         if (stats == null) {
403             if (LOGD) {
404                 Log.d(TAG, "No network stats data. App list cleared.");
405             }
406             return;
407         }
408 
409         final ArrayList<AppItem> items = new ArrayList<>();
410         long largest = 0;
411 
412         final int currentUserId = ActivityManager.getCurrentUser();
413         final UserManager userManager = UserManager.get(getContext());
414         final List<UserHandle> profiles = userManager.getUserProfiles();
415         final SparseArray<AppItem> knownItems = new SparseArray<AppItem>();
416 
417         final Bucket bucket = new Bucket();
418         while (stats.hasNextBucket() && stats.getNextBucket(bucket)) {
419             // Decide how to collapse items together
420             final int uid = bucket.getUid();
421             final int collapseKey;
422             final int category;
423             final int userId = UserHandle.getUserId(uid);
424             if (UserHandle.isApp(uid) || Process.isSdkSandboxUid(uid)) {
425                 if (profiles.contains(new UserHandle(userId))) {
426                     if (userId != currentUserId) {
427                         // Add to a managed user item.
428                         final int managedKey = UidDetailProvider.buildKeyForUser(userId);
429                         largest = accumulate(managedKey, knownItems, bucket,
430                             AppItem.CATEGORY_USER, items, largest);
431                     }
432                     // Map SDK sandbox back to its corresponding app
433                     if (Process.isSdkSandboxUid(uid)) {
434                         collapseKey = Process.getAppUidForSdkSandboxUid(uid);
435                     } else {
436                         collapseKey = uid;
437                     }
438                     category = AppItem.CATEGORY_APP;
439                 } else {
440                     // If it is a removed user add it to the removed users' key
441                     final UserInfo info = userManager.getUserInfo(userId);
442                     if (info == null) {
443                         collapseKey = UID_REMOVED;
444                         category = AppItem.CATEGORY_APP;
445                     } else {
446                         // Add to other user item.
447                         collapseKey = UidDetailProvider.buildKeyForUser(userId);
448                         category = AppItem.CATEGORY_USER;
449                     }
450                 }
451             } else if (uid == UID_REMOVED || uid == UID_TETHERING
452                     || uid == Process.OTA_UPDATE_UID) {
453                 collapseKey = uid;
454                 category = AppItem.CATEGORY_APP;
455             } else {
456                 collapseKey = android.os.Process.SYSTEM_UID;
457                 category = AppItem.CATEGORY_APP;
458             }
459             largest = accumulate(collapseKey, knownItems, bucket, category, items, largest);
460         }
461         stats.close();
462 
463         final int restrictedUidsMax = restrictedUids.length;
464         for (int i = 0; i < restrictedUidsMax; ++i) {
465             final int uid = restrictedUids[i];
466             // Only splice in restricted state for current user or managed users
467             if (!profiles.contains(new UserHandle(UserHandle.getUserId(uid)))) {
468                 continue;
469             }
470 
471             AppItem item = knownItems.get(uid);
472             if (item == null) {
473                 item = new AppItem(uid);
474                 item.total = -1;
475                 item.addUid(uid);
476                 items.add(item);
477                 knownItems.put(item.key, item);
478             }
479             item.restricted = true;
480         }
481 
482         Collections.sort(items);
483         for (int i = 0; i < items.size(); i++) {
484             final int percentTotal = largest != 0 ? (int) (items.get(i).total * 100 / largest) : 0;
485             final AppDataUsagePreference preference = new AppDataUsagePreference(getContext(),
486                     items.get(i), percentTotal, mUidDetailProvider);
487             preference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
488                 @Override
489                 public boolean onPreferenceClick(Preference preference) {
490                     AppDataUsagePreference pref = (AppDataUsagePreference) preference;
491                     AppItem item = pref.getItem();
492                     startAppDataUsage(item);
493                     return true;
494                 }
495             });
496             mApps.addPreference(preference);
497         }
498     }
499 
500     @VisibleForTesting
startAppDataUsage(AppItem item)501     void startAppDataUsage(AppItem item) {
502         final Bundle args = new Bundle();
503         args.putParcelable(AppDataUsage.ARG_APP_ITEM, item);
504         args.putParcelable(AppDataUsage.ARG_NETWORK_TEMPLATE, mTemplate);
505         if (mCycles == null) {
506             mCycles = new ArrayList<>();
507             for (NetworkCycleChartData data : mCycleData) {
508                 if (mCycles.isEmpty()) {
509                     mCycles.add(data.getEndTime());
510                 }
511                 mCycles.add(data.getStartTime());
512             }
513         }
514         args.putSerializable(AppDataUsage.ARG_NETWORK_CYCLES, mCycles);
515         args.putLong(AppDataUsage.ARG_SELECTED_CYCLE,
516             mCycleData.get(mCycleSpinner.getSelectedItemPosition()).getEndTime());
517 
518         new SubSettingLauncher(getContext())
519                 .setDestination(AppDataUsage.class.getName())
520                 .setTitleRes(R.string.data_usage_app_summary_title)
521                 .setArguments(args)
522                 .setSourceMetricsCategory(getMetricsCategory())
523                 .launch();
524     }
525 
526     /**
527      * Accumulate data usage of a network stats entry for the item mapped by the collapse key.
528      * Creates the item if needed.
529      *
530      * @param collapseKey  the collapse key used to map the item.
531      * @param knownItems   collection of known (already existing) items.
532      * @param bucket       the network stats bucket to extract data usage from.
533      * @param itemCategory the item is categorized on the list view by this category. Must be
534      */
accumulate(int collapseKey, final SparseArray<AppItem> knownItems, Bucket bucket, int itemCategory, ArrayList<AppItem> items, long largest)535     private static long accumulate(int collapseKey, final SparseArray<AppItem> knownItems,
536             Bucket bucket, int itemCategory, ArrayList<AppItem> items, long largest) {
537         final int uid = bucket.getUid();
538         AppItem item = knownItems.get(collapseKey);
539         if (item == null) {
540             item = new AppItem(collapseKey);
541             item.category = itemCategory;
542             items.add(item);
543             knownItems.put(item.key, item);
544         }
545         item.addUid(uid);
546         item.total += bucket.getRxBytes() + bucket.getTxBytes();
547         return Math.max(largest, item.total);
548     }
549 
550     private final OnItemSelectedListener mCycleListener = new OnItemSelectedListener() {
551         @Override
552         public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
553             updateSelectedCycle();
554         }
555 
556         @Override
557         public void onNothingSelected(AdapterView<?> parent) {
558             // ignored
559         }
560     };
561 
562     @VisibleForTesting
563     final LoaderCallbacks<List<NetworkCycleChartData>> mNetworkCycleDataCallbacks =
564             new LoaderCallbacks<List<NetworkCycleChartData>>() {
565         @Override
566         public Loader<List<NetworkCycleChartData>> onCreateLoader(int id, Bundle args) {
567             return NetworkCycleChartDataLoader.builder(getContext())
568                     .setNetworkTemplate(mTemplate)
569                     .build();
570         }
571 
572         @Override
573         public void onLoadFinished(Loader<List<NetworkCycleChartData>> loader,
574                 List<NetworkCycleChartData> data) {
575             mLoadingViewController.showContent(false /* animate */);
576             mCycleData = data;
577             // calculate policy cycles based on available data
578             updatePolicy();
579             mCycleSpinner.setVisibility(View.VISIBLE);
580         }
581 
582         @Override
583         public void onLoaderReset(Loader<List<NetworkCycleChartData>> loader) {
584             mCycleData = null;
585         }
586     };
587 
588     private final LoaderCallbacks<NetworkStats> mNetworkStatsDetailCallbacks =
589             new LoaderCallbacks<NetworkStats>() {
590         @Override
591         public Loader<NetworkStats> onCreateLoader(int id, Bundle args) {
592             return new NetworkStatsSummaryLoader.Builder(getContext())
593                     .setStartTime(mChart.getInspectStart())
594                     .setEndTime(mChart.getInspectEnd())
595                     .setNetworkTemplate(mTemplate)
596                     .build();
597         }
598 
599         @Override
600         public void onLoadFinished(Loader<NetworkStats> loader, NetworkStats data) {
601             final int[] restrictedUids = services.mPolicyManager.getUidsWithPolicy(
602                     POLICY_REJECT_METERED_BACKGROUND);
603             bindStats(data, restrictedUids);
604             updateEmptyVisible();
605         }
606 
607         @Override
608         public void onLoaderReset(Loader<NetworkStats> loader) {
609             bindStats(null, new int[0]);
610             updateEmptyVisible();
611         }
612 
613         private void updateEmptyVisible() {
614             if ((mApps.getPreferenceCount() != 0) !=
615                     (getPreferenceScreen().getPreferenceCount() != 0)) {
616                 if (mApps.getPreferenceCount() != 0) {
617                     getPreferenceScreen().addPreference(mUsageAmount);
618                     getPreferenceScreen().addPreference(mApps);
619                 } else {
620                     getPreferenceScreen().removeAll();
621                 }
622             }
623         }
624     };
625 
isGuestUser(Context context)626     private static boolean isGuestUser(Context context) {
627         if (context == null) return false;
628         final UserManager userManager = context.getSystemService(UserManager.class);
629         if (userManager == null) return false;
630         return userManager.isGuestUser();
631     }
632 }
633