├── .classpath
├── .gitignore
├── .project
├── .settings
└── org.eclipse.jdt.core.prefs
├── AndroidManifest.xml
├── README.md
├── libs
└── android-support-v13.jar
├── proguard-project.txt
├── project.properties
├── res
├── drawable-hdpi
│ └── ic_launcher.png
├── drawable-xhdpi
│ ├── back_button.png
│ ├── category_button_bg_left.9.png
│ ├── category_button_bg_middle.9.png
│ ├── category_button_bg_right.9.png
│ ├── file_copy.png
│ ├── file_cut.png
│ ├── file_delete.png
│ ├── file_new.png
│ ├── file_refresh.png
│ ├── file_search.png
│ ├── file_viewmode_grid.png
│ ├── file_viewmode_list.png
│ ├── format_apk.png
│ ├── format_app.png
│ ├── format_chm.png
│ ├── format_ebook.png
│ ├── format_excel.png
│ ├── format_flash.png
│ ├── format_folder.png
│ ├── format_html.png
│ ├── format_media.png
│ ├── format_music.png
│ ├── format_pdf.png
│ ├── format_picture.png
│ ├── format_picture_broken.png
│ ├── format_ppt.png
│ ├── format_text.png
│ ├── format_torrent.png
│ ├── format_unkown.png
│ ├── format_word.png
│ ├── format_zip.png
│ ├── ic_launcher.png
│ └── sym_link.png
├── drawable-xxhdpi
│ └── ic_launcher.png
├── drawable
│ ├── bg_file_item_normal.xml
│ ├── bg_file_item_select.xml
│ ├── category_button_left.xml
│ ├── category_button_middle.xml
│ └── category_button_right.xml
├── layout
│ ├── activity_image_browse.xml
│ ├── activity_main.xml
│ ├── activity_picker.xml
│ ├── activity_search.xml
│ ├── dialog_file_property.xml
│ ├── layout_file_bookmark.xml
│ ├── layout_file_category.xml
│ ├── layout_file_explorer.xml
│ ├── layout_file_list.xml
│ ├── view_ancestor_item.xml
│ ├── view_file_item.xml
│ └── view_grid_file_item.xml
├── menu
│ ├── filelist.xml
│ ├── fileop.xml
│ └── main.xml
├── values-sw600dp
│ └── dimens.xml
├── values-sw720dp-land
│ └── dimens.xml
├── values-v14
│ └── styles.xml
└── values
│ ├── arrays.xml
│ ├── attrs.xml
│ ├── colors.xml
│ ├── dimens.xml
│ ├── strings.xml
│ └── styles.xml
└── src
└── net
└── nashlegend
└── legendexplorer
├── ImageBrowseActivity.java
├── MainActivity.java
├── PickerActivity.java
├── SearchActivity.java
├── adapter
├── FileListAdapter.java
├── FilePagerAdapter.java
└── ImagePagerAdapter.java
├── application
└── ExplorerApplication.java
├── consts
└── FileConst.java
├── db
├── BookmarkColumn.java
├── BookmarkHelper.java
└── FileDataBase.java
├── dialog
└── FilePropertyDialog.java
├── fragment
├── BaseFragment.java
├── BookMarksFragment.java
├── CategoriedFragment.java
├── Explorable.java
├── FileListFragment.java
└── FilesFragment.java
├── model
└── FileItem.java
├── utils
├── FileCategoryHelper.java
├── IconContainer.java
├── SharePreferencesUtil.java
└── StorageObserver.java
└── view
├── DropDownAncestorList.java
├── FileGridItemView.java
├── FileItemView.java
├── FilePropertyView.java
├── FolderViewPager.java
├── ImageViewState.java
├── ImageViewer.java
├── TheImage.java
└── ZoomImageView.java
/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Files for the Dalvik VM
2 | *.dex
3 |
4 | # Java class files
5 | *.class
6 |
7 | # Generated files
8 | bin/
9 | gen/
10 |
11 | # Gradle files
12 | .gradle/
13 | build/
14 |
15 | # Local configuration file (sdk path, etc)
16 | local.properties
17 |
18 | # Proguard folder generated by Eclipse
19 | proguard/
20 |
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | LegendExplorer
4 |
5 |
6 |
7 |
8 |
9 | com.android.ide.eclipse.adt.ResourceManagerBuilder
10 |
11 |
12 |
13 |
14 | com.android.ide.eclipse.adt.PreCompilerBuilder
15 |
16 |
17 |
18 |
19 | org.eclipse.jdt.core.javabuilder
20 |
21 |
22 |
23 |
24 | com.android.ide.eclipse.adt.ApkBuilder
25 |
26 |
27 |
28 |
29 |
30 | com.android.ide.eclipse.adt.AndroidNature
31 | org.eclipse.jdt.core.javanature
32 |
33 |
34 |
--------------------------------------------------------------------------------
/.settings/org.eclipse.jdt.core.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
3 | org.eclipse.jdt.core.compiler.compliance=1.6
4 | org.eclipse.jdt.core.compiler.source=1.6
5 |
--------------------------------------------------------------------------------
/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
23 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
50 |
51 |
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | LegendExplorer
2 | ==============
3 | 文件管理器,功能齐全,依赖 https://github.com/NashLegend/LegendUtils
4 |
--------------------------------------------------------------------------------
/libs/android-support-v13.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NashLegend/LegendExplorer/419db73d9005f508f59135c9d001c9b60482318b/libs/android-support-v13.jar
--------------------------------------------------------------------------------
/proguard-project.txt:
--------------------------------------------------------------------------------
1 | # To enable ProGuard in your project, edit project.properties
2 | # to define the proguard.config property as described in that file.
3 | #
4 | # Add project specific ProGuard rules here.
5 | # By default, the flags in this file are appended to flags specified
6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt
7 | # You can edit the include path and order by changing the ProGuard
8 | # include property in project.properties.
9 | #
10 | # For more details, see
11 | # http://developer.android.com/guide/developing/tools/proguard.html
12 |
13 | # Add any project specific keep options here:
14 |
15 | # If your project uses WebView with JS, uncomment the following
16 | # and specify the fully qualified class name to the JavaScript interface
17 | # class:
18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
19 | # public *;
20 | #}
21 |
--------------------------------------------------------------------------------
/project.properties:
--------------------------------------------------------------------------------
1 | # This file is automatically generated by Android Tools.
2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3 | #
4 | # This file must be checked in Version Control Systems.
5 | #
6 | # To customize properties used by the Ant build system edit
7 | # "ant.properties", and override values to adapt the script to your
8 | # project structure.
9 | #
10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
12 |
13 | # Project target.
14 | target=android-19
15 | android.library.reference.1=../LegendUtils
16 |
--------------------------------------------------------------------------------
/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NashLegend/LegendExplorer/419db73d9005f508f59135c9d001c9b60482318b/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/back_button.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NashLegend/LegendExplorer/419db73d9005f508f59135c9d001c9b60482318b/res/drawable-xhdpi/back_button.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/category_button_bg_left.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NashLegend/LegendExplorer/419db73d9005f508f59135c9d001c9b60482318b/res/drawable-xhdpi/category_button_bg_left.9.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/category_button_bg_middle.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NashLegend/LegendExplorer/419db73d9005f508f59135c9d001c9b60482318b/res/drawable-xhdpi/category_button_bg_middle.9.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/category_button_bg_right.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NashLegend/LegendExplorer/419db73d9005f508f59135c9d001c9b60482318b/res/drawable-xhdpi/category_button_bg_right.9.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/file_copy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NashLegend/LegendExplorer/419db73d9005f508f59135c9d001c9b60482318b/res/drawable-xhdpi/file_copy.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/file_cut.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NashLegend/LegendExplorer/419db73d9005f508f59135c9d001c9b60482318b/res/drawable-xhdpi/file_cut.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/file_delete.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NashLegend/LegendExplorer/419db73d9005f508f59135c9d001c9b60482318b/res/drawable-xhdpi/file_delete.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/file_new.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NashLegend/LegendExplorer/419db73d9005f508f59135c9d001c9b60482318b/res/drawable-xhdpi/file_new.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/file_refresh.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NashLegend/LegendExplorer/419db73d9005f508f59135c9d001c9b60482318b/res/drawable-xhdpi/file_refresh.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/file_search.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NashLegend/LegendExplorer/419db73d9005f508f59135c9d001c9b60482318b/res/drawable-xhdpi/file_search.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/file_viewmode_grid.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NashLegend/LegendExplorer/419db73d9005f508f59135c9d001c9b60482318b/res/drawable-xhdpi/file_viewmode_grid.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/file_viewmode_list.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NashLegend/LegendExplorer/419db73d9005f508f59135c9d001c9b60482318b/res/drawable-xhdpi/file_viewmode_list.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/format_apk.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NashLegend/LegendExplorer/419db73d9005f508f59135c9d001c9b60482318b/res/drawable-xhdpi/format_apk.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/format_app.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NashLegend/LegendExplorer/419db73d9005f508f59135c9d001c9b60482318b/res/drawable-xhdpi/format_app.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/format_chm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NashLegend/LegendExplorer/419db73d9005f508f59135c9d001c9b60482318b/res/drawable-xhdpi/format_chm.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/format_ebook.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NashLegend/LegendExplorer/419db73d9005f508f59135c9d001c9b60482318b/res/drawable-xhdpi/format_ebook.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/format_excel.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NashLegend/LegendExplorer/419db73d9005f508f59135c9d001c9b60482318b/res/drawable-xhdpi/format_excel.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/format_flash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NashLegend/LegendExplorer/419db73d9005f508f59135c9d001c9b60482318b/res/drawable-xhdpi/format_flash.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/format_folder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NashLegend/LegendExplorer/419db73d9005f508f59135c9d001c9b60482318b/res/drawable-xhdpi/format_folder.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/format_html.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NashLegend/LegendExplorer/419db73d9005f508f59135c9d001c9b60482318b/res/drawable-xhdpi/format_html.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/format_media.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NashLegend/LegendExplorer/419db73d9005f508f59135c9d001c9b60482318b/res/drawable-xhdpi/format_media.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/format_music.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NashLegend/LegendExplorer/419db73d9005f508f59135c9d001c9b60482318b/res/drawable-xhdpi/format_music.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/format_pdf.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NashLegend/LegendExplorer/419db73d9005f508f59135c9d001c9b60482318b/res/drawable-xhdpi/format_pdf.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/format_picture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NashLegend/LegendExplorer/419db73d9005f508f59135c9d001c9b60482318b/res/drawable-xhdpi/format_picture.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/format_picture_broken.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NashLegend/LegendExplorer/419db73d9005f508f59135c9d001c9b60482318b/res/drawable-xhdpi/format_picture_broken.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/format_ppt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NashLegend/LegendExplorer/419db73d9005f508f59135c9d001c9b60482318b/res/drawable-xhdpi/format_ppt.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/format_text.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NashLegend/LegendExplorer/419db73d9005f508f59135c9d001c9b60482318b/res/drawable-xhdpi/format_text.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/format_torrent.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NashLegend/LegendExplorer/419db73d9005f508f59135c9d001c9b60482318b/res/drawable-xhdpi/format_torrent.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/format_unkown.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NashLegend/LegendExplorer/419db73d9005f508f59135c9d001c9b60482318b/res/drawable-xhdpi/format_unkown.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/format_word.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NashLegend/LegendExplorer/419db73d9005f508f59135c9d001c9b60482318b/res/drawable-xhdpi/format_word.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/format_zip.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NashLegend/LegendExplorer/419db73d9005f508f59135c9d001c9b60482318b/res/drawable-xhdpi/format_zip.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NashLegend/LegendExplorer/419db73d9005f508f59135c9d001c9b60482318b/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/sym_link.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NashLegend/LegendExplorer/419db73d9005f508f59135c9d001c9b60482318b/res/drawable-xhdpi/sym_link.png
--------------------------------------------------------------------------------
/res/drawable-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NashLegend/LegendExplorer/419db73d9005f508f59135c9d001c9b60482318b/res/drawable-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/res/drawable/bg_file_item_normal.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/res/drawable/bg_file_item_select.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/res/drawable/category_button_left.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/res/drawable/category_button_middle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/res/drawable/category_button_right.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/res/layout/activity_image_browse.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/res/layout/activity_picker.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/res/layout/activity_search.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/res/layout/dialog_file_property.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
15 |
16 |
21 |
22 |
26 |
27 |
28 |
29 |
30 |
37 |
38 |
43 |
44 |
48 |
49 |
50 |
51 |
52 |
59 |
60 |
65 |
66 |
70 |
71 |
72 |
73 |
74 |
81 |
82 |
87 |
88 |
92 |
93 |
94 |
95 |
96 |
103 |
104 |
109 |
110 |
114 |
115 |
116 |
117 |
118 |
125 |
126 |
131 |
132 |
136 |
137 |
138 |
--------------------------------------------------------------------------------
/res/layout/layout_file_bookmark.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
13 |
14 |
23 |
24 |
30 |
31 |
37 |
38 |
39 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/res/layout/layout_file_category.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
11 |
12 |
17 |
18 |
24 |
25 |
31 |
32 |
36 |
37 |
40 |
41 |
44 |
45 |
48 |
49 |
50 |
54 |
55 |
58 |
59 |
62 |
63 |
66 |
67 |
68 |
72 |
73 |
76 |
77 |
80 |
81 |
84 |
85 |
86 |
87 |
93 |
94 |
98 |
99 |
102 |
103 |
106 |
107 |
110 |
111 |
112 |
116 |
117 |
120 |
121 |
124 |
125 |
128 |
129 |
130 |
134 |
135 |
138 |
139 |
142 |
143 |
146 |
147 |
148 |
149 |
150 |
154 |
155 |
158 |
159 |
164 |
165 |
170 |
171 |
172 |
177 |
178 |
179 |
180 |
181 |
186 |
187 |
188 |
--------------------------------------------------------------------------------
/res/layout/layout_file_explorer.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
13 |
14 |
23 |
24 |
30 |
31 |
37 |
38 |
39 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/res/layout/layout_file_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
11 |
12 |
13 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/res/layout/view_ancestor_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
14 |
15 |
20 |
21 |
29 |
30 |
31 |
35 |
36 |
--------------------------------------------------------------------------------
/res/layout/view_file_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
12 |
13 |
17 |
18 |
24 |
25 |
26 |
33 |
34 |
39 |
40 |
--------------------------------------------------------------------------------
/res/layout/view_grid_file_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
14 |
15 |
23 |
24 |
31 |
32 |
43 |
44 |
--------------------------------------------------------------------------------
/res/menu/filelist.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/res/menu/fileop.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/res/menu/main.xml:
--------------------------------------------------------------------------------
1 |
10 |
--------------------------------------------------------------------------------
/res/values-sw600dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/res/values-sw720dp-land/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 | 128dp
8 |
9 |
10 |
--------------------------------------------------------------------------------
/res/values-v14/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
11 |
12 |
13 |
14 |
17 |
18 |
--------------------------------------------------------------------------------
/res/values/arrays.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | - png
6 | - gif
7 | - jpg
8 | - jpeg
9 | - bmp
10 |
11 |
12 | - mp3
13 | - wav
14 | - ogg
15 | - midi
16 |
17 |
18 | - mp4
19 | - rmvb
20 | - avi
21 | - flv
22 | - mkv
23 | - wmv
24 |
25 |
26 | - apk
27 |
28 |
29 | - jar
30 | - zip
31 | - rar
32 | - gz
33 | - 7z
34 | - img
35 | - tar
36 |
37 |
38 | - htm
39 | - html
40 | - php
41 | - jsp
42 | - asp
43 |
44 |
45 | - txt
46 | - java
47 | - c
48 | - cpp
49 | - py
50 | - xml
51 | - json
52 | - log
53 |
54 |
55 | - doc
56 | - docx
57 |
58 |
59 | - xls
60 | - xlsx
61 |
62 |
63 | - ppt
64 | - pptx
65 |
66 |
67 | - pdf
68 |
69 |
70 | - epub
71 | - caj
72 | - umd
73 | - ebk2
74 | - ebk3
75 |
76 |
77 | - torrent
78 |
79 |
80 | - chm
81 |
82 |
83 |
--------------------------------------------------------------------------------
/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | #ff00ffff
5 |
6 |
--------------------------------------------------------------------------------
/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 16dp
5 | 16dp
6 | 100dp
7 | 8dp
8 |
9 |
10 |
--------------------------------------------------------------------------------
/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | LeX
5 | 设置
6 | 复制
7 | 剪切
8 | 删除
9 | 压缩为zip
10 | 解压zip
11 | 收藏
12 | 重命名
13 | 属性
14 | 搜索
15 | 添加
16 | 视图模式
17 | 显示/不显示隐藏文件
18 | 刷新
19 | 取消
20 | 确定
21 | 返回
22 | 全部
23 | 安装包
24 | 文档
25 | 音乐
26 | 图片
27 | 视频
28 | zip
29 |
30 | 文件名
31 | 文件类型
32 | 文件路径
33 | 文件大小
34 | 包含文件数量
35 | 创建时间
36 | 文件选择
37 | 昵嚎!
38 | 搜索
39 | 图片
40 | 音频
41 |
42 |
--------------------------------------------------------------------------------
/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
11 |
16 |
17 |
23 |
24 |
30 |
31 |
34 |
35 |
36 |
37 |
40 |
41 |
42 |
45 |
46 |
49 |
50 |
--------------------------------------------------------------------------------
/src/net/nashlegend/legendexplorer/ImageBrowseActivity.java:
--------------------------------------------------------------------------------
1 |
2 | package net.nashlegend.legendexplorer;
3 |
4 | import net.nashlegend.legendexplorer.adapter.ImagePagerAdapter;
5 | import net.nashlegend.legendexplorer.consts.FileConst;
6 | import net.nashlegend.legendexplorer.view.ImageViewer;
7 |
8 | import net.nashlegend.legendexplorer.R;
9 |
10 | import android.annotation.SuppressLint;
11 | import android.app.Activity;
12 | import android.os.Bundle;
13 | import android.support.v4.view.ViewPager;
14 | import android.view.Window;
15 | import android.view.WindowManager;
16 |
17 | public class ImageBrowseActivity extends Activity {
18 |
19 | ImageViewer imageViewer;
20 | ViewPager viewPager;
21 | ImagePagerAdapter adapter;
22 |
23 | @Override
24 | protected void onCreate(Bundle savedInstanceState) {
25 | requestWindowFeature(Window.FEATURE_NO_TITLE);
26 | getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
27 | WindowManager.LayoutParams.FLAG_FULLSCREEN);
28 | super.onCreate(savedInstanceState);
29 | setContentView(R.layout.activity_image_browse);
30 | final String path = getIntent().getStringExtra(FileConst.Extra_File_Path);
31 | viewPager = (ViewPager) findViewById(R.id.fullscreen_content);
32 | adapter = new ImagePagerAdapter(this, path);
33 | if (adapter.getImageIndex() >= 0) {
34 | viewPager.setAdapter(adapter);
35 | viewPager.setCurrentItem(adapter.getImageIndex());
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/net/nashlegend/legendexplorer/MainActivity.java:
--------------------------------------------------------------------------------
1 | package net.nashlegend.legendexplorer;
2 |
3 | import java.util.ArrayList;
4 | import java.util.Timer;
5 |
6 | import net.nashlegend.legendexplorer.adapter.FilePagerAdapter;
7 | import net.nashlegend.legendexplorer.consts.FileConst;
8 | import net.nashlegend.legendexplorer.fragment.BaseFragment;
9 | import net.nashlegend.legendexplorer.fragment.BookMarksFragment;
10 | import net.nashlegend.legendexplorer.fragment.CategoriedFragment;
11 | import net.nashlegend.legendexplorer.fragment.FilesFragment;
12 | import net.nashlegend.legendexplorer.utils.StorageObserver;
13 | import net.nashlegend.legendexplorer.view.FolderViewPager;
14 |
15 | import net.nashlegend.legendexplorer.R;
16 | import net.nashlegend.legendutils.Tools.TimerUtil;
17 | import net.nashlegend.legendutils.Tools.ToastUtil;
18 |
19 | import android.os.Bundle;
20 | import android.os.Environment;
21 | import android.os.FileObserver;
22 | import android.app.Activity;
23 | import android.content.BroadcastReceiver;
24 | import android.content.Context;
25 | import android.content.Intent;
26 | import android.content.IntentFilter;
27 | import android.util.Log;
28 | import android.view.KeyEvent;
29 | import android.view.Menu;
30 | import android.view.MenuItem;
31 | import android.view.MenuItem.OnActionExpandListener;
32 | import android.widget.SearchView;
33 | import android.widget.SearchView.OnQueryTextListener;
34 |
35 | public class MainActivity extends Activity {
36 |
37 | private FolderViewPager pager;
38 | private FilePagerAdapter adapter;
39 | private ArrayList list;
40 | private FilesFragment filesFragment;
41 | private BookMarksFragment bookMarksFragment;
42 | private CategoriedFragment classifiedFragment;
43 | private FileBroadcastReceiver fileBroadcastReceiver;
44 | private Menu mMenu;
45 | private SearchView searchView;
46 |
47 | public static final int FlagSearchFileItem = 1;
48 | public static final int FlagToggleViewItem = 2;
49 | public static final int FlagAddFileItem = 4;
50 | public static final int FlagToggleHiddleItem = 8;
51 | public static final int FlagRefreshListItem = 16;
52 | public static final int MaskAllFileList = 31;
53 |
54 | public static final int FlagCopyFileItem = 1;
55 | public static final int FlagCutFileItem = 2;
56 | public static final int FlagDeleteFileItem = 4;
57 | public static final int FlagRenameFileItem = 8;
58 | public static final int FlagZipFileItem = 16;
59 | public static final int PropertyItemFlag = 32;
60 | public static final int FlagUnzipFileItem = 64;
61 | public static final int FlagFavorItem = 128;
62 | public static final int MaskAllOperation = 255;
63 |
64 | public static final int MaskNormalListUnzip = FlagFavorItem
65 | | FlagZipFileItem;
66 | public static final int MaskNormalListFavor = FlagUnzipFileItem;
67 | public static final int MaskNormalListNormal = FlagFavorItem
68 | | FlagUnzipFileItem;
69 |
70 | @Override
71 | protected void onCreate(Bundle savedInstanceState) {
72 | super.onCreate(savedInstanceState);
73 | setContentView(R.layout.activity_main);
74 |
75 | filesFragment = new FilesFragment();
76 | bookMarksFragment = new BookMarksFragment();
77 | classifiedFragment = new CategoriedFragment();
78 |
79 | list = new ArrayList();
80 | list.add(filesFragment);
81 | list.add(bookMarksFragment);
82 | list.add(classifiedFragment);
83 |
84 | pager = (FolderViewPager) findViewById(R.id.pager);
85 | adapter = new FilePagerAdapter(getFragmentManager());
86 | adapter.setList(list);
87 | pager.setAdapter(adapter);
88 | pager.setScrollEnabled(true);
89 |
90 | IntentFilter filter = new IntentFilter();
91 | filter.addAction(FileConst.Action_Open_Folder);
92 | filter.addAction(FileConst.Action_FileItem_Long_Click);
93 | filter.addAction(FileConst.Action_FileItem_Unselect);
94 | filter.addAction(FileConst.Action_FileItem_Select);
95 | filter.addAction(FileConst.Action_Set_File_Operation_ActionBar);
96 | filter.addAction(FileConst.Action_Set_File_View_ActionBar);
97 | filter.addAction(FileConst.Action_File_Operation_Done);
98 | filter.addAction(FileConst.Action_Quit_Search);
99 | fileBroadcastReceiver = new FileBroadcastReceiver();
100 | registerReceiver(fileBroadcastReceiver, filter);
101 | }
102 |
103 | @Override
104 | public boolean onCreateOptionsMenu(Menu menu) {
105 | mMenu = menu;
106 | getMenuInflater().inflate(R.menu.filelist, menu);
107 | MenuItem searchItem = mMenu.findItem(R.id.action_search);
108 | searchView = (SearchView) searchItem.getActionView();
109 | searchItem.setOnActionExpandListener(onActionExpandListener);
110 | searchView.setOnQueryTextListener(onQueryTextListener);
111 | return true;
112 | }
113 |
114 | @Override
115 | public boolean onOptionsItemSelected(MenuItem item) {
116 | switch (item.getItemId()) {
117 | case R.id.action_new:
118 | addNewFile();
119 | break;
120 | case R.id.action_refresh:
121 | refreshFileList();
122 | break;
123 | case R.id.action_viewmode:
124 | toggleViewMode();
125 | break;
126 | case R.id.action_toggle_hidden:
127 | toggleShowHidden();
128 | break;
129 | case R.id.action_copy:
130 | copyFile();
131 | break;
132 | case R.id.action_cut:
133 | moveFile();
134 | break;
135 | case R.id.action_delete:
136 | deleteFile();
137 | break;
138 | case R.id.action_rename:
139 | renameFile();
140 | break;
141 | case R.id.action_zip:
142 | zipFile();
143 | break;
144 | case R.id.action_property:
145 | propertyFile();
146 | break;
147 | case R.id.action_favor:
148 | favorFile();
149 | break;
150 | case R.id.action_unzip:
151 | unzipFile();
152 | break;
153 |
154 | default:
155 | break;
156 | }
157 | return super.onOptionsItemSelected(item);
158 | }
159 |
160 | public void showFileOperationMenu(int exclu) {
161 | if (mMenu == null) {
162 | return;
163 | }
164 | searchView.setOnQueryTextListener(null);
165 | pager.setScrollEnabled(false);
166 | if (mMenu.findItem(R.id.action_copy) == null) {
167 | mMenu.clear();
168 | getMenuInflater().inflate(R.menu.fileop, mMenu);
169 | }
170 | if (exclu >= FlagFavorItem) {
171 | mMenu.findItem(R.id.action_favor).setVisible(false);
172 | exclu = exclu ^ FlagFavorItem;
173 | } else {
174 | mMenu.findItem(R.id.action_favor).setVisible(true);
175 | }
176 | if (exclu >= FlagUnzipFileItem) {
177 | mMenu.findItem(R.id.action_unzip).setVisible(false);
178 | exclu = exclu ^ FlagUnzipFileItem;
179 | } else {
180 | mMenu.findItem(R.id.action_unzip).setVisible(true);
181 | }
182 | if (exclu >= PropertyItemFlag) {
183 | mMenu.findItem(R.id.action_property).setVisible(false);
184 | exclu = exclu ^ PropertyItemFlag;
185 | } else {
186 | mMenu.findItem(R.id.action_property).setVisible(true);
187 | }
188 | if (exclu >= FlagZipFileItem) {
189 | mMenu.findItem(R.id.action_zip).setVisible(false);
190 | exclu = exclu ^ FlagZipFileItem;
191 | } else {
192 | mMenu.findItem(R.id.action_zip).setVisible(true);
193 | }
194 | if (exclu >= FlagRenameFileItem) {
195 | mMenu.findItem(R.id.action_rename).setVisible(false);
196 | exclu = exclu ^ FlagRenameFileItem;
197 | } else {
198 | mMenu.findItem(R.id.action_rename).setVisible(true);
199 | }
200 | if (exclu >= FlagDeleteFileItem) {
201 | mMenu.findItem(R.id.action_delete).setVisible(false);
202 | exclu = exclu ^ FlagDeleteFileItem;
203 | } else {
204 | mMenu.findItem(R.id.action_delete).setVisible(true);
205 | }
206 | if (exclu >= FlagCutFileItem) {
207 | mMenu.findItem(R.id.action_cut).setVisible(false);
208 | exclu = exclu ^ FlagCutFileItem;
209 | } else {
210 | mMenu.findItem(R.id.action_cut).setVisible(true);
211 | }
212 | if (exclu >= FlagCopyFileItem) {
213 | mMenu.findItem(R.id.action_copy).setVisible(false);
214 | } else {
215 | mMenu.findItem(R.id.action_copy).setVisible(true);
216 | }
217 | }
218 |
219 | public void showFileListMenu(int exclu) {
220 | if (mMenu == null) {
221 | return;
222 | }
223 | pager.setScrollEnabled(true);
224 | if (mMenu.findItem(R.id.action_search) == null) {
225 | mMenu.clear();
226 | getMenuInflater().inflate(R.menu.filelist, mMenu);
227 | }
228 |
229 | if (exclu >= FlagRefreshListItem) {
230 | mMenu.findItem(R.id.action_refresh).setVisible(false);
231 | exclu = exclu ^ FlagRefreshListItem;
232 | } else {
233 | mMenu.findItem(R.id.action_refresh).setVisible(true);
234 | }
235 | if (exclu >= FlagToggleHiddleItem) {
236 | mMenu.findItem(R.id.action_toggle_hidden).setVisible(false);
237 | exclu = exclu ^ FlagToggleHiddleItem;
238 | } else {
239 | mMenu.findItem(R.id.action_toggle_hidden).setVisible(true);
240 | }
241 | if (exclu >= FlagAddFileItem) {
242 | mMenu.findItem(R.id.action_new).setVisible(false);
243 | exclu = exclu ^ FlagAddFileItem;
244 | } else {
245 | mMenu.findItem(R.id.action_new).setVisible(true);
246 | }
247 | if (exclu >= FlagToggleViewItem) {
248 | mMenu.findItem(R.id.action_viewmode).setVisible(false);
249 | exclu = exclu ^ FlagToggleViewItem;
250 | } else {
251 | mMenu.findItem(R.id.action_viewmode).setVisible(true);
252 | }
253 | if (exclu >= FlagSearchFileItem) {
254 | mMenu.findItem(R.id.action_search).setVisible(false);
255 | } else {
256 | MenuItem searchItem = mMenu.findItem(R.id.action_search);
257 | searchItem.setVisible(true);
258 | searchView = (SearchView) searchItem.getActionView();
259 | searchItem.setOnActionExpandListener(onActionExpandListener);
260 | searchView.setOnQueryTextListener(onQueryTextListener);
261 | }
262 | }
263 |
264 | private void toggleViewMode() {
265 | Intent intent = new Intent();
266 | intent.setAction(FileConst.Action_Toggle_View_Mode);
267 | adapter.getItem(pager.getCurrentItem()).doVeryAction(intent);
268 | }
269 |
270 | private void toggleShowHidden() {
271 | Intent intent = new Intent();
272 | intent.setAction(FileConst.Action_Toggle_Show_Hidden);
273 | adapter.getItem(pager.getCurrentItem()).doVeryAction(intent);
274 | }
275 |
276 | private void copyFile() {
277 | Intent intent = new Intent();
278 | intent.setAction(FileConst.Action_Copy_File);
279 | adapter.getItem(pager.getCurrentItem()).doVeryAction(intent);
280 | }
281 |
282 | private void moveFile() {
283 | Intent intent = new Intent();
284 | intent.setAction(FileConst.Action_Move_File);
285 | adapter.getItem(pager.getCurrentItem()).doVeryAction(intent);
286 | }
287 |
288 | private void deleteFile() {
289 | Intent intent = new Intent();
290 | intent.setAction(FileConst.Action_Delete_File);
291 | adapter.getItem(pager.getCurrentItem()).doVeryAction(intent);
292 | }
293 |
294 | private void renameFile() {
295 | Intent intent = new Intent();
296 | intent.setAction(FileConst.Action_Rename_File);
297 | adapter.getItem(pager.getCurrentItem()).doVeryAction(intent);
298 | }
299 |
300 | private void zipFile() {
301 | Intent intent = new Intent();
302 | intent.setAction(FileConst.Action_Zip_File);
303 | adapter.getItem(pager.getCurrentItem()).doVeryAction(intent);
304 | }
305 |
306 | private void propertyFile() {
307 | Intent intent = new Intent();
308 | intent.setAction(FileConst.Action_Property_File);
309 | adapter.getItem(pager.getCurrentItem()).doVeryAction(intent);
310 | }
311 |
312 | private void addNewFile() {
313 | Intent intent = new Intent();
314 | intent.setAction(FileConst.Action_Add_New_File);
315 | adapter.getItem(pager.getCurrentItem()).doVeryAction(intent);
316 | }
317 |
318 | private void refreshFileList() {
319 | Intent intent = new Intent();
320 | intent.setAction(FileConst.Action_Refresh_FileList);
321 | adapter.getItem(pager.getCurrentItem()).doVeryAction(intent);
322 | }
323 |
324 | private void searchFile(String query) {
325 | Intent intent = new Intent();
326 | intent.setAction(FileConst.Action_Search_File);
327 | intent.putExtra(FileConst.Key_Search_File_Query, query);
328 | adapter.getItem(pager.getCurrentItem()).doVeryAction(intent);
329 | }
330 |
331 | private void unzipFile() {
332 | Intent intent = new Intent();
333 | intent.setAction(FileConst.Action_Unzip_File);
334 | adapter.getItem(pager.getCurrentItem()).doVeryAction(intent);
335 | }
336 |
337 | private void favorFile() {
338 | Intent intent = new Intent();
339 | intent.setAction(FileConst.Action_Favor_File);
340 | adapter.getItem(pager.getCurrentItem()).doVeryAction(intent);
341 | }
342 |
343 | private void quitSearchFile() {
344 | MenuItem searchItem = mMenu.findItem(R.id.action_search);
345 | if (searchItem != null) {
346 | searchItem.collapseActionView();
347 | }
348 | }
349 |
350 | @Override
351 | public boolean onKeyUp(int keyCode, KeyEvent event) {
352 | if (keyCode == KeyEvent.KEYCODE_BACK) {
353 | if (doBackAction()) {
354 | return true;
355 | }
356 | }
357 | return super.onKeyUp(keyCode, event);
358 | }
359 |
360 | private boolean doBackAction() {
361 | return adapter.getItem(pager.getCurrentItem()).doBackAction();
362 | }
363 |
364 | @Override
365 | protected void onDestroy() {
366 | unregisterReceiver(fileBroadcastReceiver);
367 | super.onDestroy();
368 | }
369 |
370 | private OnActionExpandListener onActionExpandListener = new OnActionExpandListener() {
371 |
372 | @Override
373 | public boolean onMenuItemActionExpand(MenuItem item) {
374 | pager.setScrollEnabled(false);
375 | return true;
376 | }
377 |
378 | @Override
379 | public boolean onMenuItemActionCollapse(MenuItem item) {
380 | pager.setScrollEnabled(true);
381 | searchFile("");
382 | return true;
383 | }
384 | };
385 |
386 | private OnQueryTextListener onQueryTextListener = new OnQueryTextListener() {
387 | private int delayMillis = 300;
388 | private String query = "";
389 | private Timer timer;
390 | Runnable runnable = new Runnable() {
391 |
392 | @Override
393 | public void run() {
394 | searchFile(query);
395 | }
396 | };
397 |
398 | @Override
399 | public boolean onQueryTextSubmit(String query) {
400 | ToastUtil.showToast(getApplicationContext(), query);
401 | return false;
402 | }
403 |
404 | @Override
405 | public boolean onQueryTextChange(String newText) {
406 | TimerUtil.clearTimeOut(timer);
407 | query = newText;
408 | timer = TimerUtil.setTimeOut(runnable, delayMillis);
409 | return false;
410 | }
411 | };
412 |
413 | class FileBroadcastReceiver extends BroadcastReceiver {
414 |
415 | @Override
416 | public void onReceive(Context context, Intent intent) {
417 | String action = intent.getAction();
418 | int mask = intent.getIntExtra(FileConst.Extra_Menu_Mask, 0);
419 | if (FileConst.Action_Set_File_Operation_ActionBar.equals(action)) {
420 | showFileOperationMenu(mask);
421 | return;
422 | } else if (FileConst.Action_Set_File_View_ActionBar.equals(action)) {
423 | showFileListMenu(mask);
424 | return;
425 | } else if (FileConst.Action_Quit_Search.equals(action)) {
426 | quitSearchFile();
427 | return;
428 | }
429 | adapter.getItem(pager.getCurrentItem()).doVeryAction(intent);
430 | }
431 | }
432 |
433 | }
434 |
--------------------------------------------------------------------------------
/src/net/nashlegend/legendexplorer/PickerActivity.java:
--------------------------------------------------------------------------------
1 | package net.nashlegend.legendexplorer;
2 |
3 | import java.io.File;
4 | import java.util.ArrayList;
5 |
6 | import net.nashlegend.legendexplorer.R;
7 | import net.nashlegend.legendexplorer.R.color;
8 | import net.nashlegend.legendutils.BuildIn.FileDialogView;
9 | import net.nashlegend.legendutils.Dialogs.FileDialog;
10 |
11 | import android.app.Activity;
12 | import android.content.Context;
13 | import android.content.Intent;
14 | import android.net.Uri;
15 | import android.os.Bundle;
16 | import android.os.Environment;
17 | import android.util.Log;
18 | import android.view.Menu;
19 | import android.view.MenuItem;
20 | import android.view.View;
21 | import android.view.View.OnClickListener;
22 | import android.view.Window;
23 | import android.widget.Button;
24 |
25 | /**
26 | * 全局文件选择器,Intent.ACTION_GET_CONTENT用来发出要选择项的Action。setType决定要选择的类型
27 | *
28 | * Intent intent = new Intent(Intent.ACTION_GET_CONTENT);_______________________
29 | * intent.setType("*\/*"); _____________________________________________________
30 | * Intent wrapperIntent = Intent.createChooser(intent, null);___________________
31 | * startActivityForResult(wrapperIntent, 1001);_________________________________
32 | *
33 | * @author NashLegend
34 | *
35 | */
36 | public class PickerActivity extends Activity {
37 |
38 | private FileDialogView pickerView;
39 | private Button cancelButton;
40 | private Button okButton;
41 |
42 | @Override
43 | protected void onCreate(Bundle savedInstanceState) {
44 | super.onCreate(savedInstanceState);
45 | setContentView(R.layout.activity_picker);
46 | setTitle("选择文件");
47 | Intent intent = getIntent();
48 | if (intent != null
49 | && Intent.ACTION_GET_CONTENT.equals(intent.getAction())) {
50 | pickerView = (FileDialogView) findViewById(R.id.picker);
51 | pickerView.setFileMode(FileDialog.FILE_MODE_OPEN_FILE_SINGLE);
52 | pickerView.setInitialPath(Environment.getExternalStorageDirectory()
53 | .getAbsolutePath());
54 | pickerView.openFolder();
55 | cancelButton = (Button) pickerView
56 | .findViewById(net.nashlegend.legendutils.R.id.button_dialog_file_cancel);
57 | okButton = (Button) pickerView
58 | .findViewById(net.nashlegend.legendutils.R.id.button_dialog_file_ok);
59 | cancelButton.setOnClickListener(new OnClickListener() {
60 |
61 | @Override
62 | public void onClick(View v) {
63 | setResult(RESULT_CANCELED);
64 | finish();
65 | }
66 | });
67 | okButton.setOnClickListener(new OnClickListener() {
68 |
69 | @Override
70 | public void onClick(View v) {
71 | ArrayList files = pickerView.getSelectedFiles();
72 | if (files != null && files.size() > 0) {
73 | File file = files.get(0);
74 | Intent intent = new Intent();
75 | Uri uri = Uri.fromFile(file);
76 | intent.setData(uri);
77 | setResult(RESULT_OK, intent);
78 | finish();
79 | }
80 | }
81 | });
82 | }
83 |
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/src/net/nashlegend/legendexplorer/SearchActivity.java:
--------------------------------------------------------------------------------
1 | package net.nashlegend.legendexplorer;
2 |
3 | import net.nashlegend.legendexplorer.R;
4 |
5 | import android.app.Activity;
6 | import android.os.Bundle;
7 | import android.view.Menu;
8 | import android.view.MenuItem;
9 |
10 | public class SearchActivity extends Activity {
11 |
12 | @Override
13 | protected void onCreate(Bundle savedInstanceState) {
14 | super.onCreate(savedInstanceState);
15 | setContentView(R.layout.activity_search);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/net/nashlegend/legendexplorer/adapter/FileListAdapter.java:
--------------------------------------------------------------------------------
1 | package net.nashlegend.legendexplorer.adapter;
2 |
3 | import java.io.File;
4 | import java.util.ArrayList;
5 | import java.util.Collections;
6 | import java.util.Comparator;
7 | import java.util.Iterator;
8 |
9 | import net.nashlegend.legendexplorer.consts.FileConst;
10 | import net.nashlegend.legendexplorer.db.BookmarkHelper;
11 | import net.nashlegend.legendexplorer.fragment.CategoriedFragment.FileCategory;
12 | import net.nashlegend.legendexplorer.model.FileItem;
13 | import net.nashlegend.legendexplorer.utils.FileCategoryHelper;
14 | import net.nashlegend.legendexplorer.utils.SharePreferencesUtil;
15 | import net.nashlegend.legendexplorer.view.FileGridItemView;
16 | import net.nashlegend.legendexplorer.view.FileItemView;
17 |
18 | import net.nashlegend.legendutils.Tools.FileUtil;
19 | import net.nashlegend.legendutils.Tools.SystemUtil;
20 |
21 | import android.annotation.SuppressLint;
22 | import android.content.Context;
23 | import android.database.Cursor;
24 | import android.media.MediaScannerConnection;
25 | import android.os.AsyncTask;
26 | import android.util.Log;
27 | import android.view.View;
28 | import android.view.ViewGroup;
29 | import android.widget.BaseAdapter;
30 | import android.widget.Filter;
31 | import android.widget.Filterable;
32 |
33 | @SuppressLint("DefaultLocale")
34 | public class FileListAdapter extends BaseAdapter implements Filterable {
35 | private ArrayList list = new ArrayList();
36 | private Context mContext;
37 | private File currentDirectory;
38 | private boolean displayModeGrid = false;
39 | private Cursor mCursor;
40 | private FileCategory fc;
41 |
42 | public FileListAdapter(Context Context) {
43 | mContext = Context;
44 | }
45 |
46 | @Override
47 | public int getCount() {
48 | return list.size();
49 | }
50 |
51 | @Override
52 | public Object getItem(int position) {
53 | return list.get(position);
54 | }
55 |
56 | @Override
57 | public long getItemId(int position) {
58 | return position;
59 | }
60 |
61 | @Override
62 | public int getViewTypeCount() {
63 | return 2;
64 | }
65 |
66 | @Override
67 | public int getItemViewType(int position) {
68 | return displayModeGrid ? 1 : 0;
69 | }
70 |
71 | @Override
72 | public View getView(int position, View convertView, ViewGroup parent) {
73 | ViewHolder holder = null;
74 | if (displayModeGrid) {
75 | if (convertView == null) {
76 | holder = new ViewHolder();
77 | convertView = new FileGridItemView(mContext);
78 | holder.fileGridItemView = (FileGridItemView) convertView;
79 | convertView.setTag(holder);
80 | } else {
81 | holder = (ViewHolder) convertView.getTag();
82 | }
83 | holder.fileGridItemView.setFileItem(list.get(position), this);
84 | } else {
85 | if (convertView == null) {
86 | holder = new ViewHolder();
87 | convertView = new FileItemView(mContext);
88 | holder.fileItemView = (FileItemView) convertView;
89 | convertView.setTag(holder);
90 | } else {
91 | holder = (ViewHolder) convertView.getTag();
92 | }
93 | holder.fileItemView.setFileItem(list.get(position), this);
94 | }
95 | return convertView;
96 | }
97 |
98 | class ViewHolder {
99 | FileItemView fileItemView;
100 | FileGridItemView fileGridItemView;
101 | }
102 |
103 | public ArrayList getList() {
104 | return list;
105 | }
106 |
107 | public void setList(ArrayList list) {
108 | this.list = list;
109 | }
110 |
111 | /**
112 | * 打开文件夹,更新文件列表
113 | *
114 | * @param file
115 | */
116 | public void openFolder(File file) {
117 | OpenFolderTask task = new OpenFolderTask();
118 | task.execute(file);
119 | }
120 |
121 | class OpenFolderTask extends AsyncTask> {
122 |
123 | @Override
124 | protected ArrayList doInBackground(File... params) {
125 | ArrayList flist = new ArrayList();
126 | boolean showhidden = SharePreferencesUtil.readBoolean(
127 | FileConst.Key_Show_Hiddle_Files, false);
128 | File file = params[0];
129 | currentDirectory = file;
130 | if (file != null
131 | && (file.isDirectory() || file.equals(new File(
132 | FileConst.Value_File_Path_Never_Existed)))) {
133 | flist.clear();
134 | if (file.equals(new File(
135 | FileConst.Value_File_Path_Never_Existed))) {
136 | BookmarkHelper helper = new BookmarkHelper(mContext);
137 | helper.open();
138 | flist = helper.getBookmarks();
139 | helper.close();
140 | } else {
141 | File[] files = null;
142 | if (file.canRead()) {
143 | files = file.listFiles();
144 | } else {
145 | if (SystemUtil.isRooted()) {
146 | files = FileUtil.ListFilesWithRoot(file
147 | .getAbsolutePath());
148 | }
149 | }
150 | if (files != null) {
151 | for (int i = 0; i < files.length; i++) {
152 | if (showhidden) {
153 | flist.add(new FileItem(files[i]));
154 | } else {
155 | if (!files[i].isHidden()) {
156 | flist.add(new FileItem(files[i]));
157 | }
158 | }
159 |
160 | }
161 | }
162 | files = null;
163 | sortList(flist);
164 | }
165 | }
166 | return flist;
167 | }
168 |
169 | @Override
170 | protected void onPostExecute(ArrayList result) {
171 | setList(result);
172 | notifyDataSetChanged();
173 | }
174 |
175 | }
176 |
177 | public void openCursor(FileCategory f) {
178 | OpenCursorTask task = new OpenCursorTask();
179 | this.fc = f;
180 | task.execute(fc);
181 | }
182 |
183 | public void closeCursor() {
184 | if (mCursor != null && !mCursor.isClosed()) {
185 | mCursor.close();
186 | }
187 | }
188 |
189 | class OpenCursorTask extends
190 | AsyncTask> {
191 |
192 | @Override
193 | protected ArrayList doInBackground(FileCategory... params) {
194 | ArrayList flist = new ArrayList();
195 | currentDirectory = null;
196 | fc = params[0];
197 | Cursor cursor = FileCategoryHelper.query(fc, mContext);
198 | mCursor = cursor;
199 | flist.clear();
200 | ArrayList fileNos = new ArrayList();
201 | if (cursor != null && cursor.getCount() > 0) {
202 | cursor.moveToPosition(-1);
203 | while (cursor.moveToNext()) {
204 | FileItem item = new FileItem(cursor.getString(1));
205 | if (item.exists()) {
206 | flist.add(item);
207 | } else {
208 | fileNos.add(item);
209 | }
210 | }
211 | }
212 | if (fileNos.size() > 0) {
213 | String[] files = new String[fileNos.size()];
214 | for (int i = 0; i < fileNos.size(); i++) {
215 | files[i] = fileNos.get(i).getAbsolutePath();
216 | }
217 | if (mContext != null) {
218 | MediaScannerConnection
219 | .scanFile(mContext, files, null, null);
220 | }
221 | }
222 | sortList(flist);
223 | return flist;
224 | }
225 |
226 | @Override
227 | protected void onPostExecute(ArrayList result) {
228 | setList(result);
229 | notifyDataSetChanged();
230 | }
231 |
232 | }
233 |
234 | /**
235 | * 选择当前目录下所有文件
236 | */
237 | public void selectAll() {
238 | for (Iterator iterator = list.iterator(); iterator.hasNext();) {
239 | FileItem fileItem = (FileItem) iterator.next();
240 | fileItem.setSelected(true);
241 | }
242 | notifyDataSetChanged();
243 | }
244 |
245 | /**
246 | * 取消所有文件的选中状态
247 | */
248 | public void unselectAll() {
249 | for (Iterator iterator = list.iterator(); iterator.hasNext();) {
250 | FileItem fileItem = (FileItem) iterator.next();
251 | fileItem.setSelected(false);
252 | }
253 | notifyDataSetChanged();
254 | }
255 |
256 | public void change2SelectMode() {
257 | for (Iterator iterator = list.iterator(); iterator.hasNext();) {
258 | FileItem fileItem = (FileItem) iterator.next();
259 | fileItem.setInSelectMode(true);
260 | }
261 | notifyDataSetChanged();
262 | }
263 |
264 | public void exitSelectMode() {
265 | for (Iterator iterator = list.iterator(); iterator.hasNext();) {
266 | FileItem fileItem = (FileItem) iterator.next();
267 | fileItem.setInSelectMode(false);
268 | fileItem.setSelected(false);
269 | }
270 | notifyDataSetChanged();
271 | }
272 |
273 | public void sortList() {
274 | FileItemComparator comparator = new FileItemComparator();
275 | Collections.sort(list, comparator);
276 | }
277 |
278 | public void sortList(ArrayList lis) {
279 | FileItemComparator comparator = new FileItemComparator();
280 | Collections.sort(lis, comparator);
281 | }
282 |
283 | /**
284 | * @return 选中的文件列表
285 | */
286 | public ArrayList getSelectedFiles() {
287 | ArrayList selectedFiles = new ArrayList();
288 | for (Iterator iterator = list.iterator(); iterator.hasNext();) {
289 | FileItem file = iterator.next();// 强制转换为File
290 | if (file.isSelected()) {
291 | selectedFiles.add(file);
292 | }
293 | }
294 | return selectedFiles;
295 | }
296 |
297 | public class FileItemComparator implements Comparator {
298 |
299 | @Override
300 | public int compare(FileItem lhs, FileItem rhs) {
301 | if (lhs.isDirectory() != rhs.isDirectory()) {
302 | // 如果一个是文件,一个是文件夹,优先按照类型排序
303 | if (lhs.isDirectory()) {
304 | return -1;
305 | } else {
306 | return 1;
307 | }
308 | } else {
309 | // 如果同是文件夹或者文件,则按名称排序
310 | return lhs.getName().toLowerCase()
311 | .compareTo(rhs.getName().toLowerCase());
312 | }
313 | }
314 | }
315 |
316 | public File getCurrentDirectory() {
317 | return currentDirectory;
318 | }
319 |
320 | public boolean isDisplayModeGrid() {
321 | return displayModeGrid;
322 | }
323 |
324 | public void setDisplayModeGrid(boolean displayModeGrid) {
325 | this.displayModeGrid = displayModeGrid;
326 | }
327 |
328 | @Override
329 | public Filter getFilter() {
330 | return filter;
331 | }
332 |
333 | private Filter filter = new Filter() {
334 |
335 | @SuppressWarnings("unchecked")
336 | @Override
337 | protected void publishResults(CharSequence constraint,
338 | FilterResults results) {
339 | setList((ArrayList) results.values);
340 | if (results.count > 0) {
341 | notifyDataSetChanged();
342 | } else {
343 | notifyDataSetInvalidated();
344 | }
345 | }
346 |
347 | @Override
348 | protected FilterResults performFiltering(CharSequence constraint) {
349 | boolean showhidden = SharePreferencesUtil.readBoolean(
350 | FileConst.Key_Show_Hiddle_Files, false);
351 | String mat = constraint.toString().toLowerCase();
352 | FilterResults results = new FilterResults();
353 | ArrayList tmpList = new ArrayList();
354 | File file = currentDirectory;
355 | if (file != null) {
356 | if (currentDirectory.equals(new File(
357 | FileConst.Value_File_Path_Never_Existed))) {
358 | BookmarkHelper helper = new BookmarkHelper(mContext);
359 | helper.open();
360 | tmpList = helper.getBookmarks();
361 | helper.close();
362 | } else if (file.isDirectory()) {
363 | File[] files = file.listFiles();
364 | if (files != null) {
365 | for (int i = 0; i < files.length; i++) {
366 | File tmpFile = files[i];
367 | if (tmpFile.getName().toLowerCase().contains(mat)) {
368 | if (showhidden) {
369 | tmpList.add(new FileItem(tmpFile));
370 | } else {
371 | if (!files[i].isHidden()) {
372 | tmpList.add(new FileItem(tmpFile));
373 | }
374 | }
375 | }
376 |
377 | }
378 | }
379 | files = null;
380 | }
381 | } else if (mCursor != null) {
382 | if (mCursor.getCount() > 0) {
383 | mCursor.moveToPosition(-1);
384 | while (mCursor.moveToNext()) {
385 | FileItem item = new FileItem(mCursor.getString(1));
386 | if (item.getName().toLowerCase().contains(mat)) {
387 | tmpList.add(item);
388 | }
389 | }
390 | }
391 | }
392 | sortList(tmpList);
393 | results.values = tmpList;
394 | results.count = tmpList.size();
395 | return results;
396 | }
397 | };
398 |
399 | }
400 |
--------------------------------------------------------------------------------
/src/net/nashlegend/legendexplorer/adapter/FilePagerAdapter.java:
--------------------------------------------------------------------------------
1 |
2 | package net.nashlegend.legendexplorer.adapter;
3 |
4 | import java.util.ArrayList;
5 |
6 | import net.nashlegend.legendexplorer.fragment.BaseFragment;
7 |
8 |
9 | import android.app.FragmentManager;
10 | import android.support.v13.app.FragmentPagerAdapter;
11 |
12 | public class FilePagerAdapter extends FragmentPagerAdapter {
13 |
14 | ArrayList list = new ArrayList();
15 |
16 | public FilePagerAdapter(FragmentManager fm) {
17 | super(fm);
18 | }
19 |
20 | @Override
21 | public BaseFragment getItem(int arg0) {
22 | return list.get(arg0);
23 | }
24 |
25 | @Override
26 | public int getCount() {
27 | return list.size();
28 | }
29 |
30 | public ArrayList getList() {
31 | return list;
32 | }
33 |
34 | public void setList(ArrayList list) {
35 | this.list = list;
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/src/net/nashlegend/legendexplorer/adapter/ImagePagerAdapter.java:
--------------------------------------------------------------------------------
1 |
2 | package net.nashlegend.legendexplorer.adapter;
3 |
4 | import java.io.File;
5 | import java.util.ArrayList;
6 |
7 | import net.nashlegend.legendexplorer.view.ZoomImageView;
8 |
9 | import net.nashlegend.legendutils.Tools.FileUtil;
10 |
11 | import android.content.Context;
12 | import android.support.v4.view.PagerAdapter;
13 | import android.view.View;
14 | import android.view.ViewGroup;
15 |
16 | public class ImagePagerAdapter extends PagerAdapter {
17 | String mPath;
18 | Context mContext;
19 | ArrayList files = new ArrayList();
20 | private int imageIndex;
21 |
22 | public ImagePagerAdapter(Context context, String path) {
23 | mPath = path;
24 | mContext = context;
25 |
26 | File FirstImage = new File(path);
27 |
28 | if (isImageFile(FirstImage)) {
29 | File parentFile = FirstImage.getParentFile();
30 | File[] listFiles = parentFile.listFiles();
31 | if (listFiles != null) {
32 | for (int i = 0; i < parentFile.listFiles().length; i++) {
33 | File file = listFiles[i];
34 | if (isImageFile(file)) {
35 | files.add(file);
36 | if (file.equals(FirstImage)) {
37 | imageIndex = files.size() - 1;
38 | }
39 | }
40 | }
41 | }
42 | }
43 | }
44 |
45 | public int getImageIndex() {
46 | return imageIndex;
47 | }
48 |
49 | public boolean isImageFile(File file) {
50 | return FileUtil.getFileType(file) == FileUtil.FILE_TYPE_IMAGE;
51 | }
52 |
53 | @Override
54 | public int getCount() {
55 | // TODO Auto-generated method stub
56 | return files.size();
57 | }
58 |
59 | @Override
60 | public Object instantiateItem(ViewGroup container, int position) {
61 | // TODO
62 | ZoomImageView imageView = new ZoomImageView(mContext);
63 | imageView.setImageFile(files.get(position).getAbsolutePath());
64 | container.addView(imageView);
65 | return imageView;
66 | }
67 |
68 | @Override
69 | public void destroyItem(ViewGroup container, int position, Object object) {
70 | try {
71 | container.removeView((View) object);
72 | } catch (Exception e) {
73 |
74 | }
75 | }
76 |
77 | @Override
78 | public boolean isViewFromObject(View arg0, Object arg1) {
79 | return arg0 == arg1;
80 | }
81 |
82 | }
83 |
--------------------------------------------------------------------------------
/src/net/nashlegend/legendexplorer/application/ExplorerApplication.java:
--------------------------------------------------------------------------------
1 | package net.nashlegend.legendexplorer.application;
2 |
3 | import net.nashlegend.legendexplorer.consts.FileConst;
4 | import net.nashlegend.legendexplorer.db.BookmarkHelper;
5 | import net.nashlegend.legendexplorer.utils.SharePreferencesUtil;
6 |
7 |
8 | import android.app.Application;
9 | import android.content.Context;
10 | import android.media.MediaScannerConnection;
11 | import android.os.Environment;
12 | import android.widget.ImageView;
13 |
14 | public class ExplorerApplication extends Application {
15 |
16 | public static Context GlobalContext;
17 |
18 | public ExplorerApplication() {
19 |
20 | }
21 |
22 | @Override
23 | public void onCreate() {
24 | super.onCreate();
25 | GlobalContext = this;
26 | // MediaScannerConnection.scanFile(getApplicationContext(),
27 | // new String[] { Environment.getExternalStorageDirectory()
28 | // .getAbsolutePath() }, null, null);
29 | if (SharePreferencesUtil.readBoolean(FileConst.Key_Is_First_Open, true)) {
30 | SharePreferencesUtil
31 | .saveBoolean(FileConst.Key_Is_First_Open, false);
32 | BookmarkHelper helper = new BookmarkHelper(this);
33 | helper.initBookmarks();
34 | }
35 | }
36 |
37 | public static Context getGlobalContext() {
38 | return GlobalContext;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/net/nashlegend/legendexplorer/consts/FileConst.java:
--------------------------------------------------------------------------------
1 | package net.nashlegend.legendexplorer.consts;
2 |
3 | public class FileConst {
4 |
5 | // Actions
6 | public static final String Action_FileItem_Long_Click = "legendexplorer.fileitemlongclick";
7 | public static final String Action_FileItem_Unselect = "legendexplorer.fileitemunselect";
8 | public static final String Action_FileItem_Select = "legendexplorer.fileitemselect";
9 | public static final String Action_Refresh_FileList = "legendexplorer.refreshfilelist";
10 | public static final String Action_Toggle_View_Mode = "legendexplorer.toggleviewmode";
11 | public static final String Action_Property_File = "legendexplorer.propertyfile";
12 | public static final String Action_Add_New_File = "legendexplorer.addnewfile";
13 | public static final String Action_Search_File = "legendexplorer.searchfile";
14 | public static final String Action_Quit_Search = "legendexplorer.quitsearch";
15 | public static final String Action_Open_Folder = "legendexplorer.openfolder";
16 | public static final String Action_Copy_File = "legendexplorer.copyfile";
17 | public static final String Action_Move_File = "legendexplorer.movefile";
18 | public static final String Action_Zip_File = "legendexplorer.zipfile";
19 | public static final String Action_Unzip_File = "legendexplorer.unzipfile";
20 | public static final String Action_Favor_File = "legendexplorer.favorfile";
21 | public static final String Action_Rename_File = "legendexplorer.renamefile";
22 | public static final String Action_Delete_File = "legendexplorer.deletefile";
23 | public static final String Action_Toggle_Show_Hidden = "legendexplorer.toggleshowhidden";
24 | public static final String Action_File_Operation_Done = "legendexplorer.fileoperationdone";
25 | public static final String Action_Enable_Pager_Scroll = "legendexplorer.enablepagerscroll";
26 | public static final String Action_Disable_Pager_Scroll = "legendexplorer.disablepagerscroll";
27 | public static final String Action_Set_File_View_ActionBar = "legendexplorer.setfileviewactionbar";
28 | public static final String Action_Set_File_Operation_ActionBar = "legendexplorer.setfileoperationactionbar";
29 |
30 | // Extras
31 | public static final String Extra_File_Path = "filepath";
32 | public static final String Extra_Item_Type = "itemtype";
33 | public static final String Extra_Explore_Type = "exploretype";
34 | public static final String Extra_Category_Type = "categorytype";
35 | public static final String Extra_Path_Preffix = "pathpreffix";
36 | public static final String Extra_Menu_Mask = "menumask";
37 |
38 | // Keys
39 | public static final String Key_Is_First_Open = "isfirstopen";
40 | public static final String Key_Files_Display_Mode = "filesdisplaymode";
41 | public static final String Key_Show_Hiddle_Files = "showhiddenfiles";
42 | public static final String Key_Search_File_Query = "searchfilequery";
43 | public static final String Key_Show_More_On_Icon = "showmoreonicon";
44 |
45 | // Values
46 | public static final String Value_Bookmark_Path = "Bookmark://";
47 | public static final String Value_File_Path_Never_Existed = "/filepathneverexisted/";
48 | public static final int Value_Files_Display_List = 0;
49 | public static final int Value_Files_Display_Grid = 1;
50 |
51 | public static final int Value_Explore_Type_Files = 0;
52 | public static final int Value_Explore_Type_Bookmarks = 1;
53 | public static final int Value_Explore_Type_Categories = 2;
54 |
55 | public static final int Value_Item_Type_File_Or_Folder = 0;
56 | public static final int Value_Item_Type_Bookmark = 1;
57 | public static final int Value_Item_Type_Category = 2;
58 |
59 | }
60 |
--------------------------------------------------------------------------------
/src/net/nashlegend/legendexplorer/db/BookmarkColumn.java:
--------------------------------------------------------------------------------
1 |
2 | package net.nashlegend.legendexplorer.db;
3 |
4 | import android.provider.BaseColumns;
5 |
6 | public class BookmarkColumn implements BaseColumns {
7 |
8 | public BookmarkColumn() {
9 |
10 | }
11 |
12 | // 列名
13 | public static final String FILE_NAME = "FILE_NAME"; // 文件名
14 | public static final String FILE_PATH = "FILE_PATH"; // 文件路径
15 |
16 | // 索引值
17 | public static final int FILE_NAME_COLUMN = 0;
18 | public static final int FILE_PATH_COLUMN = FILE_NAME_COLUMN + 1;
19 | // 查询结果集
20 | public static final String[] PROJECTION =
21 | {
22 | FILE_NAME,
23 | FILE_PATH
24 | };
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/src/net/nashlegend/legendexplorer/db/BookmarkHelper.java:
--------------------------------------------------------------------------------
1 | package net.nashlegend.legendexplorer.db;
2 |
3 | import java.io.File;
4 | import java.util.ArrayList;
5 |
6 | import net.nashlegend.legendexplorer.consts.FileConst;
7 | import net.nashlegend.legendexplorer.model.FileItem;
8 |
9 |
10 | import android.content.ContentValues;
11 | import android.content.Context;
12 | import android.database.Cursor;
13 | import android.database.sqlite.SQLiteDatabase;
14 | import android.os.Environment;
15 | import android.util.Log;
16 |
17 | public class BookmarkHelper {
18 |
19 | private final Context mContext;
20 | private FileDataBase mDbHelper;
21 | private SQLiteDatabase mSqlDB;
22 |
23 | public BookmarkHelper(Context context) {
24 | this.mContext = context;
25 | }
26 |
27 | public BookmarkHelper open() {
28 | mDbHelper = FileDataBase.getInstance(mContext);
29 | mSqlDB = mDbHelper.getWritableDatabase();
30 | return this;
31 | }
32 |
33 | public void close() {
34 | if (mDbHelper != null) {
35 | mDbHelper.close();
36 | }
37 | }
38 |
39 | public boolean deleteBookmark(ArrayList list) {
40 | try {
41 | mSqlDB.beginTransaction();
42 | for (File item : list) {
43 | deleteBookmark(item);
44 | }
45 | mSqlDB.setTransactionSuccessful();
46 | } finally {
47 | mSqlDB.endTransaction();
48 | }
49 | return true;
50 | }
51 |
52 | public boolean deleteBookmark(File item) {
53 | String whereClause = BookmarkColumn.FILE_PATH + "='"
54 | + item.getAbsolutePath() + "'";
55 | Log.i("where", whereClause);
56 | int num = mSqlDB.delete(FileDataBase.TableBookmark, whereClause, null);
57 | return num > 0;
58 | }
59 |
60 | public boolean insertBookmark(ArrayList list) {
61 | try {
62 | mSqlDB.beginTransaction();
63 | for (FileItem item : list) {
64 | insert(item);
65 | }
66 | mSqlDB.setTransactionSuccessful();
67 | } finally {
68 | mSqlDB.endTransaction();
69 | }
70 | return true;
71 | }
72 |
73 | public boolean insert(FileItem item) {
74 | long ret = -1;
75 | ContentValues values = new ContentValues();
76 | values.put(BookmarkColumn.FILE_NAME, item.getName());
77 | values.put(BookmarkColumn.FILE_PATH, item.getAbsolutePath());
78 | ret = mSqlDB.insert(FileDataBase.TableBookmark, null, values);
79 | return ret != -1;
80 | }
81 |
82 | public ArrayList getBookmarks() {
83 |
84 | ArrayList list = new ArrayList();
85 |
86 | Cursor cursor = mSqlDB.query(FileDataBase.TableBookmark,
87 | BookmarkColumn.PROJECTION, null, null, null, null, null,
88 | String.valueOf(10));
89 |
90 | if (cursor.getCount() > 0) {
91 | for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor
92 | .moveToNext()) {
93 | String filePath = cursor
94 | .getString(BookmarkColumn.FILE_PATH_COLUMN);
95 | FileItem item = new FileItem(filePath);
96 | item.setItemType(FileConst.Value_Item_Type_Bookmark);
97 | list.add(item);
98 | }
99 | }
100 |
101 | cursor.close();
102 | cursor = null;
103 |
104 | return list;
105 |
106 | }
107 |
108 | public boolean truncate() {
109 | int ret = mSqlDB.delete(FileDataBase.TableBookmark, null, null);
110 | return ret > 0 ? true : false;
111 | }
112 |
113 | public void initBookmarks() {
114 | // 当文件不存在时isDirectory和isFile都返回false
115 | ArrayList fileItems = new ArrayList();
116 | FileItem item_download = new FileItem(
117 | Environment
118 | .getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS));
119 | if (item_download.exists() && item_download.isDirectory()) {
120 | fileItems.add(item_download);
121 | }
122 | FileItem item_camera = new FileItem(
123 | Environment
124 | .getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM));
125 | if (item_camera.exists() && item_camera.isDirectory()) {
126 | fileItems.add(item_camera);
127 | }
128 | FileItem item_movie = new FileItem(
129 | Environment
130 | .getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES));
131 | if (item_movie.exists() && item_movie.isDirectory()) {
132 | fileItems.add(item_movie);
133 | }
134 | FileItem item_music = new FileItem(
135 | Environment
136 | .getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC));
137 | if (item_music.exists() && item_music.isDirectory()) {
138 | fileItems.add(item_music);
139 | }
140 | FileItem item_picture = new FileItem(
141 | Environment
142 | .getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES));
143 | if (item_picture.exists() && item_picture.isDirectory()) {
144 | fileItems.add(item_picture);
145 | }
146 |
147 | open();
148 | truncate();
149 | insertBookmark(fileItems);
150 | close();
151 | }
152 | }
153 |
--------------------------------------------------------------------------------
/src/net/nashlegend/legendexplorer/db/FileDataBase.java:
--------------------------------------------------------------------------------
1 |
2 | package net.nashlegend.legendexplorer.db;
3 |
4 | import android.content.Context;
5 | import android.database.SQLException;
6 | import android.database.sqlite.SQLiteDatabase;
7 | import android.database.sqlite.SQLiteOpenHelper;
8 |
9 | public class FileDataBase extends SQLiteOpenHelper {
10 |
11 | public static final String DatabaseName = "explorer.db";
12 | public static final String TableBookmark = "bookmark";
13 | public static final int DBVersion = 1;
14 | public static FileDataBase mFileDataBase = null;
15 |
16 | public FileDataBase(Context context) {
17 | super(context, DatabaseName, null, DBVersion);
18 | }
19 |
20 | public static FileDataBase getInstance(Context context) {
21 | if (mFileDataBase == null) {
22 | mFileDataBase = new FileDataBase(context);
23 | }
24 | return mFileDataBase;
25 | }
26 |
27 | @Override
28 | public void onCreate(SQLiteDatabase db) {
29 | createBookmarkDB(db);
30 | }
31 |
32 | private void createBookmarkDB(SQLiteDatabase db) {
33 | String section_sql = "create table IF NOT EXISTS " + TableBookmark + "("
34 | + BookmarkColumn._ID + " integer primary key AUTOINCREMENT,"
35 | + BookmarkColumn.FILE_NAME + " varchar default '',"
36 | + BookmarkColumn.FILE_PATH + " varchar default '' )";
37 | try {
38 | db.execSQL(section_sql);
39 | } catch (SQLException e) {
40 | } finally {
41 | }
42 | }
43 |
44 | @Override
45 | public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
46 |
47 | }
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/src/net/nashlegend/legendexplorer/dialog/FilePropertyDialog.java:
--------------------------------------------------------------------------------
1 | package net.nashlegend.legendexplorer.dialog;
2 |
3 | import java.io.File;
4 |
5 | import net.nashlegend.legendexplorer.view.FilePropertyView;
6 |
7 | import net.nashlegend.legendutils.BuildIn.FileDialogView;
8 |
9 | import android.app.Dialog;
10 | import android.content.Context;
11 | import android.content.DialogInterface;
12 | import android.view.ViewGroup.LayoutParams;
13 |
14 | public class FilePropertyDialog extends Dialog {
15 |
16 | public FilePropertyDialog(Context context) {
17 | super(context);
18 | }
19 |
20 | public FilePropertyDialog(Context context, int theme) {
21 | super(context, theme);
22 | }
23 |
24 | public FilePropertyDialog(Context context, boolean cancelable,
25 | OnCancelListener cancelListener) {
26 | super(context, cancelable, cancelListener);
27 | }
28 |
29 | public static class Builder {
30 | private boolean allInOneFolder = true;
31 | private String title = "属性";
32 | private File[] files;
33 | private Context mContext;
34 |
35 | public Builder(Context context) {
36 | mContext = context;
37 | }
38 |
39 | public Builder setAllInOneFolder(boolean in) {
40 | allInOneFolder = in;
41 | return this;
42 | }
43 |
44 | public Builder setTitle(String tit) {
45 | title = tit;
46 | return this;
47 | }
48 |
49 | public Builder setFiles(File[] fs) {
50 | files = fs;
51 | return this;
52 | }
53 |
54 | public FilePropertyDialog create() {
55 | FilePropertyDialog dialog = new FilePropertyDialog(mContext);
56 | final FilePropertyView view = new FilePropertyView(mContext);
57 | view.setFiles(files, allInOneFolder);
58 |
59 | LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT,
60 | LayoutParams.WRAP_CONTENT);
61 | dialog.setTitle(title);
62 | dialog.addContentView(view, params);
63 | dialog.setOnCancelListener(new OnCancelListener() {
64 |
65 | @Override
66 | public void onCancel(DialogInterface dialog) {
67 | view.cancel();
68 | }
69 | });
70 | return dialog;
71 | }
72 | }
73 |
74 | }
75 |
--------------------------------------------------------------------------------
/src/net/nashlegend/legendexplorer/fragment/BaseFragment.java:
--------------------------------------------------------------------------------
1 |
2 | package net.nashlegend.legendexplorer.fragment;
3 |
4 | import android.app.Fragment;
5 | import android.content.Intent;
6 |
7 | public abstract class BaseFragment extends Fragment {
8 |
9 | public BaseFragment() {
10 |
11 | }
12 |
13 | public abstract boolean doBackAction();
14 |
15 | public abstract boolean doVeryAction(Intent intent);
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/src/net/nashlegend/legendexplorer/fragment/BookMarksFragment.java:
--------------------------------------------------------------------------------
1 | package net.nashlegend.legendexplorer.fragment;
2 |
3 | import java.io.File;
4 |
5 | import net.nashlegend.legendexplorer.MainActivity;
6 | import net.nashlegend.legendexplorer.consts.FileConst;
7 | import net.nashlegend.legendexplorer.model.FileItem;
8 | import net.nashlegend.legendexplorer.view.DropDownAncestorList;
9 | import net.nashlegend.legendexplorer.view.DropDownAncestorList.OnAncestorClickListener;
10 |
11 | import net.nashlegend.legendexplorer.R;
12 |
13 | import android.app.FragmentTransaction;
14 | import android.content.Intent;
15 | import android.graphics.Bitmap;
16 | import android.graphics.drawable.BitmapDrawable;
17 | import android.os.Bundle;
18 | import android.util.Log;
19 | import android.view.LayoutInflater;
20 | import android.view.View;
21 | import android.view.ViewGroup;
22 | import android.view.ViewGroup.LayoutParams;
23 | import android.widget.CheckBox;
24 | import android.widget.EditText;
25 | import android.widget.ImageButton;
26 | import android.widget.PopupWindow;
27 |
28 | /**
29 | * 书签视图
30 | *
31 | * @author NashLegend
32 | */
33 | public class BookMarksFragment extends FilesFragment {
34 | private String pathPreffix = FileConst.Value_File_Path_Never_Existed;
35 |
36 | public BookMarksFragment() {
37 |
38 | }
39 |
40 | @Override
41 | public View onCreateView(LayoutInflater inflater, ViewGroup container,
42 | Bundle savedInstanceState) {
43 | if (view == null) {
44 | view = inflater.inflate(R.layout.layout_file_bookmark, container,
45 | false);
46 | pathText = (EditText) view.findViewById(R.id.edittext_file_path);
47 |
48 | backButton = (ImageButton) view
49 | .findViewById(R.id.imagebutton_file_back);
50 | selectAllButton = (CheckBox) view
51 | .findViewById(R.id.checkbox_file_all);
52 | backButton.setOnClickListener(this);
53 | selectAllButton.setOnCheckedChangeListener(this);
54 | selectAllButton.setVisibility(View.GONE);
55 | pathText.setKeyListener(null);
56 | pathText.setOnClickListener(this);
57 |
58 | ancestorList = new DropDownAncestorList(getActivity());
59 | ancestorList
60 | .setOnAncestorClickListener(new OnAncestorClickListener() {
61 |
62 | @Override
63 | public void onClick(String path) {
64 | openAncestorFolder(new File(path));
65 | popupWindow.dismiss();
66 | }
67 | });
68 |
69 | popupWindow = new PopupWindow(ancestorList,
70 | LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT, true);
71 | popupWindow.setTouchable(true);
72 | popupWindow.setOutsideTouchable(true);
73 | popupWindow.setBackgroundDrawable(new BitmapDrawable(
74 | getResources(), (Bitmap) null));
75 |
76 | openBookMarks();
77 | } else {
78 | if (view.getParent() != null) {
79 | ((ViewGroup) view.getParent()).removeView(view);
80 | }
81 | }
82 |
83 | return view;
84 | }
85 |
86 | @Override
87 | protected void change2SelectMode() {
88 | if (fakeBackStack.size() > 0) {
89 | selectAllButton.setVisibility(View.VISIBLE);
90 | inSelectMode = true;
91 | fakeBackStack.get(fakeBackStack.size() - 1).change2SelectMode();
92 |
93 | Intent intent = new Intent();
94 | int mask = 0;
95 | if (fakeBackStack.size() > 0) {
96 | FileListFragment fragment = fakeBackStack.get(fakeBackStack
97 | .size() - 1);
98 | if (fragment.getFilePath()
99 | .equals(FileConst.Value_Bookmark_Path)) {
100 | mask = MainActivity.FlagFavorItem
101 | | MainActivity.FlagUnzipFileItem
102 | | MainActivity.FlagZipFileItem
103 | | MainActivity.FlagRenameFileItem
104 | | MainActivity.FlagCutFileItem;
105 | } else {
106 | mask = 0;
107 | }
108 | }
109 | intent.putExtra(FileConst.Extra_Menu_Mask, mask);
110 | intent.setAction(FileConst.Action_Set_File_Operation_ActionBar);
111 | getActivity().sendBroadcast(intent);
112 | }
113 | }
114 |
115 | @Override
116 | protected void exitSelectMode() {
117 | if (fakeBackStack.size() > 0) {
118 | selectAllButton.setVisibility(View.GONE);
119 | selectAllButton.setChecked(false);
120 | inSelectMode = false;
121 | fakeBackStack.get(fakeBackStack.size() - 1).exitSelectMode();
122 |
123 | Intent intent = new Intent();
124 | int mask = 0;
125 | // 事实上fakeBackStack.size==1的时候就足以判断了
126 | if (fakeBackStack.size() > 0) {
127 | FileListFragment fragment = fakeBackStack.get(fakeBackStack
128 | .size() - 1);
129 | if (fragment.getFilePath()
130 | .equals(FileConst.Value_Bookmark_Path)) {
131 | mask = MainActivity.FlagAddFileItem;
132 | } else {
133 | mask = 0;
134 | }
135 | }
136 | intent.putExtra(FileConst.Extra_Menu_Mask, mask);
137 | intent.setAction(FileConst.Action_Set_File_View_ActionBar);
138 | getActivity().sendBroadcast(intent);
139 | }
140 | }
141 |
142 | /*
143 | * @see
144 | * net.nashlegend.legendexplorer.fragment.FilesFragment#openFolder(java.io.
145 | * File, int)
146 | */
147 | public void openFolder(File file, int animation) {
148 |
149 | if (file == null || !file.isDirectory()) {
150 | throw new NullPointerException(
151 | "openFolder://file.exists() && file.isDirectory()");
152 | }
153 |
154 | if (file.equals(new File(pathPreffix))) {
155 | openBookMarks();
156 | return;
157 | }
158 |
159 | FileListFragment fragment = new FileListFragment();
160 | Bundle bundle = new Bundle();
161 | bundle.putString(FileConst.Extra_File_Path, file.getAbsolutePath());
162 | bundle.putString(FileConst.Extra_Path_Preffix, pathPreffix);
163 | bundle.putInt(FileConst.Extra_Item_Type,
164 | FileConst.Value_Item_Type_File_Or_Folder);
165 | bundle.putInt(FileConst.Extra_Explore_Type,
166 | FileConst.Value_Explore_Type_Bookmarks);
167 | fragment.setArguments(bundle);
168 |
169 | FragmentTransaction transaction = getFragmentManager()
170 | .beginTransaction();
171 | transaction.setTransition(animation);
172 | transaction.replace(R.id.content_bookmark, fragment,
173 | file.getAbsolutePath());
174 | transaction.commit();
175 | fakeBackStack.add(fragment);
176 | pathText.setText(fragment.getDisplayedFilePath());
177 |
178 | Intent intent = new Intent();
179 | int mask = 0;
180 | intent.putExtra(FileConst.Extra_Menu_Mask, mask);
181 | intent.setAction(FileConst.Action_Set_File_View_ActionBar);
182 | getActivity().sendBroadcast(intent);
183 | }
184 |
185 | /**
186 | * 打开目录
187 | *
188 | * @param file
189 | * 要打开的文件夹
190 | */
191 | public void openFolder(File file) {
192 | openFolder(file, FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
193 | }
194 |
195 | /**
196 | * 打开收藏夹目录
197 | */
198 | public void openBookMarks() {
199 | pathPreffix = FileConst.Value_File_Path_Never_Existed;
200 | fakeBackStack.clear();
201 | FileListFragment fragment = new FileListFragment();
202 | Bundle bundle = new Bundle();
203 | bundle.putString(FileConst.Extra_File_Path,
204 | FileConst.Value_Bookmark_Path);
205 | bundle.putString(FileConst.Extra_Path_Preffix, pathPreffix);
206 | bundle.putInt(FileConst.Extra_Item_Type,
207 | FileConst.Value_Item_Type_Bookmark);
208 | bundle.putInt(FileConst.Extra_Explore_Type,
209 | FileConst.Value_Explore_Type_Bookmarks);
210 | fragment.setArguments(bundle);
211 | FragmentTransaction transaction = getFragmentManager()
212 | .beginTransaction();
213 | transaction.replace(R.id.content_bookmark, fragment,
214 | FileConst.Value_Bookmark_Path);
215 | transaction.commit();
216 | fakeBackStack.add(fragment);
217 | pathText.setText(fragment.getDisplayedFilePath());
218 |
219 | Intent intent = new Intent();
220 | int mask = MainActivity.FlagAddFileItem;
221 | intent.putExtra(FileConst.Extra_Menu_Mask, mask);
222 | intent.setAction(FileConst.Action_Set_File_View_ActionBar);
223 | getActivity().sendBroadcast(intent);
224 | }
225 |
226 | /**
227 | * 回退
228 | */
229 | protected void backStack() {
230 | if (fakeBackStack.size() > 1) {
231 | fakeBackStack.remove(fakeBackStack.size() - 1);
232 | FileListFragment fragment = fakeBackStack
233 | .get(fakeBackStack.size() - 1);
234 | FragmentTransaction transaction = getFragmentManager()
235 | .beginTransaction();
236 | transaction
237 | .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_CLOSE);
238 | transaction.replace(R.id.content_bookmark, fragment,
239 | fragment.getDisplayedFilePath());
240 | transaction.commit();
241 | pathText.setText(fragment.getDisplayedFilePath());
242 |
243 | Intent intent = new Intent();
244 | int mask = 0;
245 | if (fragment.getFilePath().equals(FileConst.Value_Bookmark_Path)) {
246 | mask = MainActivity.FlagAddFileItem;
247 | } else {
248 | mask = 0;
249 | }
250 | intent.putExtra(FileConst.Extra_Menu_Mask, mask);
251 | intent.setAction(FileConst.Action_Set_File_View_ActionBar);
252 | getActivity().sendBroadcast(intent);
253 |
254 | } else {
255 | // do nothing
256 | }
257 | }
258 |
259 | @Override
260 | protected void back2ParentLevel() {
261 | backStack();
262 | }
263 |
264 | @Override
265 | protected void invokeAncestorList() {
266 | String path = fakeBackStack.get(fakeBackStack.size() - 1).getFilePath();
267 | if (FileConst.Value_Bookmark_Path.equals(path)) {
268 | return;
269 | }
270 | File file = new File(path);
271 | ancestorList
272 | .setupList(file, pathPreffix, FileConst.Value_Bookmark_Path);
273 | popupWindow.showAsDropDown(pathText);
274 | }
275 |
276 | @Override
277 | protected void doOpenFolderAction(Intent intent) {
278 | int tp = intent.getIntExtra(FileConst.Extra_Item_Type,
279 | FileConst.Value_Item_Type_File_Or_Folder);
280 | String path = intent.getStringExtra(FileConst.Extra_File_Path);
281 | File file = new File(path);
282 | if (file.getParentFile() != null) {
283 | if (tp == FileConst.Value_Item_Type_Bookmark) {
284 | if (pathPreffix == FileConst.Value_File_Path_Never_Existed) {
285 | pathPreffix = new File(path).getParent();
286 | if (pathPreffix.lastIndexOf("/") != pathPreffix.length() - 1) {
287 | pathPreffix += "/";
288 | }
289 | }
290 | }
291 | }
292 | openFolder(file);
293 | }
294 |
295 | @Override
296 | public void setUserVisibleHint(boolean isVisibleToUser) {
297 | super.setUserVisibleHint(isVisibleToUser);
298 | if (isVisibleToUser) {
299 | Intent intent = new Intent();
300 | int mask = MainActivity.FlagAddFileItem;
301 | if (fakeBackStack.size() > 0) {
302 | FileListFragment fragment = fakeBackStack.get(fakeBackStack
303 | .size() - 1);
304 | if (fragment.getFilePath()
305 | .equals(FileConst.Value_Bookmark_Path)) {
306 | mask = MainActivity.FlagAddFileItem;
307 | } else {
308 | mask = 0;
309 | }
310 | }
311 | intent.putExtra(FileConst.Extra_Menu_Mask, mask);
312 | intent.setAction(FileConst.Action_Set_File_View_ActionBar);
313 | getActivity().sendBroadcast(intent);
314 | }
315 | }
316 |
317 | }
318 |
--------------------------------------------------------------------------------
/src/net/nashlegend/legendexplorer/fragment/Explorable.java:
--------------------------------------------------------------------------------
1 | package net.nashlegend.legendexplorer.fragment;
2 |
3 | public interface Explorable {
4 | public void toggleViewMode();
5 |
6 | public void copyFile();
7 |
8 | public void moveFile();
9 |
10 | public void deleteFile();
11 |
12 | public void addNewFile();
13 |
14 | public void refreshFileList();
15 |
16 | public void searchFile(String query);
17 |
18 | public void toggleShowHidden();
19 |
20 | public void renameFile();
21 |
22 | public void zipFile();
23 |
24 | public void propertyFile();
25 | }
26 |
--------------------------------------------------------------------------------
/src/net/nashlegend/legendexplorer/fragment/FilesFragment.java:
--------------------------------------------------------------------------------
1 |
2 | package net.nashlegend.legendexplorer.fragment;
3 |
4 | import java.io.File;
5 | import java.util.ArrayList;
6 | import java.util.Iterator;
7 |
8 | import net.nashlegend.legendexplorer.MainActivity;
9 | import net.nashlegend.legendexplorer.consts.FileConst;
10 | import net.nashlegend.legendexplorer.view.DropDownAncestorList;
11 | import net.nashlegend.legendexplorer.view.DropDownAncestorList.OnAncestorClickListener;
12 |
13 | import net.nashlegend.legendexplorer.R;
14 | import net.nashlegend.legendutils.Tools.FileUtil;
15 |
16 | import android.app.FragmentTransaction;
17 | import android.content.Intent;
18 | import android.graphics.Bitmap;
19 | import android.graphics.drawable.BitmapDrawable;
20 | import android.os.Bundle;
21 | import android.os.Environment;
22 | import android.util.Log;
23 | import android.view.Gravity;
24 | import android.view.LayoutInflater;
25 | import android.view.View;
26 | import android.view.ViewGroup;
27 | import android.view.View.OnClickListener;
28 | import android.view.ViewGroup.LayoutParams;
29 | import android.widget.CheckBox;
30 | import android.widget.CompoundButton;
31 | import android.widget.EditText;
32 | import android.widget.ImageButton;
33 | import android.widget.CompoundButton.OnCheckedChangeListener;
34 | import android.widget.PopupWindow;
35 |
36 | /**
37 | * 普通视图,事实上if (fakeBackStack.size() > 0) 都是不需要的
38 | *
39 | * @author NashLegend
40 | */
41 | public class FilesFragment extends BaseFragment implements OnClickListener,
42 | OnCheckedChangeListener, Explorable {
43 | protected View view;
44 | protected EditText pathText;
45 | protected ImageButton backButton;
46 | protected CheckBox selectAllButton;
47 | protected boolean inSelectMode = false;
48 | protected DropDownAncestorList ancestorList;
49 | protected ArrayList fakeBackStack = new ArrayList();
50 | protected String initialPath = Environment.getExternalStorageDirectory()
51 | .getPath();
52 | protected PopupWindow popupWindow;
53 |
54 | public FilesFragment() {
55 |
56 | }
57 |
58 | @Override
59 | public View onCreateView(LayoutInflater inflater, ViewGroup container,
60 | Bundle savedInstanceState) {
61 | if (view == null) {
62 | view = inflater.inflate(R.layout.layout_file_explorer, container,
63 | false);
64 | pathText = (EditText) view.findViewById(R.id.edittext_file_path);
65 | backButton = (ImageButton) view
66 | .findViewById(R.id.imagebutton_file_back);
67 | selectAllButton = (CheckBox) view
68 | .findViewById(R.id.checkbox_file_all);
69 |
70 | backButton.setOnClickListener(this);
71 | selectAllButton.setOnCheckedChangeListener(this);
72 | selectAllButton.setVisibility(View.GONE);
73 | pathText.setKeyListener(null);
74 | pathText.setOnClickListener(this);
75 |
76 | ancestorList = new DropDownAncestorList(getActivity());
77 | ancestorList
78 | .setOnAncestorClickListener(new OnAncestorClickListener() {
79 |
80 | @Override
81 | public void onClick(String path) {
82 | openAncestorFolder(new File(path));
83 | popupWindow.dismiss();
84 | }
85 | });
86 |
87 | popupWindow = new PopupWindow(ancestorList,
88 | LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT, true);
89 | popupWindow.setTouchable(true);
90 | popupWindow.setOutsideTouchable(true);
91 | popupWindow.setBackgroundDrawable(new BitmapDrawable(
92 | getResources(), (Bitmap) null));
93 |
94 | openFolder();
95 | } else {
96 | if (view.getParent() != null) {
97 | ((ViewGroup) view.getParent()).removeView(view);
98 | }
99 | }
100 |
101 | return view;
102 | }
103 |
104 | protected void invokeAncestorList() {
105 | String path = pathText.getText().toString();
106 | if ("/".equals(path)) {
107 | return;
108 | } else {
109 | File file = new File(path);
110 | ancestorList.setupList(file);
111 | }
112 | popupWindow.showAsDropDown(pathText);
113 | }
114 |
115 | protected void openAncestorFolder(File file) {
116 | // file.isDirectory()为true则说明文件存在
117 | if (file != null && file.isDirectory()) {
118 | for (int i = fakeBackStack.size() - 1; i >= 0; i--) {
119 | FileListFragment subFragment = fakeBackStack.get(i);
120 | File file2 = new File(subFragment.getFilePath());
121 | if (FileUtil.isAncestorOf(file, file2) || file.equals(file2)) {
122 | fakeBackStack.remove(i);
123 | }
124 | }
125 | }
126 |
127 | openFolder(file, FragmentTransaction.TRANSIT_FRAGMENT_CLOSE);
128 | }
129 |
130 | /**
131 | * @param file
132 | * @param animation
133 | */
134 | public void openFolder(File file, int animation) {
135 | // file.isDirectory()不为true则说明文件要么不存在要么是文件
136 | if (file == null || !file.isDirectory()) {
137 | // 若不存在此目录,则打开根文件夹
138 | return;
139 | }
140 |
141 | FileListFragment fragment = new FileListFragment();
142 | Bundle bundle = new Bundle();
143 | bundle.putString(FileConst.Extra_File_Path, file.getAbsolutePath());
144 | fragment.setArguments(bundle);
145 |
146 | FragmentTransaction transaction = getFragmentManager()
147 | .beginTransaction();
148 | transaction.setTransition(animation);
149 | transaction.replace(R.id.content_explorer, fragment,
150 | file.getAbsolutePath());
151 | transaction.commit();
152 | fakeBackStack.add(fragment);
153 | pathText.setText(fragment.getDisplayedFilePath());
154 | }
155 |
156 | /**
157 | * 打开目录
158 | *
159 | * @param file 要打开的文件夹
160 | */
161 | public void openFolder(File file) {
162 | openFolder(file, FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
163 | }
164 |
165 | /**
166 | * 打开目录
167 | *
168 | * @param path 要打开的文件夹路径
169 | */
170 | public void openFolder(String path) {
171 | openFolder(new File(path));
172 | }
173 |
174 | /**
175 | * 打开初始目录
176 | */
177 | public void openFolder() {
178 | openFolder(initialPath);
179 | }
180 |
181 | /**
182 | * 返回一层fragment,不一定是上一级目录
183 | */
184 | protected void backStack() {
185 | if (fakeBackStack.size() > 1) {
186 | fakeBackStack.remove(fakeBackStack.size() - 1);
187 | FileListFragment fragment = fakeBackStack
188 | .get(fakeBackStack.size() - 1);
189 | FragmentTransaction transaction = getFragmentManager()
190 | .beginTransaction();
191 | transaction
192 | .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_CLOSE);
193 | transaction.replace(R.id.content_explorer, fragment,
194 | fragment.getDisplayedFilePath());
195 | transaction.commit();
196 | pathText.setText(fragment.getDisplayedFilePath());
197 | } else {
198 | // do nothing
199 | }
200 | }
201 |
202 | /**
203 | * 返回上一级目录
204 | */
205 | protected void back2ParentLevel() {
206 | // 相当于BackStack,但是当pFile上sd卡的父级或以上时,相当于打开父文件夹并清除其子文件夹
207 | if (fakeBackStack.size() > 0) {
208 | FileListFragment fragment = fakeBackStack
209 | .get(fakeBackStack.size() - 1);
210 | File file = new File(fragment.getDisplayedFilePath());
211 | File pFile = file.getParentFile();
212 | for (int i = fakeBackStack.size() - 1; i >= 0; i--) {
213 | FileListFragment subFragment = fakeBackStack.get(i);
214 | File file2 = new File(subFragment.getFilePath());
215 | if (FileUtil.isAncestorOf(pFile, file2) || pFile.equals(file2)) {
216 | fakeBackStack.remove(i);
217 | }
218 | }
219 | if (pFile != null && pFile.exists() && pFile.isDirectory()) {
220 | openFolder(pFile, FragmentTransaction.TRANSIT_FRAGMENT_CLOSE);
221 | }
222 | }
223 | }
224 |
225 | /**
226 | * 选中当前目录所有文件
227 | */
228 | protected void selectAll() {
229 | if (fakeBackStack.size() > 0) {
230 | fakeBackStack.get(fakeBackStack.size() - 1).selectAll();
231 | }
232 | }
233 |
234 | /**
235 | * 取消选中当前目录所有文件
236 | */
237 | protected void unselectAll() {
238 | if (fakeBackStack.size() > 0) {
239 | fakeBackStack.get(fakeBackStack.size() - 1).unselectAll();
240 | }
241 | }
242 |
243 | public void unselectCheckBox() {
244 | selectAllButton.setOnCheckedChangeListener(null);
245 | selectAllButton.setChecked(false);
246 | selectAllButton.setOnCheckedChangeListener(this);
247 | }
248 |
249 | /**
250 | * @return 返回选中的文件列表
251 | */
252 | public File[] getSelectedFiles() {
253 | if (fakeBackStack.size() > 0) {
254 | return fakeBackStack.get(fakeBackStack.size() - 1)
255 | .getSelectedFiles();
256 | }
257 | return null;
258 | }
259 |
260 | @Override
261 | public void onClick(View v) {
262 | if (inSelectMode) {
263 | exitSelectMode();
264 | }
265 | int id = v.getId();
266 | switch (id) {
267 | case R.id.imagebutton_file_back:
268 | back2ParentLevel();
269 | break;
270 | case R.id.edittext_file_path:
271 | invokeAncestorList();
272 | break;
273 | default:
274 | break;
275 | }
276 | }
277 |
278 | public EditText getPathText() {
279 | return pathText;
280 | }
281 |
282 | public String getInitialPath() {
283 | return initialPath;
284 | }
285 |
286 | public void setInitialPath(String initialPath) {
287 | this.initialPath = initialPath;
288 | }
289 |
290 | @Override
291 | public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
292 | if (selectAllButton.isChecked()) {
293 | selectAll();
294 | } else {
295 | unselectAll();
296 | }
297 | }
298 |
299 | public CheckBox getSelectAllButton() {
300 | return selectAllButton;
301 | }
302 |
303 | protected void change2SelectMode() {
304 | if (fakeBackStack.size() > 0) {
305 | selectAllButton.setVisibility(View.VISIBLE);
306 | inSelectMode = true;
307 | fakeBackStack.get(fakeBackStack.size() - 1).change2SelectMode();
308 |
309 | Intent intent = new Intent();
310 | intent.setAction(FileConst.Action_Set_File_Operation_ActionBar);
311 | getActivity().sendBroadcast(intent);
312 | }
313 | }
314 |
315 | protected void exitSelectMode() {
316 | if (fakeBackStack.size() > 0) {
317 | selectAllButton.setVisibility(View.GONE);
318 | selectAllButton.setChecked(false);
319 | inSelectMode = false;
320 | fakeBackStack.get(fakeBackStack.size() - 1).exitSelectMode();
321 |
322 | Intent intent = new Intent();
323 | intent.setAction(FileConst.Action_Set_File_View_ActionBar);
324 | getActivity().sendBroadcast(intent);
325 | }
326 | }
327 |
328 | protected void doOpenFolderAction(Intent intent) {
329 | openFolder(intent.getStringExtra(FileConst.Extra_File_Path));
330 | }
331 |
332 | private boolean isInSearchingMode() {
333 | if (fakeBackStack.size() > 0) {
334 | return fakeBackStack.get(fakeBackStack.size() - 1)
335 | .isInSearchingMode();
336 | }
337 | return false;
338 | }
339 |
340 | private void quitSearchFile() {
341 | Intent intent = new Intent();
342 | intent.setAction(FileConst.Action_Quit_Search);
343 | getActivity().sendBroadcast(intent);
344 | }
345 |
346 | @Override
347 | public boolean doBackAction() {
348 | if (inSelectMode) {
349 | exitSelectMode();
350 | return true;
351 | }
352 | if (isInSearchingMode()) {
353 | quitSearchFile();
354 | return true;
355 | }
356 | if (fakeBackStack.size() > 1) {
357 | backStack();
358 | return true;
359 | }
360 | return false;
361 | }
362 |
363 | @Override
364 | public boolean doVeryAction(Intent intent) {
365 | String action = intent.getAction();
366 | if (FileConst.Action_Open_Folder.equals(action)) {
367 | doOpenFolderAction(intent);
368 | } else if (FileConst.Action_FileItem_Long_Click.equals(action)) {
369 | change2SelectMode();
370 | getItemSelect();
371 | } else if (FileConst.Action_FileItem_Unselect.equals(action)) {
372 | getItemUnselect();
373 | } else if (FileConst.Action_FileItem_Select.equals(action)) {
374 | getItemSelect();
375 | } else if (FileConst.Action_File_Operation_Done.equals(action)) {
376 | exitSelectMode();
377 | } else if (FileConst.Action_Add_New_File.equals(action)) {
378 | addNewFile();
379 | } else if (FileConst.Action_Search_File.equals(action)) {
380 | String query = intent
381 | .getStringExtra(FileConst.Key_Search_File_Query);
382 | searchFile(query);
383 | } else if (FileConst.Action_Quit_Search.equals(action)) {
384 | searchFile("");
385 | } else if (FileConst.Action_Toggle_View_Mode.equals(action)) {
386 | toggleViewMode();
387 | } else if (FileConst.Action_Refresh_FileList.equals(action)) {
388 | refreshFileList();
389 | } else if (FileConst.Action_Copy_File.equals(action)) {
390 | copyFile();
391 | } else if (FileConst.Action_Move_File.equals(action)) {
392 | moveFile();
393 | } else if (FileConst.Action_Delete_File.equals(action)) {
394 | deleteFile();
395 | } else if (FileConst.Action_Toggle_Show_Hidden.equals(action)) {
396 | toggleShowHidden();
397 | } else if (FileConst.Action_Zip_File.equals(action)) {
398 | zipFile();
399 | } else if (FileConst.Action_Rename_File.equals(action)) {
400 | renameFile();
401 | } else if (FileConst.Action_Property_File.equals(action)) {
402 | propertyFile();
403 | } else if (FileConst.Action_Unzip_File.equals(action)) {
404 | unzipFile();
405 | } else if (FileConst.Action_Favor_File.equals(action)) {
406 | favorFile();
407 | }
408 | return false;
409 | }
410 |
411 | public void getItemSelect() {
412 | if (fakeBackStack.size() > 0) {
413 | fakeBackStack.get(fakeBackStack.size() - 1).getItemSelect();
414 | }
415 | }
416 |
417 | public void getItemUnselect() {
418 |
419 | selectAllButton.setOnCheckedChangeListener(null);
420 | selectAllButton.setChecked(false);
421 | selectAllButton.setOnCheckedChangeListener(this);
422 |
423 | if (fakeBackStack.size() > 0) {
424 | fakeBackStack.get(fakeBackStack.size() - 1).getItemUnselect();
425 | }
426 | }
427 |
428 | @Override
429 | public void setUserVisibleHint(boolean isVisibleToUser) {
430 | super.setUserVisibleHint(isVisibleToUser);
431 | if (isVisibleToUser) {
432 | Intent intent = new Intent();
433 | int mask = 0;
434 | intent.putExtra(FileConst.Extra_Menu_Mask, mask);
435 | intent.setAction(FileConst.Action_Set_File_View_ActionBar);
436 | getActivity().sendBroadcast(intent);
437 | }
438 | }
439 |
440 | @Override
441 | public void toggleViewMode() {
442 | if (fakeBackStack.size() > 0) {
443 | fakeBackStack.get(fakeBackStack.size() - 1).toggleViewMode();
444 | }
445 | }
446 |
447 | @Override
448 | public void copyFile() {
449 | if (fakeBackStack.size() > 0) {
450 | fakeBackStack.get(fakeBackStack.size() - 1).copyFile();
451 | }
452 | }
453 |
454 | @Override
455 | public void moveFile() {
456 | if (fakeBackStack.size() > 0) {
457 | fakeBackStack.get(fakeBackStack.size() - 1).moveFile();
458 | }
459 | }
460 |
461 | @Override
462 | public void deleteFile() {
463 | if (fakeBackStack.size() > 0) {
464 | fakeBackStack.get(fakeBackStack.size() - 1).deleteFile();
465 | }
466 | }
467 |
468 | @Override
469 | public void addNewFile() {
470 | if (fakeBackStack.size() > 0) {
471 | fakeBackStack.get(fakeBackStack.size() - 1).addNewFile();
472 | }
473 | }
474 |
475 | @Override
476 | public void refreshFileList() {
477 | if (fakeBackStack.size() > 0) {
478 | fakeBackStack.get(fakeBackStack.size() - 1).refreshFileList();
479 | }
480 | }
481 |
482 | @Override
483 | public void searchFile(String query) {
484 | if (fakeBackStack.size() > 0) {
485 | fakeBackStack.get(fakeBackStack.size() - 1).searchFile(query);
486 | }
487 | }
488 |
489 | @Override
490 | public void toggleShowHidden() {
491 | if (fakeBackStack.size() > 0) {
492 | fakeBackStack.get(fakeBackStack.size() - 1).toggleShowHidden();
493 | }
494 | }
495 |
496 | @Override
497 | public void zipFile() {
498 | if (fakeBackStack.size() > 0) {
499 | fakeBackStack.get(fakeBackStack.size() - 1).zipFile();
500 | }
501 | }
502 |
503 | @Override
504 | public void renameFile() {
505 | if (fakeBackStack.size() > 0) {
506 | fakeBackStack.get(fakeBackStack.size() - 1).renameFile();
507 | }
508 | }
509 |
510 | @Override
511 | public void propertyFile() {
512 | if (fakeBackStack.size() > 0) {
513 | fakeBackStack.get(fakeBackStack.size() - 1).propertyFile();
514 | }
515 | }
516 |
517 | public void unzipFile() {
518 | if (fakeBackStack.size() > 0) {
519 | fakeBackStack.get(fakeBackStack.size() - 1).unzipFile();
520 | }
521 | }
522 |
523 | public void favorFile() {
524 | if (fakeBackStack.size() > 0) {
525 | fakeBackStack.get(fakeBackStack.size() - 1).favorFile();
526 | }
527 | }
528 | }
529 |
--------------------------------------------------------------------------------
/src/net/nashlegend/legendexplorer/model/FileItem.java:
--------------------------------------------------------------------------------
1 | package net.nashlegend.legendexplorer.model;
2 |
3 | import java.io.File;
4 | import java.net.URI;
5 |
6 | import net.nashlegend.legendexplorer.application.ExplorerApplication;
7 |
8 | import net.nashlegend.legendexplorer.R;
9 | import net.nashlegend.legendexplorer.R.drawable;
10 |
11 | /**
12 | * 文件对象,继承自File
13 | *
14 | * @author NashLegend
15 | */
16 | public class FileItem extends File {
17 |
18 | /**
19 | * TODO。每次改动后都要修改serialVersionUID……
20 | */
21 | private static final long serialVersionUID = 1L;
22 | /**
23 | * 普通文件
24 | */
25 | public static final int FILE_TYPE_NORMAL = 0;
26 | /**
27 | * 文件夹
28 | */
29 | public static final int FILE_TYPE_FOLDER = 1;
30 | /**
31 | * 声音类型的文件
32 | */
33 | public static final int FILE_TYPE_AUDIO = 2;
34 | /**
35 | * 图像类型的文件
36 | */
37 | public static final int FILE_TYPE_IMAGE = 3;
38 | /**
39 | * 视频类型的文件
40 | */
41 | public static final int FILE_TYPE_VIDEO = 4;
42 | /**
43 | * APK文件
44 | */
45 | public static final int FILE_TYPE_APK = 5;
46 | /**
47 | * TXT文件
48 | */
49 | public static final int FILE_TYPE_TXT = 6;
50 | /**
51 | * ZIP文件
52 | */
53 | public static final int FILE_TYPE_ZIP = 7;
54 | /**
55 | * HTML文件
56 | */
57 | public static final int FILE_TYPE_HTML = 8;
58 | /**
59 | * WORD文件
60 | */
61 | public static final int FILE_TYPE_WORD = 9;
62 | /**
63 | * EXCEL文件
64 | */
65 | public static final int FILE_TYPE_EXCEL = 10;
66 | /**
67 | * PPT文件
68 | */
69 | public static final int FILE_TYPE_PPT = 11;
70 | /**
71 | * PDF文件
72 | */
73 | public static final int FILE_TYPE_PDF = 12;
74 | /**
75 | * 电子书文件
76 | */
77 | public static final int FILE_TYPE_EBOOK = 13;
78 | /**
79 | * 种子文件
80 | */
81 | public static final int FILE_TYPE_TORRENT = 14;
82 | /**
83 | * CHM文件
84 | */
85 | public static final int FILE_TYPE_CHM = 15;
86 |
87 | /**
88 | * 文件在文件列表中显示的icon
89 | */
90 | private int icon = R.drawable.ic_launcher;
91 |
92 | /**
93 | * 文件是否在列表中被选中
94 | */
95 | private boolean selected = false;
96 |
97 | /**
98 | * 文件类型,默认为FILE_TYPE_NORMAL,即普通文件。
99 | */
100 | private int fileType = FILE_TYPE_NORMAL;
101 |
102 | /**
103 | * 文件后缀
104 | */
105 | private String suffix = "";
106 |
107 | /**
108 | * 是否处于可选状态(可显示选择复)
109 | */
110 | private boolean inSelectMode = false;
111 | /**
112 | * FileItem类型,普通文件,收藏文件,或者类型文件
113 | */
114 | private int itemType = 0;
115 |
116 | public FileItem(File file) {
117 | this(file.getAbsolutePath());
118 | }
119 |
120 | public FileItem(String path) {
121 | super(path);
122 | setFileTypeBySuffix();
123 | }
124 |
125 | public FileItem(URI uri) {
126 | super(uri);
127 | setFileTypeBySuffix();
128 | }
129 |
130 | public FileItem(File dir, String name) {
131 | super(dir, name);
132 | setFileTypeBySuffix();
133 | }
134 |
135 | public FileItem(String dirPath, String name) {
136 | super(dirPath, name);
137 | setFileTypeBySuffix();
138 | }
139 |
140 | /**
141 | * 根据后缀取得文件类型
142 | */
143 | private void setFileTypeBySuffix() {
144 | if (isDirectory()) {
145 | setFileType(FILE_TYPE_FOLDER);
146 | } else {
147 | String suffix = getSuffixFromName();
148 | // 在此处设置后缀
149 | setSuffix(suffix);
150 | // 根据后缀获取文件类型
151 | if (isArrayContains(
152 | getStringArraySourceByName(R.array.TypePackage), suffix)) {
153 | setFileType(FILE_TYPE_APK);
154 | } else if (isArrayContains(
155 | getStringArraySourceByName(R.array.TypeImage), suffix)) {
156 | setFileType(FILE_TYPE_IMAGE);
157 | } else if (isArrayContains(
158 | getStringArraySourceByName(R.array.TypeAudio), suffix)) {
159 | setFileType(FILE_TYPE_AUDIO);
160 | } else if (isArrayContains(
161 | getStringArraySourceByName(R.array.TypeVideo), suffix)) {
162 | setFileType(FILE_TYPE_VIDEO);
163 | } else if (isArrayContains(
164 | getStringArraySourceByName(R.array.TypeText), suffix)) {
165 | setFileType(FILE_TYPE_TXT);
166 | } else if (isArrayContains(
167 | getStringArraySourceByName(R.array.TypeZip), suffix)) {
168 | setFileType(FILE_TYPE_ZIP);
169 | } else if (isArrayContains(
170 | getStringArraySourceByName(R.array.TypeExcel), suffix)) {
171 | setFileType(FILE_TYPE_EXCEL);
172 | } else if (isArrayContains(
173 | getStringArraySourceByName(R.array.TypeHTML), suffix)) {
174 | setFileType(FILE_TYPE_HTML);
175 | } else if (isArrayContains(
176 | getStringArraySourceByName(R.array.TypePDF), suffix)) {
177 | setFileType(FILE_TYPE_PDF);
178 | } else if (isArrayContains(
179 | getStringArraySourceByName(R.array.TypePPT), suffix)) {
180 | setFileType(FILE_TYPE_PPT);
181 | } else if (isArrayContains(
182 | getStringArraySourceByName(R.array.TypeWord), suffix)) {
183 | setFileType(FILE_TYPE_WORD);
184 | } else if (isArrayContains(
185 | getStringArraySourceByName(R.array.TypeChm), suffix)) {
186 | setFileType(FILE_TYPE_CHM);
187 | } else if (isArrayContains(
188 | getStringArraySourceByName(R.array.TypeTorrent), suffix)) {
189 | setFileType(FILE_TYPE_TORRENT);
190 | } else if (isArrayContains(
191 | getStringArraySourceByName(R.array.TypeEBook), suffix)) {
192 | setFileType(FILE_TYPE_EBOOK);
193 | } else {
194 | setFileType(FILE_TYPE_NORMAL);
195 | }
196 | }
197 | }
198 |
199 | private String[] getStringArraySourceByName(int id) {
200 | return ExplorerApplication.getGlobalContext().getResources()
201 | .getStringArray(id);
202 | }
203 |
204 | private boolean isArrayContains(String[] strs, String suffix) {
205 | if (strs == null || suffix == null) {
206 | return false;
207 | }
208 | for (int i = 0; i < strs.length; i++) {
209 | if (suffix.equals(strs[i])) {
210 | return true;
211 | }
212 | }
213 | return false;
214 | }
215 |
216 | private String getSuffixFromName() {
217 | String fileName = getName();
218 | String suffix = "";
219 | int offset = fileName.lastIndexOf(".");
220 | // -1则没有后缀。0,则表示是一个隐藏文件而没有后缀,offset == fileName.length() -
221 | // 1,表示"."是最后一个字符,没有后缀
222 | if (offset > 0 && offset < fileName.length() - 1) {
223 | suffix = fileName.substring(offset + 1);
224 | }
225 | return suffix.toLowerCase();
226 | }
227 |
228 | public boolean isSelected() {
229 | return selected;
230 | }
231 |
232 | public void setSelected(boolean selected) {
233 | this.selected = selected;
234 | }
235 |
236 | public int getFileType() {
237 | return fileType;
238 | }
239 |
240 | /**
241 | * 设置fileTyle,同时修改icon
242 | *
243 | * @param fileType
244 | */
245 | public void setFileType(int fileType) {
246 | this.fileType = fileType;
247 | switch (fileType) {
248 | case FILE_TYPE_APK:
249 | setIcon(R.drawable.format_apk);
250 | break;
251 | case FILE_TYPE_FOLDER:
252 | setIcon(R.drawable.format_folder);
253 | break;
254 | case FILE_TYPE_IMAGE:
255 | setIcon(R.drawable.format_picture);
256 | break;
257 | case FILE_TYPE_NORMAL:
258 | setIcon(R.drawable.format_unkown);
259 | break;
260 | case FILE_TYPE_AUDIO:
261 | setIcon(R.drawable.format_music);
262 | break;
263 | case FILE_TYPE_TXT:
264 | setIcon(R.drawable.format_text);
265 | break;
266 | case FILE_TYPE_VIDEO:
267 | setIcon(R.drawable.format_media);
268 | break;
269 | case FILE_TYPE_ZIP:
270 | setIcon(R.drawable.format_zip);
271 | break;
272 | case FILE_TYPE_HTML:
273 | setIcon(R.drawable.format_html);
274 | break;
275 | case FILE_TYPE_PDF:
276 | setIcon(R.drawable.format_pdf);
277 | break;
278 | case FILE_TYPE_WORD:
279 | setIcon(R.drawable.format_word);
280 | break;
281 | case FILE_TYPE_EXCEL:
282 | setIcon(R.drawable.format_excel);
283 | break;
284 | case FILE_TYPE_PPT:
285 | setIcon(R.drawable.format_ppt);
286 | break;
287 | case FILE_TYPE_TORRENT:
288 | setIcon(R.drawable.format_torrent);
289 | break;
290 | case FILE_TYPE_EBOOK:
291 | setIcon(R.drawable.format_ebook);
292 | break;
293 | case FILE_TYPE_CHM:
294 | setIcon(R.drawable.format_chm);
295 | break;
296 | default:
297 | setIcon(R.drawable.format_unkown);
298 | break;
299 | }
300 | }
301 |
302 | public int getIcon() {
303 | return icon;
304 | }
305 |
306 | public void setIcon(int icon) {
307 | this.icon = icon;
308 | }
309 |
310 | public String getSuffix() {
311 | return suffix;
312 | }
313 |
314 | public void setSuffix(String suffix) {
315 | this.suffix = suffix;
316 | }
317 |
318 | public boolean isInSelectMode() {
319 | return inSelectMode;
320 | }
321 |
322 | public void setInSelectMode(boolean inSelectMode) {
323 | this.inSelectMode = inSelectMode;
324 | }
325 |
326 | public int getItemType() {
327 | return itemType;
328 | }
329 |
330 | public void setItemType(int itemType) {
331 | this.itemType = itemType;
332 | }
333 | }
334 |
--------------------------------------------------------------------------------
/src/net/nashlegend/legendexplorer/utils/FileCategoryHelper.java:
--------------------------------------------------------------------------------
1 | package net.nashlegend.legendexplorer.utils;
2 |
3 | import java.util.HashMap;
4 | import java.util.HashSet;
5 | import java.util.Iterator;
6 |
7 | import net.nashlegend.legendexplorer.fragment.CategoriedFragment.FileCategory;
8 |
9 | import android.content.Context;
10 | import android.database.Cursor;
11 | import android.net.Uri;
12 | import android.provider.MediaStore.Audio;
13 | import android.provider.MediaStore.Files;
14 | import android.provider.MediaStore.Images;
15 | import android.provider.MediaStore.Video;
16 | import android.provider.MediaStore.Files.FileColumns;
17 | import android.util.Log;
18 |
19 | public class FileCategoryHelper {
20 |
21 | public static final int COLUMN_ID = 0;
22 |
23 | public static final int COLUMN_PATH = 1;
24 |
25 | public static final int COLUMN_SIZE = 2;
26 |
27 | public static final int COLUMN_DATE = 3;
28 |
29 | private static final String LOG_TAG = "cat";
30 |
31 | public static class CategoryInfo {
32 | public long count;
33 |
34 | public long size;
35 | }
36 |
37 | private static HashMap mCategoryInfo = new HashMap();
38 |
39 | public static HashMap getCategoryInfos() {
40 | return mCategoryInfo;
41 | }
42 |
43 | public static FileCategory[] sCategories = new FileCategory[] {
44 | FileCategory.Music, FileCategory.Video, FileCategory.Picture,
45 | FileCategory.Doc, FileCategory.Zip, FileCategory.Apk };
46 |
47 | public FileCategoryHelper(Context context) {
48 |
49 | }
50 |
51 | public static void delete(FileCategory fc, String path, Context context) {
52 |
53 | }
54 |
55 | public static Cursor query(FileCategory fc, Context context) {
56 | Uri uri = getContentUriByCategory(fc);
57 | String selection = buildSelectionByCategory(fc);
58 | String sortOrder = null;
59 |
60 | if (uri == null) {
61 | return null;
62 | }
63 |
64 | String[] columns = new String[] { FileColumns._ID, FileColumns.DATA,
65 | FileColumns.SIZE, FileColumns.DATE_MODIFIED };
66 | return context.getContentResolver().query(uri, columns, selection,
67 | null, sortOrder);
68 | }
69 |
70 | private static Uri getContentUriByCategory(FileCategory cat) {
71 | Uri uri;
72 | String volumeName = "external";
73 | switch (cat) {
74 | case Doc:
75 | case Zip:
76 | case Apk:
77 | uri = Files.getContentUri(volumeName);
78 | break;
79 | case Music:
80 | uri = Audio.Media.getContentUri(volumeName);
81 | break;
82 | case Video:
83 | uri = Video.Media.getContentUri(volumeName);
84 | break;
85 | case Picture:
86 | uri = Images.Media.getContentUri(volumeName);
87 | break;
88 | default:
89 | uri = null;
90 | }
91 | return uri;
92 | }
93 |
94 | public static void refreshCategoryInfo(Context mContext) {
95 | for (FileCategory fc : sCategories) {
96 | setCategoryInfo(fc, 0, 0);
97 | }
98 | String volumeName = "external";
99 | Uri uri = Audio.Media.getContentUri(volumeName);
100 | refreshMediaCategory(FileCategory.Music, uri, mContext);
101 | uri = Video.Media.getContentUri(volumeName);
102 | refreshMediaCategory(FileCategory.Video, uri, mContext);
103 | uri = Images.Media.getContentUri(volumeName);
104 | refreshMediaCategory(FileCategory.Picture, uri, mContext);
105 | uri = Files.getContentUri(volumeName);
106 | refreshMediaCategory(FileCategory.Doc, uri, mContext);
107 | refreshMediaCategory(FileCategory.Zip, uri, mContext);
108 | refreshMediaCategory(FileCategory.Apk, uri, mContext);
109 | }
110 |
111 | private static void setCategoryInfo(FileCategory fc, long count, long size) {
112 | CategoryInfo info = mCategoryInfo.get(fc);
113 | if (info == null) {
114 | info = new CategoryInfo();
115 | mCategoryInfo.put(fc, info);
116 | }
117 | info.count = count;
118 | info.size = size;
119 | }
120 |
121 | private static boolean refreshMediaCategory(FileCategory fc, Uri uri,
122 | Context mContext) {
123 | String[] columns = new String[] { "COUNT(*)", "SUM(_size)" };
124 | Cursor c = mContext.getContentResolver().query(uri, columns,
125 | buildSelectionByCategory(fc), null, null);
126 | if (c == null) {
127 | Log.e(LOG_TAG, "fail to query uri:" + uri);
128 | return false;
129 | }
130 |
131 | if (c.moveToNext()) {
132 | setCategoryInfo(fc, c.getLong(0), c.getLong(1));
133 | c.close();
134 | return true;
135 | }
136 |
137 | return false;
138 | }
139 |
140 | public static HashSet sDocMimeTypesSet = new HashSet() {
141 | /**
142 | *
143 | */
144 | private static final long serialVersionUID = 1L;
145 |
146 | {
147 | add("text/plain");
148 | add("application/pdf");
149 | add("application/msword");
150 | add("application/vnd.ms-excel");
151 | add("application/vnd.ms-excel");
152 | }
153 | };
154 |
155 | private static String buildDocSelection() {
156 | StringBuilder selection = new StringBuilder();
157 | Iterator iter = sDocMimeTypesSet.iterator();
158 | while (iter.hasNext()) {
159 | selection.append("(" + FileColumns.MIME_TYPE + "=='" + iter.next()
160 | + "') OR ");
161 | }
162 | return selection.substring(0, selection.lastIndexOf(")") + 1);
163 | }
164 |
165 | private static String buildSelectionByCategory(FileCategory cat) {
166 | String selection = null;
167 | switch (cat) {
168 | case Doc:
169 | selection = buildDocSelection();
170 | break;
171 | case Zip:
172 | selection = "(" + FileColumns.MIME_TYPE + " == '"
173 | + "application/zip" + "')";
174 | break;
175 | case Apk:
176 | selection = FileColumns.DATA + " LIKE '%.apk' AND " + FileColumns.SIZE + " > 12288";//大于12k
177 | break;
178 | default:
179 | selection = null;
180 | }
181 | return selection;
182 | }
183 |
184 | }
185 |
--------------------------------------------------------------------------------
/src/net/nashlegend/legendexplorer/utils/IconContainer.java:
--------------------------------------------------------------------------------
1 | package net.nashlegend.legendexplorer.utils;
2 |
3 | import java.io.File;
4 | import java.lang.ref.SoftReference;
5 | import java.util.concurrent.ConcurrentHashMap;
6 |
7 | import android.graphics.Bitmap;
8 |
9 | public class IconContainer {
10 | private final static ConcurrentHashMap> mCachedIcons = new ConcurrentHashMap>();
11 |
12 | public static Bitmap get(String path) {
13 | Bitmap bm = null;
14 | if (mCachedIcons.containsKey(path)) {
15 | bm = mCachedIcons.get(path).get();
16 | }
17 | return bm;
18 | }
19 |
20 | public static Bitmap get(File file) {
21 | return get(file.getAbsolutePath());
22 | }
23 |
24 | public static void put(String path, Bitmap bm) {
25 | SoftReference soft = new SoftReference(bm);
26 | mCachedIcons.put(path, soft);
27 | }
28 |
29 | public static void put(File file, Bitmap bm) {
30 | put(file.getAbsolutePath(), bm);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/net/nashlegend/legendexplorer/utils/SharePreferencesUtil.java:
--------------------------------------------------------------------------------
1 |
2 | package net.nashlegend.legendexplorer.utils;
3 |
4 | import net.nashlegend.legendexplorer.application.ExplorerApplication;
5 |
6 | import android.content.Context;
7 | import android.content.SharedPreferences;
8 | import android.content.SharedPreferences.Editor;
9 |
10 | public class SharePreferencesUtil {
11 |
12 | // 本地xml文件名
13 | private final static String SP_NAME = "legendexplorer";
14 | private static SharedPreferences mSharedPreferences;
15 | private static Editor mEditor;
16 |
17 | public static SharedPreferences getSharedPreferences()
18 | {
19 | if (mSharedPreferences == null)
20 | {
21 | mSharedPreferences = ExplorerApplication.getGlobalContext().getSharedPreferences(
22 | SP_NAME, Context.MODE_PRIVATE);
23 | }
24 |
25 | return mSharedPreferences;
26 | }
27 |
28 | public static Editor getEditor()
29 | {
30 | if (mEditor == null)
31 | {
32 | mEditor = getSharedPreferences().edit();
33 | }
34 |
35 | return mEditor;
36 | }
37 |
38 | // 读String
39 | public static String readString(String key, String defaultvalue) {
40 | String str = getSharedPreferences().getString(key, defaultvalue);
41 | return str;
42 | }
43 |
44 | // 写String
45 | public static boolean saveString(String key, String value) {
46 | getEditor().putString(key, value);
47 | return getEditor().commit();
48 | }
49 |
50 | // 读Boolean
51 | public static boolean readBoolean(String key, boolean defaultvalue) {
52 | return getSharedPreferences().getBoolean(key, defaultvalue);
53 | }
54 |
55 | // 写Boolean
56 | public static boolean saveBoolean(String key, boolean value) {
57 | getEditor().putBoolean(key, value);
58 | return getEditor().commit();
59 | }
60 |
61 | // 读Int
62 | public static int readInt(String key, int defValue) {
63 | int n = getSharedPreferences().getInt(key, defValue);
64 | return n;
65 | }
66 |
67 | // 写Int
68 | public static boolean saveInt(String key, int value) {
69 | getEditor().putInt(key, value);
70 | return getEditor().commit();
71 | }
72 |
73 | // 布尔值读
74 | public static boolean isActive(String key, boolean defaultvalue) {
75 | return getSharedPreferences().getBoolean(key, defaultvalue);
76 | }
77 |
78 | // 布尔值写
79 | public static boolean saveActive(String key, boolean value) {
80 | getEditor().putBoolean(key, value);
81 | return getEditor().commit();
82 | }
83 |
84 | // 删除一项
85 | public static boolean remove(String key) {
86 | getEditor().remove(key);
87 | return getEditor().commit();
88 | }
89 |
90 | // 全清空
91 | public static boolean clear() {
92 | getEditor().clear();
93 | return getEditor().commit();
94 | }
95 |
96 | }
97 |
--------------------------------------------------------------------------------
/src/net/nashlegend/legendexplorer/utils/StorageObserver.java:
--------------------------------------------------------------------------------
1 | package net.nashlegend.legendexplorer.utils;
2 |
3 | import java.io.File;
4 | import java.util.ArrayList;
5 | import java.util.List;
6 | import java.util.Stack;
7 |
8 | import android.os.FileObserver;
9 | import android.util.Log;
10 |
11 | public class StorageObserver extends FileObserver {
12 |
13 | public static int CHANGES_ONLY = CLOSE_WRITE | MOVE_SELF | MOVED_FROM;
14 |
15 | List mObservers;
16 | String mPath;
17 | int mMask;
18 |
19 | public StorageObserver(String path) {
20 | this(path, ALL_EVENTS);
21 | }
22 |
23 | public StorageObserver(String path, int mask) {
24 | super(path, mask);
25 | mPath = path;
26 | mMask = mask;
27 | }
28 |
29 | @Override
30 | public void startWatching() {
31 | if (mObservers != null)
32 | return;
33 | mObservers = new ArrayList();
34 | Stack stack = new Stack();
35 | stack.push(mPath);
36 |
37 | while (!stack.empty()) {
38 | String parent = stack.pop();
39 | mObservers.add(new SingleFileObserver(parent, mMask));
40 | File path = new File(parent);
41 | File[] files = path.listFiles();
42 | if (files == null)
43 | continue;
44 | for (int i = 0; i < files.length; ++i) {
45 | if (files[i].isDirectory() && !files[i].getName().equals(".")
46 | && !files[i].getName().equals("..")) {
47 | stack.push(files[i].getPath());
48 | }
49 | }
50 | }
51 | for (int i = 0; i < mObservers.size(); i++)
52 | mObservers.get(i).startWatching();
53 | }
54 |
55 | @Override
56 | public void stopWatching() {
57 | if (mObservers == null)
58 | return;
59 |
60 | for (int i = 0; i < mObservers.size(); ++i)
61 | mObservers.get(i).stopWatching();
62 |
63 | mObservers.clear();
64 | mObservers = null;
65 | }
66 |
67 | @Override
68 | public void onEvent(int event, String path) {
69 | event &= FileObserver.ALL_EVENTS;
70 | switch (event) {
71 | case FileObserver.DELETE:
72 | Log.i("obs", "DELETE" + "__" + path);
73 | break;
74 | case FileObserver.CREATE:
75 | Log.i("obs", "CREATE" + "__" + path);
76 | File createdFile = new File(path);
77 | if (createdFile.isDirectory()) {
78 | SingleFileObserver ob = new SingleFileObserver(path, mMask);
79 | ob.startWatching();
80 | mObservers.add(ob);
81 | }
82 | break;
83 | case FileObserver.MOVED_TO:
84 | Log.i("obs", "MOVED_TO" + "__" + path);
85 | break;
86 | case FileObserver.MOVED_FROM:
87 | Log.i("obs", "MOVED_FROM" + "__" + path);
88 | break;
89 | default:
90 | break;
91 | }
92 | }
93 |
94 | private class SingleFileObserver extends FileObserver {
95 | private String mPath;
96 |
97 | public SingleFileObserver(String path, int mask) {
98 | super(path, mask);
99 | mPath = path;
100 | }
101 |
102 | @Override
103 | public void onEvent(int event, String path) {
104 | String newPath = mPath + "/" + path;
105 | StorageObserver.this.onEvent(event, newPath);
106 | }
107 |
108 | }
109 | }
--------------------------------------------------------------------------------
/src/net/nashlegend/legendexplorer/view/DropDownAncestorList.java:
--------------------------------------------------------------------------------
1 | package net.nashlegend.legendexplorer.view;
2 |
3 | import java.io.File;
4 | import java.util.ArrayList;
5 | import java.util.Collections;
6 | import java.util.Iterator;
7 |
8 | import net.nashlegend.legendexplorer.consts.FileConst;
9 |
10 | import net.nashlegend.legendexplorer.R;
11 | import net.nashlegend.legendutils.Tools.DisplayUtil;
12 |
13 | import android.content.Context;
14 | import android.text.TextUtils;
15 | import android.util.AttributeSet;
16 | import android.util.Log;
17 | import android.view.LayoutInflater;
18 | import android.view.View;
19 | import android.view.View.OnClickListener;
20 | import android.view.ViewGroup;
21 | import android.widget.LinearLayout;
22 | import android.widget.TextView;
23 |
24 | public class DropDownAncestorList extends LinearLayout implements
25 | OnClickListener {
26 |
27 | private File mFile = new File("/");
28 | private ArrayList views = new ArrayList();
29 | private int padStep = DisplayUtil.dip2px(10, getContext());
30 | private String prefix = "//////////////";
31 | private String replacer = FileConst.Value_Bookmark_Path;
32 | private OnAncestorClickListener onAncestorClickListener;
33 | private boolean hasPreffix = false;
34 | private File rootFile;
35 |
36 | public DropDownAncestorList(Context context) {
37 | super(context);
38 | setOrientation(LinearLayout.VERTICAL);
39 | setClickable(true);
40 | }
41 |
42 | public DropDownAncestorList(Context context, AttributeSet attrs) {
43 | super(context, attrs);
44 | setOrientation(LinearLayout.VERTICAL);
45 | setClickable(true);
46 | }
47 |
48 | public DropDownAncestorList(Context context, AttributeSet attrs,
49 | int defStyle) {
50 | super(context, attrs, defStyle);
51 | setOrientation(LinearLayout.VERTICAL);
52 | setClickable(true);
53 | }
54 |
55 | public OnAncestorClickListener getOnAncestorClickListener() {
56 | return onAncestorClickListener;
57 | }
58 |
59 | public void setOnAncestorClickListener(
60 | OnAncestorClickListener onAncestorClickListener) {
61 | this.onAncestorClickListener = onAncestorClickListener;
62 | }
63 |
64 | public void setupList(File currentFolder, String prefix, String replacer) {
65 | hasPreffix = true;
66 | this.prefix = prefix;
67 | this.replacer = replacer;
68 | this.rootFile = new File(prefix);
69 | setupList(currentFolder);
70 | }
71 |
72 | public void setupList(File file) {
73 | if (file != null && !file.equals(mFile)) {
74 | clearAllViews();
75 | mFile = file;
76 | buildViewList();
77 | }
78 | }
79 |
80 | private boolean isNotFileRoot(File file) {
81 | if (hasPreffix) {
82 | return !file.equals(rootFile);
83 | } else {
84 | return file.getParentFile() != null;
85 | }
86 | }
87 |
88 | private void buildViewList() {
89 |
90 | File tmpFile = mFile;
91 |
92 | while (isNotFileRoot(tmpFile)) {
93 | File file = tmpFile.getParentFile();
94 | View view = LayoutInflater.from(getContext()).inflate(
95 | R.layout.view_ancestor_item, null);
96 |
97 | view.setTag(file.getAbsolutePath());
98 | TextView tv = (TextView) view
99 | .findViewById(R.id.text_ancestor_file_title);
100 | String displatPath = file.getAbsolutePath();
101 | if (displatPath.lastIndexOf("/") != displatPath.length() - 1) {
102 | displatPath += "/";
103 | }
104 |
105 | if (hasPreffix) {
106 | displatPath = displatPath.replace(prefix, replacer);
107 | }
108 |
109 | tv.setText(displatPath);
110 | view.setOnClickListener(this);
111 | views.add(view);
112 | tmpFile = file;
113 | }
114 |
115 | Collections.reverse(views);
116 | int st = 0;
117 | for (Iterator iterator = views.iterator(); iterator.hasNext();) {
118 | View view = (View) iterator.next();
119 | LinearLayout root = (LinearLayout) view
120 | .findViewById(R.id.rootFolderItemView);
121 | root.setPadding(padStep * st, 0, 0, 0);
122 | addView(view);
123 | st++;
124 | }
125 | }
126 |
127 | public void clearAllViews() {
128 | for (Iterator iterator = views.iterator(); iterator.hasNext();) {
129 | View view = (View) iterator.next();
130 | if (view.getParent() != null) {
131 | ((ViewGroup) view.getParent()).removeView(view);
132 | }
133 | }
134 | views.clear();
135 | }
136 |
137 | @Override
138 | public void onClick(View v) {
139 | if (v.getTag() != null) {
140 | String path = v.getTag().toString();
141 | if (TextUtils.isEmpty(path)) {
142 | return;
143 | }
144 | if (onAncestorClickListener != null) {
145 | onAncestorClickListener.onClick(path);
146 | }
147 | }
148 | }
149 |
150 | public static interface OnAncestorClickListener {
151 | void onClick(String path);
152 | }
153 |
154 | }
155 |
--------------------------------------------------------------------------------
/src/net/nashlegend/legendexplorer/view/FileGridItemView.java:
--------------------------------------------------------------------------------
1 | package net.nashlegend.legendexplorer.view;
2 |
3 | import java.io.IOException;
4 |
5 | import net.nashlegend.legendexplorer.adapter.FileListAdapter;
6 | import net.nashlegend.legendexplorer.consts.FileConst;
7 | import net.nashlegend.legendexplorer.model.FileItem;
8 | import net.nashlegend.legendexplorer.utils.IconContainer;
9 |
10 | import net.nashlegend.legendexplorer.R;
11 | import net.nashlegend.legendutils.Tools.FileUtil;
12 |
13 | import android.app.Service;
14 | import android.content.ActivityNotFoundException;
15 | import android.content.Context;
16 | import android.content.Intent;
17 | import android.graphics.Bitmap;
18 | import android.net.Uri;
19 | import android.os.AsyncTask;
20 | import android.os.AsyncTask.Status;
21 | import android.os.Vibrator;
22 | import android.view.LayoutInflater;
23 | import android.view.View;
24 | import android.view.ViewGroup;
25 | import android.widget.CheckBox;
26 | import android.widget.CompoundButton;
27 | import android.widget.CompoundButton.OnCheckedChangeListener;
28 | import android.widget.FrameLayout;
29 | import android.widget.ImageView;
30 | import android.widget.TextView;
31 | import android.widget.Toast;
32 | import android.view.View.OnClickListener;
33 | import android.view.View.OnLongClickListener;
34 |
35 | /**
36 | * 文件列表单个item的view
37 | *
38 | * @author NashLegend
39 | */
40 | public class FileGridItemView extends FrameLayout implements OnClickListener,
41 | OnCheckedChangeListener, OnLongClickListener {
42 | private ImageView icon;
43 | private ImageView symbolView;
44 | private TextView title;
45 | private CheckBox checkBox;
46 | private ViewGroup rootFileItemView;
47 | private FileListAdapter adapter;
48 | private FileItem fileItem;
49 | private IconLoadTask task;
50 |
51 | public FileGridItemView(Context context) {
52 | super(context);
53 | LayoutInflater inflater = (LayoutInflater) context
54 | .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
55 | inflater.inflate(R.layout.view_grid_file_item, this);
56 | icon = (ImageView) findViewById(R.id.image_file_icon);
57 | symbolView = (ImageView) findViewById(R.id.image_file_sym_icon);
58 | title = (TextView) findViewById(R.id.text_file_title);
59 | rootFileItemView = (ViewGroup) findViewById(R.id.rootFileItemView);
60 | checkBox = (CheckBox) findViewById(R.id.checkbox_file_item_select);
61 | setOnClickListener(this);
62 | setLongClickable(true);
63 | }
64 |
65 | public FileItem getFileItem() {
66 | return fileItem;
67 | }
68 |
69 | public void setFileItem(FileItem fileItem, FileListAdapter adapter) {
70 | if (!fileItem.equals(this.fileItem)) {
71 | this.fileItem = fileItem;
72 | showFileIcon();
73 | }
74 | this.fileItem = fileItem;
75 | this.adapter = adapter;
76 | title.setText(fileItem.getName());
77 | toggleSelectState();
78 | if (fileItem.isInSelectMode()) {
79 | checkBox.setVisibility(View.VISIBLE);
80 | setOnLongClickListener(null);
81 | } else {
82 | checkBox.setVisibility(View.GONE);
83 | setOnLongClickListener(this);
84 | }
85 | }
86 |
87 | /**
88 | * 显示文件图标
89 | */
90 | private void showFileIcon() {
91 | icon.setImageResource(fileItem.getIcon());
92 | int tp = fileItem.getFileType();
93 | if (tp == FileItem.FILE_TYPE_APK || tp == FileItem.FILE_TYPE_AUDIO
94 | || tp == FileItem.FILE_TYPE_IMAGE
95 | || tp == FileItem.FILE_TYPE_VIDEO) {
96 | if (task != null && task.getStatus() == Status.RUNNING) {
97 | task.cancel(true);
98 | }
99 | Bitmap bmp = IconContainer.get(fileItem);
100 | if (bmp == null) {
101 | task = new IconLoadTask();
102 | task.execute(fileItem);
103 | } else {
104 | icon.setImageBitmap(bmp);
105 | }
106 | }
107 | try {
108 | if (fileItem.isDirectory() && FileUtil.isSymboliclink(fileItem)) {
109 | symbolView.setVisibility(View.VISIBLE);
110 | } else {
111 | symbolView.setVisibility(View.GONE);
112 | }
113 | } catch (IOException e) {
114 | symbolView.setVisibility(View.GONE);
115 | }
116 | }
117 |
118 | class IconLoadTask extends AsyncTask {
119 |
120 | FileItem originalFile;
121 |
122 | @Override
123 | protected Bitmap doInBackground(FileItem... params) {
124 | originalFile = params[0];
125 | Bitmap bmp = FileUtil.extractFileThumbnail(originalFile,
126 | getContext());
127 | if (bmp != null) {
128 | IconContainer.put(originalFile, bmp);
129 | }
130 | return bmp;
131 | }
132 |
133 | @Override
134 | protected void onPostExecute(Bitmap result) {
135 | if (fileItem.equals(this.originalFile)) {
136 | if (result != null) {
137 | icon.setImageBitmap(result);
138 | } else {
139 | icon.setImageResource(fileItem.getIcon());
140 | }
141 | }
142 | super.onPostExecute(result);
143 | }
144 |
145 | }
146 |
147 | /**
148 | * 切换选中、未选中状态,fileItem.setSelected(boolean)先发生;
149 | */
150 | public void toggleSelectState() {
151 | toggleSelectState(false);
152 | }
153 |
154 | private void toggleSelectState(boolean manual) {
155 | if (fileItem.isSelected()) {
156 | rootFileItemView
157 | .setBackgroundResource(R.drawable.bg_file_item_select);
158 | } else {
159 | rootFileItemView
160 | .setBackgroundResource(R.drawable.bg_file_item_normal);
161 | if (manual && fileItem.isInSelectMode()) {
162 | Intent intent = new Intent();
163 | intent.setAction(FileConst.Action_FileItem_Unselect);
164 | getContext().sendBroadcast(intent);
165 | }
166 | }
167 | checkBox.setOnCheckedChangeListener(null);
168 | checkBox.setChecked(fileItem.isSelected());
169 | checkBox.setOnCheckedChangeListener(this);
170 | }
171 |
172 | @Override
173 | public void onClick(View v) {
174 | if (v.getId() != R.id.checkbox_file_item_select) {
175 | if (fileItem.isInSelectMode()) {
176 | selectOne();
177 | } else {
178 | if (fileItem.isDirectory()) {
179 | openFolder();
180 | } else {
181 | openFile();
182 | }
183 | }
184 |
185 | }
186 | }
187 |
188 | /**
189 | * 打开文件
190 | */
191 | private void openFile() {
192 | Intent intent = new Intent(Intent.ACTION_VIEW);
193 | intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
194 | intent.addCategory(Intent.CATEGORY_DEFAULT);
195 | Uri data = Uri.fromFile(fileItem);
196 | intent.setDataAndType(data, "*/*");
197 | switch (fileItem.getFileType()) {
198 | case FileItem.FILE_TYPE_APK:
199 | intent.setDataAndType(data,
200 | "application/vnd.android.package-archive");
201 | break;
202 | case FileItem.FILE_TYPE_IMAGE:
203 | intent.setDataAndType(data, "image/*");
204 | break;
205 | case FileItem.FILE_TYPE_AUDIO:
206 | intent.putExtra("oneshot", 0);
207 | intent.putExtra("configchange", 0);
208 | intent.setDataAndType(data, "audio/*");
209 | break;
210 | case FileItem.FILE_TYPE_TXT:
211 | intent.setDataAndType(data, "text/plain");
212 | break;
213 | case FileItem.FILE_TYPE_VIDEO:
214 | intent.putExtra("oneshot", 0);
215 | intent.putExtra("configchange", 0);
216 | intent.setDataAndType(data, "video/*");
217 | break;
218 | case FileItem.FILE_TYPE_ZIP:
219 | intent.setDataAndType(data, "application/zip");
220 | break;
221 | case FileItem.FILE_TYPE_WORD:
222 | intent.setDataAndType(data, "application/msword");
223 | break;
224 | case FileItem.FILE_TYPE_PPT:
225 | intent.setDataAndType(data, "application/vnd.ms-powerpoint");
226 | break;
227 | case FileItem.FILE_TYPE_EXCEL:
228 | intent.setDataAndType(data, "application/vnd.ms-excel");
229 | break;
230 | case FileItem.FILE_TYPE_HTML:
231 | intent.setDataAndType(data, "text/html");
232 | break;
233 | case FileItem.FILE_TYPE_PDF:
234 | intent.setDataAndType(data, "application/pdf");
235 | break;
236 | case FileItem.FILE_TYPE_TORRENT:
237 | intent.setDataAndType(data, "torrent/*");
238 | break;
239 | case FileItem.FILE_TYPE_CHM:
240 | intent.setDataAndType(data, "application/mshelp");
241 | break;
242 |
243 | default:
244 | break;
245 | }
246 | try {
247 | getContext().startActivity(intent);
248 | } catch (ActivityNotFoundException e) {
249 | Toast.makeText(getContext(), "打不开此文件类型",
250 | Toast.LENGTH_SHORT).show();
251 | e.printStackTrace();
252 | }
253 | }
254 |
255 | public void selectOne() {
256 | if (fileItem.isInSelectMode()) {
257 | fileItem.setSelected(!fileItem.isSelected());
258 | toggleSelectState(true);
259 | }
260 | }
261 |
262 | public void openFolder() {
263 | Intent intent = new Intent();
264 | intent.setAction(FileConst.Action_Open_Folder);
265 | intent.putExtra(FileConst.Extra_File_Path, fileItem.getAbsolutePath());
266 | intent.putExtra(FileConst.Extra_Item_Type, fileItem.getItemType());
267 | getContext().sendBroadcast(intent);
268 | }
269 |
270 | public FileListAdapter getAdapter() {
271 | return adapter;
272 | }
273 |
274 | @Override
275 | public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
276 | fileItem.setSelected(isChecked);
277 | toggleSelectState(true);
278 | }
279 |
280 | @Override
281 | public boolean onLongClick(View v) {
282 | if (FileUtil.isInExternalStorage(fileItem)) {
283 | Vibrator vibrator = (Vibrator) getContext().getSystemService(
284 | Service.VIBRATOR_SERVICE);
285 | vibrator.vibrate(20);
286 |
287 | fileItem.setSelected(true);
288 |
289 | Intent intent = new Intent();
290 | intent.setAction(FileConst.Action_FileItem_Long_Click);
291 | getContext().sendBroadcast(intent);
292 | }
293 | return false;
294 | }
295 | }
296 |
--------------------------------------------------------------------------------
/src/net/nashlegend/legendexplorer/view/FileItemView.java:
--------------------------------------------------------------------------------
1 | package net.nashlegend.legendexplorer.view;
2 |
3 | import java.io.IOException;
4 |
5 | import net.nashlegend.legendexplorer.ImageBrowseActivity;
6 | import net.nashlegend.legendexplorer.adapter.FileListAdapter;
7 | import net.nashlegend.legendexplorer.consts.FileConst;
8 | import net.nashlegend.legendexplorer.model.FileItem;
9 | import net.nashlegend.legendexplorer.utils.IconContainer;
10 | import net.nashlegend.legendexplorer.view.FileGridItemView.IconLoadTask;
11 |
12 | import net.nashlegend.legendexplorer.R;
13 | import net.nashlegend.legendutils.Tools.FileUtil;
14 |
15 | import android.app.Service;
16 | import android.content.ActivityNotFoundException;
17 | import android.content.Context;
18 | import android.content.Intent;
19 | import android.graphics.Bitmap;
20 | import android.net.Uri;
21 | import android.os.AsyncTask;
22 | import android.os.AsyncTask.Status;
23 | import android.os.Vibrator;
24 | import android.view.LayoutInflater;
25 | import android.view.View;
26 | import android.view.ViewGroup;
27 | import android.widget.CheckBox;
28 | import android.widget.CompoundButton;
29 | import android.widget.CompoundButton.OnCheckedChangeListener;
30 | import android.widget.FrameLayout;
31 | import android.widget.ImageView;
32 | import android.widget.TextView;
33 | import android.widget.Toast;
34 | import android.view.View.OnClickListener;
35 | import android.view.View.OnLongClickListener;
36 |
37 | /**
38 | * 文件列表单个item的view
39 | *
40 | * @author NashLegend
41 | */
42 | public class FileItemView extends FrameLayout implements OnClickListener,
43 | OnCheckedChangeListener, OnLongClickListener {
44 | private ImageView icon;
45 | private ImageView symbolView;
46 | private TextView title;
47 | private CheckBox checkBox;
48 | private ViewGroup rootFileItemView;
49 | private FileListAdapter adapter;
50 | private FileItem fileItem;
51 | private IconLoadTask task;
52 |
53 | public FileItemView(Context context) {
54 | super(context);
55 | LayoutInflater inflater = (LayoutInflater) context
56 | .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
57 | inflater.inflate(R.layout.view_file_item, this);
58 | icon = (ImageView) findViewById(R.id.image_file_icon);
59 | symbolView = (ImageView) findViewById(R.id.image_file_sym_icon);
60 | title = (TextView) findViewById(R.id.text_file_title);
61 | rootFileItemView = (ViewGroup) findViewById(R.id.rootFileItemView);
62 | checkBox = (CheckBox) findViewById(R.id.checkbox_file_item_select);
63 | setOnClickListener(this);
64 | setLongClickable(true);
65 | }
66 |
67 | public FileItem getFileItem() {
68 | return fileItem;
69 | }
70 |
71 | public void setFileItem(FileItem fileItem, FileListAdapter adapter) {
72 | if (!fileItem.equals(this.fileItem)) {
73 | this.fileItem = fileItem;
74 | showFileIcon();
75 | }
76 | this.fileItem = fileItem;
77 | this.adapter = adapter;
78 | title.setText(fileItem.getName());
79 | toggleSelectState();
80 | if (fileItem.isInSelectMode()) {
81 | checkBox.setVisibility(View.VISIBLE);
82 | setOnLongClickListener(null);
83 | } else {
84 | checkBox.setVisibility(View.GONE);
85 | setOnLongClickListener(this);
86 | }
87 | }
88 |
89 | /**
90 | * 显示文件图标
91 | */
92 | private void showFileIcon() {
93 | icon.setImageResource(fileItem.getIcon());
94 | int tp = fileItem.getFileType();
95 | if (tp == FileItem.FILE_TYPE_APK || tp == FileItem.FILE_TYPE_AUDIO
96 | || tp == FileItem.FILE_TYPE_IMAGE
97 | || tp == FileItem.FILE_TYPE_VIDEO) {
98 | if (task != null && task.getStatus() == Status.RUNNING) {
99 | task.cancel(true);
100 | }
101 | Bitmap bmp = IconContainer.get(fileItem);
102 | if (bmp == null) {
103 | task = new IconLoadTask();
104 | task.execute(fileItem);
105 | } else {
106 | icon.setImageBitmap(bmp);
107 | }
108 | }
109 | try {
110 | if (fileItem.isDirectory() && FileUtil.isSymboliclink(fileItem)) {
111 | symbolView.setVisibility(View.VISIBLE);
112 | } else {
113 | symbolView.setVisibility(View.GONE);
114 | }
115 | } catch (IOException e) {
116 | symbolView.setVisibility(View.GONE);
117 | }
118 | }
119 |
120 | class IconLoadTask extends AsyncTask {
121 |
122 | FileItem originalFile;
123 |
124 | @Override
125 | protected Bitmap doInBackground(FileItem... params) {
126 | originalFile = params[0];
127 | Bitmap bmp = FileUtil.extractFileThumbnail(originalFile,
128 | getContext());
129 | if (bmp != null) {
130 | IconContainer.put(originalFile, bmp);
131 | }
132 | return bmp;
133 | }
134 |
135 | @Override
136 | protected void onPostExecute(Bitmap result) {
137 | if (fileItem.equals(this.originalFile)) {
138 | if (result != null) {
139 | icon.setImageBitmap(result);
140 | } else {
141 | icon.setImageResource(fileItem.getIcon());
142 | }
143 | }
144 | super.onPostExecute(result);
145 | }
146 |
147 | }
148 |
149 | /**
150 | * 切换选中、未选中状态,fileItem.setSelected(boolean)先发生;
151 | */
152 | public void toggleSelectState() {
153 | toggleSelectState(false);
154 | }
155 |
156 | private void toggleSelectState(boolean manual) {
157 | if (fileItem.isSelected()) {
158 | rootFileItemView
159 | .setBackgroundResource(R.drawable.bg_file_item_select);
160 | if (manual && fileItem.isInSelectMode()) {
161 | Intent intent = new Intent();
162 | intent.setAction(FileConst.Action_FileItem_Select);
163 | getContext().sendBroadcast(intent);
164 | }
165 | } else {
166 | rootFileItemView
167 | .setBackgroundResource(R.drawable.bg_file_item_normal);
168 | if (manual && fileItem.isInSelectMode()) {
169 | Intent intent = new Intent();
170 | intent.setAction(FileConst.Action_FileItem_Unselect);
171 | getContext().sendBroadcast(intent);
172 | }
173 | }
174 | checkBox.setOnCheckedChangeListener(null);
175 | checkBox.setChecked(fileItem.isSelected());
176 | checkBox.setOnCheckedChangeListener(this);
177 | }
178 |
179 | @Override
180 | public void onClick(View v) {
181 | if (v.getId() != R.id.checkbox_file_item_select) {
182 | if (fileItem.isInSelectMode()) {
183 | selectOne();
184 | } else {
185 | if (fileItem.isDirectory()) {
186 | openFolder();
187 | } else {
188 | openFile();
189 | }
190 | }
191 |
192 | }
193 | }
194 |
195 | /**
196 | * 打开文件
197 | */
198 | private void openFile() {
199 | Intent intent = new Intent(Intent.ACTION_VIEW);
200 | intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
201 | intent.addCategory(Intent.CATEGORY_DEFAULT);
202 | Uri data = Uri.fromFile(fileItem);
203 | intent.setDataAndType(data, "*/*");
204 | switch (fileItem.getFileType()) {
205 | case FileItem.FILE_TYPE_APK:
206 | intent.setDataAndType(data,
207 | "application/vnd.android.package-archive");
208 | break;
209 | case FileItem.FILE_TYPE_IMAGE:
210 | intent.setDataAndType(data, "image/*");
211 | Intent intentImage=new Intent();
212 | intentImage.putExtra(FileConst.Extra_File_Path, fileItem.getAbsolutePath());
213 | intentImage.setClass(getContext(), ImageBrowseActivity.class);
214 | getContext().startActivity(intentImage);
215 | return;
216 | case FileItem.FILE_TYPE_AUDIO:
217 | intent.putExtra("oneshot", 0);
218 | intent.putExtra("configchange", 0);
219 | intent.setDataAndType(data, "audio/*");
220 | break;
221 | case FileItem.FILE_TYPE_TXT:
222 | intent.setDataAndType(data, "text/plain");
223 | break;
224 | case FileItem.FILE_TYPE_VIDEO:
225 | intent.putExtra("oneshot", 0);
226 | intent.putExtra("configchange", 0);
227 | intent.setDataAndType(data, "video/*");
228 | break;
229 | case FileItem.FILE_TYPE_ZIP:
230 | intent.setDataAndType(data, "application/zip");
231 | break;
232 | case FileItem.FILE_TYPE_WORD:
233 | intent.setDataAndType(data, "application/msword");
234 | break;
235 | case FileItem.FILE_TYPE_PPT:
236 | intent.setDataAndType(data, "application/vnd.ms-powerpoint");
237 | break;
238 | case FileItem.FILE_TYPE_EXCEL:
239 | intent.setDataAndType(data, "application/vnd.ms-excel");
240 | break;
241 | case FileItem.FILE_TYPE_HTML:
242 | intent.setDataAndType(data, "text/html");
243 | break;
244 | case FileItem.FILE_TYPE_PDF:
245 | intent.setDataAndType(data, "application/pdf");
246 | break;
247 | case FileItem.FILE_TYPE_TORRENT:
248 | intent.setDataAndType(data, "torrent/*");
249 | break;
250 | case FileItem.FILE_TYPE_CHM:
251 | intent.setDataAndType(data, "application/mshelp");
252 | break;
253 |
254 | default:
255 | break;
256 | }
257 | try {
258 | getContext().startActivity(intent);
259 | } catch (ActivityNotFoundException e) {
260 | Toast.makeText(getContext(), "打不开此文件类型",
261 | Toast.LENGTH_SHORT).show();
262 | e.printStackTrace();
263 | }
264 | }
265 |
266 | public void selectOne() {
267 | if (fileItem.isInSelectMode()) {
268 | fileItem.setSelected(!fileItem.isSelected());
269 | toggleSelectState(true);
270 | }
271 | }
272 |
273 | public void openFolder() {
274 | Intent intent = new Intent();
275 | intent.setAction(FileConst.Action_Open_Folder);
276 | intent.putExtra(FileConst.Extra_File_Path, fileItem.getAbsolutePath());
277 | intent.putExtra(FileConst.Extra_Item_Type, fileItem.getItemType());
278 | getContext().sendBroadcast(intent);
279 | }
280 |
281 | public FileListAdapter getAdapter() {
282 | return adapter;
283 | }
284 |
285 | @Override
286 | public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
287 | fileItem.setSelected(isChecked);
288 | toggleSelectState(true);
289 | }
290 |
291 | @Override
292 | public boolean onLongClick(View v) {
293 | if (FileUtil.isInExternalStorage(fileItem)) {
294 | Vibrator vibrator = (Vibrator) getContext().getSystemService(
295 | Service.VIBRATOR_SERVICE);
296 | vibrator.vibrate(20);
297 |
298 | fileItem.setSelected(true);
299 |
300 | Intent intent = new Intent();
301 | intent.setAction(FileConst.Action_FileItem_Long_Click);
302 | getContext().sendBroadcast(intent);
303 | }
304 | return false;
305 | }
306 | }
307 |
--------------------------------------------------------------------------------
/src/net/nashlegend/legendexplorer/view/FilePropertyView.java:
--------------------------------------------------------------------------------
1 | package net.nashlegend.legendexplorer.view;
2 |
3 | import java.io.File;
4 | import java.text.SimpleDateFormat;
5 | import java.util.Calendar;
6 | import java.util.Date;
7 |
8 | import net.nashlegend.legendexplorer.R;
9 | import net.nashlegend.legendutils.Tools.FileUtil;
10 |
11 | import android.annotation.SuppressLint;
12 | import android.content.Context;
13 | import android.os.AsyncTask;
14 | import android.os.AsyncTask.Status;
15 | import android.text.format.DateFormat;
16 | import android.util.AttributeSet;
17 | import android.view.LayoutInflater;
18 | import android.view.View;
19 | import android.widget.FrameLayout;
20 | import android.widget.LinearLayout;
21 | import android.widget.TextView;
22 |
23 | public class FilePropertyView extends FrameLayout {
24 |
25 | private TextView fileNameTextView;
26 | private TextView fileTypeTextView;
27 | private TextView filePathTextView;
28 | private TextView fileVolumeTextView;
29 | private TextView fileNumberTextView;
30 | private TextView fileTimeTextView;
31 |
32 | public View fileNamelayout;
33 | public View fileTypelayout;
34 | public View filePathlayout;
35 | public View fileVolumelayout;
36 | public View fileNumberlayout;
37 | public View fileTimelayout;
38 |
39 | loadPropertyTask task;
40 |
41 | private File[] files;
42 |
43 | public FilePropertyView(Context context) {
44 | super(context);
45 | LayoutInflater inflater = (LayoutInflater) context
46 | .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
47 | inflater.inflate(R.layout.dialog_file_property, this);
48 | fileNameTextView = (TextView) findViewById(R.id.text_filename);
49 | fileTypeTextView = (TextView) findViewById(R.id.text_filetype);
50 | filePathTextView = (TextView) findViewById(R.id.text_filepath);
51 | fileVolumeTextView = (TextView) findViewById(R.id.text_filevolume);
52 | fileNumberTextView = (TextView) findViewById(R.id.text_fileinvolving);
53 | fileTimeTextView = (TextView) findViewById(R.id.text_modified_time);
54 | fileNamelayout = findViewById(R.id.layout_filename);
55 | fileTypelayout = findViewById(R.id.layout_filetype);
56 | filePathlayout = findViewById(R.id.layout_filepath);
57 | fileVolumelayout = findViewById(R.id.layout_filevolume);
58 | fileNumberlayout = findViewById(R.id.layout_filenumber);
59 | fileTimelayout = findViewById(R.id.layout_modifiedtime);
60 | }
61 |
62 | @SuppressLint("SimpleDateFormat")
63 | public void setFiles(File[] fs, boolean allInOneFolder) {
64 | files = fs;
65 | if (files == null || files.length == 0) {
66 | return;
67 | }
68 | boolean needTask = false;
69 |
70 | if (files.length == 1) {
71 | File file = files[0];
72 | fileNameTextView.setText(file.getName());
73 | filePathTextView.setText(file.getParent());
74 | if (file.isDirectory()) {
75 | fileVolumeTextView.setText("计算中...");
76 | fileNumberTextView.setText("计算中...");
77 | fileTypeTextView.setText("文件夹");
78 | needTask = true;
79 | } else {
80 | fileTypeTextView.setText(FileUtil.getFileSuffix(file));
81 | fileVolumeTextView.setText(FileUtil.convertStorage(file
82 | .length()));
83 | fileNumberlayout.setVisibility(View.GONE);
84 | }
85 | Date modiDate = new Date(file.lastModified());
86 | SimpleDateFormat format = new SimpleDateFormat(
87 | "yyyy-MM-dd HH:mm:ss");
88 | String dateString = format.format(modiDate);
89 | fileTimeTextView.setText(dateString + "");
90 | } else {
91 | fileNamelayout.setVisibility(View.GONE);
92 | fileTypelayout.setVisibility(View.GONE);
93 | fileTimelayout.setVisibility(View.GONE);
94 | if (allInOneFolder) {
95 | filePathTextView.setText(files[0].getParent());
96 | } else {
97 | filePathTextView.setText("N/A");
98 | }
99 | fileVolumeTextView.setText("计算中...");
100 | fileNumberTextView.setText("计算中...");
101 | needTask = true;
102 | }
103 | if (needTask) {
104 | task = new loadPropertyTask();
105 | task.execute("");
106 | }
107 | }
108 |
109 | public void cancel() {
110 | if (task != null && task.getStatus() == Status.RUNNING) {
111 | task.cancel(true);
112 | }
113 | }
114 |
115 | class loadPropertyTask extends AsyncTask {
116 |
117 | long fsize = 0l;
118 | int fnumber = 0;
119 |
120 | @Override
121 | protected Integer doInBackground(String... params) {
122 | fsize = FileUtil.getFileSize(files);
123 | // 包含文件夹数量
124 | fnumber = FileUtil.getNumFilesInFolder(files, true, true);
125 | return null;
126 | }
127 |
128 | @Override
129 | protected void onPostExecute(Integer result) {
130 | fileVolumeTextView.setText(FileUtil.convertStorage(fsize));
131 | fileNumberTextView.setText(String.valueOf(fnumber));
132 | }
133 |
134 | }
135 |
136 | public FilePropertyView(Context context, AttributeSet attrs) {
137 | super(context, attrs);
138 | }
139 |
140 | public FilePropertyView(Context context, AttributeSet attrs, int defStyle) {
141 | super(context, attrs, defStyle);
142 | }
143 |
144 | }
145 |
--------------------------------------------------------------------------------
/src/net/nashlegend/legendexplorer/view/FolderViewPager.java:
--------------------------------------------------------------------------------
1 |
2 | package net.nashlegend.legendexplorer.view;
3 |
4 | import android.content.Context;
5 | import android.support.v4.view.ViewPager;
6 | import android.util.AttributeSet;
7 | import android.util.Log;
8 | import android.view.MotionEvent;
9 |
10 | public class FolderViewPager extends ViewPager {
11 |
12 | private boolean scrollEnabled = true;
13 | private float preX = 0f;
14 | private float preY = 0f;
15 |
16 | public FolderViewPager(Context context) {
17 | super(context);
18 | }
19 |
20 | public FolderViewPager(Context context, AttributeSet attrs) {
21 | super(context, attrs);
22 | }
23 |
24 | @Override
25 | public boolean onTouchEvent(MotionEvent arg0) {
26 | if (scrollEnabled) {
27 | return super.onTouchEvent(arg0);
28 | }
29 | return true;
30 | }
31 |
32 | @Override
33 | public boolean onInterceptTouchEvent(MotionEvent arg0) {
34 | switch (arg0.getAction()) {
35 | case MotionEvent.ACTION_DOWN:
36 | preX = arg0.getX();
37 | preY = arg0.getY();
38 | break;
39 | case MotionEvent.ACTION_MOVE:
40 | if (!scrollEnabled) {
41 | float currentX = arg0.getX();
42 | float currentY = arg0.getY();
43 | if (Math.abs((currentX - preX) / (currentY - preY)) > 1) {
44 | return true;
45 | }
46 | }
47 | break;
48 |
49 | default:
50 | break;
51 | }
52 | return super.onInterceptTouchEvent(arg0);
53 | }
54 |
55 | public boolean isScrollEnabled() {
56 | return scrollEnabled;
57 | }
58 |
59 | public void setScrollEnabled(boolean scrollEnabled) {
60 | // TODO
61 | this.scrollEnabled = scrollEnabled;
62 | }
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/src/net/nashlegend/legendexplorer/view/ImageViewState.java:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2014 David Morrissey
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 net.nashlegend.legendexplorer.view;
18 |
19 | import android.graphics.PointF;
20 |
21 | import java.io.Serializable;
22 |
23 | /**
24 | * Wraps the scale, center and orientation of a displayed image for easy restoration on screen rotate.
25 | */
26 | public class ImageViewState implements Serializable {
27 |
28 | private float scale;
29 |
30 | private float centerX;
31 |
32 | private float centerY;
33 |
34 | private int orientation;
35 |
36 | public ImageViewState(float scale, PointF center, int orientation) {
37 | this.scale = scale;
38 | this.centerX = center.x;
39 | this.centerY = center.y;
40 | this.orientation = orientation;
41 | }
42 |
43 | public float getScale() {
44 | return scale;
45 | }
46 |
47 | public PointF getCenter() {
48 | return new PointF(centerX, centerY);
49 | }
50 |
51 | public int getOrientation() {
52 | return orientation;
53 | }
54 |
55 | }
56 |
--------------------------------------------------------------------------------
/src/net/nashlegend/legendexplorer/view/ImageViewer.java:
--------------------------------------------------------------------------------
1 |
2 | package net.nashlegend.legendexplorer.view;
3 |
4 | import java.io.File;
5 | import java.util.ArrayList;
6 |
7 | import net.nashlegend.legendutils.Tools.FileUtil;
8 |
9 | import android.animation.Animator;
10 | import android.animation.AnimatorSet;
11 | import android.animation.ObjectAnimator;
12 | import android.annotation.SuppressLint;
13 | import android.content.Context;
14 | import android.graphics.Point;
15 | import android.graphics.PointF;
16 | import android.util.AttributeSet;
17 | import android.view.MotionEvent;
18 | import android.view.VelocityTracker;
19 | import android.view.animation.DecelerateInterpolator;
20 | import android.widget.RelativeLayout;
21 |
22 | public class ImageViewer extends RelativeLayout {
23 |
24 | TheImage leftImage;
25 | TheImage middleImage;
26 | TheImage rightImage;
27 | int scrollDis = 30;
28 | boolean scrolling = false;
29 | boolean resizing = false;
30 |
31 | // 按下时的点
32 | PointF downPoint = new PointF(0f, 0f);
33 | // 拖动开始的点
34 | PointF startPoint = new PointF(0f, 0f);
35 | PointF lastPoint = new PointF(0f, 0f);
36 |
37 | Point leftPoint;
38 | Point middlePoint;
39 | Point rightPoint;
40 |
41 | AnimatorSet animatorSet;
42 |
43 | ArrayList files = new ArrayList();
44 | int imageIndex = 0;
45 |
46 | VelocityTracker velocityTracker;
47 |
48 | float maxVelovityInDP = 1f;
49 | float maxVelocityValue = 1f;
50 | float minValidVelocityInDP = 0.3f;
51 | float minValidVelocityValue = 0.3f;
52 |
53 | float scaleFrom = 0.8f;
54 |
55 | public ImageViewer(Context context) {
56 | super(context);
57 | }
58 |
59 | public ImageViewer(Context context, AttributeSet attrs) {
60 | super(context, attrs);
61 | }
62 |
63 | public ImageViewer(Context context, AttributeSet attrs, int defStyle) {
64 | super(context, attrs, defStyle);
65 | }
66 |
67 | /**
68 | * test only
69 | */
70 | public void test() {
71 | File[] filess = new File("/storage/emulated/0/androidesk/wallpapers/").listFiles();
72 | for (int i = 0; i < filess.length; i++) {
73 | File file = filess[i];
74 | files.add(file);
75 | }
76 | imageIndex = 0;
77 | setupImages();
78 | }
79 |
80 | public void setDataSource(String path) {
81 | File FirstImage = new File(path);
82 | if (isImageFile(FirstImage)) {
83 | File parentFile = FirstImage.getParentFile();
84 | File[] listFiles = parentFile.listFiles();
85 | if (listFiles != null) {
86 | for (int i = 0; i < parentFile.listFiles().length; i++) {
87 | File file = listFiles[i];
88 | if (isImageFile(file)) {
89 | files.add(file);
90 | if (file.equals(FirstImage)) {
91 | imageIndex = files.size() - 1;
92 | }
93 | }
94 | }
95 | setupImages();
96 | }
97 | }
98 | }
99 |
100 | @SuppressLint("Recycle")
101 | public void setupImages() {
102 | if (velocityTracker == null) {
103 | velocityTracker = VelocityTracker.obtain();
104 | }
105 | maxVelocityValue = maxVelovityInDP
106 | * getContext().getResources().getDisplayMetrics().density;
107 | minValidVelocityValue = minValidVelocityInDP
108 | * getContext().getResources().getDisplayMetrics().density;
109 |
110 | if (files.size() == 1) {
111 | leftImage = null;
112 | middleImage = new TheImage(getContext());
113 | rightImage = null;
114 | } else {
115 | if (imageIndex == 0) {
116 | leftImage = null;
117 | middleImage = new TheImage(getContext());
118 | rightImage = new TheImage(getContext());
119 | } else if (imageIndex == files.size() - 1) {
120 | rightImage = null;
121 | middleImage = new TheImage(getContext());
122 | leftImage = new TheImage(getContext());
123 | } else {
124 | leftImage = new TheImage(getContext());
125 | middleImage = new TheImage(getContext());
126 | rightImage = new TheImage(getContext());
127 | }
128 | }
129 |
130 | if (rightImage != null) {
131 | rightImage.load(files.get(imageIndex + 1), getWidth(), getHeight());
132 | LayoutParams paramsr = new LayoutParams(rightImage.initWidth, rightImage.initHeight);
133 | rightImage.setLayoutParams(paramsr);
134 | addView(rightImage);
135 | rightImage.setX((getWidth() - rightImage.initWidth) / 2);
136 | rightImage.setY((getHeight() - rightImage.initHeight) / 2);
137 | rightImage.setAlpha(0f);
138 | rightImage.setScaleX(scaleFrom);
139 | rightImage.setScaleY(scaleFrom);
140 | rightPoint = new Point((getWidth() - rightImage.initWidth) / 2,
141 | (getHeight() - rightImage.initHeight) / 2);
142 | }
143 |
144 | middleImage.load(files.get(imageIndex), getWidth(), getHeight());
145 | LayoutParams paramsm = new LayoutParams(middleImage.initWidth, middleImage.initHeight);
146 | middleImage.setLayoutParams(paramsm);
147 | addView(middleImage);
148 | middleImage.setX((getWidth() - middleImage.initWidth) / 2);
149 | middleImage.setY((getHeight() - middleImage.initHeight) / 2);
150 | middlePoint = new Point((getWidth() - middleImage.initWidth) / 2,
151 | (getHeight() - middleImage.initHeight) / 2);
152 |
153 | if (leftImage != null) {
154 | leftImage.load(files.get(imageIndex - 1), getWidth(), getHeight());
155 | LayoutParams paramsl = new LayoutParams(leftImage.initWidth, leftImage.initHeight);
156 | leftImage.setLayoutParams(paramsl);
157 | addView(leftImage);
158 | leftImage.setX((getWidth() - leftImage.initWidth) / 2 - getWidth());
159 | leftImage.setY((getHeight() - leftImage.initHeight) / 2);
160 | leftPoint = new Point((getWidth() - leftImage.initWidth) / 2 - getWidth(),
161 | (getHeight() - leftImage.initHeight) / 2);
162 | }
163 | }
164 |
165 | public boolean isImageFile(File file) {
166 | return FileUtil.getFileType(file) == FileUtil.FILE_TYPE_IMAGE;
167 | }
168 |
169 | public float distance(PointF pointF, PointF pointF2) {
170 | return PointF.length(pointF.x - pointF2.x, pointF.y - pointF2.y);
171 | }
172 |
173 | @Override
174 | public boolean onInterceptTouchEvent(MotionEvent ev) {
175 | if (files.size() == 0) {
176 | return true;
177 | }
178 | boolean flag = false;
179 | PointF pointF;
180 | switch (ev.getAction()) {
181 | case MotionEvent.ACTION_DOWN:
182 | scrolling = false;
183 | flag = false;
184 | downPoint = new PointF(ev.getX(), ev.getY());
185 | startPoint = new PointF(ev.getX(), ev.getY());
186 | lastPoint = new PointF(ev.getX(), ev.getY());
187 | break;
188 | case MotionEvent.ACTION_MOVE:
189 | pointF = new PointF(ev.getX(), ev.getY());
190 | if (middleImage.TouchMode == TheImage.MODE_NORMAL) {
191 | if (scrolling) {
192 | flag = true;
193 | } else {
194 | if (Math.abs(ev.getY() - downPoint.x) > scrollDis) {
195 | flag = true;
196 | scrolling = true;
197 | } else {
198 | flag = false;
199 | }
200 | }
201 | } else {
202 | flag = false;
203 | }
204 |
205 | lastPoint = pointF;
206 | break;
207 | case MotionEvent.ACTION_CANCEL:
208 | break;
209 | case MotionEvent.ACTION_UP:
210 | flag = scrolling;
211 | break;
212 |
213 | default:
214 | break;
215 | }
216 | return flag;
217 | }
218 |
219 | @SuppressLint("ClickableViewAccessibility")
220 | @Override
221 | public boolean onTouchEvent(MotionEvent ev) {
222 | if (files.size() == 0) {
223 | return true;
224 | }
225 | velocityTracker.addMovement(ev);
226 | PointF pointF;
227 | switch (ev.getAction()) {
228 | case MotionEvent.ACTION_DOWN:
229 |
230 | break;
231 | case MotionEvent.ACTION_MOVE:
232 | pointF = new PointF(ev.getX(), ev.getY());
233 | if (scrolling) {
234 | scrollImageBy(pointF.x - startPoint.x, pointF.y - startPoint.y);
235 | } else {
236 | if (distance(pointF, downPoint) > scrollDis) {
237 | scrolling = true;
238 | startPoint = lastPoint;
239 | scrollImageBy(pointF.x - startPoint.x, pointF.y - startPoint.y);
240 | }
241 | }
242 | lastPoint = pointF;
243 | break;
244 | case MotionEvent.ACTION_CANCEL:
245 | break;
246 | case MotionEvent.ACTION_UP:
247 | if (scrolling) {
248 | scrolling = false;
249 | }
250 | final VelocityTracker tmpTracker = velocityTracker;
251 | tmpTracker.computeCurrentVelocity(1, maxVelocityValue);
252 | onDragEnd(tmpTracker.getXVelocity(), tmpTracker.getYVelocity());
253 | break;
254 |
255 | default:
256 | break;
257 | }
258 | return super.onTouchEvent(ev);
259 | }
260 |
261 | float factor = 0.3f;
262 |
263 | public void onDragEnd(float vx, float vy) {
264 | if (resizing) {
265 |
266 | } else {
267 | int dura = 200;
268 | if (Math.abs(vx) > minValidVelocityValue) {
269 | if (vx < 0) {
270 | if (middleImage.getScaleX() < 1) {
271 | dura = Math
272 | .abs((int) ((1 - middleImage.getScaleX()) / (1 - scaleFrom)
273 | * getWidth() / vx * factor));
274 | scrollBack(dura);
275 | } else {
276 | if (imageIndex < files.size() - 1) {
277 | dura = Math
278 | .abs((int) ((getWidth() + middleImage.getX() - middlePoint.x)
279 | / vx * factor));
280 | scrollLeft(dura);
281 | }
282 | }
283 | } else {
284 | if (middleImage.getScaleX() < 1) {
285 | if (imageIndex > 0) {
286 | dura = Math
287 | .abs((int) ((middleImage.getScaleX() - scaleFrom)
288 | / (1 - scaleFrom) * getWidth() / vx * factor));
289 | scrollRight(dura);
290 | }
291 | } else {
292 | dura = Math
293 | .abs((int) ((middleImage.getX() - middlePoint.x) / vx * factor));
294 | scrollBack(dura);
295 | }
296 | }
297 | } else {
298 | if (middleImage.getScaleX() < (1 + scaleFrom) / 2) {
299 | scrollRight(dura);
300 | } else if (middleImage.getX() < middlePoint.x - getWidth() / 2) {
301 | scrollLeft(dura);
302 | } else {
303 | scrollBack(dura);
304 | }
305 | }
306 | }
307 | }
308 |
309 | public void scrollRight(int dura) {
310 | imageIndex--;
311 | if (rightImage != null) {
312 | removeView(rightImage);
313 | }
314 |
315 | rightImage = middleImage;
316 | rightPoint = new Point(middlePoint.x, middlePoint.y);
317 |
318 | middleImage = leftImage;
319 | middlePoint = new Point(leftPoint.x + getWidth(), leftPoint.y);
320 |
321 | if (imageIndex > 0) {
322 | leftImage = new TheImage(getContext());
323 | leftImage.load(files.get(imageIndex - 1), getWidth(), getHeight());
324 | LayoutParams paramsl = new LayoutParams(leftImage.initWidth, leftImage.initHeight);
325 | leftImage.setLayoutParams(paramsl);
326 | addView(leftImage);
327 | leftImage.setX((getWidth() - leftImage.initWidth) / 2 - getWidth());
328 | leftImage.setY((getHeight() - leftImage.initHeight) / 2);
329 | leftPoint = new Point((getWidth() - leftImage.initWidth) / 2 - getWidth(),
330 | (getHeight() - leftImage.initHeight) / 2);
331 | } else {
332 | leftImage = null;
333 | leftPoint = null;
334 | }
335 | scrollBack(dura);
336 | }
337 |
338 | public void scrollLeft(int dura) {
339 | imageIndex++;
340 | if (leftImage != null) {
341 | removeView(leftImage);
342 | }
343 |
344 | leftImage = middleImage;
345 | leftPoint = new Point(middlePoint.x - getWidth(), middlePoint.y);
346 |
347 | middleImage = rightImage;
348 | middlePoint = new Point(rightPoint.x, rightPoint.y);
349 |
350 | if (imageIndex < files.size() - 1) {
351 | rightImage = new TheImage(getContext());
352 | rightImage.load(files.get(imageIndex + 1), getWidth(), getHeight());
353 | LayoutParams paramsr = new LayoutParams(rightImage.initWidth, rightImage.initHeight);
354 | rightImage.setLayoutParams(paramsr);
355 | rightImage.setAlpha(0f);
356 | addView(rightImage, 0);
357 | rightImage.setX((getWidth() - rightImage.initWidth) / 2);
358 | rightImage.setY((getHeight() - rightImage.initHeight) / 2);
359 | rightImage.setScaleX(scaleFrom);
360 | rightImage.setScaleY(scaleFrom);
361 | rightPoint = new Point((getWidth() - rightImage.initWidth) / 2,
362 | (getHeight() - rightImage.initHeight) / 2);
363 | } else {
364 | rightImage = null;
365 | rightPoint = null;
366 | }
367 | scrollBack(dura);
368 | }
369 |
370 | public void scrollBack(int dura) {
371 | if (animatorSet != null && animatorSet.isRunning()) {
372 | animatorSet.cancel();
373 | }
374 | animatorSet = new AnimatorSet();
375 | ArrayList animators = new ArrayList();
376 | if (leftImage != null) {
377 | ObjectAnimator animatorLeft = ObjectAnimator.ofFloat(leftImage, "x",
378 | leftImage.getX(), leftPoint.x);
379 | animators.add(animatorLeft);
380 | }
381 |
382 | ObjectAnimator holderMiddleX = ObjectAnimator.ofFloat(middleImage, "x",
383 | middleImage.getX(), middlePoint.x);
384 | ObjectAnimator holderMiddleAlpha = ObjectAnimator.ofFloat(middleImage, "alpha",
385 | middleImage.getAlpha(), 1f);
386 | ObjectAnimator holderMiddleScaleX = ObjectAnimator.ofFloat(middleImage, "scaleX",
387 | middleImage.getScaleX(), 1f);
388 | ObjectAnimator holderMiddleScaleY = ObjectAnimator.ofFloat(middleImage, "scaleY",
389 | middleImage.getScaleY(), 1f);
390 |
391 | animators.add(holderMiddleX);
392 | animators.add(holderMiddleAlpha);
393 | animators.add(holderMiddleScaleX);
394 | animators.add(holderMiddleScaleY);
395 |
396 | if (rightImage != null) {
397 | ObjectAnimator holderRightX = ObjectAnimator.ofFloat(rightImage, "x",
398 | rightImage.getX(), rightPoint.x);
399 | ObjectAnimator holderRightAlpha = ObjectAnimator.ofFloat(rightImage, "alpha",
400 | rightImage.getAlpha(), 0f);
401 | ObjectAnimator holderRightScaleX = ObjectAnimator.ofFloat(rightImage, "scaleX",
402 | rightImage.getScaleX(), scaleFrom);
403 | ObjectAnimator holderRightScaleY = ObjectAnimator.ofFloat(rightImage, "scaleY",
404 | rightImage.getScaleY(), scaleFrom);
405 |
406 | animators.add(holderRightX);
407 | animators.add(holderRightAlpha);
408 | animators.add(holderRightScaleX);
409 | animators.add(holderRightScaleY);
410 | }
411 | animatorSet.playTogether(animators);
412 | animatorSet.setInterpolator(new DecelerateInterpolator());
413 | animatorSet.setDuration(dura);
414 | animatorSet.start();
415 | }
416 |
417 | public void scrollImageBy(float x, float y) {
418 | if (resizing) {
419 |
420 | } else {
421 | scrollThreeBodyBy(x, y);
422 | }
423 | }
424 |
425 | public void scrollThreeBodyBy(float x, float y) {
426 | if (x > 0) {
427 | // 右侧,rightImage不动
428 | if (leftImage == null) {
429 | middleImage.setX(middlePoint.x);
430 | } else {
431 | leftImage.setX(leftPoint.x + x);
432 | // middle shrink
433 | float scale = scaleFrom + (1 - scaleFrom) * (1 - x / getWidth());
434 | middleImage.setScaleX(scale);
435 | middleImage.setScaleY(scale);
436 | middleImage.setAlpha((1 - x / getWidth()));
437 | }
438 | if (rightImage != null) {
439 | rightImage.setAlpha(0f);
440 | }
441 | } else {
442 | // 左侧,leftImage不动
443 | if (rightImage == null) {
444 | middleImage.setX(middlePoint.x);
445 | } else {
446 | middleImage.setX(middlePoint.x + x);
447 | // expand right
448 | float scale = scaleFrom + (1 - scaleFrom) * (-x / getWidth());
449 | rightImage.setScaleX(scale);
450 | rightImage.setScaleY(scale);
451 | rightImage.setAlpha((-x / getWidth()));
452 | }
453 | if (leftImage != null) {
454 | leftImage.setX(leftPoint.x);
455 | }
456 | }
457 | }
458 | }
459 |
--------------------------------------------------------------------------------
/src/net/nashlegend/legendexplorer/view/TheImage.java:
--------------------------------------------------------------------------------
1 |
2 | package net.nashlegend.legendexplorer.view;
3 |
4 | import java.io.File;
5 | import java.lang.reflect.Array;
6 | import java.util.Arrays;
7 |
8 | import android.R.integer;
9 | import android.annotation.SuppressLint;
10 | import android.content.Context;
11 | import android.graphics.Bitmap;
12 | import android.graphics.BitmapFactory;
13 | import android.graphics.Canvas;
14 | import android.graphics.Color;
15 | import android.graphics.Matrix;
16 | import android.graphics.Point;
17 | import android.graphics.PointF;
18 | import android.graphics.drawable.BitmapDrawable;
19 | import android.os.AsyncTask;
20 | import android.util.AttributeSet;
21 | import android.view.GestureDetector;
22 | import android.view.MotionEvent;
23 | import android.view.VelocityTracker;
24 | import android.view.View;
25 | import android.view.GestureDetector.SimpleOnGestureListener;
26 | import android.view.ViewGroup.LayoutParams;
27 | import android.widget.ImageView;
28 |
29 | public class TheImage extends ImageView {
30 |
31 | public int initWidth = 0;
32 | public int initHeight = 0;
33 | public float initScale = 1f;
34 |
35 | public static final int MODE_NORMAL = 0;
36 | public static final int MODE_DRAG = 1;
37 | public static final int MODE_ZOOM = 2;
38 | int TouchMode = MODE_NORMAL;
39 | boolean resizing = false;
40 | private Matrix initMatrix = new Matrix();
41 |
42 | public TheImage(Context context) {
43 | super(context);
44 | }
45 |
46 | public TheImage(Context context, AttributeSet attrs) {
47 | super(context, attrs);
48 | }
49 |
50 | public TheImage(Context context, AttributeSet attrs, int defStyle) {
51 | super(context, attrs, defStyle);
52 | }
53 |
54 | @Override
55 | protected void onDetachedFromWindow() {
56 | super.onDetachedFromWindow();
57 | try {
58 | if (!theBitmap.isRecycled()) {
59 | theBitmap.recycle();
60 | }
61 | } catch (Exception e) {
62 |
63 | }
64 | }
65 |
66 | float dist1 = 10f;
67 | float dist2 = 10f;
68 | PointF downPoint = new PointF(0f, 0f);
69 | PointF lastPoint = new PointF(0f, 0f);
70 | Bitmap theBitmap;
71 | float[] values = {
72 | 0, 0, 0, 0, 0, 0, 0, 0, 0
73 | };
74 | float[] lastStableValues = {
75 | 0, 0, 0, 0, 0, 0, 0, 0, 0
76 | };
77 | float[] initValues = {
78 | 0, 0, 0, 0, 0, 0, 0, 0, 0
79 | };
80 | float scrollDis = 36f;
81 |
82 | @SuppressLint("ClickableViewAccessibility")
83 | @Override
84 | public boolean onTouchEvent(MotionEvent event) {
85 | super.onTouchEvent(event);
86 | boolean flag = true;
87 | int pointIndex = event.getActionIndex();
88 | switch (event.getAction() & MotionEvent.ACTION_MASK) {
89 | case MotionEvent.ACTION_DOWN:
90 | downPoint = new PointF(event.getX(), event.getY());
91 | lastPoint = null;
92 | break;
93 | case MotionEvent.ACTION_POINTER_DOWN:
94 | dist1 = distance(event);
95 | getCenter(event);
96 | getImageMatrix().getValues(lastStableValues);
97 | TouchMode = MODE_ZOOM;
98 | break;
99 | case MotionEvent.ACTION_MOVE:
100 | if (TouchMode == MODE_NORMAL) {
101 | if (Math.abs(event.getX() - downPoint.x) > scrollDis) {
102 | flag = false;
103 | }
104 | } else {
105 | getImageMatrix().getValues(values);
106 | if (TouchMode == MODE_ZOOM) {
107 | dist2 = distance(event);
108 | if (values[0] * dist2 / dist1 > initValues[0]) {
109 | getImageMatrix().postScale((dist2 / dist1), (dist2 / dist1),
110 | centerPoint.x,
111 | centerPoint.y);
112 | } else {
113 | // do nothing
114 | }
115 | dist1 = dist2;
116 | } else {
117 | if (lastPoint != null) {
118 | // top left
119 | // top right
120 | // bottom left
121 | // bottom right
122 |
123 | getImageMatrix().postTranslate(event.getX() - lastPoint.x,
124 | event.getY() - lastPoint.y);
125 | } else {
126 | lastPoint = new PointF();
127 | }
128 | lastPoint.set(event.getX(), event.getY());
129 |
130 | }
131 | postInvalidate();
132 | }
133 |
134 | break;
135 | case MotionEvent.ACTION_CANCEL:
136 | break;
137 | case MotionEvent.ACTION_UP:
138 | break;
139 | case MotionEvent.ACTION_POINTER_UP:
140 | if (resizing) {
141 | TouchMode = MODE_DRAG;
142 | } else {
143 | TouchMode = MODE_DRAG;
144 | }
145 | lastPoint=null;
146 | break;
147 | default:
148 | break;
149 | }
150 | detector.onTouchEvent(event);
151 | return flag;
152 | }
153 |
154 | public float distance(MotionEvent event) {
155 | float a = event.getX(1) - event.getX(0);
156 | float b = event.getY(1) - event.getY(0);
157 | return (float) Math.sqrt(Math.pow(a, 2) + Math.pow(b, 2));
158 | }
159 |
160 | private Point centerPoint = new Point();
161 |
162 | private void getCenter(MotionEvent event) {
163 | float a = event.getX(1) + event.getX(0);
164 | float b = event.getY(1) + event.getY(0);
165 | centerPoint.set((int) a / 2, (int) b / 2);
166 | }
167 |
168 | public float distance(PointF pointF, PointF pointF2) {
169 | return PointF.length(pointF.x - pointF2.x, pointF.y - pointF2.y);
170 | }
171 |
172 | GestureDetector detector;
173 |
174 | public void load(File file, int w, int h) {
175 | setBackgroundColor(Color.TRANSPARENT);
176 | detector = new GestureDetector(getContext(), new GestureListener());
177 |
178 | final BitmapFactory.Options options = new BitmapFactory.Options();
179 | options.inJustDecodeBounds = true;
180 | BitmapFactory.decodeFile(file.getAbsolutePath(), options);
181 | options.inJustDecodeBounds = false;
182 | float hei = options.outHeight;
183 | float wid = options.outWidth;
184 |
185 | float r = 1;
186 | if (wid > w || hei > h) {
187 | float beWidth = wid / w;
188 | float beHeight = hei / h;
189 | if (beWidth < beHeight) {
190 | r = beHeight;
191 | } else {
192 | r = beWidth;
193 | }
194 | }
195 | initWidth = (int) (wid / r);
196 | initHeight = h;
197 | initScale = 1 / r;
198 | if (r < 1) {
199 | r = 1;
200 | }
201 | LoadBMPTask task = new LoadBMPTask();
202 | task.execute(file.getAbsolutePath());
203 | }
204 |
205 | class LoadBMPTask extends AsyncTask {
206 |
207 | @Override
208 | protected Bitmap doInBackground(String... params) {
209 | return BitmapFactory.decodeFile(params[0]);
210 | }
211 |
212 | @Override
213 | protected void onPostExecute(Bitmap result) {
214 | theBitmap = result;
215 | setImageBitmap(theBitmap);
216 | getImageMatrix().getValues(initValues);
217 | initMatrix.set(getImageMatrix());
218 | }
219 | }
220 |
221 | public void resetMatrix() {
222 | if (TouchMode == MODE_NORMAL) {
223 | getImageMatrix().postScale(2, 2, getWidth() / 2, getHeight() / 2);
224 | TouchMode = MODE_DRAG;
225 | } else {
226 | getImageMatrix().set(initMatrix);
227 | TouchMode = MODE_NORMAL;
228 | }
229 |
230 | postInvalidate();
231 | }
232 |
233 | class GestureListener extends SimpleOnGestureListener {
234 | public GestureListener() {
235 |
236 | }
237 |
238 | @Override
239 | public boolean onDoubleTap(MotionEvent e) {
240 | resetMatrix();
241 | return super.onDoubleTap(e);
242 | }
243 | }
244 |
245 | }
246 |
--------------------------------------------------------------------------------