Home | History | Annotate | Download | only in deletionhelper
      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.storagemanager.deletionhelper;
     18 
     19 import android.content.Context;
     20 import android.support.annotation.VisibleForTesting;
     21 import android.support.v7.preference.Preference;
     22 import android.support.v7.preference.PreferenceScreen;
     23 import android.text.format.Formatter;
     24 import android.util.AttributeSet;
     25 import com.android.internal.logging.MetricsLogger;
     26 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
     27 import com.android.storagemanager.R;
     28 import com.android.storagemanager.utils.PreferenceListCache;
     29 import java.util.List;
     30 
     31 /**
     32  * AppDeletionPreferenceGroup is a collapsible checkbox preference group which contains many
     33  * apps to be cleared in the Deletion Helper.
     34  */
     35 public class AppDeletionPreferenceGroup extends CollapsibleCheckboxPreferenceGroup
     36         implements AppDeletionType.AppListener, Preference.OnPreferenceChangeListener {
     37     private AppDeletionType mBackend;
     38 
     39     @VisibleForTesting PreferenceScreen mScreen;
     40 
     41     public AppDeletionPreferenceGroup(Context context) {
     42         this(context, null);
     43     }
     44 
     45     public AppDeletionPreferenceGroup(Context context, AttributeSet attrs) {
     46         super(context, attrs);
     47         setOnPreferenceChangeListener(this);
     48         updateText();
     49     }
     50 
     51     @Override
     52     public void onAppRebuild(List<AppsAsyncLoader.PackageInfo> apps) {
     53         int appCount = apps.size();
     54         int currentUserId = getContext().getUserId();
     55         PreferenceListCache cache = new PreferenceListCache(this);
     56         for (int i = 0; i < appCount; i++) {
     57             AppsAsyncLoader.PackageInfo app = apps.get(i);
     58 
     59             if (app.userId != currentUserId) {
     60                 continue;
     61             }
     62 
     63             final String packageName = app.packageName;
     64             AppDeletionPreference preference =
     65                     (AppDeletionPreference) cache.getCachedPreference(packageName);
     66             if (preference == null) {
     67                 preference = new AppDeletionPreference(getContext(), app);
     68                 preference.setKey(packageName);
     69                 preference.setOnPreferenceChangeListener(this);
     70             }
     71             addThresholdDependentPreference(preference, isNoThreshold());
     72             preference.setChecked(mBackend.isChecked(packageName));
     73             preference.setOrder(i);
     74             preference.updateSummary();
     75         }
     76         cache.removeCachedPrefs();
     77         updateText();
     78     }
     79 
     80     private void addThresholdDependentPreference(
     81             AppDeletionPreference preference, boolean isThresholded) {
     82         if (isNoThreshold()) {
     83             addPreferenceToScreen(preference);
     84         } else {
     85             addPreference(preference);
     86         }
     87     }
     88 
     89     private boolean isNoThreshold() {
     90         return mBackend.getDeletionThreshold() == 0;
     91     }
     92 
     93     @VisibleForTesting
     94     void addPreferenceToScreen(AppDeletionPreference preference) {
     95         if (mScreen == null) {
     96             mScreen = getPreferenceManager().getPreferenceScreen();
     97         }
     98         mScreen.addPreference(preference);
     99     }
    100 
    101     @Override
    102     public boolean onPreferenceChange(Preference preference, Object newValue) {
    103         boolean isChecked = (boolean) newValue;
    104 
    105         // If we have no AppDeletionType, we have no apps to toggle.
    106         if (mBackend == null) {
    107             return true;
    108         }
    109 
    110         if (preference == this) {
    111             for (int i = 0; i < getPreferenceCount(); i++) {
    112                 AppDeletionPreference p = (AppDeletionPreference) getPreference(i);
    113                 p.setOnPreferenceChangeListener(null);
    114                 p.setChecked(isChecked);
    115                 mBackend.setChecked(p.getPackageName(), isChecked);
    116                 p.setOnPreferenceChangeListener(this);
    117             }
    118             updateText();
    119             MetricsLogger.action(getContext(), MetricsEvent.ACTION_DELETION_SELECTION_ALL_APPS,
    120                     isChecked);
    121             return true;
    122         }
    123 
    124         // If a single preference changed, we need to toggle just itself.
    125         AppDeletionPreference p = (AppDeletionPreference) preference;
    126         mBackend.setChecked(p.getPackageName(), isChecked);
    127         logAppToggle(isChecked, p.getPackageName());
    128         updateText();
    129         return true;
    130     }
    131 
    132     @Override
    133     public void onClick() {
    134         super.onClick();
    135         MetricsLogger.action(
    136                 getContext(), MetricsEvent.ACTION_DELETION_APPS_COLLAPSED, isCollapsed());
    137     }
    138 
    139     /**
    140      * Initializes the PreferenceGroup with a source of apps to list.
    141      *
    142      * @param type The AppDeletionType which provides the app list.
    143      */
    144     public void setDeletionType(AppDeletionType type) {
    145         mBackend = type;
    146     }
    147 
    148     private void updateText() {
    149         long freeableBytes = 0;
    150         long deletionThreshold = AppsAsyncLoader.UNUSED_DAYS_DELETION_THRESHOLD;
    151         if (mBackend != null) {
    152             freeableBytes =
    153                     mBackend.getTotalAppsFreeableSpace(DeletionHelperSettings.COUNT_UNCHECKED);
    154             deletionThreshold = mBackend.getDeletionThreshold();
    155             switchSpinnerToCheckboxOrDisablePreference(freeableBytes, mBackend.getLoadingStatus());
    156         }
    157         Context app = getContext();
    158         setTitle(app.getString(R.string.deletion_helper_apps_group_title));
    159         setSummary(
    160                 app.getString(
    161                         R.string.deletion_helper_apps_group_summary,
    162                         Formatter.formatFileSize(app, freeableBytes),
    163                         deletionThreshold));
    164     }
    165 
    166     private void logAppToggle(boolean checked, String packageName) {
    167         if (checked) {
    168             MetricsLogger.action(
    169                     getContext(), MetricsEvent.ACTION_DELETION_SELECTION_APP_ON, packageName);
    170         } else {
    171             MetricsLogger.action(getContext(), MetricsEvent.ACTION_DELETION_SELECTION_APP_OFF,
    172                     packageName);
    173         }
    174     }
    175 }
    176