Change Downloads to show individual files in the Deletion Helper.
The first implementation simply had every file in the Downloads folder be under a single checkbox. This iteration makes Downloads an expandable dropdown preference listing every single file individually for selection to be deleted. Bug: 28621781 Change-Id: I5169caf718cee4c0fa7f0248bc4c443984766005
This commit is contained in:
@@ -7604,7 +7604,7 @@
|
||||
<string name="deletion_helper_downloads_title">Downloads (<xliff:g id="numItems" example="67">%1$d</xliff:g>)</string>
|
||||
|
||||
<!-- Summary of how much stale data can be cleared from the local download folder. [CHAR LIMIT=NONE]-->
|
||||
<string name="deletion_helper_downloads_summary"><xliff:g id="used" example="1.2GB">%1$s</xliff:g>, last modified <xliff:g id="days">%2$s</xliff:g></string>
|
||||
<string name="deletion_helper_downloads_summary"><xliff:g id="used" example="1.2GB">%1$s</xliff:g> • last modified <xliff:g id="days">%2$s</xliff:g></string>
|
||||
|
||||
<!-- Summary for when when there is nothing in the downloads folder to clear. [CHAR LIMIT=NONE]-->
|
||||
<string name="deletion_helper_downloads_summary_empty"><xliff:g id="used" example="1.2GB">%1$s</xliff:g></string>
|
||||
|
@@ -20,8 +20,9 @@
|
||||
<com.android.settings.PhotosDeletionPreference
|
||||
android:key="delete_photos" />
|
||||
|
||||
<com.android.settings.deletionhelper.DownloadsDeletionPreference
|
||||
android:key="delete_downloads" />
|
||||
<com.android.settings.deletionhelper.DownloadsDeletionPreferenceGroup
|
||||
android:key="delete_downloads"
|
||||
android:icon="@drawable/ic_keyboard_arrow_down_black_32"/>
|
||||
|
||||
<com.android.settings.CollapsibleCheckboxPreferenceGroup
|
||||
android:key="apps_group"
|
||||
|
@@ -25,10 +25,7 @@ import android.text.format.Formatter;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.LinearLayout;
|
||||
import com.android.settings.deletionhelper.DownloadsDeletionPreference;
|
||||
import com.android.settings.CollapsibleCheckboxPreferenceGroup;
|
||||
import com.android.settings.PhotosDeletionPreference;
|
||||
import com.android.settings.SettingsPreferenceFragment;
|
||||
@@ -70,7 +67,7 @@ public class DeletionHelperFragment extends SettingsPreferenceFragment implement
|
||||
private Button mCancel, mFree;
|
||||
private CollapsibleCheckboxPreferenceGroup mApps;
|
||||
private PhotosDeletionPreference mPhotoPreference;
|
||||
private DownloadsDeletionPreference mDownloadsPreference;
|
||||
private DownloadsDeletionPreferenceGroup mDownloadsPreference;
|
||||
|
||||
private ApplicationsState mState;
|
||||
private Session mSession;
|
||||
@@ -96,7 +93,7 @@ public class DeletionHelperFragment extends SettingsPreferenceFragment implement
|
||||
mApps = (CollapsibleCheckboxPreferenceGroup) findPreference(KEY_APPS_GROUP);
|
||||
mPhotoPreference = (PhotosDeletionPreference) findPreference(KEY_PHOTOS_VIDEOS_PREFERENCE);
|
||||
mDownloadsPreference =
|
||||
(DownloadsDeletionPreference) findPreference(KEY_DOWNLOADS_PREFERENCE);
|
||||
(DownloadsDeletionPreferenceGroup) findPreference(KEY_DOWNLOADS_PREFERENCE);
|
||||
mProvider =
|
||||
FeatureFactory.getFactory(app).getDeletionHelperFeatureProvider();
|
||||
if (mProvider != null) {
|
||||
@@ -155,14 +152,12 @@ public class DeletionHelperFragment extends SettingsPreferenceFragment implement
|
||||
super.onResume();
|
||||
mSession.resume();
|
||||
mDataUsageBridge.resume();
|
||||
mDownloadsDeletion.onResume();
|
||||
getLoaderManager().initLoader(DOWNLOADS_LOADER_ID, new Bundle(), mDownloadsDeletion);
|
||||
|
||||
if (mPhotoVideoDeletion != null) {
|
||||
mPhotoVideoDeletion.onResume();
|
||||
}
|
||||
if (mDownloadsDeletion != null) {
|
||||
mDownloadsDeletion.onResume();
|
||||
getLoaderManager().initLoader(DOWNLOADS_LOADER_ID, new Bundle(), mDownloadsDeletion);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -180,13 +175,11 @@ public class DeletionHelperFragment extends SettingsPreferenceFragment implement
|
||||
super.onPause();
|
||||
mDataUsageBridge.pause();
|
||||
mSession.pause();
|
||||
mDownloadsDeletion.onPause();
|
||||
|
||||
if (mPhotoVideoDeletion != null) {
|
||||
mPhotoVideoDeletion.onPause();
|
||||
}
|
||||
if (mDownloadsDeletion != null) {
|
||||
mDownloadsDeletion.onPause();
|
||||
}
|
||||
}
|
||||
|
||||
private void rebuild() {
|
||||
@@ -316,6 +309,7 @@ public class DeletionHelperFragment extends SettingsPreferenceFragment implement
|
||||
if (mPhotoPreference != null && mPhotoPreference.isChecked()) {
|
||||
mPhotoVideoDeletion.clearFreeableData();
|
||||
}
|
||||
mDownloadsDeletion.clearFreeableData();
|
||||
|
||||
ArraySet<String> apps = new ArraySet<>();
|
||||
for (AppEntry entry : mAppEntries) {
|
||||
@@ -351,9 +345,7 @@ public class DeletionHelperFragment extends SettingsPreferenceFragment implement
|
||||
if (mPhotoPreference != null) {
|
||||
freeableSpace += mPhotoPreference.getFreeableBytes();
|
||||
}
|
||||
if (mDownloadsPreference != null) {
|
||||
freeableSpace += mDownloadsPreference.getFreeableBytes();
|
||||
}
|
||||
freeableSpace += mDownloadsDeletion.getFreeableBytes();
|
||||
return freeableSpace;
|
||||
}
|
||||
|
||||
|
@@ -1,60 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.deletionhelper;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.format.DateUtils;
|
||||
import android.util.AttributeSet;
|
||||
import android.text.format.Formatter;
|
||||
import com.android.settings.DeletionPreference;
|
||||
import com.android.settings.R;
|
||||
|
||||
/**
|
||||
* Preference to handle the deletion of photos and videos in the Deletion Helper.
|
||||
*/
|
||||
public class DownloadsDeletionPreference extends DeletionPreference {
|
||||
public DownloadsDeletionPreference(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
updatePreferenceText(0, 0, Long.MAX_VALUE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFreeableChanged(int numItems, long freeableBytes) {
|
||||
super.onFreeableChanged(numItems, freeableBytes);
|
||||
DownloadsDeletionType deletionService = (DownloadsDeletionType) getDeletionService();
|
||||
updatePreferenceText(numItems, freeableBytes, deletionService.getMostRecentLastModified());
|
||||
}
|
||||
|
||||
private void updatePreferenceText(int items, long bytes, long mostRecent) {
|
||||
Context context = getContext();
|
||||
setTitle(context.getString(R.string.deletion_helper_downloads_title,
|
||||
items));
|
||||
// If there are no files to clear, show the empty text instead.
|
||||
if (mostRecent < Long.MAX_VALUE) {
|
||||
setSummary(context.getString(R.string.deletion_helper_downloads_summary,
|
||||
Formatter.formatFileSize(context, bytes),
|
||||
DateUtils.getRelativeTimeSpanString(mostRecent,
|
||||
System.currentTimeMillis(),
|
||||
DateUtils.DAY_IN_MILLIS,
|
||||
DateUtils.FORMAT_ABBREV_RELATIVE)));
|
||||
} else {
|
||||
setSummary(context.getString(R.string.deletion_helper_downloads_summary_empty,
|
||||
Formatter.formatFileSize(context, bytes)));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.deletionhelper;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.v7.preference.Preference;
|
||||
import android.text.format.DateUtils;
|
||||
import android.text.format.Formatter;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.AttributeSet;
|
||||
import com.android.settings.CollapsibleCheckboxPreferenceGroup;
|
||||
import com.android.settings.R;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* DownloadsDeletionPreferenceGroup defines a checkable preference group which contains
|
||||
* downloads file deletion preferences.
|
||||
*/
|
||||
public class DownloadsDeletionPreferenceGroup extends CollapsibleCheckboxPreferenceGroup
|
||||
implements DeletionType.FreeableChangedListener, Preference.OnPreferenceChangeListener {
|
||||
private DownloadsDeletionType mDeletionType;
|
||||
private DeletionType.FreeableChangedListener mListener;
|
||||
|
||||
public DownloadsDeletionPreferenceGroup(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public DownloadsDeletionPreferenceGroup(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
setOrderingAsAdded(false);
|
||||
setOnPreferenceChangeListener(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up a deletion type to get info for the preference group.
|
||||
* @param type A {@link DownloadsDeletionType}.
|
||||
*/
|
||||
public void registerDeletionService(DownloadsDeletionType type) {
|
||||
mDeletionType = type;
|
||||
mDeletionType.registerFreeableChangedListener(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a callback to be called when the amount of freeable space updates.
|
||||
* @param listener The callback listener.
|
||||
*/
|
||||
public void registerFreeableChangedListener(DeletionType.FreeableChangedListener listener) {
|
||||
mListener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFreeableChanged(int numItems, long freeableBytes) {
|
||||
updatePreferenceText(numItems, freeableBytes, mDeletionType.getMostRecentLastModified());
|
||||
maybeUpdateListener(numItems, freeableBytes);
|
||||
updateFiles();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
boolean checked = (boolean) newValue;
|
||||
if (!checked) {
|
||||
// Temporarily stop listening to avoid propagating the checked change to children.
|
||||
setOnPreferenceChangeListener(null);
|
||||
setChecked(false);
|
||||
setOnPreferenceChangeListener(this);
|
||||
}
|
||||
|
||||
// If the group checkbox changed, we need to toggle every child preference.
|
||||
if (preference == this) {
|
||||
for (int i = 0; i < getPreferenceCount(); i++) {
|
||||
DownloadsFilePreference p = (DownloadsFilePreference) getPreference(i);
|
||||
p.setOnPreferenceChangeListener(null);
|
||||
mDeletionType.toggleFile(p.getFile(), checked);
|
||||
p.setChecked(checked);
|
||||
p.setOnPreferenceChangeListener(this);
|
||||
}
|
||||
maybeUpdateListener(mDeletionType.getFiles().size(), mDeletionType.getFreeableBytes());
|
||||
return true;
|
||||
}
|
||||
|
||||
// If a single DownloadFilePreference changed, we need to toggle just itself.
|
||||
DownloadsFilePreference p = (DownloadsFilePreference) preference;
|
||||
mDeletionType.toggleFile(p.getFile(), checked);
|
||||
maybeUpdateListener(mDeletionType.getFiles().size(), mDeletionType.getFreeableBytes());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
private void updatePreferenceText(int itemCount, long bytes, long mostRecent) {
|
||||
Context context = getContext();
|
||||
setTitle(context.getString(R.string.deletion_helper_downloads_title, itemCount));
|
||||
// If there are no files to clear, show the empty text instead.
|
||||
if (itemCount != 0) {
|
||||
setSummary(context.getString(R.string.deletion_helper_downloads_summary,
|
||||
Formatter.formatFileSize(context, bytes),
|
||||
DateUtils.getRelativeTimeSpanString(mostRecent,
|
||||
System.currentTimeMillis(),
|
||||
DateUtils.DAY_IN_MILLIS,
|
||||
DateUtils.FORMAT_ABBREV_RELATIVE)));
|
||||
} else {
|
||||
setSummary(context.getString(R.string.deletion_helper_downloads_summary_empty,
|
||||
Formatter.formatFileSize(context, bytes)));
|
||||
}
|
||||
}
|
||||
|
||||
private void maybeUpdateListener(int numItems, long bytesFreeable) {
|
||||
if (mListener != null) {
|
||||
mListener.onFreeableChanged(numItems, bytesFreeable);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateFiles() {
|
||||
// TODO: Remove impl overlap with the cached preferences methods in
|
||||
// SettingsPreferenceFragment.
|
||||
|
||||
// Cache the existing file preferences.
|
||||
ArrayMap<String, Preference> cachedPreferences = new ArrayMap<>();
|
||||
for (int i = 0; i < getPreferenceCount(); i++) {
|
||||
Preference p = getPreference(i);
|
||||
cachedPreferences.put(p.getKey(), p);
|
||||
}
|
||||
|
||||
// Iterate over all of the files and re-use the old file preference, if it exists.
|
||||
Set<File> files = mDeletionType.getFiles();
|
||||
for (File file : files) {
|
||||
DownloadsFilePreference filePreference =
|
||||
(DownloadsFilePreference) cachedPreferences.remove(file.getPath());
|
||||
if (filePreference == null) {
|
||||
filePreference = new DownloadsFilePreference(getContext(), file);
|
||||
filePreference.setChecked(isChecked());
|
||||
filePreference.setOnPreferenceChangeListener(this);
|
||||
}
|
||||
addPreference(filePreference);
|
||||
}
|
||||
|
||||
// Remove all of the unused preferences.
|
||||
for (Preference p : cachedPreferences.values()) {
|
||||
removePreference(p);
|
||||
}
|
||||
}
|
||||
}
|
@@ -22,26 +22,30 @@ import android.content.Loader;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.ArraySet;
|
||||
import com.android.settings.deletionhelper.FetchDownloadsLoader.DownloadsResult;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* The DownloadsDeletionType provides stale download file information to the
|
||||
* {@link DownloadsDeletionPreference}.
|
||||
* {@link DownloadsDeletionPreferenceGroup}.
|
||||
*/
|
||||
public class DownloadsDeletionType implements DeletionType, LoaderCallbacks<DownloadsResult> {
|
||||
private int mItems;
|
||||
private long mBytes;
|
||||
private long mMostRecent;
|
||||
private FreeableChangedListener mListener;
|
||||
private FetchDownloadsLoader mTask;
|
||||
private ArrayList<File> mFiles;
|
||||
private Context mContext;
|
||||
private ArrayMap<File, Boolean> mFiles;
|
||||
|
||||
public DownloadsDeletionType(Context context) {
|
||||
mContext = context;
|
||||
mFiles = new ArrayMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -66,8 +70,10 @@ public class DownloadsDeletionType implements DeletionType, LoaderCallbacks<Down
|
||||
AsyncTask.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
for (File file : mFiles) {
|
||||
file.delete();
|
||||
for (Map.Entry<File, Boolean> entry : mFiles.entrySet()) {
|
||||
if (entry.getValue()) {
|
||||
entry.getKey().delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -83,9 +89,13 @@ public class DownloadsDeletionType implements DeletionType, LoaderCallbacks<Down
|
||||
@Override
|
||||
public void onLoadFinished(Loader<DownloadsResult> loader, DownloadsResult data) {
|
||||
mMostRecent = data.youngestLastModified;
|
||||
mFiles = data.files;
|
||||
for (File file : data.files) {
|
||||
if (mFiles.containsKey(file)) {
|
||||
continue;
|
||||
}
|
||||
mFiles.put(file, false);
|
||||
}
|
||||
mBytes = data.totalSize;
|
||||
mItems = mFiles.size();
|
||||
maybeUpdateListener();
|
||||
}
|
||||
|
||||
@@ -101,9 +111,39 @@ public class DownloadsDeletionType implements DeletionType, LoaderCallbacks<Down
|
||||
return mMostRecent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the files in the Downloads folder after the loader task finishes.
|
||||
*/
|
||||
public Set<File> getFiles() {
|
||||
if (mFiles == null) {
|
||||
return null;
|
||||
}
|
||||
return mFiles.keySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle if a file should be deleted when the service is asked to clear files.
|
||||
*/
|
||||
public void toggleFile(File file, boolean checked) {
|
||||
mFiles.put(file, checked);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of bytes that would be cleared if the deletion tasks runs.
|
||||
*/
|
||||
public long getFreeableBytes() {
|
||||
long freedBytes = 0;
|
||||
for (Map.Entry<File, Boolean> entry : mFiles.entrySet()) {
|
||||
if (entry.getValue()) {
|
||||
freedBytes += entry.getKey().length();
|
||||
}
|
||||
}
|
||||
return freedBytes;
|
||||
}
|
||||
|
||||
private void maybeUpdateListener() {
|
||||
if (mListener != null) {
|
||||
mListener.onFreeableChanged(mItems, mBytes);
|
||||
mListener.onFreeableChanged(mFiles.size(), mBytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.deletionhelper;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.v7.preference.Preference;
|
||||
import android.support.v7.preference.CheckBoxPreference;
|
||||
import android.text.format.DateUtils;
|
||||
import android.text.format.Formatter;
|
||||
import com.android.settings.R;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* DownloadsFilePreference is a preference representing a file in the Downloads folder
|
||||
* with a checkbox that represents if the file should be deleted.
|
||||
*/
|
||||
public class DownloadsFilePreference extends CheckBoxPreference {
|
||||
private File mFile;
|
||||
|
||||
public DownloadsFilePreference(Context context, File file) {
|
||||
super(context);
|
||||
mFile = file;
|
||||
setKey(mFile.getPath());
|
||||
setTitle(file.getName());
|
||||
setSummary(context.getString(R.string.deletion_helper_downloads_summary,
|
||||
Formatter.formatFileSize(getContext(), file.length()),
|
||||
DateUtils.getRelativeTimeSpanString(mFile.lastModified(),
|
||||
System.currentTimeMillis(),
|
||||
DateUtils.DAY_IN_MILLIS,
|
||||
DateUtils.FORMAT_ABBREV_RELATIVE)));
|
||||
}
|
||||
|
||||
public File getFile() {
|
||||
return mFile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Preference other) {
|
||||
if (other == null) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (other instanceof DownloadsFilePreference) {
|
||||
DownloadsFilePreference preference = (DownloadsFilePreference) other;
|
||||
return Long.compare(getFile().length(), preference.getFile().length());
|
||||
} else {
|
||||
// If a non-DownloadsFilePreference appears, consider ourselves to be greater.
|
||||
// This means if a non-DownloadsFilePreference sneaks into a DownloadsPreferenceGroup
|
||||
// then the DownloadsFilePreference will appear higher.
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user