1 package com.supermario.filemanager; 2 3 import java.io.File; 4 import java.io.FileInputStream; 5 import java.io.FileNotFoundException; 6 import java.io.FileOutputStream; 7 import java.io.IOException; 8 import java.util.ArrayList; 9 import java.util.HashMap; 10 import java.util.List; 11 12 13 14 import android.app.AlertDialog; 15 import android.app.ListActivity; 16 17 import android.app.AlertDialog.Builder; 18 import android.content.BroadcastReceiver; 19 import android.content.Context; 20 import android.content.DialogInterface; 21 import android.content.Intent; 22 import android.content.IntentFilter; 23 import android.content.ServiceConnection; 24 import android.content.DialogInterface.OnClickListener; 25 import android.graphics.Bitmap; 26 import android.graphics.BitmapFactory; 27 import android.net.Uri; 28 import android.os.Bundle; 29 import android.os.Environment; 30 import android.util.Log; 31 import android.view.Gravity; 32 import android.view.LayoutInflater; 33 import android.view.View; 34 import android.view.ViewGroup; 35 import android.widget.AdapterView; 36 import android.widget.BaseAdapter; 37 import android.widget.EditText; 38 import android.widget.GridView; 39 import android.widget.ImageView; 40 import android.widget.LinearLayout; 41 import android.widget.ListView; 42 import android.widget.RadioButton; 43 import android.widget.RadioGroup; 44 import android.widget.SimpleAdapter; 45 import android.widget.TextView; 46 import android.widget.Toast; 47 import android.widget.AdapterView.OnItemClickListener; 48 import android.widget.AdapterView.OnItemLongClickListener; 49 50 public class MainActivity extends ListActivity implements OnItemLongClickListener{ 51 // 声明成员变量: 52 //存放显示的文件列表的名称 53 private List<String> mFileNames = null; 54 //存放显示的文件列表的相对应的路径 55 private List<String> mFilePaths = null; 56 //起始目录“/” 57 private String mRootPath = java.io.File.separator; 58 // SD卡根目录 59 private String mSDCard = Environment.getExternalStorageDirectory().toString(); 60 private String mOldFilePath = ""; 61 private String mNewFilePath = ""; 62 private String keyWords; 63 //用于显示当前路径 64 private TextView mPathTextView; 65 //用于放置工具栏 66 private GridView mToolbarGridView; 67 private int[] girdview_menu_image = {R.drawable.menu_phone,R.drawable.menu_sdcard,R.drawable.menu_search, 68 R.drawable.menu_create,R.drawable.menu_palse,R.drawable.menu_exit}; 69 private String[] gridview_menu_title = {"手机","SD卡","搜索","创建","粘贴","退出"}; 70 // 代表手机或SD卡,1代表手机,2代表SD卡 71 private static int menuPosition = 1; 72 73 @Override 74 public void onCreate(Bundle savedInstanceState) { 75 super.onCreate(savedInstanceState); 76 setContentView(R.layout.main); 77 mPathTextView = (TextView)findViewById(R.id.mPath); 78 mToolbarGridView = (GridView)findViewById(R.id.file_gridview_toolbar); 79 //一开始程序的时候加载手机目录下的文件列表 80 initFileListInfo(mRootPath); 81 //初始化菜单视图 82 initGridViewMenu(); 83 //初始化菜单监听器 84 initMenuListener(); 85 //为列表项绑定长按监听器 86 getListView().setOnItemLongClickListener(this); 87 88 89 90 } 91 92 public static String mCurrentFilePath=""; 93 private void initFileListInfo(String filePath) { 94 mCurrentFilePath = filePath; 95 //显示当前的路径 96 mPathTextView.setText(filePath); 97 mFileNames = new ArrayList<String>(); 98 mFilePaths = new ArrayList<String>(); 99 File mFile = new File(filePath); 100 //遍历出该文件夹路径下的所有文件/文件夹 101 File[] mFiles = mFile.listFiles(); 102 //只要当前路径不是手机根目录或者是sd卡根目录则显示“返回根目录”和“返回上一级” 103 if(menuPosition == 1&&!mCurrentFilePath.equals(mRootPath)){ 104 initAddBackUp(filePath,mRootPath); 105 }else if(menuPosition == 2&&!mCurrentFilePath.equals(mSDCard)){ 106 initAddBackUp(filePath,mSDCard); 107 } 108 109 /*将所有文件信息添加到集合中*/ 110 for(File mCurrentFile:mFiles){ 111 mFileNames.add(mCurrentFile.getName()); 112 mFilePaths.add(mCurrentFile.getPath()); 113 } 114 115 /*适配数据*/ 116 setListAdapter(new FileAdapter(MainActivity.this,mFileNames,mFilePaths)); 117 } 118 119 private boolean isAddBackUp = false; 120 private void initAddBackUp(String filePath,String phone_sdcard){ 121 if(!filePath.equals(phone_sdcard)){ 122 /*列表项的第一项设置为返回根目录*/ 123 mFileNames.add("BacktoRoot"); 124 mFilePaths.add(phone_sdcard); 125 126 /*列表项的第二项设置为返回上一级*/ 127 mFileNames.add("BacktoUp"); 128 //回到当前目录的父目录即回到上级 129 mFilePaths.add(new File(filePath).getParent()); 130 //将添加返回按键标识位置为true 131 isAddBackUp = true; 132 } 133 134 } 135 136 /**为GridView配饰菜单资源*/ 137 private void initGridViewMenu(){ 138 139 //设置选中时候的背景图片 140 mToolbarGridView.setSelector(R.drawable.menu_item_selected); 141 //设置背景图片 142 mToolbarGridView.setBackgroundResource(R.drawable.menu_background); 143 //设置列数 144 mToolbarGridView.setNumColumns(6); 145 //设置剧中对齐 146 mToolbarGridView.setGravity(Gravity.CENTER); 147 //设置水平,垂直间距为10 148 mToolbarGridView.setVerticalSpacing(10); 149 mToolbarGridView.setHorizontalSpacing(10); 150 //设置适配器 151 mToolbarGridView.setAdapter(getMenuAdapter(gridview_menu_title,girdview_menu_image)); 152 } 153 154 /**菜单项的监听*/ 155 protected void initMenuListener(){ 156 mToolbarGridView.setOnItemClickListener(new OnItemClickListener(){ 157 158 public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,long arg3) { 159 switch(arg2) 160 { 161 //回到根目录 162 case 0: 163 menuPosition = 1; 164 initFileListInfo(mRootPath); 165 break; 166 //回到SD卡根目录 167 case 1: 168 menuPosition = 2; 169 initFileListInfo(mSDCard); 170 break; 171 //显示搜索对话框 172 case 2: 173 searchDilalog(); 174 break; 175 // //创建文件夹 176 case 3: 177 createFolder(); 178 break; 179 // //粘贴文件 180 case 4: 181 palseFile(); 182 break; 183 //退出 184 case 5: 185 MainActivity.this.finish(); 186 break; 187 } 188 } 189 }); 190 } 191 192 193 private String mNewFolderName = ""; 194 private File mCreateFile; 195 private RadioGroup mCreateRadioGroup; 196 private static int mChecked; 197 /**创建文件夹的方法:当用户点击软件下面的创建菜单的时候,是在当前目录下创建的一个文件夹 198 * 静态变量mCurrentFilePath存储的就是当前路径 199 * java.io.File.separator是JAVA给我们提供的一个File类中的静态成员,它会根据系统的不同来创建分隔符 200 * mNewFolderName正是我们要创建的新文件的名称,从EditText组件上得到的*/ 201 private void createFolder(){ 202 //用于标识当前选中的是文件或者文件夹 203 mChecked = 2; 204 LayoutInflater mLI = (LayoutInflater)this.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 205 //初始化对话框布局 206 final LinearLayout mLL = (LinearLayout)mLI.inflate(R.layout.create_dialog, null); 207 mCreateRadioGroup = (RadioGroup)mLL.findViewById(R.id.radiogroup_create); 208 final RadioButton mCreateFileButton = (RadioButton)mLL.findViewById(R.id.create_file); 209 final RadioButton mCreateFolderButton = (RadioButton)mLL.findViewById(R.id.create_folder); 210 //设置默认为创建文件夹 211 mCreateFolderButton.setChecked(true); 212 //为按钮设置监听器 213 mCreateRadioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener(){ 214 //当选择改变时触发 215 public void onCheckedChanged(RadioGroup arg0, int arg1) { 216 if(arg1 == mCreateFileButton.getId()){ 217 mChecked = 1; 218 }else if(arg1 == mCreateFolderButton.getId()){ 219 mChecked = 2; 220 } 221 } 222 }); 223 //显示对话框 224 Builder mBuilder = new AlertDialog.Builder(MainActivity.this) 225 .setTitle("新建") 226 .setView(mLL) 227 .setPositiveButton("创建", new DialogInterface.OnClickListener(){ 228 public void onClick(DialogInterface dialog, int which) { 229 //或者用户输入的名称 230 mNewFolderName = ((EditText)mLL.findViewById(R.id.new_filename)).getText().toString(); 231 if(mChecked == 1){ 232 try { 233 mCreateFile = new File(mCurrentFilePath+java.io.File.separator+mNewFolderName+".txt"); 234 mCreateFile.createNewFile(); 235 //刷新当前目录文件列表 236 initFileListInfo(mCurrentFilePath); 237 } catch (IOException e) { 238 Toast.makeText(MainActivity.this, "文件名拼接出错..!!", Toast.LENGTH_SHORT).show(); 239 } 240 }else if(mChecked == 2){ 241 mCreateFile = new File(mCurrentFilePath+java.io.File.separator+mNewFolderName); 242 if(!mCreateFile.exists()&&!mCreateFile.isDirectory()&&mNewFolderName.length() != 0){ 243 if(mCreateFile.mkdirs()){ 244 //刷新当前目录文件列表 245 initFileListInfo(mCurrentFilePath); 246 }else{ 247 Toast.makeText(MainActivity.this, "创建失败,可能是系统权限不够,root一下?!", Toast.LENGTH_SHORT).show(); 248 } 249 }else{ 250 Toast.makeText(MainActivity.this, "文件名为空,还是重名了呢?", Toast.LENGTH_SHORT).show(); 251 } 252 } 253 } 254 }).setNeutralButton("取消", null); 255 mBuilder.show(); 256 } 257 /**粘贴*/ 258 private void palseFile(){ 259 mNewFilePath = mCurrentFilePath+java.io.File.separator+mCopyFileName;//得到新路径 260 Log.d("copy", "mOldFilePath is "+mOldFilePath+"| mNewFilePath is "+mNewFilePath+"| isCopy is "+isCopy); 261 if(!mOldFilePath.equals(mNewFilePath)&&isCopy == true){//在不同路径下复制才起效 262 if(!new File(mNewFilePath).exists()){ 263 copyFile(mOldFilePath,mNewFilePath); 264 Toast.makeText(MainActivity.this, "执行了粘贴", Toast.LENGTH_SHORT).show(); 265 initFileListInfo(mCurrentFilePath); 266 }else{ 267 new AlertDialog.Builder(MainActivity.this) 268 .setTitle("提示!") 269 .setMessage("该文件名已存在,是否要覆盖?") 270 .setPositiveButton("确定", new DialogInterface.OnClickListener(){ 271 public void onClick(DialogInterface dialog,int which){ 272 copyFile(mOldFilePath,mNewFilePath); 273 initFileListInfo(mCurrentFilePath); 274 } 275 }) 276 .setNegativeButton("取消", null).show(); 277 } 278 }else{ 279 Toast.makeText(MainActivity.this, "未复制文件!", Toast.LENGTH_LONG).show(); 280 } 281 } 282 283 private int i; 284 FileInputStream fis; 285 FileOutputStream fos; 286 //复制文件 287 private void copyFile(String oldFile,String newFile){ 288 try { 289 fis = new FileInputStream(oldFile); 290 fos = new FileOutputStream(newFile); 291 do{ 292 //逐个byte读取文件,并写入另一个文件中 293 if((i = fis.read()) != -1){ 294 fos.write(i); 295 } 296 }while(i != -1); 297 //关闭输入文件流 298 if(fis != null){ 299 fis.close(); 300 } 301 //关闭输出文件流 302 if(fos != null){ 303 fos.close(); 304 } 305 } catch (FileNotFoundException e) { 306 e.printStackTrace(); 307 } catch (IOException e) { 308 e.printStackTrace(); 309 } 310 } 311 312 /**菜单适配器*/ 313 private SimpleAdapter getMenuAdapter(String[] menuNameArray, 314 int[] imageResourceArray) { 315 //数组列表用于存放映射表 316 ArrayList<HashMap<String, Object>> mData = new ArrayList<HashMap<String, Object>>(); 317 for (int i = 0; i < menuNameArray.length; i++) { 318 HashMap<String, Object> mMap = new HashMap<String, Object>(); 319 //将“image”映射成图片资源 320 mMap.put("image", imageResourceArray[i]); 321 //将“title”映射成标题 322 mMap.put("title", menuNameArray[i]); 323 mData.add(mMap); 324 } 325 //新建简单适配器,设置适配器的布局文件,映射关系 326 SimpleAdapter mAdapter = new SimpleAdapter(this, mData,R.layout.item_menu, new String[] { "image", "title" },new int[] { R.id.item_image, R.id.item_text }); 327 return mAdapter; 328 } 329 /**列表项点击时的事件监听*/ 330 @Override 331 protected void onListItemClick(ListView listView, View view, int position, long id){ 332 final File mFile = new File(mFilePaths.get(position)); 333 //如果该文件是可读的,我们进去查看文件 334 if(mFile.canRead()){ 335 if(mFile.isDirectory()){ 336 //如果是文件夹,则直接进入该文件夹,查看文件目录 337 initFileListInfo(mFilePaths.get(position)); 338 } 339 else 340 { 341 openFile(mFile); 342 } 343 344 } 345 else 346 { 347 //如果该文件不可读,我们给出提示不能访问,防止用户操作系统文件造成系统崩溃等 348 Toast.makeText(MainActivity.this, "对不起,您的访问权限不足!", Toast.LENGTH_SHORT).show(); 349 } 350 } 351 352 353 /**调用系统的方法,来打开文件的方法*/ 354 private void openFile(File file){ 355 if(file.isDirectory()){ 356 initFileListInfo(file.getPath()); 357 }else{ 358 Intent intent = new Intent(); 359 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 360 intent.setAction(android.content.Intent.ACTION_VIEW); 361 //设置当前文件类型 362 intent.setDataAndType(Uri.fromFile(file), getMIMEType(file)); 363 startActivity(intent); 364 } 365 } 366 /**获得MIME类型的方法*/ 367 private String getMIMEType(File file){ 368 String type = ""; 369 String fileName = file.getName(); 370 //取出文件后缀名并转成小写 371 String fileEnds = fileName.substring(fileName.lastIndexOf(".")+1,fileName.length()).toLowerCase(); 372 if(fileEnds.equals("m4a")||fileEnds.equals("mp3")||fileEnds.equals("mid")||fileEnds.equals("xmf")||fileEnds.equals("ogg")||fileEnds.equals("wav")){ 373 type = "audio/*";// 系统将列出所有可能打开音频文件的程序选择器 374 }else if(fileEnds.equals("3gp")||fileEnds.equals("mp4")){ 375 type = "video/*";// 系统将列出所有可能打开视频文件的程序选择器 376 }else if(fileEnds.equals("jpg")||fileEnds.equals("gif")||fileEnds.equals("png")||fileEnds.equals("jpeg")||fileEnds.equals("bmp")){ 377 type = "image/*";// 系统将列出所有可能打开图片文件的程序选择器 378 }else{ 379 type = "*/*"; // 系统将列出所有可能打开该文件的程序选择器 380 } 381 return type; 382 } 383 384 385 //长按列表项的事件监听:对长按需要进行一个控制,当列表中包括”返回根目录“和”返回上一级“时,需要对这两列进行屏蔽 386 387 @Override 388 public boolean onItemLongClick(AdapterView<?> arg0, View arg1, final int position, long arg3) { 389 if(isAddBackUp == true){//说明存在返回根目录和返回上一级两列,接下来要对这两列进行屏蔽 390 if(position != 0 && position != 1){ 391 initItemLongClickListener(new File(mFilePaths.get(position))); 392 } 393 } 394 else{ 395 initItemLongClickListener(new File(mFilePaths.get(position))); 396 } 397 return false; 398 } 399 400 private String mCopyFileName; 401 private boolean isCopy = false; 402 /**长按文件或文件夹时弹出的带ListView效果的功能菜单*/ 403 private void initItemLongClickListener(final File file){ 404 OnClickListener listener = new DialogInterface.OnClickListener(){ 405 //item的值就是从0开始的索引值(从列表的第一项开始) 406 public void onClick(DialogInterface dialog, int item) { 407 if(file.canRead()){//注意,所有对文件的操作必须是在该文件可读的情况下才可以,否则报错 408 if(item == 0){//复制 409 if(file.isFile()&&"txt".equals((file.getName().substring(file.getName().lastIndexOf(".")+1, file.getName().length())).toLowerCase())){ 410 Toast.makeText(MainActivity.this, "已复制!", Toast.LENGTH_SHORT).show(); 411 //复制标志位,表明已复制文件 412 isCopy = true; 413 //取得复制文件的名字 414 mCopyFileName = file.getName(); 415 //记录复制文件的路径 416 mOldFilePath = mCurrentFilePath+java.io.File.separator+mCopyFileName; 417 }else{ 418 Toast.makeText(MainActivity.this, "对不起,目前只支持复制文本文件!", Toast.LENGTH_SHORT).show(); 419 } 420 }else if(item == 1){//重命名 421 initRenameDialog(file); 422 }else if(item == 2){//删除 423 initDeleteDialog(file); 424 } 425 }else{ 426 Toast.makeText(MainActivity.this, "对不起,您的访问权限不足!", Toast.LENGTH_SHORT).show(); 427 } 428 } 429 }; 430 //列表项名称 431 String[] mMenu = {"复制","重命名","删除"}; 432 //显示操作选择对话框 433 new AlertDialog.Builder(MainActivity.this) 434 .setTitle("请选择操作!") 435 .setItems(mMenu, listener) 436 .setPositiveButton("取消",null).show(); 437 } 438 439 440 441 EditText mET; 442 //显示重命名对话框 443 private void initRenameDialog(final File file){ 444 LayoutInflater mLI = LayoutInflater.from(MainActivity.this); 445 //初始化重命名对话框 446 LinearLayout mLL = (LinearLayout)mLI.inflate(R.layout.rename_dialog, null); 447 mET = (EditText)mLL.findViewById(R.id.new_filename); 448 //显示当前的文件名 449 mET.setText(file.getName()); 450 //设置监听器 451 OnClickListener listener = new DialogInterface.OnClickListener(){ 452 public void onClick(DialogInterface dialog,int which){ 453 String modifyName = mET.getText().toString(); 454 final String modifyFilePath = file.getParentFile().getPath()+java.io.File.separator; 455 final String newFilePath = modifyFilePath+modifyName; 456 //判断该新的文件名是否已经在当前目录下存在 457 if(new File(newFilePath).exists()){ 458 if(!modifyName.equals(file.getName())){//把“重命名”操作时没做任何修改的情况过滤掉 459 //弹出该新命名后的文件已经存在的提示,并提示接下来的操作 460 new AlertDialog.Builder(MainActivity.this) 461 .setTitle("提示!") 462 .setMessage("该文件名已存在,是否要覆盖?") 463 .setPositiveButton("确定", new DialogInterface.OnClickListener(){ 464 public void onClick(DialogInterface dialog,int which){ 465 file.renameTo(new File(newFilePath)); 466 Toast.makeText(MainActivity.this, 467 "the file path is "+new File(newFilePath), Toast.LENGTH_SHORT).show(); 468 //更新当前目录信息 469 initFileListInfo(file.getParentFile().getPath()); 470 } 471 }) 472 .setNegativeButton("取消", null).show(); 473 } 474 }else{ 475 //文件名不重复时直接修改文件名后再次刷新列表 476 file.renameTo(new File(newFilePath)); 477 initFileListInfo(file.getParentFile().getPath()); 478 } 479 } 480 481 }; 482 //显示对话框 483 AlertDialog renameDialog = new AlertDialog.Builder(MainActivity.this).create(); 484 renameDialog.setView(mLL); 485 renameDialog.setButton("确定", listener); 486 renameDialog.setButton2("取消", new DialogInterface.OnClickListener(){ 487 public void onClick(DialogInterface dialog,int which){ 488 //什么都不做,关闭当前对话框 489 } 490 }); 491 renameDialog.show(); 492 } 493 494 //弹出删除文件/文件夹的对话框 495 private void initDeleteDialog(final File file){ 496 new AlertDialog.Builder(MainActivity.this) 497 .setTitle("提示!") 498 .setMessage("您确定要删除该"+(file.isDirectory()?"文件夹":"文件")+"吗?") 499 .setPositiveButton("确定", new DialogInterface.OnClickListener(){ 500 public void onClick(DialogInterface dialog,int which){ 501 if(file.isFile()){ 502 //是文件则直接删除 503 file.delete(); 504 }else{ 505 //是文件夹则用这个方法删除 506 deleteFolder(file); 507 } 508 //重新遍历该文件的父目录 509 initFileListInfo(file.getParent()); 510 } 511 }) 512 .setNegativeButton("取消", null).show(); 513 } 514 515 //删除文件夹的方法(递归删除该文件夹下的所有文件) 516 public void deleteFolder(File folder){ 517 File[] fileArray = folder.listFiles(); 518 if(fileArray.length == 0){ 519 //空文件夹则直接删除 520 folder.delete(); 521 }else{ 522 //遍历该目录 523 for(File currentFile:fileArray){ 524 if(currentFile.exists()&¤tFile.isFile()){ 525 //文件则直接删除 526 currentFile.delete(); 527 }else{ 528 //递归删除 529 deleteFolder(currentFile); 530 } 531 } 532 folder.delete(); 533 } 534 } 535 536 Intent serviceIntent; 537 ServiceConnection mSC; 538 RadioGroup mRadioGroup; 539 static int mRadioChecked; 540 public static final String KEYWORD_BROADCAST = "com.supermario.file.KEYWORD_BROADCAST"; 541 //显示搜索对话框 542 private void searchDilalog(){ 543 //用于确定是在当前目录搜索或者是在整个目录搜索的标志 544 mRadioChecked = 1; 545 LayoutInflater mLI = LayoutInflater.from(MainActivity.this); 546 final View mLL = (View)mLI.inflate(R.layout.search_dialog, null); 547 mRadioGroup = (RadioGroup)mLL.findViewById(R.id.radiogroup_search); 548 final RadioButton mCurrentPathButton = (RadioButton)mLL.findViewById(R.id.radio_currentpath); 549 final RadioButton mWholePathButton = (RadioButton)mLL.findViewById(R.id.radio_wholepath); 550 //设置默认选择在当前路径搜 551 mCurrentPathButton.setChecked(true); 552 mRadioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener(){ 553 //当选择改变时触发 554 public void onCheckedChanged(RadioGroup radiogroup, int checkId) { 555 //当前路径的标志为1 556 if(checkId == mCurrentPathButton.getId()){ 557 mRadioChecked = 1; 558 //整个目录的标志为2 559 }else if(checkId == mWholePathButton.getId()){ 560 mRadioChecked = 2; 561 } 562 } 563 }); 564 Builder mBuilder = new AlertDialog.Builder(MainActivity.this) 565 .setTitle("搜索").setView(mLL) 566 .setPositiveButton("确定", new OnClickListener(){ 567 public void onClick(DialogInterface arg0, int arg1) { 568 keyWords = ((EditText)mLL.findViewById(R.id.edit_search)).getText().toString(); 569 if(keyWords.length() == 0){ 570 Toast.makeText(MainActivity.this, "关键字不能为空!", Toast.LENGTH_SHORT).show(); 571 searchDilalog(); 572 }else{ 573 if(menuPosition == 1){ 574 mPathTextView.setText(mRootPath); 575 }else{ 576 mPathTextView.setText(mSDCard); 577 } 578 //获取用户输入的关键字并开始搜索服务 579 serviceIntent = new Intent("com.android.service.FILE_SEARCH_START"); 580 //传递搜索的范围区间:1.当前路径下搜索 2.SD卡下搜索 581 if(mRadioChecked == 1){ 582 serviceIntent.putExtra("searchpath", mCurrentFilePath); 583 }else{ 584 serviceIntent.putExtra("searchpath", mSDCard); 585 } 586 //传递关键字 587 serviceIntent.putExtra("keyword", keyWords); 588 589 590 MainActivity.this.startService(serviceIntent);//开启服务,启动搜索 591 isComeBackFromNotification = false; 592 } 593 } 594 }) 595 .setNegativeButton("取消", null); 596 mBuilder.create().show(); 597 } 598 599 /**注册广播*/ 600 private IntentFilter mFilter; 601 private FileBroadcast mFileBroadcast; 602 private IntentFilter mIntentFilter; 603 @Override 604 protected void onStart() { 605 super.onStart(); 606 mFilter = new IntentFilter(); 607 mFilter.addAction(FileService.FILE_SEARCH_COMPLETED); 608 mFilter.addAction(FileService.FILE_NOTIFICATION); 609 if(mFileBroadcast == null){ 610 mFileBroadcast = new FileBroadcast(); 611 } 612 613 this.registerReceiver(mFileBroadcast, mFilter); 614 615 } 616 617 618 /**注销广播*/ 619 @Override 620 protected void onDestroy() { 621 super.onDestroy(); 622 Log.d("NullPointError", "onDestroy"); 623 mFileNames.clear(); 624 mFilePaths.clear(); 625 this.unregisterReceiver(mFileBroadcast); 626 } 627 628 private String mAction; 629 public static boolean isComeBackFromNotification = false; 630 /**内部广播类*/ 631 class FileBroadcast extends BroadcastReceiver{ 632 @Override 633 public void onReceive(Context context, Intent intent) { 634 mAction = intent.getAction(); 635 // 搜索完毕的广播 636 if(FileService.FILE_SEARCH_COMPLETED.equals(mAction)){ 637 mFileNames = intent.getStringArrayListExtra("mFileNameList"); 638 mFilePaths = intent.getStringArrayListExtra("mFilePathsList"); 639 Toast.makeText(MainActivity.this, "搜索完毕!", Toast.LENGTH_SHORT).show(); 640 //这里搜索完毕之后应该弹出一个弹出框提示用户要不要显示数据 641 searchCompletedDialog("搜索完毕,是否马上显示结果?"); 642 getApplicationContext().stopService(serviceIntent);//当搜索完毕的时候停止服务,然后在服务中取消通知 643 // 点击通知栏跳转过来的广播 644 }else if(FileService.FILE_NOTIFICATION.equals(mAction)){//点击通知回到当前Activity,读取其中信息 645 String mNotification = intent.getStringExtra("notification"); 646 Toast.makeText(MainActivity.this, mNotification, Toast.LENGTH_LONG).show(); 647 searchCompletedDialog("你确定要取消搜索吗?"); 648 } 649 } 650 } 651 652 //搜索完毕和点击通知过来时的提示框 653 private void searchCompletedDialog(String message){ 654 Builder searchDialog = new AlertDialog.Builder(MainActivity.this) 655 .setTitle("提示") 656 .setMessage(message) 657 .setPositiveButton("确定", new OnClickListener(){ 658 public void onClick(DialogInterface dialog,int which) { 659 //当弹出框时,需要对这个确定按钮进行一个判断,因为要对不同的情况做不同的处理(2种情况) 660 // 1.搜索完毕 661 // 2.取消搜索 662 if(FileService.FILE_SEARCH_COMPLETED.equals(mAction)){ 663 if(mFileNames.size() == 0){ 664 Toast.makeText(MainActivity.this, "无相关文件/文件夹!", Toast.LENGTH_SHORT).show(); 665 setListAdapter(new FileAdapter(MainActivity.this,mFileNames,mFilePaths));//清空列表 666 }else{ 667 //显示文件列表 668 setListAdapter(new FileAdapter(MainActivity.this,mFileNames,mFilePaths)); 669 } 670 }else{ 671 //设置搜索标志为true, 672 isComeBackFromNotification = true; 673 //关闭服务,取消搜索 674 getApplicationContext().stopService(serviceIntent); 675 } 676 } 677 }) 678 .setNegativeButton("取消", null); 679 searchDialog.create(); 680 searchDialog.show(); 681 } 682 683 684 class FileAdapter extends BaseAdapter{ 685 //返回键,各种格式的文件的图标 686 private Bitmap mBackRoot; 687 private Bitmap mBackUp; 688 private Bitmap mImage; 689 private Bitmap mAudio; 690 private Bitmap mRar; 691 private Bitmap mVideo; 692 private Bitmap mFolder; 693 private Bitmap mApk; 694 private Bitmap mOthers; 695 private Bitmap mTxt; 696 private Bitmap mWeb; 697 private Context mContext; 698 //文件名列表 699 private List<String> mFileNameList; 700 //文件对应的路径列表 701 private List<String> mFilePathList; 702 703 public FileAdapter(Context context,List<String> fileName,List<String> filePath){ 704 mContext = context; 705 mFileNameList = fileName; 706 mFilePathList = filePath; 707 //初始化图片资源 708 //返回到根目录 709 mBackRoot = BitmapFactory.decodeResource(mContext.getResources(),R.drawable.back_to_root); 710 //返回到上一级目录 711 mBackUp = BitmapFactory.decodeResource(mContext.getResources(),R.drawable.back_to_up); 712 //图片文件对应的icon 713 mImage = BitmapFactory.decodeResource(mContext.getResources(),R.drawable.image); 714 //音频文件对应的icon 715 mAudio = BitmapFactory.decodeResource(mContext.getResources(),R.drawable.audio); 716 //视频文件对应的icon 717 mVideo = BitmapFactory.decodeResource(mContext.getResources(),R.drawable.video); 718 //可执行文件对应的icon 719 mApk = BitmapFactory.decodeResource(mContext.getResources(),R.drawable.apk); 720 //文本文档对应的icon 721 mTxt = BitmapFactory.decodeResource(mContext.getResources(),R.drawable.txt); 722 //其他类型文件对应的icon 723 mOthers = BitmapFactory.decodeResource(mContext.getResources(),R.drawable.others); 724 //文件夹对应的icon 725 mFolder = BitmapFactory.decodeResource(mContext.getResources(),R.drawable.folder); 726 //zip文件对应的icon 727 mRar = BitmapFactory.decodeResource(mContext.getResources(),R.drawable.zip_icon); 728 //网页文件对应的icon 729 mWeb = BitmapFactory.decodeResource(mContext.getResources(),R.drawable.web_browser); 730 } 731 //获得文件的总数 732 @Override 733 public int getCount() { 734 return mFilePathList.size(); 735 } 736 //获得当前位置对应的文件名 737 @Override 738 public Object getItem(int position) { 739 return mFileNameList.get(position); 740 } 741 //获得当前的位置 742 @Override 743 public long getItemId(int position) { 744 return position; 745 } 746 //获得视图 747 @Override 748 public View getView(int position, View convertView, ViewGroup viewgroup) { 749 ViewHolder viewHolder = null; 750 if (convertView == null) { 751 viewHolder = new ViewHolder(); 752 LayoutInflater mLI = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 753 //初始化列表元素界面 754 convertView = mLI.inflate(R.layout.list_child, null); 755 //获取列表布局界面元素 756 viewHolder.mIV = (ImageView)convertView.findViewById(R.id.image_list_childs); 757 viewHolder.mTV = (TextView)convertView.findViewById(R.id.text_list_childs); 758 //将每一行的元素集合设置成标签 759 convertView.setTag(viewHolder); 760 } else { 761 //获取视图标签 762 viewHolder = (ViewHolder) convertView.getTag(); 763 } 764 File mFile = new File(mFilePathList.get(position).toString()); 765 //如果 766 if(mFileNameList.get(position).toString().equals("BacktoRoot")){ 767 //添加返回根目录的按钮 768 viewHolder.mIV.setImageBitmap(mBackRoot); 769 viewHolder.mTV.setText("返回根目录"); 770 }else if(mFileNameList.get(position).toString().equals("BacktoUp")){ 771 //添加返回上一级菜单的按钮 772 viewHolder.mIV.setImageBitmap(mBackUp); 773 viewHolder.mTV.setText("返回上一级"); 774 }else if(mFileNameList.get(position).toString().equals("BacktoSearchBefore")){ 775 //添加返回搜索之前目录的按钮 776 viewHolder.mIV.setImageBitmap(mBackRoot); 777 viewHolder.mTV.setText("返回搜索之前目录"); 778 }else{ 779 String fileName = mFile.getName(); 780 viewHolder.mTV.setText(fileName); 781 if(mFile.isDirectory()){ 782 viewHolder.mIV.setImageBitmap(mFolder); 783 }else{ 784 String fileEnds = fileName.substring(fileName.lastIndexOf(".")+1,fileName.length()).toLowerCase();//取出文件后缀名并转成小写 785 if(fileEnds.equals("m4a")||fileEnds.equals("mp3")||fileEnds.equals("mid")||fileEnds.equals("xmf")||fileEnds.equals("ogg")||fileEnds.equals("wav")){ 786 viewHolder.mIV.setImageBitmap(mVideo); 787 }else if(fileEnds.equals("3gp")||fileEnds.equals("mp4")){ 788 viewHolder.mIV.setImageBitmap(mAudio); 789 }else if(fileEnds.equals("jpg")||fileEnds.equals("gif")||fileEnds.equals("png")||fileEnds.equals("jpeg")||fileEnds.equals("bmp")){ 790 viewHolder.mIV.setImageBitmap(mImage); 791 }else if(fileEnds.equals("apk")){ 792 viewHolder.mIV.setImageBitmap(mApk); 793 }else if(fileEnds.equals("txt")){ 794 viewHolder.mIV.setImageBitmap(mTxt); 795 }else if(fileEnds.equals("zip")||fileEnds.equals("rar")){ 796 viewHolder.mIV.setImageBitmap(mRar); 797 }else if(fileEnds.equals("html")||fileEnds.equals("htm")||fileEnds.equals("mht")){ 798 viewHolder.mIV.setImageBitmap(mWeb); 799 }else { 800 viewHolder.mIV.setImageBitmap(mOthers); 801 } 802 } 803 } 804 return convertView; 805 } 806 //用于存储列表每一行元素的图片和文本 807 class ViewHolder { 808 ImageView mIV; 809 TextView mTV; 810 } 811 812 813 } 814 815 816 } 817 818 819
MainActivity.java
1 package com.supermario.filemanager; 2 import java.io.File; 3 import java.util.ArrayList; 4 import android.app.Notification; 5 import android.app.NotificationManager; 6 import android.app.PendingIntent; 7 import android.app.Service; 8 import android.content.Intent; 9 import android.os.AsyncTask; 10 import android.os.IBinder; 11 import android.util.Log; 12 public class FileService extends Service { 13 14 private ArrayList<String> mFileName = null; 15 private ArrayList<String> mFilePaths = null; 16 public static String mServiceKeyword = "";//接收搜索关键字的静态变量 17 public static String mServiceSearchPath = "";//接收搜索路径的静态变量 18 public static final String FILE_SEARCH_COMPLETED = "com.supermario.file.FILE_SEARCH_COMPLETED"; 19 public static final String FILE_NOTIFICATION = "com.supermario.file.FILE_NOTIFICATION"; 20 @Override 21 public IBinder onBind(Intent arg0) { 22 return null; 23 } 24 25 26 @Override 27 public int onStartCommand(Intent intent, int flags, int startId) { 28 mServiceKeyword=intent.getStringExtra("keyword"); 29 mServiceSearchPath=intent.getStringExtra("searchpath"); 30 mFileName = new ArrayList<String>(); 31 mFilePaths = new ArrayList<String>(); 32 //发出通知表明正在进行搜索 33 fileSearchNotification(); 34 new DoBackgroundTask().execute(); 35 return START_STICKY; 36 } 37 38 private int m = -1; 39 /**具体做搜索事件的可回调函数*/ 40 private void initFileArray(File file){ 41 Log.d("FileService", "currentArray is "+file.getPath()); 42 //只能遍历可读的文件夹,否则会报错 43 if(file.canRead()){ 44 File[] mFileArray = file.listFiles(); 45 for(File currentArray:mFileArray){ 46 if(currentArray.getName().indexOf(mServiceKeyword) != -1){ 47 if (m == -1) { 48 m++; 49 // 返回搜索之前目录 50 mFileName.add("BacktoSearchBefore"); 51 mFilePaths.add(MainActivity.mCurrentFilePath); 52 } 53 mFileName.add(currentArray.getName()); 54 mFilePaths.add(currentArray.getPath()); 55 } 56 //如果是文件夹则回调该方法 57 if(currentArray.exists()&¤tArray.isDirectory()){ 58 //如果用户取消了搜索,应该停止搜索的过程 59 if(MainActivity.isComeBackFromNotification == true){ 60 return; 61 } 62 initFileArray(currentArray); 63 } 64 } 65 } 66 } 67 68 private class DoBackgroundTask extends AsyncTask<java.lang.Void, java.lang.Void, java.lang.Void> 69 { 70 71 72 @Override 73 protected Void doInBackground(Void... params) { 74 // TODO Auto-generated method stub 75 76 initFileArray(new File(mServiceSearchPath)); 77 //当用户点击了取消搜索则不发生广播 78 Intent intent = new Intent(FILE_SEARCH_COMPLETED); 79 if(MainActivity.isComeBackFromNotification == false){ 80 81 intent.putStringArrayListExtra("mFileNameList", mFileName); 82 intent.putStringArrayListExtra("mFilePathsList", mFilePaths); 83 sendBroadcast(intent); 84 } 85 86 return null; 87 } 88 89 protected void onPostExecute(Long result) { 90 //搜索完毕之后携带数据并发送广播 91 92 } 93 94 } 95 96 97 @Override 98 public void onDestroy() { 99 super.onDestroy(); 100 //取消通知 101 mNF.cancel(R.string.app_name); 102 } 103 104 105 NotificationManager mNF; 106 /**通知*/ 107 private void fileSearchNotification(){ 108 Notification mNotification = new Notification(R.drawable.logo,"后台搜索中...",System.currentTimeMillis()); 109 Intent intent = new Intent(FILE_NOTIFICATION); 110 //打开notice时的提示内容 111 intent.putExtra("notification", "当通知还存在,说明搜索未完成,可以在这里触发一个事件,当点击通知回到Activity之后,可以弹出一个框,提示是否取消搜索!"); 112 PendingIntent mPI = PendingIntent.getBroadcast(this,0,intent,0); 113 mNotification.setLatestEventInfo(this, "在"+mServiceSearchPath+"下搜索", "搜索关键字为"+mServiceKeyword+"【点击可取消搜索】", mPI); 114 if(mNF == null){ 115 mNF = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); 116 } 117 mNF.notify(R.string.app_name, mNotification); 118 } 119 }
FileService.JAVA 搜索服务
源文件下载