package com.njlabs.showjava.ui; import android.Manifest; import android.annotation.SuppressLint; 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.Bitmap; import android.graphics.BitmapFactory; import android.graphics.drawable.BitmapDrawable; import android.net.Uri; import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.support.annotation.NonNull; import android.support.v4.app.ActivityCompat; import android.support.v4.content.ContextCompat; import android.support.v7.app.AlertDialog; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; import com.anjlab.android.iab.v3.BillingProcessor; import com.anjlab.android.iab.v3.TransactionDetails; import com.crashlytics.android.Crashlytics; import com.loopj.android.http.AsyncHttpClient; import com.loopj.android.http.JsonHttpResponseHandler; import com.loopj.android.http.RequestParams; import com.mikepenz.materialdrawer.Drawer; import com.mikepenz.materialdrawer.DrawerBuilder; import com.mikepenz.materialdrawer.accountswitcher.AccountHeader; import com.mikepenz.materialdrawer.accountswitcher.AccountHeaderBuilder; import com.mikepenz.materialdrawer.model.DividerDrawerItem; import com.mikepenz.materialdrawer.model.PrimaryDrawerItem; import com.mikepenz.materialdrawer.model.ProfileDrawerItem; import com.mikepenz.materialdrawer.model.interfaces.IDrawerItem; import com.njlabs.showjava.BuildConfig; import com.njlabs.showjava.Constants; import com.njlabs.showjava.R; import com.njlabs.showjava.utils.AesCbcWithIntegrity; import com.njlabs.showjava.utils.SourceInfo; import com.njlabs.showjava.utils.Utils; import com.njlabs.showjava.utils.Verify; import com.njlabs.showjava.utils.logging.Ln; import com.nononsenseapps.filepicker.FilePickerActivity; import org.apache.commons.io.FileUtils; import org.apache.commons.io.FilenameUtils; import org.json.JSONException; import org.json.JSONObject; import java.io.File; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.security.GeneralSecurityException; import java.util.ArrayList; import java.util.List; import cz.msebera.android.httpclient.Header; import xyz.codezero.apl.SV; @SuppressWarnings("unused") public class Landing extends BaseActivity implements BillingProcessor.IBillingHandler{ private static final int FILE_PICKER = 0; private LinearLayout welcomeLayout; private ListView listView; private BillingProcessor bp; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setupLayout(R.layout.activity_landing); listView = (ListView) findViewById(R.id.history_list); View header = getLayoutInflater().inflate(R.layout.history_header_view, listView, false); listView.addHeaderView(header, null, false); welcomeLayout = (LinearLayout) findViewById(R.id.welcome_layout); AccountHeader headerResult = new AccountHeaderBuilder() .withActivity(this) .withHeaderBackground(R.drawable.navbar_header) .addProfiles( new ProfileDrawerItem().withName(getResources().getString(R.string.app_name)+(isPro()?" Pro":"")).withEmail("Version " + BuildConfig.VERSION_NAME).setSelectable(false) ) .withSelectionListEnabledForSingleProfile(false) .build(); ArrayList<IDrawerItem> drawerItems = new ArrayList<>(); drawerItems.add(new PrimaryDrawerItem().withName("Home").withIcon(R.drawable.ic_action_home).withCheckable(false)); drawerItems.add(new DividerDrawerItem()); drawerItems.add(new PrimaryDrawerItem().withName("Report a Bug").withIcon(R.drawable.ic_action_bug_report).withCheckable(false)); drawerItems.add(new PrimaryDrawerItem().withName("About the app").withIcon(R.drawable.ic_action_info).withCheckable(false)); drawerItems.add(new PrimaryDrawerItem().withName("Settings").withIcon(R.drawable.ic_action_settings).withCheckable(false)); if(!isPro()) { drawerItems.add(new DividerDrawerItem()); drawerItems.add(new PrimaryDrawerItem().withName("Get Show Java Pro").withIcon(R.mipmap.ic_logo_plain).withCheckable(false)); } else { if(!Verify.good(baseContext)){ put(false); AlertDialog.Builder alertDialog = new AlertDialog.Builder(baseContext, R.style.AlertDialog); alertDialog.setCancelable(false); alertDialog.setMessage("Show Java Pro has been disabled. Either you have Lucky Patcher (or) Freedom (or) the apk has been tampered with. If you have really purchased Pro, please fix the above mentioned errors to get the purchase restored."); alertDialog.setPositiveButton("I Understand", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); Toast.makeText(baseContext, "Thanks for understanding ... :)", Toast.LENGTH_LONG).show(); } }); alertDialog.setNegativeButton("I'm a Pirate", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { Toast.makeText(baseContext, "Well... I'm not :)", Toast.LENGTH_LONG).show(); finish(); } }); alertDialog.show(); } } Drawer result = new DrawerBuilder() .withActivity(this) .withToolbar(toolbar) .withAccountHeader(headerResult) .withDrawerItems(drawerItems) .withOnDrawerItemClickListener(new Drawer.OnDrawerItemClickListener() { @Override public boolean onItemClick(AdapterView<?> parent, View view, int position, long id, IDrawerItem drawerItem) { switch (position) { case 2: Uri uri = Uri.parse("https://github.com/niranjan94/show-java/issues/new"); startActivity(new Intent(Intent.ACTION_VIEW, uri)); overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out); break; case 3: startActivity(new Intent(baseContext, About.class)); break; case 4: startActivity(new Intent(baseContext, SettingsActivity.class)); break; case 6: startActivity(new Intent(baseContext, PurchaseActivity.class)); break; } return false; } }) .withCloseOnClick(true) .build(); if(isMarshmallow()){ if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{ Manifest.permission.WRITE_EXTERNAL_STORAGE }, Constants.STORAGE_PERMISSION_REQUEST); } else { initHistoryLoader(); } } else { initHistoryLoader(); } try { AesCbcWithIntegrity.SecretKeys keys = new AesCbcWithIntegrity.SecretKeys(getResources().getString(R.string.cc),getResources().getString(R.string.ii)); String plainText = AesCbcWithIntegrity.decryptString(BuildConfig.GOOGLE_PLAY_LICENSE_KEY, keys); bp = new BillingProcessor(this, plainText, this); } catch (GeneralSecurityException | UnsupportedEncodingException e) { Crashlytics.logException(e); } } public void initHistoryLoader(){ HistoryLoader historyLoader = new HistoryLoader(); historyLoader.execute(); } public void SetupList(List<SourceInfo> AllPackages) { if (AllPackages.size() < 1) { listView.setVisibility(View.GONE); welcomeLayout.setVisibility(View.VISIBLE); } else { welcomeLayout.setVisibility(View.INVISIBLE); ArrayAdapter<SourceInfo> decompileHistoryItemArrayAdapter = new ArrayAdapter<SourceInfo>(getBaseContext(), R.layout.history_list_item, AllPackages) { @SuppressLint("InflateParams") @Override public View getView(int position, View convertView, ViewGroup parent) { if (convertView == null) { convertView = getLayoutInflater().inflate(R.layout.history_list_item, null); } SourceInfo pkg = getItem(position); ViewHolder holder = new ViewHolder(); holder.packageLabel = (TextView) convertView.findViewById(R.id.history_item_label); holder.packageName = (TextView) convertView.findViewById(R.id.history_item_package); holder.packageIcon = (ImageView) convertView.findViewById(R.id.history_item_icon); convertView.setTag(holder); holder.packageLabel.setText(pkg.getPackageLabel()); holder.packageName.setText(pkg.getPackageName()); if (pkg.getPackageLabel().equalsIgnoreCase(pkg.getPackageName())) { holder.packageName.setVisibility(View.INVISIBLE); } String iconPath = Environment.getExternalStorageDirectory() + "/ShowJava/sources/" + pkg.getPackageName() + "/icon.png"; if (new File(iconPath).exists()) { Bitmap iconBitmap = BitmapFactory.decodeFile(iconPath); holder.packageIcon.setImageDrawable(new BitmapDrawable(getResources(), iconBitmap)); } else { holder.packageIcon.setImageResource(R.drawable.generic_icon); } return convertView; } }; listView.setAdapter(decompileHistoryItemArrayAdapter); listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { public void onItemClick(AdapterView<?> parent, View view, int position, long id) { final ViewHolder holder = (ViewHolder) view.getTag(); final File sourceDir = new File(Environment.getExternalStorageDirectory() + "/ShowJava/sources/" + holder.packageName.getText().toString() + ""); Intent i = new Intent(getApplicationContext(), JavaExplorer.class); i.putExtra("java_source_dir", sourceDir + "/"); i.putExtra("package_id", holder.packageName.getText().toString()); startActivity(i); } }); listView.setVisibility(View.VISIBLE); } } public void OpenAppListing(View v) { Intent i = new Intent(getApplicationContext(), AppListing.class); startActivity(i); } public void OpenFilePicker(View v) { Intent i = new Intent(this, FilePicker.class); i.putExtra(FilePickerActivity.EXTRA_ALLOW_MULTIPLE, false); i.putExtra(FilePickerActivity.EXTRA_ALLOW_CREATE_DIR, false); i.putExtra(FilePickerActivity.EXTRA_MODE, FilePickerActivity.MODE_FILE); i.putExtra(FilePickerActivity.EXTRA_START_PATH, Environment.getExternalStorageDirectory().getPath()); startActivityForResult(i, FILE_PICKER); } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == FILE_PICKER) { if (data != null) { Uri uri = data.getData(); File apkFile = new File(uri.getPath()); final String PackageDir = apkFile.getAbsolutePath(); Ln.d(PackageDir); final String PackageName; final String PackageId; if (FilenameUtils.isExtension(PackageDir, "apk")) { PackageManager pm = getPackageManager(); PackageInfo info = pm.getPackageArchiveInfo(PackageDir, PackageManager.GET_ACTIVITIES); if (info != null) { ApplicationInfo appInfo = info.applicationInfo; if (Build.VERSION.SDK_INT >= 8) { appInfo.sourceDir = PackageDir; appInfo.publicSourceDir = PackageDir; } PackageName = info.applicationInfo.loadLabel(getPackageManager()).toString(); PackageId = info.packageName; } else { PackageName = ""; PackageId = ""; } if(!prefs.getBoolean("hide_decompiler_select",false)){ final CharSequence[] items = { "CFR 0.102", "JaDX 0.6.1" }; 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) { Intent i = new Intent(getApplicationContext(), AppProcessActivity.class); i.putExtra("package_id", PackageId); i.putExtra("package_label", PackageName); i.putExtra("package_file_path", PackageDir); i.putExtra("decompiler", (item==1?"jadx":"cfr")); startActivity(i); } }); AlertDialog alert = builder.create(); alert.show(); } else { Intent i = new Intent(getApplicationContext(), AppProcessActivity.class); i.putExtra("package_id", PackageId); i.putExtra("package_label", PackageName); i.putExtra("package_file_path", PackageDir); i.putExtra("decompiler", prefs.getString("decompiler", "cfr")); startActivity(i); } } } } else { bp.handleActivityResult(requestCode, resultCode, data); } } private void cleanOldSources() { File dir = new File(Environment.getExternalStorageDirectory() + "/ShowJava"); if (dir.exists()) { File[] files = dir.listFiles(); for (File file : files) { if (!file.getName().equalsIgnoreCase("sources")) { try { if(file.exists()){ if(file.isDirectory()){ FileUtils.deleteDirectory(file); } else { file.delete(); } } } catch (Exception e) { Ln.d(e); } } } } else { dir.mkdirs(); } } @Override public void onResume() { super.onResume(); rerunHistoryLoader(); } private void rerunHistoryLoader() { HistoryLoader historyLoaderTwo = new HistoryLoader(); historyLoaderTwo.execute(); } private static class ViewHolder { TextView packageLabel; TextView packageName; ImageView packageIcon; int position; } private class HistoryLoader extends AsyncTask<String, String, List<SourceInfo>> { @Override protected List<SourceInfo> doInBackground(String... params) { List<SourceInfo> historyItems = new ArrayList<>(); File showJavaDir = new File(Environment.getExternalStorageDirectory() + "/ShowJava/"); showJavaDir.mkdirs(); File nomedia = new File(showJavaDir, ".nomedia"); if (!nomedia.exists() || !nomedia.isFile()) { try { nomedia.createNewFile(); } catch (IOException e) { Ln.d(e); } } File dir = new File(Environment.getExternalStorageDirectory() + "/ShowJava/sources"); if (dir.exists()) { File[] files = dir.listFiles(); if (files != null && files.length > 0) for (File file : files) { if (Utils.sourceExists(file)) { historyItems.add(Utils.getSourceInfoFromSourcePath(file)); } else { if (!Utils.isProcessorServiceRunning(baseContext)) { try { if (file.exists()) { if (file.isDirectory()) { FileUtils.deleteDirectory(file); } else { file.delete(); } } } catch (Exception e) { Ln.d(e); } } if (file.exists() && !file.isDirectory()) { file.delete(); } } } } return historyItems; } @Override protected void onPostExecute(List<SourceInfo> AllPackages) { SetupList(AllPackages); } @Override protected void onPreExecute() { } @Override protected void onProgressUpdate(String... text) { } } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) { switch (requestCode) { case Constants.STORAGE_PERMISSION_REQUEST: { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { initHistoryLoader(); } else { Toast.makeText(baseContext, "Storage permission is required to use this app", Toast.LENGTH_LONG).show(); finish(); } } } } @Override public void onBillingInitialized() { if(!isPro()) { bp.loadOwnedPurchasesFromGoogle(); } } @Override public void onProductPurchased(String productId, TransactionDetails transactionDetails) { } @Override public void onBillingError(int i, Throwable throwable) { Ln.e(throwable); } @Override public void onPurchaseHistoryRestored() { try { final TransactionDetails transactionDetails = bp.getPurchaseTransactionDetails(BuildConfig.IAP_PRODUCT_ID); if(transactionDetails.productId.equals(BuildConfig.IAP_PRODUCT_ID)) { AsyncHttpClient client = new AsyncHttpClient(); RequestParams params = new RequestParams(); params.put("payload", SV.gen(baseContext,transactionDetails.purchaseToken)); params.put("order_id", transactionDetails.orderId); client.post(com.njlabs.showjava.Constants.VERIFICATION_URL, params, new JsonHttpResponseHandler() { @Override public void onSuccess(int statusCode, Header[] headers, JSONObject response) { try { if (response.has("status") && response.getString("status").equals("ok")) { if (response.has("payload")) { if (SV.good(baseContext, response.getString("payload"), transactionDetails.purchaseToken)) { showPurchased(); } else { showError(); } } else { showError(); } } else { showError(); } } catch (JSONException e) { showError(); } } @Override public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { Ln.e(throwable); } }); } else { put(false); } } catch (Exception ignored) { put(false); } } @Override public void onDestroy() { if (bp != null) bp.release(); super.onDestroy(); } public void showError() { Toast.makeText(this, "Your purchase could not be verified.", Toast.LENGTH_SHORT).show(); } public void showPurchased() { put(true); Toast.makeText(this, "Thank you for purchasing Show Java Pro :)", Toast.LENGTH_SHORT).show(); } }