MiscFilesHandler.java revision 8128ff8cbe239c1d50f8ba12cf375c754862df0a
1/*
2 * Copyright (C) 2010 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
17package com.android.settings.deviceinfo;
18
19import com.android.settings.R;
20import com.android.settings.deviceinfo.MemoryMeasurement.FileInfo;
21
22import android.app.ListActivity;
23import android.content.Context;
24import android.os.Bundle;
25import android.text.format.Formatter;
26import android.util.Log;
27import android.util.SparseBooleanArray;
28import android.view.ActionMode;
29import android.view.LayoutInflater;
30import android.view.Menu;
31import android.view.MenuInflater;
32import android.view.MenuItem;
33import android.view.View;
34import android.view.View.OnClickListener;
35import android.view.View.OnLongClickListener;
36import android.view.ViewGroup;
37import android.widget.BaseAdapter;
38import android.widget.CompoundButton;
39import android.widget.CompoundButton.OnCheckedChangeListener;
40import android.widget.ListView;
41
42import java.io.File;
43import java.util.ArrayList;
44import java.util.List;
45
46/**
47 * This class handles the selection and removal of Misc files.
48 */
49public class MiscFilesHandler extends ListActivity {
50    private static final String TAG = "MemorySettings";
51    private String mNumSelectedFormat;
52    private String mNumBytesSelectedFormat;
53    private MemoryMearurementAdapter mAdapter;
54    private LayoutInflater mInflater;
55
56    @Override
57    public void onCreate(Bundle savedInstanceState) {
58        super.onCreate(savedInstanceState);
59        setFinishOnTouchOutside(true);
60        setTitle(R.string.misc_files);
61        mNumSelectedFormat = getString(R.string.misc_files_selected_count);
62        mNumBytesSelectedFormat = getString(R.string.misc_files_selected_count_bytes);
63        mAdapter = new MemoryMearurementAdapter(this);
64        mInflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
65        setContentView(R.layout.settings_storage_miscfiles_list);
66        ListView lv = getListView();
67        lv.setItemsCanFocus(true);
68        lv.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
69        lv.setMultiChoiceModeListener(new ModeCallback(this));
70        setListAdapter(mAdapter);
71    }
72
73    private class ModeCallback implements ListView.MultiChoiceModeListener {
74        private int mDataCount;
75        private final Context mContext;
76
77        public ModeCallback(Context context) {
78            mContext = context;
79            mDataCount = mAdapter.getCount();
80        }
81
82        public boolean onCreateActionMode(ActionMode mode, Menu menu) {
83            final MenuInflater inflater = getMenuInflater();
84            inflater.inflate(R.menu.misc_files_menu, menu);
85            return true;
86        }
87
88        public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
89            return true;
90        }
91
92        public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
93            ListView lv = getListView();
94            switch (item.getItemId()) {
95            case R.id.action_delete:
96                // delete the files selected
97                SparseBooleanArray checkedItems = lv.getCheckedItemPositions();
98                int checkedCount = getListView().getCheckedItemCount();
99                if (checkedCount > mDataCount) {
100                    throw new IllegalStateException("checked item counts do not match. " +
101                            "checkedCount: " + checkedCount + ", dataSize: " + mDataCount);
102                }
103                if (mDataCount > 0) {
104                    ArrayList<Object> toRemove = new ArrayList<Object>();
105                    for (int i = 0; i < mDataCount; i++) {
106                        if (!checkedItems.get(i)) {
107                            //item not selected
108                            continue;
109                        }
110                        if (MemoryMeasurement.LOGV) {
111                            Log.i(TAG, "deleting: " + mAdapter.getItem(i));
112                        }
113                        // delete the file
114                        File file = new File(mAdapter.getItem(i).mFileName);
115                        if (file.isDirectory()) {
116                            deleteDir(file);
117                        } else {
118                            file.delete();
119                        }
120                        toRemove.add(mAdapter.getItem(i));
121                    }
122                    mAdapter.removeAll(toRemove);
123                    mAdapter.notifyDataSetChanged();
124                    mDataCount = mAdapter.getCount();
125                }
126                mode.finish();
127                break;
128
129            case R.id.action_select_all:
130                // check ALL items
131                for (int i = 0; i < mDataCount; i++) {
132                    lv.setItemChecked(i, true);
133                }
134                // update the title and subtitle with number selected and numberBytes selected
135                onItemCheckedStateChanged(mode, 1, 0, true);
136                break;
137            }
138            return true;
139        }
140
141        // Deletes all files and subdirectories under given dir.
142        // Returns true if all deletions were successful.
143        // If a deletion fails, the method stops attempting to delete and returns false.
144        private boolean deleteDir(File dir) {
145            if (dir.isDirectory()) {
146                String[] children = dir.list();
147                for (int i=0; i < children.length; i++) {
148                    boolean success = deleteDir(new File(dir, children[i]));
149                    if (!success) {
150                        return false;
151                    }
152                }
153            }
154            // The directory is now empty so delete it
155            return dir.delete();
156        }
157
158        public void onDestroyActionMode(ActionMode mode) {
159        }
160
161        public void onItemCheckedStateChanged(ActionMode mode, int position, long id,
162                boolean checked) {
163            ListView lv = getListView();
164            int numChecked = lv.getCheckedItemCount();
165            mode.setTitle(String.format(mNumSelectedFormat, numChecked, mAdapter.getCount()));
166
167            // total the sizes of all items selected so far
168            SparseBooleanArray checkedItems = lv.getCheckedItemPositions();
169            long selectedDataSize = 0;
170            if (numChecked > 0) {
171                for (int i = 0; i < mDataCount; i++) {
172                    if (checkedItems.get(i)) {
173                        // item is checked
174                        selectedDataSize += mAdapter.getItem(i).mSize;
175                    }
176                }
177            }
178            mode.setSubtitle(String.format(mNumBytesSelectedFormat,
179                    Formatter.formatFileSize(mContext, selectedDataSize),
180                    Formatter.formatFileSize(mContext, mAdapter.getDataSize())));
181        }
182    }
183
184    public class MemoryMearurementAdapter extends BaseAdapter {
185        private ArrayList<MemoryMeasurement.FileInfo> mData = null;
186        private long mDataSize = 0;
187        private Context mContext;
188
189        public MemoryMearurementAdapter(Context context) {
190            mContext = context;
191            MemoryMeasurement mMeasurement = MemoryMeasurement.getInstance(context);
192            mData = (ArrayList<MemoryMeasurement.FileInfo>)mMeasurement.mFileInfoForMisc;
193            if (mData != null) {
194                for (MemoryMeasurement.FileInfo info : mData) {
195                    mDataSize += info.mSize;
196                }
197            }
198        }
199
200        @Override
201        public int getCount() {
202            return (mData == null) ? 0 : mData.size();
203        }
204
205        @Override
206        public MemoryMeasurement.FileInfo getItem(int position) {
207            if (mData == null || mData.size() <= position) {
208                return null;
209            }
210            return mData.get(position);
211        }
212
213        @Override
214        public long getItemId(int position) {
215            if (mData == null || mData.size() <= position) {
216                return 0;
217            }
218            return mData.get(position).mId;
219        }
220        public void removeAll(List<Object> objs) {
221            if (mData == null) {
222                return;
223            }
224            for (Object o : objs) {
225                mData.remove(o);
226                mDataSize -= ((MemoryMeasurement.FileInfo) o).mSize;
227            }
228        }
229
230        public long getDataSize() {
231            return mDataSize;
232        }
233
234        @Override
235        public void notifyDataSetChanged() {
236            super.notifyDataSetChanged();
237        }
238
239        @Override
240        public View getView(int position, View convertView, ViewGroup parent) {
241            final FileItemInfoLayout view = (convertView == null) ?
242                    (FileItemInfoLayout) mInflater.inflate(R.layout.settings_storage_miscfiles,
243                            parent, false) : (FileItemInfoLayout) convertView;
244            FileInfo item = getItem(position);
245            view.setFileName(item.mFileName);
246            view.setFileSize(Formatter.formatFileSize(mContext, item.mSize));
247            final ListView listView = (ListView) parent;
248            final int listPosition = position;
249            view.getCheckBox().setOnCheckedChangeListener(new OnCheckedChangeListener() {
250
251                @Override
252                public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
253                    listView.setItemChecked(listPosition, isChecked);
254                }
255
256            });
257            view.setOnLongClickListener(new OnLongClickListener() {
258                @Override
259                public boolean onLongClick(View v) {
260                    if (listView.getCheckedItemCount() > 0) {
261                        return false;
262                    }
263                    listView.setItemChecked(listPosition, !view.isChecked());
264                    return true;
265                }
266            });
267            view.setOnClickListener(new OnClickListener() {
268                @Override
269                public void onClick(View v) {
270                    if (listView.getCheckedItemCount() > 0) {
271                        listView.setItemChecked(listPosition, !view.isChecked());
272                    }
273                }
274            });
275            return view;
276        }
277    }
278}