package me.xiaopan.sketchsample.fragment; import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.os.AsyncTask; import android.os.Bundle; import android.os.Environment; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.text.format.Formatter; import android.view.View; import net.sourceforge.pinyin4j.PinyinHelper; import java.io.File; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Queue; import java.util.concurrent.LinkedBlockingQueue; import java.util.zip.ZipFile; import me.xiaopan.androidinjector.InjectContentView; import me.xiaopan.androidinjector.InjectView; import me.xiaopan.assemblyadapter.AssemblyRecyclerAdapter; import me.xiaopan.sketch.util.SketchUtils; import me.xiaopan.sketchsample.MyFragment; import me.xiaopan.sketchsample.R; import me.xiaopan.sketchsample.adapter.itemfactory.AppItemFactory; import me.xiaopan.sketchsample.adapter.itemfactory.AppListHeaderItemFactory; import me.xiaopan.sketchsample.bean.AppInfo; import me.xiaopan.sketchsample.util.ScrollingPauseLoadManager; import me.xiaopan.sketchsample.util.XpkInfo; import me.xiaopan.sketchsample.widget.HintView; /** * 本地安装包页面 */ @InjectContentView(R.layout.fragment_installed_app) public class AppPackageFragment extends MyFragment { @InjectView(R.id.recyclerView_installedApp_content) private RecyclerView contentRecyclerView; @InjectView(R.id.hint_installedApp_hint) private HintView hintView; private AssemblyRecyclerAdapter adapter = null; @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); contentRecyclerView.setLayoutManager(new LinearLayoutManager(view.getContext())); contentRecyclerView.setOnScrollListener(new ScrollingPauseLoadManager(view.getContext())); if (adapter != null) { contentRecyclerView.setAdapter(adapter); contentRecyclerView.scheduleLayoutAnimation(); } else { loadAppList(); } } private void loadAppList() { new AsyncTask<Integer, Integer, List<AppInfo>>() { private Context context = getActivity().getBaseContext(); private long time; @Override protected void onPreExecute() { super.onPreExecute(); hintView.loading("正在扫描本地APK文件,请稍后..."); time = System.currentTimeMillis(); } @Override protected List<AppInfo> doInBackground(Integer... params) { if (!Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) { return null; } List<AppInfo> appInfoList = new ArrayList<AppInfo>(); Queue<File> dirs = new LinkedBlockingQueue<File>(); dirs.add(Environment.getExternalStorageDirectory()); File dir; File[] childDirs; while (!dirs.isEmpty()) { if (getActivity() == null) { break; } dir = dirs.poll(); if (dir == null) { continue; } childDirs = dir.listFiles(); if (childDirs == null || childDirs.length == 0) { continue; } for (File childFile : childDirs) { if (getActivity() == null) { break; } if (childFile.isDirectory()) { dirs.add(childFile); continue; } String fileName = childFile.getName(); if (SketchUtils.checkSuffix(fileName, ".apk")) { AppInfo appInfo = parseFromApk(context, childFile); if (appInfo != null) { appInfoList.add(appInfo); } } else if (SketchUtils.checkSuffix(fileName, ".xpk")) { AppInfo appInfo = parseFromXpk(childFile); if (appInfo != null) { appInfoList.add(appInfo); } } } } Collections.sort(appInfoList, new Comparator<AppInfo>() { @Override public int compare(AppInfo lhs, AppInfo rhs) { return lhs.getSortName().compareToIgnoreCase(rhs.getSortName()); } }); return appInfoList; } private String toPinYin(String text) { StringBuilder stringBuilder = new StringBuilder(); for (char c : text.toCharArray()) { String[] a = PinyinHelper.toHanyuPinyinStringArray(c); if (a != null) { stringBuilder.append(a[0]); } else { stringBuilder.append(c); } } return stringBuilder.toString(); } private AppInfo parseFromApk(Context context, File file) { PackageInfo packageInfo = context.getPackageManager().getPackageArchiveInfo(file.getPath(), PackageManager.GET_ACTIVITIES); if (packageInfo == null) { return null; } packageInfo.applicationInfo.sourceDir = file.getPath(); packageInfo.applicationInfo.publicSourceDir = file.getPath(); AppInfo appInfo = new AppInfo(false); appInfo.setName(String.valueOf(packageInfo.applicationInfo.loadLabel(context.getPackageManager()))); appInfo.setSortName(toPinYin(appInfo.getName())); appInfo.setId(packageInfo.packageName); appInfo.setVersionName(packageInfo.versionName); appInfo.setApkFilePath(file.getPath()); appInfo.setAppSize(Formatter.formatFileSize(context, file.length())); return appInfo; } private AppInfo parseFromXpk(File file) { try { AppInfo appInfo = new AppInfo(false); XpkInfo xpkInfo = XpkInfo.getXPKManifestDom(new ZipFile(file)); if (xpkInfo == null) { throw new Exception(); } appInfo.setName(xpkInfo.getAppName()); appInfo.setSortName(toPinYin(appInfo.getName())); appInfo.setId(xpkInfo.getPackageName()); appInfo.setVersionName(xpkInfo.getVersionName()); appInfo.setApkFilePath(file.getPath()); appInfo.setAppSize(Formatter.formatFileSize(context, file.length())); return appInfo; } catch (Exception e) { e.printStackTrace(); return null; } } @Override protected void onPostExecute(List<AppInfo> appInfoList) { if (getActivity() == null) { return; } hintView.hidden(); long useTime = System.currentTimeMillis() - time; String headerString; if (useTime != -1) { headerString = String.format("您的设备上共有%d个安装包,扫描耗时%d秒", appInfoList != null ? appInfoList.size() : 0, useTime / 1000); } else { headerString = String.format("您的设备上共有%d个安装包", appInfoList != null ? appInfoList.size() : 0); } List<Object> dataList = new ArrayList<Object>((appInfoList != null ? appInfoList.size() : 0) + 1); dataList.add(headerString); if (appInfoList != null) { dataList.addAll(appInfoList); } AssemblyRecyclerAdapter adapter = new AssemblyRecyclerAdapter(dataList); adapter.addItemFactory(new AppItemFactory()); adapter.addItemFactory(new AppListHeaderItemFactory()); contentRecyclerView.setAdapter(adapter); contentRecyclerView.scheduleLayoutAnimation(); AppPackageFragment.this.adapter = adapter; } }.execute(0); } }