OSDN Git Service

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