Home | History | Annotate | Download | only in deviceinfo
      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 }