Merge "Add a collapsible checkbox preference for deletion helper." into nyc-mr1-dev
diff --git a/res/drawable/ic_keyboard_arrow_down_black_32.xml b/res/drawable/ic_keyboard_arrow_down_black_32.xml
new file mode 100644
index 0000000..12ce9c2
--- /dev/null
+++ b/res/drawable/ic_keyboard_arrow_down_black_32.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="32dp"
+ android:height="32dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M7.41,7.84L12,12.42l4.59,-4.58L18,9.25l-6,6 -6,-6z"/>
+</vector>
\ No newline at end of file
diff --git a/res/drawable/ic_keyboard_arrow_up_black_32.xml b/res/drawable/ic_keyboard_arrow_up_black_32.xml
new file mode 100644
index 0000000..d419800
--- /dev/null
+++ b/res/drawable/ic_keyboard_arrow_up_black_32.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="32dp"
+ android:height="32dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M7.41,15.41L12,10.83l4.59,4.58L18,14l-6,-6 -6,6z"/>
+</vector>
\ No newline at end of file
diff --git a/res/values/strings.xml b/res/values/strings.xml
index bb96edd..95ce23b 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -7627,4 +7627,10 @@
<!-- Button to activate the storage manager on the storage manager upsell. [CHAR LIMIT=20]-->
<string name="deletion_helper_upsell_activate">Turn on</string>
+ <!-- Title for the apps category in the deletion helper, showing how many apps to delete. [CHAR LIMIT=40]-->
+ <string name="deletion_helper_apps_group_title">Apps (<xliff:g id="num_items">%1$d</xliff:g>)</string>
+
+ <!-- Summary for the apps category in the deletion helper, showing how many space to clear. [CHAR LIMIT=NONE]-->
+ <string name="deletion_helper_apps_group_summary"><xliff:g id="used" example="1.2GB">%1$s</xliff:g></string>
+
</resources>
diff --git a/res/xml/deletion_helper_list.xml b/res/xml/deletion_helper_list.xml
index 78d3b14..ac5a851 100644
--- a/res/xml/deletion_helper_list.xml
+++ b/res/xml/deletion_helper_list.xml
@@ -23,8 +23,8 @@
<com.android.settings.deletionhelper.DownloadsDeletionPreference
android:key="delete_downloads" />
- <PreferenceCategory
- android:key="apps_group"
- android:title="@string/deletion_helper_apps_title" />
+ <com.android.settings.CollapsibleCheckboxPreferenceGroup
+ android:key="apps_group"
+ android:icon="@drawable/ic_keyboard_arrow_down_black_32"/>
</PreferenceScreen>
diff --git a/src/com/android/settings/CollapsibleCheckboxPreferenceGroup.java b/src/com/android/settings/CollapsibleCheckboxPreferenceGroup.java
new file mode 100644
index 0000000..a0f9d98
--- /dev/null
+++ b/src/com/android/settings/CollapsibleCheckboxPreferenceGroup.java
@@ -0,0 +1,147 @@
+/*
+ * 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;
+
+import android.content.Context;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceGroup;
+import android.support.v7.preference.PreferenceViewHolder;
+import android.util.AttributeSet;
+
+import android.util.Log;
+import android.util.TypedValue;
+import android.view.View;
+import android.widget.Checkable;
+import android.widget.TextView;
+
+import java.util.LinkedHashMap;
+
+/**
+ * CollapsibleCheckboxPreferenceGroup is a preference group that can be expanded or collapsed and
+ * also has a checkbox.
+ */
+public class CollapsibleCheckboxPreferenceGroup extends PreferenceGroup implements
+ View.OnClickListener {
+ private boolean mCollapsed;
+ private boolean mChecked;
+
+ public CollapsibleCheckboxPreferenceGroup(Context context) {
+ this(context, null);
+ }
+
+ public CollapsibleCheckboxPreferenceGroup(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ setWidgetLayoutResource(com.android.settings.R.layout.preference_widget_checkbox);
+ }
+
+ @Override
+ public void onBindViewHolder(PreferenceViewHolder holder) {
+ super.onBindViewHolder(holder);
+ View checkbox = holder.findViewById(com.android.internal.R.id.checkbox);
+ if (checkbox != null && checkbox instanceof Checkable) {
+ ((Checkable) checkbox).setChecked(mChecked);
+ checkbox.setClickable(true);
+ checkbox.setFocusable(true);
+ checkbox.setOnClickListener(this);
+ }
+
+ final TextView titleView = (TextView) holder.findViewById(android.R.id.title);
+ if (titleView != null) {
+ Context context = getContext();
+ TypedValue value = new TypedValue();
+ context.getTheme().resolveAttribute(android.R.attr.colorAccent, value, true);
+ titleView.setTextColor(context.getColor(value.resourceId));
+ }
+ }
+
+ @Override
+ public boolean addPreference(Preference p) {
+ super.addPreference(p);
+ p.setVisible(!isCollapsed());
+ return true;
+ }
+
+ // The preference click handler.
+ @Override
+ protected void onClick() {
+ super.onClick();
+ setCollapse(!isCollapsed());
+ }
+
+ // The checkbox view click handler.
+ @Override
+ public void onClick(View v) {
+ setChecked(!isChecked());
+ }
+
+ /**
+ * Return if the view is collapsed.
+ */
+ public boolean isCollapsed() {
+ return mCollapsed;
+ }
+
+ /**
+ * Returns the checked state of the preference.
+ */
+ public boolean isChecked() {
+ return mChecked;
+ }
+
+ /**
+ * Sets the checked state and notifies listeners of the state change.
+ */
+ public void setChecked(boolean checked) {
+ if (mChecked != checked) {
+ mChecked = checked;
+
+ callChangeListener(checked);
+ notifyDependencyChange(shouldDisableDependents());
+ notifyChanged();
+ }
+ }
+
+ private void setCollapse(boolean isCollapsed) {
+ if (mCollapsed == isCollapsed) {
+ return;
+ }
+
+ mCollapsed = isCollapsed;
+ if (isCollapsed) {
+ hideDropdownPreferences();
+ } else {
+ showDropdownPreferences();
+ }
+ }
+
+ private void showDropdownPreferences() {
+ setAllPreferencesVisibility(true);
+ setIcon(R.drawable.ic_keyboard_arrow_down_black_32);
+ }
+
+ private void hideDropdownPreferences() {
+ setAllPreferencesVisibility(false);
+ setIcon(R.drawable.ic_keyboard_arrow_up_black_32);
+ }
+
+ private void setAllPreferencesVisibility(boolean visible) {
+ for (int i = 0; i < getPreferenceCount(); i++) {
+ Preference p = getPreference(i);
+ p.setVisible(visible);
+ }
+ }
+}
diff --git a/src/com/android/settings/deletionhelper/DeletionHelperFragment.java b/src/com/android/settings/deletionhelper/DeletionHelperFragment.java
index 6361917..e6b99df 100644
--- a/src/com/android/settings/deletionhelper/DeletionHelperFragment.java
+++ b/src/com/android/settings/deletionhelper/DeletionHelperFragment.java
@@ -16,17 +16,18 @@
package com.android.settings.deletionhelper;
+import android.app.Activity;
import android.app.Application;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.preference.Preference;
-import android.support.v7.preference.PreferenceGroup;
import android.text.format.Formatter;
import android.util.ArraySet;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import com.android.settings.deletionhelper.DownloadsDeletionPreference;
+import com.android.settings.CollapsibleCheckboxPreferenceGroup;
import com.android.settings.PhotosDeletionPreference;
import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.R;
@@ -65,7 +66,7 @@
private static final int DOWNLOADS_LOADER_ID = 1;
private Button mCancel, mFree;
- private PreferenceGroup mApps;
+ private CollapsibleCheckboxPreferenceGroup mApps;
private PhotosDeletionPreference mPhotoPreference;
private DownloadsDeletionPreference mDownloadsPreference;
@@ -82,6 +83,7 @@
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ setAnimationAllowed(true);
Application app = getActivity().getApplication();
mState = ApplicationsState.getInstance(app);
mSession = mState.newSession(this);
@@ -89,7 +91,7 @@
mDataUsageBridge = new AppStateUsageStatsBridge(getActivity(), mState, this);
addPreferencesFromResource(R.xml.deletion_helper_list);
- mApps = (PreferenceGroup) findPreference(KEY_APPS_GROUP);
+ mApps = (CollapsibleCheckboxPreferenceGroup) findPreference(KEY_APPS_GROUP);
mPhotoPreference = (PhotosDeletionPreference) findPreference(KEY_PHOTOS_VIDEOS_PREFERENCE);
mDownloadsPreference =
(DownloadsDeletionPreference) findPreference(KEY_DOWNLOADS_PREFERENCE);
@@ -131,6 +133,7 @@
mDownloadsPreference.registerFreeableChangedListener(this);
mDownloadsPreference.registerDeletionService(mDownloadsDeletion);
+ mApps.setOnPreferenceChangeListener(this);
}
@Override
@@ -191,24 +194,7 @@
ApplicationsState.SIZE_COMPARATOR);
if (apps == null) return;
mAppEntries = apps;
- cacheRemoveAllPrefs(mApps);
- int entryCount = apps.size();
- for (int i = 0; i < entryCount; i++) {
- AppEntry entry = apps.get(i);
- final String packageName = entry.label;
- AppDeletionPreference preference =
- (AppDeletionPreference) getCachedPreference(entry.label);
- if (preference == null) {
- preference = new AppDeletionPreference(getActivity(), entry,
- mState);
- preference.setKey(packageName);
- preference.setChecked(mCheckedApplications.contains(packageName));
- preference.setOnPreferenceChangeListener(this);
- mApps.addPreference(preference);
- }
- preference.setOrder(i);
- }
- removeCachedPrefs(mApps);
+ refreshAppGroup(apps);
// All applications should be filled in if we've received the sizes.
// setLoading being called multiple times causes flickering, so we only do it once.
@@ -277,11 +263,20 @@
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
boolean checked = (boolean) newValue;
+ if (preference.getKey().equals(mApps.getKey())) {
+ return toggleAllApps(checked);
+ }
+
String packageName = ((AppDeletionPreference) preference).getPackageName();
if (checked) {
mCheckedApplications.add(packageName);
} else {
mCheckedApplications.remove(packageName);
+
+ // We remove the preference change listener to avoid toggling every app on and off.
+ mApps.setOnPreferenceChangeListener(null);
+ mApps.setChecked(false);
+ mApps.setOnPreferenceChangeListener(this);
}
updateFreeButtonText();
return true;
@@ -346,17 +341,7 @@
private long getTotalFreeableSpace() {
long freeableSpace = 0;
- if (mAppEntries != null) {
-
- for (int i = 0; i < mAppEntries.size(); i++) {
- final AppEntry entry = mAppEntries.get(i);
- long entrySize = mAppEntries.get(i).size;
- // If the entrySize is negative, it is either an unknown size or an error occurred.
- if (mCheckedApplications.contains(entry.label) && entrySize > 0) {
- freeableSpace += entrySize;
- }
- }
- }
+ freeableSpace += getTotalAppsFreeableSpace(false);
if (mPhotoPreference != null) {
freeableSpace += mPhotoPreference.getFreeableBytes();
}
@@ -365,4 +350,67 @@
}
return freeableSpace;
}
+
+ private void refreshAppGroup(ArrayList<AppEntry> apps) {
+ int entryCount = apps.size();
+ cacheRemoveAllPrefs(mApps);
+ for (int i = 0; i < entryCount; i++) {
+ AppEntry entry = apps.get(i);
+ final String packageName = entry.label;
+ AppDeletionPreference preference =
+ (AppDeletionPreference) getCachedPreference(entry.label);
+ if (preference == null) {
+ preference = new AppDeletionPreference(getActivity(), entry, mState);
+ preference.setKey(packageName);
+ preference.setOnPreferenceChangeListener(this);
+ mApps.addPreference(preference);
+ }
+ preference.setChecked(mCheckedApplications.contains(packageName));
+ preference.setOrder(i);
+ }
+ removeCachedPrefs(mApps);
+ updateAppsGroupText();
+ }
+
+ private long getTotalAppsFreeableSpace(boolean countUnchecked) {
+ long freeableSpace = 0;
+ if (mAppEntries != null) {
+ for (int i = 0; i < mAppEntries.size(); i++) {
+ final AppEntry entry = mAppEntries.get(i);
+ long entrySize = mAppEntries.get(i).size;
+ // If the entrySize is negative, it is either an unknown size or an error occurred.
+ if ((countUnchecked ||
+ mCheckedApplications.contains(entry.label)) && entrySize > 0) {
+ freeableSpace += entrySize;
+ }
+ }
+ }
+
+ return freeableSpace;
+ }
+
+ private void updateAppsGroupText() {
+ if (mAppEntries != null) {
+ Activity app = getActivity();
+ mApps.setTitle(app.getString(R.string.deletion_helper_apps_group_title,
+ mAppEntries.size()));
+ mApps.setSummary(app.getString(R.string.deletion_helper_apps_group_summary,
+ Formatter.formatFileSize(app,
+ getTotalAppsFreeableSpace(true))));
+ }
+ }
+
+ private boolean toggleAllApps(boolean checked) {
+ for (AppEntry entry : mAppEntries) {
+ final String packageName = entry.label;
+ if (checked) {
+ mCheckedApplications.add(packageName);
+ } else {
+ mCheckedApplications.remove(packageName);
+ }
+ }
+ refreshAppGroup(mAppEntries);
+ updateFreeButtonText();
+ return true;
+ }
}
\ No newline at end of file