MiscFilesHandler.java revision 21809740f2fd8fe8df4e300e5d1d15f0ccedbb5f
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 mNumSelectedStr;
52    private String mNumSelectedOutOfStr;
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        mNumSelectedStr = getString(R.string.misc_files_selected_count);
62        mNumSelectedOutOfStr = getString(R.string.misc_files_selected_count_out_of);
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(mNumSelectedStr + " : " + numChecked +
166                    " " + mNumSelectedOutOfStr + " " + mAdapter.getCount());
167
168            // total the sizes of all items selected so far
169            SparseBooleanArray checkedItems = lv.getCheckedItemPositions();
170            long selectedDataSize = 0;
171            if (numChecked > 0) {
172                for (int i = 0; i < mDataCount; i++) {
173                    if (checkedItems.get(i)) {
174                        // item is checked
175                        selectedDataSize += mAdapter.getItem(i).mSize;
176                    }
177                }
178            }
179            mode.setSubtitle(Formatter.formatFileSize(mContext, selectedDataSize) +
180                    " " + mNumSelectedOutOfStr + " " +
181                    Formatter.formatFileSize(mContext, mAdapter.getDataSize()));
182        }
183    }
184
185    public class MemoryMearurementAdapter extends BaseAdapter {
186        private ArrayList<MemoryMeasurement.FileInfo> mData = null;
187        private long mDataSize = 0;
188        private Context mContext;
189
190        public MemoryMearurementAdapter(Context context) {
191            mContext = context;
192            MemoryMeasurement mMeasurement = MemoryMeasurement.getInstance(context);
193            mData = (ArrayList<MemoryMeasurement.FileInfo>)mMeasurement.mFileInfoForMisc;
194            if (mData != null) {
195                for (MemoryMeasurement.FileInfo info : mData) {
196                    mDataSize += info.mSize;
197                }
198            }
199        }
200
201        @Override
202        public int getCount() {
203            return (mData == null) ? 0 : mData.size();
204        }
205
206        @Override
207        public MemoryMeasurement.FileInfo getItem(int position) {
208            if (mData == null || mData.size() <= position) {
209                return null;
210            }
211            return mData.get(position);
212        }
213
214        @Override
215        public long getItemId(int position) {
216            if (mData == null || mData.size() <= position) {
217                return 0;
218            }
219            return mData.get(position).mId;
220        }
221        public void removeAll(List<Object> objs) {
222            if (mData == null) {
223                return;
224            }
225            for (Object o : objs) {
226                mData.remove(o);
227                mDataSize -= ((MemoryMeasurement.FileInfo) o).mSize;
228            }
229        }
230
231        public long getDataSize() {
232            return mDataSize;
233        }
234
235        @Override
236        public void notifyDataSetChanged() {
237            super.notifyDataSetChanged();
238        }
239
240        @Override
241        public View getView(int position, View convertView, ViewGroup parent) {
242            final FileItemInfoLayout view = (convertView == null) ?
243                    (FileItemInfoLayout) mInflater.inflate(R.layout.settings_storage_miscfiles,
244                            parent, false) : (FileItemInfoLayout) convertView;
245            FileInfo item = getItem(position);
246            view.setFileName(item.mFileName);
247            view.setFileSize(Formatter.formatFileSize(mContext, item.mSize));
248            final ListView listView = (ListView) parent;
249            final int listPosition = position;
250            view.getCheckBox().setOnCheckedChangeListener(new OnCheckedChangeListener() {
251
252                @Override
253                public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
254                    listView.setItemChecked(listPosition, isChecked);
255                }
256
257            });
258            view.setOnLongClickListener(new OnLongClickListener() {
259                @Override
260                public boolean onLongClick(View v) {
261                    if (listView.getCheckedItemCount() > 0) {
262                        return false;
263                    }
264                    listView.setItemChecked(listPosition, !view.isChecked());
265                    return true;
266                }
267            });
268            view.setOnClickListener(new OnClickListener() {
269                @Override
270                public void onClick(View v) {
271                    if (listView.getCheckedItemCount() > 0) {
272                        listView.setItemChecked(listPosition, !view.isChecked());
273                    }
274                }
275            });
276            return view;
277        }
278    }
279}