OSDN Git Service

Fixed ANR & Memory Leak Associated with 3GP
[android-x86/packages-apps-CMFileManager.git] / src / com / cyanogenmod / filemanager / adapters / FileSystemObjectAdapter.java
1 /*
2  * Copyright (C) 2012 The CyanogenMod 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.cyanogenmod.filemanager.adapters;
18
19 import android.content.Context;
20 import android.content.res.Resources;
21 import android.graphics.drawable.Drawable;
22 import android.text.TextUtils;
23 import android.view.LayoutInflater;
24 import android.view.View;
25 import android.view.View.OnClickListener;
26 import android.view.ViewGroup;
27 import android.widget.ArrayAdapter;
28 import android.widget.ImageButton;
29 import android.widget.ImageView;
30 import android.widget.TextView;
31
32 import com.cyanogenmod.filemanager.R;
33 import com.cyanogenmod.filemanager.model.FileSystemObject;
34 import com.cyanogenmod.filemanager.model.ParentDirectory;
35 import com.cyanogenmod.filemanager.preferences.FileManagerSettings;
36 import com.cyanogenmod.filemanager.preferences.Preferences;
37 import com.cyanogenmod.filemanager.ui.IconHolder;
38 import com.cyanogenmod.filemanager.ui.ThemeManager;
39 import com.cyanogenmod.filemanager.ui.ThemeManager.Theme;
40 import com.cyanogenmod.filemanager.util.FileHelper;
41 import com.cyanogenmod.filemanager.util.MimeTypeHelper;
42
43 import java.util.ArrayList;
44 import java.util.Arrays;
45 import java.util.HashSet;
46 import java.util.List;
47
48 /**
49  * An implementation of {@link ArrayAdapter} for display file system objects.
50  */
51 public class FileSystemObjectAdapter
52     extends ArrayAdapter<FileSystemObject> implements OnClickListener {
53
54     /**
55      * An interface to communicate selection changes events.
56      */
57     public interface OnSelectionChangedListener {
58         /**
59          * Method invoked when the selection changed.
60          *
61          * @param selectedItems The new selected items
62          */
63         void onSelectionChanged(List<FileSystemObject> selectedItems);
64     }
65
66     /**
67      * A class that conforms with the ViewHolder pattern to performance
68      * the list view rendering.
69      */
70     private static class ViewHolder {
71         /**
72          * @hide
73          */
74         public ViewHolder() {
75             super();
76         }
77         ImageButton mBtCheck;
78         ImageView mIvIcon;
79         TextView mTvName;
80         TextView mTvSummary;
81         TextView mTvSize;
82         Boolean mHasSelectedBg;
83     }
84
85     private IconHolder mIconHolder;
86     private final int mItemViewResourceId;
87     private HashSet<FileSystemObject> mSelectedItems;
88     private final boolean mPickable;
89
90     private OnSelectionChangedListener mOnSelectionChangedListener;
91
92     //The resource of the item check
93     private static final int RESOURCE_ITEM_CHECK = R.id.navigation_view_item_check;
94     //The resource of the item icon
95     private static final int RESOURCE_ITEM_ICON = R.id.navigation_view_item_icon;
96     //The resource of the item name
97     private static final int RESOURCE_ITEM_NAME = R.id.navigation_view_item_name;
98     //The resource of the item summary information
99     private static final int RESOURCE_ITEM_SUMMARY = R.id.navigation_view_item_summary;
100     //The resource of the item size information
101     private static final int RESOURCE_ITEM_SIZE = R.id.navigation_view_item_size;
102
103     /**
104      * Constructor of <code>FileSystemObjectAdapter</code>.
105      *
106      * @param context The current context
107      * @param files The list of file system objects
108      * @param itemViewResourceId The identifier of the layout that represents an item
109      * of the list adapter
110      * @param pickable If the adapter should act as a pickable browser.
111      */
112     public FileSystemObjectAdapter(
113             Context context, List<FileSystemObject> files,
114             int itemViewResourceId, boolean pickable) {
115         super(context, RESOURCE_ITEM_NAME, files);
116         this.mItemViewResourceId = itemViewResourceId;
117         this.mSelectedItems = new HashSet<FileSystemObject>();
118         this.mPickable = pickable;
119         notifyThemeChanged(); // Reload icons
120     }
121
122     /**
123      * Method that sets the listener which communicates selection changes.
124      *
125      * @param onSelectionChangedListener The listener reference
126      */
127     public void setOnSelectionChangedListener(
128             OnSelectionChangedListener onSelectionChangedListener) {
129         this.mOnSelectionChangedListener = onSelectionChangedListener;
130     }
131
132     /**
133      * Method that loads the default icons (known icons and more common icons).
134      */
135     private void loadDefaultIcons() {
136         this.mIconHolder.getDrawable("ic_fso_folder_drawable"); //$NON-NLS-1$
137         this.mIconHolder.getDrawable("ic_fso_default_drawable"); //$NON-NLS-1$
138     }
139
140     /**
141      * Method that dispose the elements of the adapter.
142      */
143     public void dispose() {
144         clear();
145         if (mIconHolder != null) {
146             mIconHolder.cleanup();
147             mIconHolder = null;
148         }
149         this.mSelectedItems.clear();
150     }
151
152     /**
153      * Method that returns the {@link FileSystemObject} reference from his path.
154      *
155      * @param path The path of the file system object
156      * @return FileSystemObject The file system object reference
157      */
158     public FileSystemObject getItem(String path) {
159         int cc = getCount();
160         for (int i = 0; i < cc; i++) {
161           //File system object info
162             FileSystemObject fso = getItem(i);
163             if (fso.getFullPath().compareTo(path) == 0) {
164                 return fso;
165             }
166         }
167         return null;
168     }
169
170     /**
171      * {@inheritDoc}
172      */
173     @Override
174     public View getView(int position, View convertView, ViewGroup parent) {
175         //Check to reuse view
176         View v = convertView;
177         Theme theme = ThemeManager.getCurrentTheme(getContext());
178
179         if (v == null) {
180             //Create the view holder
181             LayoutInflater li =
182                     (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
183             v = li.inflate(this.mItemViewResourceId, parent, false);
184             ViewHolder viewHolder = new FileSystemObjectAdapter.ViewHolder();
185             viewHolder.mIvIcon = (ImageView)v.findViewById(RESOURCE_ITEM_ICON);
186             viewHolder.mTvName = (TextView)v.findViewById(RESOURCE_ITEM_NAME);
187             viewHolder.mTvSummary = (TextView)v.findViewById(RESOURCE_ITEM_SUMMARY);
188             viewHolder.mTvSize = (TextView)v.findViewById(RESOURCE_ITEM_SIZE);
189             if (!this.mPickable) {
190                 viewHolder.mBtCheck = (ImageButton)v.findViewById(RESOURCE_ITEM_CHECK);
191                 viewHolder.mBtCheck.setOnClickListener(this);
192             } else {
193                 viewHolder.mBtCheck = (ImageButton)v.findViewById(RESOURCE_ITEM_CHECK);
194                 viewHolder.mBtCheck.setVisibility(View.GONE);
195             }
196             v.setTag(viewHolder);
197         }
198
199         //Retrieve the view holder
200         ViewHolder viewHolder = (ViewHolder)v.getTag();
201         if (this.mPickable) {
202             theme.setBackgroundDrawable(getContext(), v, "background_drawable"); //$NON-NLS-1$
203         }
204
205         FileSystemObject fso = getItem(position);
206
207         Drawable dwIcon = this.mIconHolder.getDrawable(
208                 MimeTypeHelper.getIcon(getContext(), fso, true));
209         mIconHolder.loadDrawable(viewHolder.mIvIcon, fso, dwIcon);
210
211         viewHolder.mTvName.setText(fso.getName());
212         theme.setTextColor(getContext(), viewHolder.mTvName, "text_color"); //$NON-NLS-1$
213         if (viewHolder.mTvSummary != null) {
214             StringBuilder sbSummary = new StringBuilder();
215             if (fso instanceof ParentDirectory) {
216                 sbSummary.append(getContext().getResources().getString(R.string.parent_dir));
217             } else {
218                 sbSummary.append(
219                         FileHelper.formatFileTime(
220                                 getContext(), fso.getLastModifiedTime()));
221                 sbSummary.append("   "); //$NON-NLS-1$
222                 sbSummary.append(fso.toRawPermissionString());
223             }
224             viewHolder.mTvSummary.setText(sbSummary);
225             theme.setTextColor(getContext(), viewHolder.mTvSummary, "text_color"); //$NON-NLS-1$
226         }
227         if (viewHolder.mTvSize != null) {
228             viewHolder.mTvSize.setText(FileHelper.getHumanReadableSize(fso));
229             theme.setTextColor(getContext(), viewHolder.mTvSize, "text_color"); //$NON-NLS-1$
230         }
231         if (!this.mPickable) {
232             viewHolder.mBtCheck.setVisibility(
233                     TextUtils.equals(fso.getName(), FileHelper.PARENT_DIRECTORY) ?
234                             View.INVISIBLE : View.VISIBLE);
235
236             boolean selected = mSelectedItems.contains(fso);
237             Drawable dwCheck;
238             if (selected) {
239                 dwCheck = theme.getDrawable(getContext(), "checkbox_selected_drawable"); //$NON-NLS-1$
240             } else {
241                 dwCheck = theme.getDrawable(getContext(), "checkbox_deselected_drawable"); //$NON-NLS-1$
242             }
243             viewHolder.mBtCheck.setImageDrawable(dwCheck);
244             viewHolder.mBtCheck.setTag(position);
245
246             if (viewHolder.mHasSelectedBg == null
247                     || viewHolder.mHasSelectedBg != selected) {
248                 String drawableId = selected
249                         ? "selectors_selected_drawable" //$NON-NLS-1$
250                         : "selectors_deselected_drawable"; //$NON-NLS-1$
251
252                 theme.setBackgroundDrawable(getContext(), v, drawableId);
253                 viewHolder.mHasSelectedBg = selected;
254             }
255         }
256
257         //Return the view
258         return v;
259     }
260
261     /**
262      * Method that returns if the item of the passed position is selected.
263      *
264      * @param position The position of the item
265      * @return boolean If the item of the passed position is selected
266      */
267     public boolean isSelected(int position) {
268         return mSelectedItems.contains(getItem(position));
269     }
270
271     /**
272      * Method that selects in the {@link ArrayAdapter} the passed item.
273      *
274      * @param fso The file system object to select
275      */
276     public void toggleSelection(FileSystemObject fso) {
277         toggleSelection(null, fso);
278     }
279
280     /**
281      * Method that selects in the {@link ArrayAdapter} the passed item.
282      *
283      * @param v The check view object (can be null)
284      * @param fso The file system object to select
285      */
286     private void toggleSelection(View v, FileSystemObject fso) {
287         Theme theme = ThemeManager.getCurrentTheme(getContext());
288
289         boolean selected = !mSelectedItems.remove(fso);
290         if (selected) {
291             mSelectedItems.add(fso);
292         }
293         if (v != null) {
294             ((View)v.getParent()).setSelected(selected);
295         }
296
297         //Communicate event
298         if (this.mOnSelectionChangedListener != null) {
299             this.mOnSelectionChangedListener.onSelectionChanged(
300                     new ArrayList<FileSystemObject>(mSelectedItems));
301         }
302
303         notifyDataSetChanged();
304     }
305
306     /**
307      * Method that deselect all items.
308      */
309     public void deselectedAll() {
310         this.mSelectedItems.clear();
311         doSelectDeselectAllVisibleItems(false);
312     }
313
314     /**
315      * Method that select all visible items.
316      */
317     public void selectedAllVisibleItems() {
318         doSelectDeselectAllVisibleItems(true);
319     }
320
321     /**
322      * Method that deselect all visible items.
323      */
324     public void deselectedAllVisibleItems() {
325         doSelectDeselectAllVisibleItems(false);
326     }
327
328     /**
329      * Method that select/deselect all items.
330      *
331      * @param select Indicates if select (true) or deselect (false) all items.
332      */
333     private void doSelectDeselectAllVisibleItems(boolean select) {
334         int cc = getCount();
335         for (int i = 0; i < cc; i++) {
336             FileSystemObject fso = getItem(i);
337             if (fso.getName().compareTo(FileHelper.PARENT_DIRECTORY) == 0) {
338                 // No select the parent directory
339                 continue;
340             }
341             if (select) {
342                 mSelectedItems.add(fso);
343             } else {
344                 mSelectedItems.remove(fso);
345             }
346         }
347
348         //Communicate event
349         if (this.mOnSelectionChangedListener != null) {
350             this.mOnSelectionChangedListener.onSelectionChanged(
351                     new ArrayList<FileSystemObject>(mSelectedItems));
352         }
353
354         notifyDataSetChanged();
355     }
356
357     /**
358      * Method that returns the selected items.
359      *
360      * @return List<FileSystemObject> The selected items
361      */
362     public List<FileSystemObject> getSelectedItems() {
363         return new ArrayList<FileSystemObject>(this.mSelectedItems);
364     }
365
366     /**
367      * Method that sets the selected items.
368      *
369      * @param selectedItems The selected items
370      */
371     public void setSelectedItems(List<FileSystemObject> selectedItems) {
372         mSelectedItems.clear();
373         mSelectedItems.addAll(selectedItems);
374         notifyDataSetChanged();
375     }
376
377     /**
378      * {@inheritDoc}
379      */
380     @Override
381     public void onClick(View v) {
382
383         //Select or deselect the item
384         int pos = ((Integer)v.getTag()).intValue();
385
386         if (pos >= getCount() || pos < 0) {
387             return;
388         }
389
390         //Retrieve data holder
391         final FileSystemObject fso = getItem(pos);
392
393         //What button was pressed?
394         switch (v.getId()) {
395             case RESOURCE_ITEM_CHECK:
396                 //Get the row item view
397                 toggleSelection(v, fso);
398                 break;
399             default:
400                 break;
401         }
402     }
403
404     /**
405      * Method that should be invoked when the theme of the app was changed
406      */
407     public void notifyThemeChanged() {
408         // Empty icon holder
409         if (this.mIconHolder != null) {
410             this.mIconHolder.cleanup();
411         }
412         final boolean displayThumbs = Preferences.getSharedPreferences().getBoolean(
413                 FileManagerSettings.SETTINGS_DISPLAY_THUMBS.getId(),
414                 ((Boolean)FileManagerSettings.SETTINGS_DISPLAY_THUMBS.getDefaultValue()).booleanValue());
415         this.mIconHolder = new IconHolder(getContext(), displayThumbs);
416         loadDefaultIcons();
417     }
418
419 }