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.os.Parcel; 21 import android.os.Parcelable; 22 import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat; 23 import android.support.v7.preference.Preference; 24 import android.support.v7.preference.PreferenceGroup; 25 import android.support.v7.preference.PreferenceViewHolder; 26 import android.util.AttributeSet; 27 28 import android.view.View; 29 import android.view.ViewGroup; 30 import android.widget.Checkable; 31 import android.widget.ImageView; 32 33 import com.android.storagemanager.R; 34 35 /** 36 * CollapsibleCheckboxPreferenceGroup is a preference group that can be expanded or collapsed and 37 * also has a checkbox. 38 */ 39 public class CollapsibleCheckboxPreferenceGroup extends PreferenceGroup implements 40 View.OnClickListener { 41 private boolean mCollapsed; 42 private boolean mChecked; 43 44 public CollapsibleCheckboxPreferenceGroup(Context context) { 45 this(context, null); 46 } 47 48 public CollapsibleCheckboxPreferenceGroup(Context context, AttributeSet attrs) { 49 super(context, attrs); 50 setLayoutResource(R.layout.deletion_preference); 51 setWidgetLayoutResource(R.layout.preference_widget_checkbox); 52 } 53 54 @Override 55 public void onBindViewHolder(PreferenceViewHolder holder) { 56 super.onBindViewHolder(holder); 57 View checkbox = holder.findViewById(com.android.internal.R.id.checkbox); 58 if (checkbox != null && checkbox instanceof Checkable) { 59 ((Checkable) checkbox).setChecked(mChecked); 60 61 // Expand the touch target by making the parent the touch target. 62 View parent = (View) checkbox.getParent(); 63 parent.setClickable(true); 64 parent.setFocusable(true); 65 parent.setOnClickListener(this); 66 } 67 68 // CollapsibleCheckboxPreferenceGroup considers expansion to be its "longer-term 69 // (activation) state." 70 final ImageView imageView = (ImageView) holder.findViewById(android.R.id.icon); 71 imageView.setActivated(!mCollapsed); 72 } 73 74 @Override 75 public boolean addPreference(Preference p) { 76 super.addPreference(p); 77 p.setVisible(!isCollapsed()); 78 return true; 79 } 80 81 // The preference click handler. 82 @Override 83 protected void onClick() { 84 super.onClick(); 85 setCollapse(!isCollapsed()); 86 } 87 88 // The checkbox view click handler. 89 @Override 90 public void onClick(View v) { 91 super.onClick(); 92 setChecked(!isChecked()); 93 94 // We need to find the CheckBox in the parent view that we are using as a touch target. 95 // If we don't update it before onClick finishes, the accessibility gives invalid 96 // responses. 97 ViewGroup parent = (ViewGroup) v; 98 View child = parent.findViewById(com.android.internal.R.id.checkbox); 99 Checkable checkable = (Checkable) child; 100 checkable.setChecked(mChecked); 101 } 102 103 /** 104 * Return if the view is collapsed. 105 */ 106 public boolean isCollapsed() { 107 return mCollapsed; 108 } 109 110 /** 111 * Returns the checked state of the preference. 112 */ 113 public boolean isChecked() { 114 return mChecked; 115 } 116 117 /** 118 * Sets the checked state and notifies listeners of the state change. 119 */ 120 public void setChecked(boolean checked) { 121 if (mChecked != checked) { 122 mChecked = checked; 123 124 callChangeListener(checked); 125 notifyDependencyChange(shouldDisableDependents()); 126 notifyChanged(); 127 } 128 } 129 130 @Override 131 public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfoCompat info) { 132 super.onInitializeAccessibilityNodeInfo(info); 133 info.setCheckable(true); 134 info.setChecked(isChecked()); 135 } 136 137 @Override 138 protected Parcelable onSaveInstanceState() { 139 final Parcelable superState = super.onSaveInstanceState(); 140 141 final SavedState myState = new SavedState(superState); 142 myState.checked = isChecked(); 143 myState.collapsed = isCollapsed(); 144 return myState; 145 } 146 147 @Override 148 protected void onRestoreInstanceState(Parcelable state) { 149 // Only restore the state if it is valid and our saved state. 150 if (state == null || !SavedState.class.equals(state.getClass())) { 151 super.onRestoreInstanceState(state); 152 return; 153 } 154 155 SavedState myState = (SavedState) state; 156 super.onRestoreInstanceState(myState.getSuperState()); 157 setChecked(myState.checked); 158 setCollapse(myState.collapsed); 159 } 160 161 private void setCollapse(boolean isCollapsed) { 162 if (mCollapsed == isCollapsed) { 163 return; 164 } 165 166 mCollapsed = isCollapsed; 167 setAllPreferencesVisibility(!isCollapsed); 168 notifyChanged(); 169 } 170 171 private void setAllPreferencesVisibility(boolean visible) { 172 for (int i = 0; i < getPreferenceCount(); i++) { 173 Preference p = getPreference(i); 174 p.setVisible(visible); 175 } 176 } 177 178 private static class SavedState extends BaseSavedState { 179 boolean checked; 180 boolean collapsed; 181 182 public SavedState(Parcel source) { 183 super(source); 184 checked = source.readInt() != 0; 185 collapsed = source.readInt() != 0; 186 } 187 188 public SavedState(Parcelable superState) { 189 super(superState); 190 } 191 192 @Override 193 public void writeToParcel(Parcel dest, int flags) { 194 super.writeToParcel(dest, flags); 195 dest.writeInt(checked ? 1 : 0); 196 dest.writeInt(collapsed ? 1 : 0); 197 } 198 199 public static final Parcelable.Creator<SavedState> CREATOR = 200 new Parcelable.Creator<SavedState>() { 201 public SavedState createFromParcel(Parcel in) { 202 return new SavedState(in); 203 } 204 205 public SavedState[] newArray(int size) { 206 return new SavedState[size]; 207 } 208 }; 209 } 210 } 211