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.v7.preference.Preference; 21 import android.text.format.DateUtils; 22 import android.text.format.Formatter; 23 import android.util.AttributeSet; 24 import android.view.View; 25 import com.android.internal.logging.MetricsLogger; 26 import com.android.internal.logging.MetricsProto.MetricsEvent; 27 import com.android.storagemanager.PreferenceListCache; 28 import com.android.storagemanager.R; 29 30 import java.io.File; 31 import java.util.Set; 32 33 /** 34 * DownloadsDeletionPreferenceGroup defines a checkable preference group which contains 35 * downloads file deletion preferences. 36 */ 37 public class DownloadsDeletionPreferenceGroup extends CollapsibleCheckboxPreferenceGroup 38 implements DeletionType.FreeableChangedListener, Preference.OnPreferenceChangeListener { 39 private DownloadsDeletionType mDeletionType; 40 private DeletionType.FreeableChangedListener mListener; 41 42 public DownloadsDeletionPreferenceGroup(Context context) { 43 this(context, null); 44 } 45 46 public DownloadsDeletionPreferenceGroup(Context context, AttributeSet attrs) { 47 super(context, attrs); 48 setChecked(true); 49 setOrderingAsAdded(false); 50 setOnPreferenceChangeListener(this); 51 } 52 53 /** 54 * Set up a deletion type to get info for the preference group. 55 * @param type A {@link DownloadsDeletionType}. 56 */ 57 public void registerDeletionService(DownloadsDeletionType type) { 58 mDeletionType = type; 59 mDeletionType.registerFreeableChangedListener(this); 60 } 61 62 /** 63 * Registers a callback to be called when the amount of freeable space updates. 64 * @param listener The callback listener. 65 */ 66 public void registerFreeableChangedListener(DeletionType.FreeableChangedListener listener) { 67 mListener = listener; 68 } 69 70 @Override 71 public void onFreeableChanged(int numItems, long freeableBytes) { 72 updatePreferenceText(numItems, freeableBytes, mDeletionType.getMostRecentLastModified()); 73 maybeUpdateListener(numItems, freeableBytes); 74 updateFiles(); 75 } 76 77 @Override 78 public boolean onPreferenceChange(Preference preference, Object newValue) { 79 boolean checked = (boolean) newValue; 80 if (!checked) { 81 // Temporarily stop listening to avoid propagating the checked change to children. 82 setOnPreferenceChangeListener(null); 83 setChecked(false); 84 setOnPreferenceChangeListener(this); 85 } 86 87 // If we have no deletion type, we have no files to toggle. 88 if (mDeletionType == null) { 89 return true; 90 } 91 92 // If the group checkbox changed, we need to toggle every child preference. 93 if (preference == this) { 94 for (int i = 0; i < getPreferenceCount(); i++) { 95 DownloadsFilePreference p = (DownloadsFilePreference) getPreference(i); 96 p.setOnPreferenceChangeListener(null); 97 mDeletionType.toggleFile(p.getFile(), checked); 98 p.setChecked(checked); 99 p.setOnPreferenceChangeListener(this); 100 } 101 maybeUpdateListener(mDeletionType.getFiles().size(), mDeletionType.getFreeableBytes()); 102 MetricsLogger.action(getContext(), MetricsEvent.ACTION_DELETION_SELECTION_DOWNLOADS, 103 checked); 104 return true; 105 } 106 107 // If a single DownloadFilePreference changed, we need to toggle just itself. 108 DownloadsFilePreference p = (DownloadsFilePreference) preference; 109 mDeletionType.toggleFile(p.getFile(), checked); 110 maybeUpdateListener(mDeletionType.getFiles().size(), mDeletionType.getFreeableBytes()); 111 return true; 112 } 113 114 @Override 115 public void onClick() { 116 super.onClick(); 117 MetricsLogger.action(getContext(), MetricsEvent.ACTION_DELETION_DOWNLOADS_COLLAPSED, 118 isCollapsed()); 119 } 120 121 private void updatePreferenceText(int itemCount, long bytes, long mostRecent) { 122 Context context = getContext(); 123 setTitle(context.getString(R.string.deletion_helper_downloads_title, itemCount)); 124 // If there are no files to clear, show the empty text instead. 125 if (itemCount != 0) { 126 setSummary(context.getString(R.string.deletion_helper_downloads_category_summary, 127 Formatter.formatFileSize(context, bytes))); 128 } else { 129 setSummary(context.getString(R.string.deletion_helper_downloads_summary_empty, 130 Formatter.formatFileSize(context, bytes))); 131 } 132 } 133 134 private void maybeUpdateListener(int numItems, long bytesFreeable) { 135 if (mListener != null) { 136 mListener.onFreeableChanged(numItems, bytesFreeable); 137 } 138 } 139 140 private void updateFiles() { 141 PreferenceListCache cache = new PreferenceListCache(this); 142 Set<File> files = mDeletionType.getFiles(); 143 for (File file : files) { 144 DownloadsFilePreference filePreference = 145 (DownloadsFilePreference) cache.getCachedPreference(file.getPath()); 146 if (filePreference == null) { 147 filePreference = new DownloadsFilePreference(getContext(), file); 148 filePreference.setChecked(mDeletionType.isChecked(file)); 149 filePreference.setOnPreferenceChangeListener(this); 150 } 151 addPreference(filePreference); 152 } 153 cache.removeCachedPrefs(); 154 } 155 } 156