package com.njlabs.showjava.ui; import android.annotation.SuppressLint; import android.app.ProgressDialog; import android.content.DialogInterface; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.graphics.drawable.Drawable; import android.os.AsyncTask; import android.os.Bundle; import android.os.Environment; import android.support.v7.app.AlertDialog; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.ArrayAdapter; import android.widget.ImageView; import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; import com.crashlytics.android.Crashlytics; import com.njlabs.showjava.R; import com.njlabs.showjava.utils.Utils; import com.njlabs.showjava.utils.logging.Ln; import org.apache.commons.io.FileUtils; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; public class AppListing extends BaseActivity { private ProgressDialog packageLoadDialog; private ListView listView = null; private boolean isDestroyed; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setupLayout(R.layout.activity_app_listing, "Show Java"+(isPro()?" Pro":"")); listView = (ListView) findViewById(R.id.list); ApplicationLoader runner = new ApplicationLoader(); runner.execute(); } private void showProgressDialog() { if (packageLoadDialog == null) { packageLoadDialog = new ProgressDialog(this); packageLoadDialog.setIndeterminate(false); packageLoadDialog.setCancelable(false); packageLoadDialog.setInverseBackgroundForced(false); packageLoadDialog.setCanceledOnTouchOutside(false); packageLoadDialog.setMessage("Loading installed applications..."); } packageLoadDialog.show(); } private void dismissProgressDialog() { if (packageLoadDialog != null && packageLoadDialog.isShowing()) { packageLoadDialog.dismiss(); } } private void setupList(ArrayList<PackageInfoHolder> AllPackages) { ArrayAdapter<PackageInfoHolder> aa = new ArrayAdapter<PackageInfoHolder>(getBaseContext(), R.layout.package_list_item, AllPackages) { @SuppressLint("InflateParams") @Override public View getView(int position, View convertView, ViewGroup parent) { if (convertView == null) { convertView = getLayoutInflater().inflate(R.layout.package_list_item, null); } PackageInfoHolder pkg = getItem(position); ViewHolder holder = new ViewHolder(); holder.packageLabel = (TextView) convertView.findViewById(R.id.pkg_name); holder.packageName = (TextView) convertView.findViewById(R.id.pkg_id); holder.packageVersion = (TextView) convertView.findViewById(R.id.pkg_version); holder.packageFilePath = (TextView) convertView.findViewById(R.id.pkg_dir); holder.packageIcon = (ImageView) convertView.findViewById(R.id.pkg_img); holder.position = position; convertView.setTag(holder); holder.packageLabel.setText(pkg.packageLabel); holder.packageName.setText(pkg.packageName); holder.packageVersion.setText("version " + pkg.packageVersion); holder.packageFilePath.setText(pkg.packageFilePath); holder.packageIcon.setImageDrawable(pkg.packageIcon); return convertView; } }; listView.setAdapter(aa); listView.setTextFilterEnabled(true); listView.setOnItemClickListener(new OnItemClickListener() { public void onItemClick(AdapterView<?> parent, View view, int position, long id) { final ViewHolder holder = (ViewHolder) view.getTag(); String myApp = "com.njlabs.tester"; if (holder.packageName.getText().toString().toLowerCase().contains(myApp.toLowerCase())) { Toast.makeText(getApplicationContext(), "The application " + holder.packageName.getText().toString() + " cannot be decompiled !", Toast.LENGTH_SHORT).show(); } else { final File sourceDir = new File(Environment.getExternalStorageDirectory() + "/ShowJava/sources/" + holder.packageName.getText().toString() + ""); if (Utils.sourceExists(sourceDir)) { showAlreadyExistsDialog(holder, sourceDir); } else { showDecompilerSelection(holder); } } } }); } private ArrayList<PackageInfoHolder> getInstalledApps(ApplicationLoader task) { ArrayList<PackageInfoHolder> res = new ArrayList<>(); List<PackageInfo> packages = getPackageManager().getInstalledPackages(0); int totalPackages = packages.size(); for (int i = 0; i < totalPackages; i++) { PackageInfo p = packages.get(i); if (!isSystemPackage(p)) { ApplicationInfo appInfo = null; try { appInfo = getPackageManager().getApplicationInfo(p.packageName, 0); } catch (PackageManager.NameNotFoundException e) { Ln.e(e); } int count = i + 1; final PackageInfoHolder newInfo = new PackageInfoHolder(); newInfo.packageLabel = p.applicationInfo.loadLabel(getPackageManager()).toString(); task.doProgress("Loading application " + count + " of " + totalPackages + " (" + newInfo.packageLabel + ")"); newInfo.packageName = p.packageName; newInfo.packageVersion = p.versionName; if (appInfo != null) { newInfo.packageFilePath = appInfo.publicSourceDir; } newInfo.packageIcon = p.applicationInfo.loadIcon(getPackageManager()); res.add(newInfo); } } Comparator<PackageInfoHolder> AppNameComparator = new Comparator<PackageInfoHolder>() { public int compare(PackageInfoHolder o1, PackageInfoHolder o2) { return o1.getPackageLabel().toLowerCase().compareTo(o2.getPackageLabel().toLowerCase()); } }; Collections.sort(res, AppNameComparator); return res; } private boolean isSystemPackage(PackageInfo pkgInfo) { return ((pkgInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0); } @Override protected void onDestroy() { isDestroyed = true; dismissProgressDialog(); super.onDestroy(); } private static class ViewHolder { TextView packageLabel; TextView packageName; TextView packageVersion; TextView packageFilePath; ImageView packageIcon; int position; } private class ApplicationLoader extends AsyncTask<String, String, ArrayList<PackageInfoHolder>> { @Override protected ArrayList<PackageInfoHolder> doInBackground(String... params) { publishProgress("Retrieving installed application"); return getInstalledApps(this); } @Override protected void onPostExecute(ArrayList<PackageInfoHolder> AllPackages) { setupList(AllPackages); if (!isDestroyed) { dismissProgressDialog(); } } public void doProgress(String value) { publishProgress(value); } @Override protected void onPreExecute() { showProgressDialog(); } @Override protected void onProgressUpdate(String... text) { packageLoadDialog.setMessage(text[0]); } } class PackageInfoHolder { private String packageLabel = ""; private String packageName = ""; private String packageVersion = ""; private String packageFilePath = ""; private Drawable packageIcon; public String getPackageLabel() { return packageLabel; } } private void showAlreadyExistsDialog(final ViewHolder holder, final File sourceDir){ AlertDialog.Builder alertDialog = new AlertDialog.Builder(AppListing.this, R.style.AlertDialog); alertDialog.setTitle("This Package has already been decompiled"); alertDialog.setMessage("This application has already been decompiled once and the source exists on your sdcard. What would you like to do ?"); alertDialog.setPositiveButton("View Source", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { Intent i = new Intent(getApplicationContext(), JavaExplorer.class); i.putExtra("java_source_dir", sourceDir + "/"); i.putExtra("package_id", holder.packageName.getText().toString()); startActivity(i); } }); alertDialog.setNegativeButton("Decompile", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { try { FileUtils.deleteDirectory(sourceDir); } catch (IOException e) { Crashlytics.logException(e); } showDecompilerSelection(holder); } }); alertDialog.show(); } private void openProcessActivity(ViewHolder holder, String decompiler){ Intent i = new Intent(getApplicationContext(), AppProcessActivity.class); i.putExtra("package_label", holder.packageLabel.getText().toString()); i.putExtra("package_file_path", holder.packageFilePath.getText().toString()); i.putExtra("decompiler", decompiler); startActivity(i); } private void showDecompilerSelection(final ViewHolder holder){ if(!prefs.getBoolean("hide_decompiler_select", false)){ final CharSequence[] items = getResources().getTextArray(R.array.decompilers); final CharSequence[] itemsVals = getResources().getTextArray(R.array.decompilers_values); AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle("Pick a decompiler"); builder.setItems(items, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int item) { openProcessActivity(holder, itemsVals[item].toString()); } }); AlertDialog alert = builder.create(); alert.show(); } else { openProcessActivity(holder, prefs.getString("decompiler","cfr")); } } }