package com.mcxiaoke.apptoolkit.fragment; import android.app.AlertDialog; import android.app.ProgressDialog; import android.content.DialogInterface; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentTransaction; import android.util.Pair; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.ListView; import com.actionbarsherlock.view.ActionMode; import com.actionbarsherlock.view.Menu; import com.actionbarsherlock.view.MenuInflater; import com.actionbarsherlock.view.MenuItem; import com.mcxiaoke.apptoolkit.AppConfig; import com.mcxiaoke.apptoolkit.AppContext; import com.mcxiaoke.apptoolkit.R; import com.mcxiaoke.apptoolkit.adapter.AppListAdapter; import com.mcxiaoke.apptoolkit.adapter.MultiChoiceArrayAdapter; import com.mcxiaoke.apptoolkit.cache.CacheManager; import com.mcxiaoke.apptoolkit.callback.IPackageMonitor; import com.mcxiaoke.apptoolkit.exception.NoPermissionException; import com.mcxiaoke.apptoolkit.menu.PopupMenuFragment; import com.mcxiaoke.apptoolkit.model.AppInfo; import com.mcxiaoke.apptoolkit.task.AsyncTaskCallback; import com.mcxiaoke.apptoolkit.task.BackupAppsApkTask; import com.mcxiaoke.apptoolkit.task.BackupAppsDataTask; import com.mcxiaoke.apptoolkit.task.LoadAppsTask; import com.mcxiaoke.apptoolkit.task.TaskMessage; import com.mcxiaoke.apptoolkit.util.Utils; import java.util.List; /** * Project: filemanager * Package: com.com.mcxiaoke.appmanager.fragment * User: com.mcxiaoke * Date: 13-6-11 * Time: 上午10:55 */ public class PackageListFragment extends BaseFragment implements AdapterView.OnItemClickListener, AdapterView.OnItemLongClickListener, MultiChoiceArrayAdapter.OnCheckedListener, IPackageMonitor { private static final String TAG = PackageListFragment.class.getSimpleName(); private static void debug(String message) { AppContext.v(message); } private static final int MSG_PACKAGE_ADDED = 1001; private static final int MSG_PACKAGE_REMOVED = 1002; private ListView mListView; private List<AppInfo> mAppData; private MultiChoiceArrayAdapter<AppInfo> mArrayAdapter; private ActionModeCallback mActionModeCallback; private LoadAppsTask mLoadAppsTask; private TaskMessage mLoadAppsTaskParam; private BackupAppsApkTask mBackupApkTask; private BackupAppsDataTask mBackupDataTask; private ProgressDialog mProgressDialog; private ActionMode mActionMode; private boolean isBackuping; private boolean isAppLoading; private Handler mUiHandler; private int mType; private boolean mSystem; public static PackageListFragment newInstance(int type, boolean system) { PackageListFragment fragment = new PackageListFragment(); Bundle args = new Bundle(); args.putInt(AppConfig.EXTRA_TYPE, type); args.putBoolean(AppConfig.EXTRA_SYSTEM, system); fragment.setArguments(args); return fragment; } public PackageListFragment() { } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); AppContext.v("AppListFragment onCreate()"); Bundle args = getArguments(); if (args != null) { mType = args.getInt(AppConfig.EXTRA_TYPE, AppConfig.TYPE_USER_APP_MANAGER); mSystem = args.getBoolean(AppConfig.EXTRA_SYSTEM, false); } mLoadAppsTaskParam = new TaskMessage(mType, mSystem); mAppData = CacheManager.getInstance().getAll(); setHasOptionsMenu(true); mUiHandler = new Handler(Looper.getMainLooper()); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { AppContext.v("AppListFragment onCreateView()"); View root = inflater.inflate(R.layout.fm_applist, null); mListView = (ListView) root.findViewById(android.R.id.list); return root; } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); AppContext.v("AppListFragment onActivityCreated()"); mActionModeCallback = new ActionModeCallback(this); mListView.setOnItemClickListener(this); mListView.setOnItemLongClickListener(this); mArrayAdapter = new AppListAdapter(getActivity(), mAppData); mArrayAdapter.setOnCheckedListener(this); mListView.setAdapter(mArrayAdapter); refresh(); } @Override public void refresh() { AppContext.v("AppListFragment refresh()"); if (mActionMode != null) { mActionMode.finish(); } startLoadAppsTask(); } private void stopLoadAppsTask() { if (mLoadAppsTask != null) { mLoadAppsTask.cancel(false); } } private void startLoadAppsTask() { stopLoadAppsTask(); isAppLoading = true; mArrayAdapter.clear(); AppContext.v("AppListFragment startLoadAppsTask()"); mLoadAppsTask = new LoadAppsTask(getActivity(), new AsyncTaskCallback<Pair<Integer, Integer>, List<AppInfo>>() { @Override public void onTaskProgress(int code, Pair<Integer, Integer> integerIntegerPair) { } @Override public void onTaskSuccess(int code, List<AppInfo> appInfos) { AppContext.v("AppListFragment onTaskSuccess() size is " + (appInfos == null ? "null" : appInfos.size())); hideProgress(); isAppLoading = false; mArrayAdapter.addAll(appInfos); } @Override public void onTaskFailure(int code, Throwable e) { AppContext.v("AppListFragment onTaskFailure()"); hideProgress(); isAppLoading = false; } }); mLoadAppsTask.start(mLoadAppsTaskParam); showProgress(); } private void showDialog(AppInfo app) { if (app != null) { FragmentManager fm = getFragmentManager(); FragmentTransaction ft = fm.beginTransaction(); Fragment prev = getFragmentManager().findFragmentByTag(DIALOG_TAG); if (prev != null) { ft.remove(prev); } ft.addToBackStack(null); PopupMenuFragment newFragment = PopupMenuFragment.newInstance(app, mType); newFragment.show(ft, DIALOG_TAG); } } @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { AppContext.v("AppListFragment onItemClick() position=" + position + " mActionMode=" + mActionMode); if (mActionMode != null) { mArrayAdapter.toggleChecked(position); checkActionMode(); } else { final AppInfo app = mArrayAdapter.getItem(position); showDialog(app); } } @Override public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { AppContext.v("AppListFragment onItemLongClick() position=" + position + " mActionMode=" + mActionMode); if (mActionMode == null) { mArrayAdapter.toggleChecked(position); checkActionMode(); } return true; } @Override public void onCheckedChanged(int position, boolean isChecked) { checkActionMode(); } private void checkActionMode() { if (mActionMode == null) { getSherlockActivity().startActionMode(mActionModeCallback); } setActionModeTitle(); } private void setActionModeTitle() { if (mActionMode != null) { int checkedCount = mArrayAdapter.getCheckedItemCount(); if (checkedCount == 0) { mActionMode.finish(); } else { mActionMode.setTitle(R.string.menu_mode_title); mActionMode.setSubtitle(String.format(getString(R.string.menu_mode_subtitle), checkedCount)); } } } private void onSelectAll() { if (mActionMode != null) { mArrayAdapter.checkAll(); setActionModeTitle(); } } private void onUnselectAll() { } private void onBackupApps() { List<AppInfo> checkedApps = mArrayAdapter.getCheckedItems(); if (checkedApps != null && checkedApps.size() > 0) { showBackupConfirmDialog(checkedApps, false); } } private void onBackupData() { List<AppInfo> checkedApps = mArrayAdapter.getCheckedItems(); if (checkedApps != null && checkedApps.size() > 0) { showBackupConfirmDialog(checkedApps, true); } } private boolean onActionItemClicked(ActionMode mode, MenuItem item) { int id = item.getItemId(); switch (id) { case R.id.menu_mode_select_all: onSelectAll(); break; case R.id.menu_mode_backup_app: onBackupApps(); break; case R.id.menu_mode_backup_data: onBackupData(); break; } return false; } private void onCreateActionMode(ActionMode mode, Menu menu) { MenuInflater inflater = mode.getMenuInflater(); inflater.inflate(R.menu.menu_mode_applist, menu); mActionMode = mode; mArrayAdapter.setActionModeState(true); setActionModeTitle(); } private boolean onPrepareActionMode(ActionMode mode, Menu menu) { return false; } private void onDestroyActionMode(ActionMode mode) { mArrayAdapter.setActionModeState(false); mActionMode = null; } private static final String DIALOG_TAG = "DIALOG_TAG"; static class ActionModeCallback implements ActionMode.Callback { private PackageListFragment mFragment; public ActionModeCallback(PackageListFragment fragment) { this.mFragment = fragment; } @Override public boolean onActionItemClicked(ActionMode mode, MenuItem item) { return mFragment.onActionItemClicked(mode, item); } @Override public boolean onCreateActionMode(ActionMode mode, Menu menu) { mFragment.onCreateActionMode(mode, menu); return true; } @Override public void onDestroyActionMode(ActionMode mode) { mFragment.onDestroyActionMode(mode); } @Override public boolean onPrepareActionMode(ActionMode mode, Menu menu) { return mFragment.onPrepareActionMode(mode, menu); } } private void showProgressDialog() { if (mProgressDialog == null) { mProgressDialog = new ProgressDialog(getActivity()); mProgressDialog.setIndeterminate(true); mProgressDialog.setTitle(R.string.dialog_backup_title); mProgressDialog.setCancelable(true); mProgressDialog.setCanceledOnTouchOutside(false); mProgressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() { @Override public void onCancel(DialogInterface dialog) { AppContext.v("OnCancelListener"); stopBackup(); } }); } mProgressDialog.show(); } private void updateProgressDialog(final String text) { mUiHandler.post(new Runnable() { @Override public void run() { if (mProgressDialog != null && mProgressDialog.isShowing()) { mProgressDialog.setMessage(text); } } }); } private void dismissProgressDialog() { if (mProgressDialog != null) { mProgressDialog.dismiss(); mProgressDialog = null; } } private void showBackupConfirmDialog(final List<AppInfo> apps, final boolean backupData) { AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); builder.setTitle(backupData ? R.string.dialog_backup_all_data_title : R.string.dialog_backup_all_apk_title); builder.setMessage(backupData ? R.string.dialog_backup_all_data_message : R.string.dialog_backup_all_apk_message); builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); startBackup(apps, backupData); } }); builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); } }); builder.create().show(); } private void showBackupCompleteDialog(int count, int totalCount, boolean backupData) { String backupDir = backupData ? Utils.getBackupDataDir().getPath() : Utils.getBackupAppsDir().getPath(); String message = String.format(getString(backupData ? R.string.dialog_backup_complete_data_message : R.string.dialog_backup_complete_apk_message), backupDir, totalCount, count); AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); builder.setTitle(backupData ? R.string.dialog_backup_complete_data_title : R.string.dialog_backup_all_apk_title); builder.setMessage(message); builder.setNeutralButton(android.R.string.ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); mArrayAdapter.notifyDataSetChanged(); } }); builder.create().show(); } private void startBackup(final List<AppInfo> apps, final boolean backupData) { if (isBackuping) { return; } if (apps == null || apps.isEmpty()) { return; } final int totalCount = apps.size(); AppContext.v("startBackup totalCount=" + totalCount + " backupData=" + backupData); isBackuping = true; final AsyncTaskCallback<AppInfo, Integer> callback = new AsyncTaskCallback<AppInfo, Integer>() { @Override public void onTaskProgress(int code, AppInfo app) { AppContext.v("BackupAsyncTask.onTaskProgress " + app.appName); updateProgressDialog(Utils.buildProgressText(app, backupData)); } @Override public void onTaskSuccess(int code, Integer integer) { AppContext.v("BackupAsyncTask.onTaskSuccess apkBackup count is " + integer); int backuped = integer == null ? 0 : integer; dismissProgressDialog(); showBackupCompleteDialog(backuped, totalCount, backupData); isBackuping = false; } @Override public void onTaskFailure(int code, Throwable e) { AppContext.v("BackupAsyncTask.onTaskFailure ex is " + e); isBackuping = false; dismissProgressDialog(); if (e instanceof NoPermissionException) { AppContext.showToast(getActivity(), R.string.msg_backup_failed_no_permission); } } }; if (backupData) { stopBackupData(); mBackupDataTask = new BackupAppsDataTask(getActivity(), callback); mBackupDataTask.start(apps); } else { stopBackupApk(); mBackupApkTask = new BackupAppsApkTask(getActivity(), callback); mBackupApkTask.start(apps); } if (mActionMode != null) { mActionMode.finish(); } showProgressDialog(); } private void stopBackup() { stopBackupApk(); stopBackupData(); } private void stopBackupApk() { if (mBackupApkTask != null) { AppContext.v("stopBackup"); mBackupApkTask.stop(); mBackupApkTask = null; isBackuping = false; } } private void stopBackupData() { if (mBackupApkTask != null) { AppContext.v("stopBackup"); mBackupApkTask.stop(); mBackupApkTask = null; isBackuping = false; } } @Override public void onPackageAdded(String packageName, int uid) { } @Override public void onPackageChanged(String packageName, int uid, String[] components) { } @Override public void onPackageModified(String packageName) { } @Override public void onPackageRemoved(String packageName, int uid) { if (packageName != null) { synchronized (this) { for (AppInfo app : mAppData) { if (app.packageName.equalsIgnoreCase(packageName)) { mAppData.remove(app); mArrayAdapter.notifyDataSetChanged(); } } } } } @Override public void onUidRemoved(int uid) { if (uid > AppConfig.UID_SYSTEM) { synchronized (this) { for (AppInfo app : mAppData) { if (app.uid == uid) { mAppData.remove(app); mArrayAdapter.notifyDataSetChanged(); } } } } } @Override public void onStart() { super.onStart(); } @Override public void onStop() { super.onStop(); } @Override public void onPause() { super.onPause(); } @Override public void onResume() { super.onResume(); } @Override public void onDestroy() { super.onDestroy(); dismissProgressDialog(); stopLoadAppsTask(); stopBackup(); } }