display amount of storage on /sdcard by downloads, music etc

when music storage usage is clicked on, show music app
when downloads storage usage is clicked on, show download app
when pic/videos storage usage is clicked on, show gallery app

Change-Id: Ia1c341013e550acb537e6f8a4f4558030888cc45
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 86903ed..e092bc9 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -4,6 +4,7 @@
 
     <original-package android:name="com.android.settings" />
 
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.WRITE_SETTINGS" />
     <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
     <uses-permission android:name="android.permission.DEVICE_POWER" />
@@ -763,6 +764,9 @@
                 android:resource="@id/storage_settings" />
         </activity>
 
+        <activity android:name=".deviceinfo.MiscFilesHandler"
+                android:theme="@android:style/Theme.Holo.DialogWhenLarge"/>
+
         <activity android:name="ApnEditor"
                 android:label="@string/apn_edit"
                 android:theme="@android:style/Theme.Holo.DialogWhenLarge">
diff --git a/res/layout/settings_storage_miscfiles.xml b/res/layout/settings_storage_miscfiles.xml
new file mode 100644
index 0000000..7c52efa
--- /dev/null
+++ b/res/layout/settings_storage_miscfiles.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2010, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<com.android.settings.deviceinfo.FileItemInfoLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="?android:attr/listPreferredItemHeight"
+    android:paddingRight="?android:attr/scrollbarSize"
+    android:background="?android:attr/selectableItemBackground"
+    android:gravity="center_vertical"
+    android:focusable="true">
+
+    <CheckBox android:id="@+id/misc_checkbox"
+              android:layout_width="wrap_content"
+              android:layout_height="match_parent"
+              android:layout_alignParentLeft="true"
+              android:paddingLeft="16dip"
+              android:scaleType="fitCenter"
+              android:layout_centerVertical="true"/>
+
+    <TextView android:id="@+id/misc_filename"
+              android:layout_width="wrap_content"
+              android:layout_height="wrap_content"
+              android:layout_toRightOf="@id/misc_checkbox"
+              android:maxLines="1"
+              android:paddingLeft="16dip"
+              android:textAppearance="?android:attr/textAppearanceSmall"/>
+
+    <TextView android:id="@+id/misc_filesize"
+              android:layout_width="wrap_content"
+              android:layout_height="wrap_content"
+              android:layout_toRightOf="@id/misc_checkbox"
+              android:layout_below="@id/misc_filename"
+              android:maxLines="1"
+              android:paddingLeft="16dip"
+              android:textStyle="bold"
+              android:textAppearance="?android:attr/textAppearanceSmall" />
+</com.android.settings.deviceinfo.FileItemInfoLayout>
+
diff --git a/res/layout/settings_storage_miscfiles_list.xml b/res/layout/settings_storage_miscfiles_list.xml
new file mode 100644
index 0000000..5f8c5ed
--- /dev/null
+++ b/res/layout/settings_storage_miscfiles_list.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2010, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:paddingRight="16dip"
+    android:paddingLeft="16dip">
+
+    <ListView android:id="@android:id/list"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"/>
+
+</FrameLayout>
+
diff --git a/res/menu/misc_files_menu.xml b/res/menu/misc_files_menu.xml
new file mode 100644
index 0000000..80fdd2f
--- /dev/null
+++ b/res/menu/misc_files_menu.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:id="@+id/action_delete"
+          android:title="@string/delete"
+          android:icon="@android:drawable/ic_menu_delete"/>
+    <item android:id="@+id/action_select_all"
+          android:title="@string/select_all"
+          android:showAsAction="ifRoom" />
+</menu>
+
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 0b8beb6..715a679 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -19,9 +19,12 @@
     <color name="red">#F00</color>
 
     <color name="memory_avail">#333</color>
-    <color name="memory_media_usage">#F33</color>
-    <color name="memory_apps_usage">#3F3</color>
-    <color name="memory_used">#FFF</color>
+    <color name="memory_apps_usage">#FFF</color>
+    <color name="memory_used">#F00</color>
+    <color name="memory_downloads">#F00</color>
+    <color name="memory_video">#0F0</color>
+    <color name="memory_audio">#00F</color>
+    <color name="memory_misc">#FF0</color>
     
     <color name="crypt_keeper_clock_background">#ff9a9a9a</color>
     <color name="crypt_keeper_clock_foreground">#ff666666</color>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 80a4a37..5d2aa33 100755
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -18,4 +18,5 @@
     <dimen name="vpn_connect_margin_right">10sp</dimen>
     <dimen name="vpn_connect_normal_text_size">16sp</dimen>
     <dimen name="vpn_connect_input_box_label_width">90sp</dimen>
+    <dimen name="device_memory_usage_button_size">32dip</dimen>
 </resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index f4ecc63..b481ffe 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1566,10 +1566,18 @@
     <string name="memory_size">Total</string>
     <!-- SD card & phone storage settings summary. Displayed when the total memory usage is being calculated. Will be replaced with a number like "12.3 GB" when finished calucating. [CHAR LIMIT=30] -->
     <string name="memory_calculating_size">Calculating…</string>
-    <!-- SD card & phone storage settings title. Displayed as a title when showing the total usage of applications installed. Below it will be a number like "123.4 MB" indicating used storage. [CHAR LIMIT=30] -->
+    <!-- SD card & phone storage settings title. Displayed as a title when showing the total usage of applications installed. Below it will be a number like "123.4 MB" indicating used storage. [CHAR LIMIT=50] -->
     <string name="memory_apps_usage">Applications</string>
-    <!-- SD card & phone storage settings title. Displayed as a title when showing the total usage of media on the device. Below it will be a number like "123.4 MB" indicating used storage. [CHAR LIMIT=30] -->
+    <!-- SD card & phone storage settings title. Displayed as a title when showing the total usage of media on the device. Below it will be a number like "123.4 MB" indicating used storage. [CHAR LIMIT=50] -->
     <string name="memory_media_usage">Media</string>
+    <!-- SD card & phone storage settings title. Displayed as a title when showing the total usage of /sdcard/Download on the device. Below it will be a number like "123.4 MB" indicating used storage. [CHAR LIMIT=50] -->
+    <string name="memory_downloads_usage">Downloads</string>
+    <!-- SD card & phone storage settings title. Displayed as a title when showing the total usage of all pictures, videos in /sdcard/DCIM, /sdcard/Pictures folders on the device. Below it will be a number like "123.4 MB" indicating used storage. [CHAR LIMIT=50] -->
+    <string name="memory_dcim_usage">Pictures, Videos</string>
+    <!-- SD card & phone storage settings title. Displayed as a title when showing the total usage of audio files in /sdcard on the device. Below it will be a number like "123.4 MB" indicating used storage. [CHAR LIMIT=50] -->
+    <string name="memory_music_usage">Audio (music, ringtones, podcasts etc)</string>
+    <!-- SD card & phone storage settings title. Displayed as a title when showing the total usage of misc files on the device. Below it will be a number like "123.4 MB" indicating used storage. [CHAR LIMIT=50] -->
+    <string name="memory_media_misc_usage">Misc.</string>
     <!-- SD card & phone storage settings item title that will result in the phone unmounting the SD card.  This will be done before the user phyiscally removes the SD card from the phone.  Kind of like the "Safely remove" on some operating systems.   [CHAR LIMIT=25] -->
     <string name="sd_eject" product="nosdcard">Unmount shared storage</string>
     <!-- SD card & phone storage settings item title that will result in the phone unmounting the SD card.  This will be done before the user phyiscally removes the SD card from the phone.  Kind of like the "Safely remove" on some operating systems.   -->
@@ -3257,4 +3265,15 @@
     <!-- This error message is displayed when the vpn profile is going to be saved but the vpn service is busy [CHAR LIMIT=NONE] -->
     <string name="service_busy">Service busy, try again</string>
 
+    <!-- the following are for Settings Storage screen -->
+    <!-- Menu item/button 'delete' -->
+    <string name="delete">Delete</string>
+    <!-- Misc files [CHAR LIMIT=25] -->
+    <string name="misc_files">Misc Files</string>
+    <!-- number of misc files selected [CHAR LIMIT=20] -->
+    <string name="misc_files_selected_count">selected</string>
+    <!-- the string 'out of' displayed when saying "selected N out of M" [CHAR LIMIT=20] -->
+    <string name="misc_files_selected_count_out_of">out of</string>
+    <!--  action to select all [CHAR LIMIT=30] -->
+    <string name="select_all">Select All</string>
 </resources>
diff --git a/res/xml/device_info_memory.xml b/res/xml/device_info_memory.xml
index 368862a..b536d00 100644
--- a/res/xml/device_info_memory.xml
+++ b/res/xml/device_info_memory.xml
@@ -41,14 +41,29 @@
         <Preference android:key="memory_internal_size"
             android:title="@string/memory_size"
             android:summary="@string/memory_calculating_size"/>
-        <Preference android:key="memory_internal_media"
-            android:title="@string/memory_media_usage"
+
+        <Preference android:key="memory_internal_avail"
+            android:title="@string/memory_available"
             android:summary="@string/memory_calculating_size"/>
+
         <Preference android:key="memory_internal_apps"
             android:title="@string/memory_apps_usage"
             android:summary="@string/memory_calculating_size"/>
-        <Preference android:key="memory_internal_avail"
-            android:title="@string/memory_available"
+
+        <Preference android:key="memory_internal_downloads"
+            android:title="@string/memory_downloads_usage"
+            android:summary="@string/memory_calculating_size"/>
+
+        <Preference android:key="memory_internal_dcim"
+            android:title="@string/memory_dcim_usage"
+            android:summary="@string/memory_calculating_size"/>
+
+        <Preference android:key="memory_internal_music"
+            android:title="@string/memory_music_usage"
+            android:summary="@string/memory_calculating_size"/>
+
+        <Preference android:key="memory_internal_media_misc"
+            android:title="@string/memory_media_misc_usage"
             android:summary="@string/memory_calculating_size"/>
     </PreferenceCategory>
 
diff --git a/src/com/android/settings/deviceinfo/Constants.java b/src/com/android/settings/deviceinfo/Constants.java
new file mode 100644
index 0000000..9f49479
--- /dev/null
+++ b/src/com/android/settings/deviceinfo/Constants.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.settings.deviceinfo;
+
+import android.os.Environment;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Some of the constants used in this package
+ */
+class Constants {
+    static final int MEDIA_INDEX = 0;
+    static final int DOWNLOADS_INDEX = 1;
+    static final int PIC_VIDEO_INDEX = 2;
+    static final int MUSIC_INDEX = 3;
+    static final int MEDIA_APPS_DATA_INDEX = 4;
+    static final int MEDIA_MISC_INDEX = 5;
+    static final int NUM_MEDIA_DIRS_TRACKED = MEDIA_MISC_INDEX + 1;
+
+    static class MediaDirectory {
+        final String[] mDirPaths;
+        final String mKey;
+        final String mPreferenceName;
+        MediaDirectory(String pref, String debugInfo, String... paths) {
+            mDirPaths = paths;
+            mKey = debugInfo;
+            mPreferenceName = pref;
+        }
+    }
+    static final ArrayList<MediaDirectory> mMediaDirs = new ArrayList<MediaDirectory>();
+    static final List<String> ExclusionTargetsForMiscFiles = new ArrayList<String>();
+    static {
+        mMediaDirs.add(MEDIA_INDEX,
+                new MediaDirectory(null,
+                        "/sdcard",
+                        Environment.getExternalStorageDirectory().getAbsolutePath()));
+        mMediaDirs.add(DOWNLOADS_INDEX,
+                new MediaDirectory("memory_internal_downloads",
+                        "/sdcard/download",
+                        Environment.getExternalStoragePublicDirectory(
+                                Environment.DIRECTORY_DOWNLOADS).getAbsolutePath()));
+        mMediaDirs.add(PIC_VIDEO_INDEX,
+                new MediaDirectory("memory_internal_dcim",
+                        "/sdcard/pic_video",
+                        Environment.getExternalStoragePublicDirectory(
+                                Environment.DIRECTORY_DCIM).getAbsolutePath(),
+                        Environment.getExternalStoragePublicDirectory(
+                                Environment.DIRECTORY_MOVIES).getAbsolutePath(),
+                        Environment.getExternalStoragePublicDirectory(
+                                Environment.DIRECTORY_PICTURES).getAbsolutePath()));
+        mMediaDirs.add(MUSIC_INDEX,
+                new MediaDirectory("memory_internal_music",
+                        "/sdcard/audio",
+                        Environment.getExternalStoragePublicDirectory(
+                                Environment.DIRECTORY_MUSIC).getAbsolutePath(),
+                        Environment.getExternalStoragePublicDirectory(
+                                Environment.DIRECTORY_ALARMS).getAbsolutePath(),
+                        Environment.getExternalStoragePublicDirectory(
+                                Environment.DIRECTORY_NOTIFICATIONS).getAbsolutePath(),
+                        Environment.getExternalStoragePublicDirectory(
+                                Environment.DIRECTORY_RINGTONES).getAbsolutePath(),
+                        Environment.getExternalStoragePublicDirectory(
+                                Environment.DIRECTORY_PODCASTS).getAbsolutePath()));
+        mMediaDirs.add(MEDIA_APPS_DATA_INDEX,
+                new MediaDirectory(null,
+                        "/sdcard/Android",
+                        Environment.getExternalStorageAndroidDataDir().getAbsolutePath()));
+        mMediaDirs.add(MEDIA_MISC_INDEX,
+                new MediaDirectory("memory_internal_media_misc",
+                        "misc on /sdcard",
+                        "not relevant"));
+        // prepare a lit of strings representing dirpaths that should be skipped while looking
+        // for 'other' files
+        for (int j = 0; j < Constants.NUM_MEDIA_DIRS_TRACKED - 1; j++) {
+            String[] dirs = Constants.mMediaDirs.get(j).mDirPaths;
+            int len = dirs.length;
+            if (len > 0) {
+                for (int k = 0; k < len; k++) {
+                    ExclusionTargetsForMiscFiles.add(dirs[k]);
+                }
+            }
+            // also add /sdcard/Android
+            ExclusionTargetsForMiscFiles.add(
+                    Environment.getExternalStorageDirectory().getAbsolutePath() + "/Android");
+        }
+    }
+}
diff --git a/src/com/android/settings/deviceinfo/FileItemInfoLayout.java b/src/com/android/settings/deviceinfo/FileItemInfoLayout.java
new file mode 100644
index 0000000..990f7f2
--- /dev/null
+++ b/src/com/android/settings/deviceinfo/FileItemInfoLayout.java
@@ -0,0 +1,78 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+package com.android.settings.deviceinfo;
+
+import com.android.settings.R;
+
+import android.content.Context;
+import android.os.Environment;
+import android.util.AttributeSet;
+import android.view.ViewDebug;
+import android.widget.CheckBox;
+import android.widget.Checkable;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+/**
+ * Handles display of a single row entry on Settings --> Storage --> Misc Files screen
+ */
+public class FileItemInfoLayout extends RelativeLayout implements Checkable {
+    private TextView mFileNameView;
+    private TextView mFileSizeView;
+    private CheckBox mCheckbox;
+    private static final int mLengthExternalStorageDirPrefix =
+            Environment.getExternalStorageDirectory().getAbsolutePath().length() + 1;
+
+    public FileItemInfoLayout(Context context) {
+        this(context, null);
+    }
+
+    public FileItemInfoLayout(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public FileItemInfoLayout(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    public void toggle() {
+        setChecked(!mCheckbox.isChecked());
+    }
+
+    /* (non-Javadoc)
+     * @see android.view.View#onFinishInflate()
+     */
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mFileNameView = (TextView) findViewById(R.id.misc_filename);
+        mFileSizeView = (TextView) findViewById(R.id.misc_filesize);
+        mCheckbox = (CheckBox) findViewById(R.id.misc_checkbox);
+    }
+
+    public void setFileName(String fileName) {
+        mFileNameView.setText(fileName.substring(mLengthExternalStorageDirPrefix));
+    }
+
+    public void setFileSize(String filesize) {
+        mFileSizeView.setText(filesize);
+    }
+
+    @ViewDebug.ExportedProperty
+    public boolean isChecked() {
+        return mCheckbox.isChecked();
+    }
+
+    public CheckBox getCheckBox() {
+        return mCheckbox;
+    }
+
+    /**
+     * <p>Changes the checked state of this text view.</p>
+     *
+     * @param checked true to check the text, false to uncheck it
+     */
+    public void setChecked(boolean checked) {
+        mCheckbox.setChecked(checked);
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/settings/deviceinfo/Memory.java b/src/com/android/settings/deviceinfo/Memory.java
index db1ff65..7cb378c 100644
--- a/src/com/android/settings/deviceinfo/Memory.java
+++ b/src/com/android/settings/deviceinfo/Memory.java
@@ -23,6 +23,7 @@
 import android.app.ActivityManager;
 import android.app.AlertDialog;
 import android.app.Dialog;
+import android.app.DownloadManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.DialogInterface;
@@ -32,9 +33,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.res.Resources;
 import android.graphics.drawable.ShapeDrawable;
-import android.graphics.drawable.shapes.RectShape;
 import android.graphics.drawable.shapes.RoundRectShape;
-import android.hardware.UsbManager;
 import android.os.Bundle;
 import android.os.Environment;
 import android.os.Handler;
@@ -56,8 +55,7 @@
 
 public class Memory extends SettingsPreferenceFragment implements OnCancelListener,
         MeasurementReceiver {
-    private static final String TAG = "Memory";
-    static final boolean localLOGV = false;
+    private static final String TAG = "MemorySettings";
 
     private static final String MEMORY_SD_SIZE = "memory_sd_size";
 
@@ -75,8 +73,6 @@
 
     private static final String MEMORY_INTERNAL_APPS = "memory_internal_apps";
 
-    private static final String MEMORY_INTERNAL_MEDIA = "memory_internal_media";
-
     private static final String MEMORY_INTERNAL_CHART = "memory_internal_chart";
 
     private static final int DLG_CONFIRM_UNMOUNT = 1;
@@ -94,13 +90,13 @@
     // Internal storage preferences
     private Preference mInternalSize;
     private Preference mInternalAvail;
-    private Preference mInternalMediaUsage;
     private Preference mInternalAppsUsage;
+    private final Preference[] mMediaPreferences = new Preference[Constants.NUM_MEDIA_DIRS_TRACKED];
     private UsageBarPreference mInternalUsageChart;
 
     // Internal storage chart colors
-    private int mInternalMediaColor;
     private int mInternalAppsColor;
+    private int mInternalAvailColor;
     private int mInternalUsedColor;
 
     boolean mSdMountToggleAdded = true;
@@ -134,9 +130,12 @@
                     Bundle bundle = msg.getData();
                     final long totalSize = bundle.getLong(MemoryMeasurement.TOTAL_SIZE);
                     final long availSize = bundle.getLong(MemoryMeasurement.AVAIL_SIZE);
-                    final long mediaUsed = bundle.getLong(MemoryMeasurement.MEDIA_USED);
                     final long appsUsed = bundle.getLong(MemoryMeasurement.APPS_USED);
-                    updateUiExact(totalSize, availSize, mediaUsed, appsUsed);
+                    final long[] mediaSizes = new long[Constants.NUM_MEDIA_DIRS_TRACKED];
+                    for (int i = 0; i < Constants.NUM_MEDIA_DIRS_TRACKED; i++) {
+                        mediaSizes[i] = bundle.getLong(Constants.mMediaDirs.get(i).mKey);
+                    }
+                    updateUiExact(totalSize, availSize, appsUsed, mediaSizes);
                     break;
                 }
                 case MSG_UI_UPDATE_EXTERNAL_APPROXIMATE: {
@@ -175,31 +174,59 @@
         }
 
         mInternalSize = findPreference(MEMORY_INTERNAL_SIZE);
-        mInternalAvail = findPreference(MEMORY_INTERNAL_AVAIL);
-        mInternalMediaUsage = findPreference(MEMORY_INTERNAL_MEDIA);
-        mInternalAppsUsage = findPreference(MEMORY_INTERNAL_APPS);
-
-        mInternalMediaColor = mRes.getColor(R.color.memory_media_usage);
         mInternalAppsColor = mRes.getColor(R.color.memory_apps_usage);
         mInternalUsedColor = android.graphics.Color.GRAY;
-
+        mInternalAvailColor = mRes.getColor(R.color.memory_avail);
+        final int buttonSize = (int) mRes.getDimension(R.dimen.device_memory_usage_button_size);
         float[] radius = new float[] {
                 5f, 5f, 5f, 5f, 5f, 5f, 5f, 5f
         };
         RoundRectShape shape1 = new RoundRectShape(radius, null, null);
 
-        ShapeDrawable mediaShape = new ShapeDrawable(shape1);
-        mediaShape.setIntrinsicWidth(32);
-        mediaShape.setIntrinsicHeight(32);
-        mediaShape.getPaint().setColor(mInternalMediaColor);
-        mInternalMediaUsage.setIcon(mediaShape);
+        // total available space
+        mInternalAvail = findPreference(MEMORY_INTERNAL_AVAIL);
+        ShapeDrawable availShape = new ShapeDrawable(shape1);
+        availShape.setIntrinsicWidth(buttonSize);
+        availShape.setIntrinsicHeight(buttonSize);
+        availShape.getPaint().setColor(mInternalAvailColor);
+        mInternalAvail.setIcon(availShape);
 
+        // used by apps
+        mInternalAppsUsage = findPreference(MEMORY_INTERNAL_APPS);
         ShapeDrawable appsShape = new ShapeDrawable(shape1);
-        appsShape.setIntrinsicWidth(32);
-        appsShape.setIntrinsicHeight(32);
+        appsShape.setIntrinsicWidth(buttonSize);
+        appsShape.setIntrinsicHeight(buttonSize);
         appsShape.getPaint().setColor(mInternalAppsColor);
         mInternalAppsUsage.setIcon(appsShape);
 
+        // space used by individual major directories on /sdcard
+        for (int i = 0; i < Constants.NUM_MEDIA_DIRS_TRACKED; i++) {
+            // nothing to be displayed for certain entries in Constants.mMediaDirs
+            if (Constants.mMediaDirs.get(i).mPreferenceName == null) {
+                continue;
+            }
+            mMediaPreferences[i] = findPreference(Constants.mMediaDirs.get(i).mPreferenceName);
+            ShapeDrawable shape = new ShapeDrawable(shape1);
+            shape.setIntrinsicWidth(buttonSize);
+            shape.setIntrinsicHeight(buttonSize);
+            int color = 0;
+            switch (i) {
+                case Constants.DOWNLOADS_INDEX:
+                    color = mRes.getColor(R.color.memory_downloads);
+                    break;
+                case Constants.PIC_VIDEO_INDEX:
+                    color = mRes.getColor(R.color.memory_video);
+                    break;
+                case Constants.MUSIC_INDEX:
+                    color = mRes.getColor(R.color.memory_audio);
+                    break;
+                case Constants.MEDIA_MISC_INDEX:
+                    color = mRes.getColor(R.color.memory_misc);
+                    break;
+            }
+            shape.getPaint().setColor(color);
+            mMediaPreferences[i].setIcon(shape);
+        }
         mInternalUsageChart = (UsageBarPreference) findPreference(MEMORY_INTERNAL_CHART);
 
         mMeasurement = MemoryMeasurement.getInstance(getActivity());
@@ -209,7 +236,7 @@
     @Override
     public void onResume() {
         super.onResume();
-
+        mMeasurement.setReceiver(this);
         IntentFilter intentFilter = new IntentFilter(Intent.ACTION_MEDIA_SCANNER_STARTED);
         intentFilter.addAction(Intent.ACTION_MEDIA_SCANNER_FINISHED);
         intentFilter.addDataScheme("file");
@@ -282,6 +309,27 @@
                     com.android.settings.Settings.ManageApplicationsActivity.class);
             startActivity(intent);
             return true;
+        } else if (preference == mMediaPreferences[Constants.DOWNLOADS_INDEX]) {
+            Intent intent = new Intent(DownloadManager.ACTION_VIEW_DOWNLOADS)
+                    .putExtra(DownloadManager.INTENT_EXTRAS_SORT_BY_SIZE, true);
+            startActivity(intent);
+            return true;
+        } else if (preference == mMediaPreferences[Constants.MUSIC_INDEX]) {
+            Intent intent = new Intent("android.intent.action.GET_CONTENT");
+            intent.setType("audio/mp3");
+            startActivity(intent);
+            return true;
+        } else if (preference == mMediaPreferences[Constants.PIC_VIDEO_INDEX]) {
+            Intent intent = new Intent("android.intent.action.GET_CONTENT");
+            intent.setType("image/jpeg");
+            startActivity(intent);
+            return true;
+        } else if (preference == mMediaPreferences[Constants.MEDIA_MISC_INDEX]) {
+            Context context = getActivity().getApplicationContext();
+            if (MemoryMeasurement.getInstance(context).isSizeOfMiscCategorynonZero()) {
+                startActivity(new Intent(context, MiscFilesHandler.class));
+            }
+            return true;
         }
 
         return false;
@@ -375,7 +423,6 @@
         // Check if external media is in use.
         try {
            if (hasAppsAccessingStorage()) {
-               if (localLOGV) Log.i(TAG, "Do have storage users accessing media");
                // Present dialog to user
                showDialogInner(DLG_CONFIRM_UNMOUNT);
            } else {
@@ -400,19 +447,45 @@
         }
     }
 
-    private void updateUiExact(long totalSize, long availSize, long mediaSize, long appsSize) {
+    private void updateUiExact(long totalSize, long availSize, long appsSize, long[] mediaSizes) {
         // There are other things that can take up storage, but we didn't measure it.
         // add that unaccounted-for-usage to Apps Usage
-        final long appsPlusRemaining = totalSize - availSize - mediaSize;
-
+        long appsPlusRemaining = totalSize - availSize - mediaSizes[Constants.DOWNLOADS_INDEX] -
+                mediaSizes[Constants.PIC_VIDEO_INDEX] - mediaSizes[Constants.MUSIC_INDEX] -
+                mediaSizes[Constants.MEDIA_MISC_INDEX];
         mInternalSize.setSummary(formatSize(totalSize));
         mInternalAvail.setSummary(formatSize(availSize));
-        mInternalMediaUsage.setSummary(formatSize(mediaSize));
         mInternalAppsUsage.setSummary(formatSize(appsPlusRemaining));
 
         mInternalUsageChart.clear();
-        mInternalUsageChart.addEntry(mediaSize / (float) totalSize, mInternalMediaColor);
         mInternalUsageChart.addEntry(appsPlusRemaining / (float) totalSize, mInternalAppsColor);
+
+        for (int i = 0; i < Constants.NUM_MEDIA_DIRS_TRACKED; i++) {
+            if (Constants.mMediaDirs.get(i).mPreferenceName == null) {
+                continue;
+            }
+            this.mMediaPreferences[i].setSummary(formatSize(mediaSizes[i]));
+            // don't add entry to color chart for media usage and for zero-sized dirs
+            if (i != Constants.MEDIA_INDEX && mediaSizes[i] > 0) {
+                int color = 0;
+                switch (i) {
+                    case Constants.DOWNLOADS_INDEX:
+                        color = mRes.getColor(R.color.memory_downloads);
+                        break;
+                    case Constants.PIC_VIDEO_INDEX:
+                        color = mRes.getColor(R.color.memory_video);
+                        break;
+                    case Constants.MUSIC_INDEX:
+                        color = mRes.getColor(R.color.memory_audio);
+                        break;
+                    case Constants.MEDIA_MISC_INDEX:
+                        color = mRes.getColor(R.color.memory_misc);
+                        break;
+                }
+                mInternalUsageChart.addEntry(mediaSizes[i] / (float) totalSize, color);
+            }
+        }
+        mInternalUsageChart.addEntry(availSize / (float) totalSize, mInternalAvailColor);
         mInternalUsageChart.commit();
     }
 
diff --git a/src/com/android/settings/deviceinfo/MemoryMeasurement.java b/src/com/android/settings/deviceinfo/MemoryMeasurement.java
index 1aef202..3f57f21 100644
--- a/src/com/android/settings/deviceinfo/MemoryMeasurement.java
+++ b/src/com/android/settings/deviceinfo/MemoryMeasurement.java
@@ -23,6 +23,7 @@
 import java.io.File;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 
 /**
@@ -35,14 +36,16 @@
  *
  *   Filesystem stats (using StatFs)
  *   Directory measurements (using DefaultContainerService.measureDir)
- *   Applicaiton measurements (using PackageManager)
+ *   Application measurements (using PackageManager)
  *
  * Then the calling application would just specify the type and an argument.
  * This class would keep track of it while the calling application would
  * decide on how to use it.
  */
 public class MemoryMeasurement {
-    private static final String TAG = "MemoryMeasurement";
+    private static final String TAG = "MemorySettings";
+    private static final boolean LOCAL_LOGV = true;
+    static final boolean LOGV = LOCAL_LOGV && Log.isLoggable(TAG, Log.VERBOSE);
 
     public static final String TOTAL_SIZE = "total_size";
 
@@ -50,7 +53,7 @@
 
     public static final String APPS_USED = "apps_used";
 
-    public static final String MEDIA_USED = "media_used";
+    private long[] mMediaSizes = new long[Constants.NUM_MEDIA_DIRS_TRACKED];
 
     private static final String DEFAULT_CONTAINER_PACKAGE = "com.android.defcontainer";
 
@@ -66,13 +69,13 @@
     // Internal memory fields
     private long mInternalTotalSize;
     private long mInternalAvailSize;
-    private long mInternalMediaSize;
     private long mInternalAppsSize;
 
     // External memory fields
     private long mExternalTotalSize;
 
     private long mExternalAvailSize;
+    List<FileInfo> mFileInfoForMisc;
 
     private MemoryMeasurement(Context context) {
         // Start the thread that will measure the disk usage.
@@ -98,7 +101,9 @@
     }
 
     public void setReceiver(MeasurementReceiver receiver) {
-        mReceiver = new WeakReference<MeasurementReceiver>(receiver);
+        if (mReceiver == null || mReceiver.get() == null) {
+            mReceiver = new WeakReference<MeasurementReceiver>(receiver);
+        }
     }
 
     public void measureExternal() {
@@ -134,6 +139,9 @@
     private void sendInternalExactUpdate() {
         MeasurementReceiver receiver = (mReceiver != null) ? mReceiver.get() : null;
         if (receiver == null) {
+            if (LOGV) {
+                Log.i(TAG, "measurements dropped because receiver is null! wasted effort");
+            }
             return;
         }
 
@@ -141,7 +149,9 @@
         bundle.putLong(TOTAL_SIZE, mInternalTotalSize);
         bundle.putLong(AVAIL_SIZE, mInternalAvailSize);
         bundle.putLong(APPS_USED, mInternalAppsSize);
-        bundle.putLong(MEDIA_USED, mInternalMediaSize);
+        for (int i = 0; i < Constants.NUM_MEDIA_DIRS_TRACKED; i++) {
+            bundle.putLong(Constants.mMediaDirs.get(i).mKey, mMediaSizes[i]);
+        }
 
         receiver.updateExactInternal(bundle);
     }
@@ -252,6 +262,7 @@
                 case MSG_CONNECTED: {
                     IMediaContainerService imcs = (IMediaContainerService) msg.obj;
                     measureExactInternalStorage(imcs);
+                    break;
                 }
                 case MSG_DISCONNECT: {
                     synchronized (mLock) {
@@ -265,6 +276,7 @@
                             context.unbindService(mDefContainerConn);
                         }
                     }
+                    break;
                 }
                 case MSG_COMPLETED: {
                     mMeasured = true;
@@ -356,24 +368,40 @@
             if (context == null) {
                 return;
             }
-
             // We have to get installd to measure the package sizes.
             PackageManager pm = context.getPackageManager();
             if (pm == null) {
                 return;
             }
-
-            long mediaSize;
-            try {
-                mediaSize = imcs.calculateDirectorySize(
-                        Environment.getExternalStorageDirectory().getAbsolutePath());
-            } catch (Exception e) {
-                Log.i(TAG, "Could not read memory from default container service");
-                return;
+            // measure sizes for all except "media_misc" - which is computed
+            for (int i = 0; i < Constants.NUM_MEDIA_DIRS_TRACKED - 1; i++) {
+                mMediaSizes[i] = 0;
+                String[] dirs = Constants.mMediaDirs.get(i).mDirPaths;
+                int len = dirs.length;
+                if (len > 0) {
+                    for (int k = 0; k < len; k++) {
+                        long dirSize = getSize(imcs, dirs[k]);
+                        mMediaSizes[i] += dirSize;
+                        if (LOGV) {
+                            Log.i(TAG, "size of " + dirs[k] + ": " + dirSize);
+                        }
+                    }
+                }
             }
 
-            mInternalMediaSize = mediaSize;
+            // compute the size of "misc"
+            mMediaSizes[Constants.MEDIA_MISC_INDEX] = mMediaSizes[Constants.MEDIA_INDEX];
+            for (int i = 1; i < Constants.NUM_MEDIA_DIRS_TRACKED - 1; i++) {
+                mMediaSizes[Constants.MEDIA_MISC_INDEX] -= mMediaSizes[i];
+            }
+            if (LOGV) {
+                Log.i(TAG, "media_misc size: " + mMediaSizes[Constants.MEDIA_MISC_INDEX]);
+            }
 
+            // compute the sizes of each of the files/directories under 'misc' category
+            measureSizesOfMisc(imcs);
+
+            // compute apps sizes
             final List<ApplicationInfo> apps = pm
                     .getInstalledApplications(PackageManager.GET_UNINSTALLED_PACKAGES
                             | PackageManager.GET_DISABLED_COMPONENTS);
@@ -393,6 +421,43 @@
             // Sending of the message back to the MeasurementReceiver is
             // completed in the PackageObserver
         }
+        private void measureSizesOfMisc(IMediaContainerService imcs) {
+            File top = Environment.getExternalStorageDirectory();
+            mFileInfoForMisc = new ArrayList<FileInfo>();
+            File[] files = top.listFiles();
+            int len = files.length;
+            if (len == 0) {
+                return;
+            }
+            // get sizes of all top level nodes in /sdcard dir except the ones already computed...
+            long counter = 0;
+            for (int i = 0; i < len; i++) {
+                String path = files[i].getAbsolutePath();
+                if (Constants.ExclusionTargetsForMiscFiles.contains(path)) {
+                    continue;
+                }
+                if (files[i].isFile()) {
+                    mFileInfoForMisc.add(new FileInfo(path, files[i].length(), counter++));
+                } else if (files[i].isDirectory()) {
+                    long dirSize = getSize(imcs, path);
+                    mFileInfoForMisc.add(new FileInfo(path, dirSize, counter++));
+                } else {
+                }
+            }
+            // sort the list of FileInfo objects collected above in descending order of their sizes
+            Collections.sort(mFileInfoForMisc);
+        }
+
+        private long getSize(IMediaContainerService imcs, String dir) {
+            try {
+                long size = imcs.calculateDirectorySize(dir);
+                return size;
+            } catch (Exception e) {
+                Log.w(TAG, "Could not read memory from default container service for " +
+                        dir, e);
+                return -1;
+            }
+        }
 
         public void measureApproximateExternalStorage() {
             File path = Environment.getExternalStorageDirectory();
@@ -412,4 +477,29 @@
     public void invalidate() {
         mHandler.sendEmptyMessage(MeasurementHandler.MSG_INVALIDATE);
     }
+
+    boolean isSizeOfMiscCategorynonZero() {
+        return mFileInfoForMisc.size() > 0;
+    }
+
+    static class FileInfo implements Comparable<FileInfo> {
+        String mFileName;
+        long mSize;
+        long mId;
+        FileInfo(String fileName, long size, long id) {
+            mFileName = fileName;
+            mSize = size;
+            mId = id;
+        }
+        @Override
+        public int compareTo(FileInfo that) {
+            if (this == that || mSize == that.mSize) return 0;
+            else if (mSize < that.mSize) return 1; // for descending sort
+            else return -1;
+        }
+        @Override
+        public String toString() {
+            return mFileName  + " : " + mSize + ", id:" + mId;
+        }
+    }
 }
diff --git a/src/com/android/settings/deviceinfo/MiscFilesHandler.java b/src/com/android/settings/deviceinfo/MiscFilesHandler.java
new file mode 100644
index 0000000..5a92115
--- /dev/null
+++ b/src/com/android/settings/deviceinfo/MiscFilesHandler.java
@@ -0,0 +1,279 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.deviceinfo;
+
+import com.android.settings.R;
+import com.android.settings.deviceinfo.MemoryMeasurement.FileInfo;
+
+import android.app.ListActivity;
+import android.content.Context;
+import android.os.Bundle;
+import android.text.format.Formatter;
+import android.util.Log;
+import android.util.SparseBooleanArray;
+import android.view.ActionMode;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.View.OnLongClickListener;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.CompoundButton;
+import android.widget.CompoundButton.OnCheckedChangeListener;
+import android.widget.ListView;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class handles the selection and removal of Misc files.
+ */
+public class MiscFilesHandler extends ListActivity {
+    private static final String TAG = "MemorySettings";
+    private String mNumSelectedStr;
+    private String mNumSelectedOutOfStr;
+    private MemoryMearurementAdapter mAdapter;
+    private LayoutInflater mInflater;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setFinishOnTouchOutside(true);
+        setTitle(R.string.misc_files);
+        mNumSelectedStr = getString(R.string.misc_files_selected_count);
+        mNumSelectedOutOfStr = getString(R.string.misc_files_selected_count_out_of);
+        mAdapter = new MemoryMearurementAdapter(this);
+        mInflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+        setContentView(R.layout.settings_storage_miscfiles_list);
+        ListView lv = getListView();
+        lv.setItemsCanFocus(true);
+        lv.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
+        lv.setMultiChoiceModeListener(new ModeCallback(this));
+        setListAdapter(mAdapter);
+    } 
+
+    private class ModeCallback implements ListView.MultiChoiceModeListener {
+        private int mDataCount;
+        private final Context mContext;
+
+        public ModeCallback(Context context) {
+            mContext = context;
+            mDataCount = mAdapter.getCount();
+        }
+
+        public boolean onCreateActionMode(ActionMode mode, Menu menu) {
+            final MenuInflater inflater = getMenuInflater();
+            inflater.inflate(R.menu.misc_files_menu, menu);
+            return true;
+        }
+
+        public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
+            return true;
+        }
+
+        public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
+            ListView lv = getListView();
+            switch (item.getItemId()) {
+            case R.id.action_delete:
+                // delete the files selected
+                SparseBooleanArray checkedItems = lv.getCheckedItemPositions();
+                int checkedCount = getListView().getCheckedItemCount();
+                if (checkedCount > mDataCount) {
+                    throw new IllegalStateException("checked item counts do not match. " +
+                            "checkedCount: " + checkedCount + ", dataSize: " + mDataCount);
+                }
+                if (mDataCount > 0) {
+                    ArrayList<Object> toRemove = new ArrayList<Object>();
+                    for (int i = 0; i < mDataCount; i++) {
+                        if (!checkedItems.get(i)) {
+                            //item not selected
+                            continue;
+                        }
+                        if (MemoryMeasurement.LOGV) {
+                            Log.i(TAG, "deleting: " + mAdapter.getItem(i));
+                        }
+                        // delete the file
+                        File file = new File(mAdapter.getItem(i).mFileName);
+                        if (file.isDirectory()) {
+                            deleteDir(file);
+                        } else {
+                            file.delete();                            
+                        }
+                        toRemove.add(mAdapter.getItem(i));
+                    }
+                    mAdapter.removeAll(toRemove);
+                    mAdapter.notifyDataSetChanged();
+                    mDataCount = mAdapter.getCount();
+                }
+                mode.finish();
+                break;
+
+            case R.id.action_select_all:
+                // check ALL items
+                for (int i = 0; i < mDataCount; i++) {
+                    lv.setItemChecked(i, true);
+                }
+                // update the title and subtitle with number selected and numberBytes selected
+                onItemCheckedStateChanged(mode, 1, 0, true);
+                break;
+            }
+            return true;
+        }
+
+        // Deletes all files and subdirectories under given dir.
+        // Returns true if all deletions were successful.
+        // If a deletion fails, the method stops attempting to delete and returns false.
+        private boolean deleteDir(File dir) {
+            if (dir.isDirectory()) {
+                String[] children = dir.list();
+                for (int i=0; i < children.length; i++) {
+                    boolean success = deleteDir(new File(dir, children[i]));
+                    if (!success) {
+                        return false;
+                    }
+                }
+            }
+            // The directory is now empty so delete it
+            return dir.delete();
+        }
+
+        public void onDestroyActionMode(ActionMode mode) {
+        }
+
+        public void onItemCheckedStateChanged(ActionMode mode, int position, long id,
+                boolean checked) {
+            ListView lv = getListView();
+            int numChecked = lv.getCheckedItemCount();
+            mode.setTitle(mNumSelectedStr + " : " + numChecked +
+                    " " + mNumSelectedOutOfStr + " " + mAdapter.getCount());
+
+            // total the sizes of all items selected so far
+            SparseBooleanArray checkedItems = lv.getCheckedItemPositions();
+            long selectedDataSize = 0;
+            if (numChecked > 0) {
+                for (int i = 0; i < mDataCount; i++) {
+                    if (checkedItems.get(i)) {
+                        // item is checked
+                        selectedDataSize += mAdapter.getItem(i).mSize;
+                    }
+                }
+            }
+            mode.setSubtitle(Formatter.formatFileSize(mContext, selectedDataSize) +
+                    " " + mNumSelectedOutOfStr + " " +
+                    Formatter.formatFileSize(mContext, mAdapter.getDataSize()));
+        }
+    }
+
+    public class MemoryMearurementAdapter extends BaseAdapter {
+        private ArrayList<MemoryMeasurement.FileInfo> mData = null;
+        private long mDataSize = 0;
+        private Context mContext;
+
+        public MemoryMearurementAdapter(Context context) {
+            mContext = context;
+            MemoryMeasurement mMeasurement = MemoryMeasurement.getInstance(context);
+            mData = (ArrayList<MemoryMeasurement.FileInfo>)mMeasurement.mFileInfoForMisc;
+            if (mData != null) {
+                for (MemoryMeasurement.FileInfo info : mData) {
+                    mDataSize += info.mSize;
+                }
+            }
+        }
+
+        @Override
+        public int getCount() {
+            return (mData == null) ? 0 : mData.size();
+        }
+
+        @Override
+        public MemoryMeasurement.FileInfo getItem(int position) {
+            if (mData == null || mData.size() <= position) {
+                return null;
+            }
+            return mData.get(position);
+        }
+
+        @Override
+        public long getItemId(int position) {
+            if (mData == null || mData.size() <= position) {
+                return 0;
+            }
+            return mData.get(position).mId;
+        }
+        public void removeAll(List<Object> objs) {
+            if (mData == null) {
+                return;
+            }
+            for (Object o : objs) {
+                mData.remove(o);
+                mDataSize -= ((MemoryMeasurement.FileInfo) o).mSize;
+            }
+        }
+
+        public long getDataSize() {
+            return mDataSize;
+        }
+
+        @Override
+        public void notifyDataSetChanged() {
+            super.notifyDataSetChanged();
+        }
+
+        @Override
+        public View getView(int position, View convertView, ViewGroup parent) {
+            final FileItemInfoLayout view = (convertView == null) ?
+                    (FileItemInfoLayout) mInflater.inflate(R.layout.settings_storage_miscfiles,
+                            parent, false) : (FileItemInfoLayout) convertView;
+            FileInfo item = getItem(position);
+            view.setFileName(item.mFileName);
+            view.setFileSize(Formatter.formatFileSize(mContext, item.mSize));
+            final ListView listView = (ListView) parent;
+            final int listPosition = position;
+            view.getCheckBox().setOnCheckedChangeListener(new OnCheckedChangeListener() {
+                
+                @Override
+                public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+                    listView.setItemChecked(listPosition, isChecked);
+                }
+                
+            });
+            view.setOnLongClickListener(new OnLongClickListener() {
+                @Override
+                public boolean onLongClick(View v) {
+                    if (listView.getCheckedItemCount() > 0) {
+                        return false;
+                    }
+                    listView.setItemChecked(listPosition, !view.isChecked());
+                    return true;
+                }
+            });
+            view.setOnClickListener(new OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    if (listView.getCheckedItemCount() > 0) {
+                        listView.setItemChecked(listPosition, !view.isChecked());
+                    }
+                }
+            });
+            return view;
+        }
+    }
+}
\ No newline at end of file