package org.softeg.slartus.forpdaplus.listfragments; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.database.sqlite.SQLiteDatabase; import android.text.Html; import android.text.InputType; import android.text.TextUtils; import android.view.ContextMenu; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.widget.AdapterView; import android.widget.BaseAdapter; import android.widget.EditText; import android.widget.Toast; import com.afollestad.materialdialogs.MaterialDialog; import org.softeg.slartus.forpdaapi.AppItem; import org.softeg.slartus.forpdaapi.IListItem; import org.softeg.slartus.forpdaapi.ListInfo; import org.softeg.slartus.forpdaplus.App; import org.softeg.slartus.forpdaplus.Client; import org.softeg.slartus.forpdaplus.R; import org.softeg.slartus.forpdaplus.classes.PdaApplication; import org.softeg.slartus.forpdaplus.common.AppLog; import org.softeg.slartus.forpdaplus.db.ApplicationRelationsTable; import org.softeg.slartus.forpdaplus.db.ApplicationsDbHelper; import org.softeg.slartus.forpdaplus.db.CacheDbHelper; import org.softeg.slartus.forpdaplus.db.DbHelper; import org.softeg.slartus.forpdaplus.listfragments.adapters.ListAdapter; import org.softeg.sqliteannotations.BaseDao; import java.io.IOException; import java.text.ParseException; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; public class AppsListFragment extends TopicsListFragment { public AppsListFragment() { super(); } @Override protected BaseAdapter createAdapter() { return new ListAdapter(getActivity(), mData, getPreferences().getBoolean("showSubMain", false)); } @Override protected ArrayList<? extends IListItem> loadTopics(Client client, ListInfo listInfo) throws IOException, ParseException { return loadItems(); } @Override protected void updateItem(IListItem item) { updateItemCache((AppItem) item, AppItem.class, true); } @Override public void saveCache() throws Exception { CacheDbHelper cacheDbHelper = new CacheDbHelper(App.getContext()); SQLiteDatabase db = null; try { db = cacheDbHelper.getWritableDatabase(); BaseDao<AppItem> baseDao = new BaseDao<>(App.getContext(), db, getListName(), AppItem.class); baseDao.createTable(db); for (IListItem item : mData) { AppItem news = (AppItem) item; baseDao.insert(news); } } finally { if (db != null) db.close(); } } @Override public void loadCache() throws IOException, IllegalAccessException, NoSuchFieldException, java.lang.InstantiationException { mCacheList=new ArrayList<>(); CacheDbHelper cacheDbHelper = new CacheDbHelper(App.getContext()); SQLiteDatabase db = null; try { db = cacheDbHelper.getReadableDatabase(); BaseDao<AppItem> baseDao = new BaseDao<>(App.getContext(), db, getListName(), AppItem.class); if (baseDao.isTableExists()) mCacheList.addAll(baseDao.getAll()); } finally { if (db != null) db.close(); } } public ArrayList<AppItem> loadItems() throws IOException { PackageManager packageManager = getContext().getPackageManager(); ArrayList<AppItem> apps = new ArrayList<>(); if (packageManager == null) return apps; List<PackageInfo> applications = packageManager.getInstalledPackages(0); ArrayList<String> appsName = new ArrayList<>(); for (PackageInfo application : applications) { if (isCancelled()) return null; if (application.applicationInfo == null) continue; if (!filterApp(application.applicationInfo)) continue; CharSequence title = application.applicationInfo.loadLabel(packageManager); AppItem topic = new AppItem("", title); topic.setDescription(application.packageName); topic.setPackageName(application.packageName); apps.add(topic); } //if(!compareFromCache(apps)) compareFromBases(appsName, apps); Boolean allFinded = apps.size() > 0;// если просто поставить тру, и нет apps, то неверно for (AppItem app : apps) { if (isCancelled()) return null; if (app.Ids.size() == 0) { allFinded = false; break; } } if (!allFinded) compareFromSite(appsName, apps); sort(apps); //saveCache(apps); return apps; } private void sort(ArrayList<AppItem> apps) { Collections.sort(apps, new Comparator<AppItem>() { public int compare(AppItem topic, AppItem topic1) { if (topic.getFindedState() != topic1.getFindedState()) { if (topic1.getFindedState() == AppItem.STATE_FINDED_AND_HAS_UPDATE) return 1; if (topic.getFindedState() == AppItem.STATE_FINDED_AND_HAS_UPDATE) return -1; if (topic1.getFindedState() == AppItem.STATE_UNFINDED) return -1; if (topic.getFindedState() == AppItem.STATE_UNFINDED) return 1; } return topic.getTitle().toString().toUpperCase().compareTo(topic1.getTitle().toString().toUpperCase()); } }); } private void compareFromBases(ArrayList<String> appsName, ArrayList<AppItem> apps) { SQLiteDatabase db = null; SQLiteDatabase appsDb = null; try { DbHelper dbHelper = new DbHelper(App.getInstance()); db = dbHelper.getReadableDatabase(); ApplicationsDbHelper applicationsDbHelper = new ApplicationsDbHelper(App.getInstance()); appsDb = applicationsDbHelper.getReadableDatabase(); for (AppItem app : apps) { if (isCancelled()) return; ArrayList<PdaApplication> pdaApps; try { pdaApps = ApplicationRelationsTable.getApplications(db, app.getPackageName()); for (PdaApplication pdaApplication : pdaApps) { if (isCancelled()) return; String id = Integer.toString(pdaApplication.AppUrl); app.Ids.add(id); app.setFindedState(AppItem.STATE_NORMAL); app.setId(id); } if (app.Ids.size() != 0) { appsName.add(null); continue; } } catch (Throwable ex) { AppLog.e(null, ex); } try { pdaApps = ApplicationRelationsTable.getApplications(appsDb, normalizePackName(app.getDescription().toString())); for (PdaApplication pdaApplication : pdaApps) { if (isCancelled()) return; String id = Integer.toString(pdaApplication.AppUrl); app.Ids.add(id); app.setFindedState(AppItem.STATE_NORMAL); app.setId(id); } //if (app.Ids.size() != 1) appsName.add(app.Ids.size() != 1 ? normalizeTitle(app.getTitle()) : null); } catch (Throwable ex) { AppLog.e(null, ex); } } } catch (IOException e) { e.printStackTrace(); } finally { if (db != null) db.close(); if (appsDb != null) appsDb.close(); } } private void compareFromSite(ArrayList<String> appsName, ArrayList<AppItem> apps) throws IOException { final String appCatalogUrl = "http://4pda.ru/forum/index.php?showtopic=112220"; final String gameCatalogUrl = "http://4pda.ru/forum/index.php?showtopic=117270"; // Client.getInstance().doOnOnProgressChanged(progressChangedListener, "Получение данных..."); String gamesBody = Client.getInstance().loadPageAndCheckLogin(gameCatalogUrl, null); String appsBody = Client.getInstance().loadPageAndCheckLogin(appCatalogUrl, null); // Client.getInstance().doOnOnProgressChanged(progressChangedListener, "Обработка данных..."); Matcher m = Pattern.compile("http://4pda.ru/forum/index.php\\?showtopic=(\\d+)[^\"]*?. target=._blank.>(.*?)</a>(.*?)</li>", Pattern.CASE_INSENSITIVE) .matcher(gamesBody); compareFromMatcher(appsName, apps, m); m = Pattern.compile("<a href=\"(?:http://4pda.ru)?/forum/index.php\\?showtopic=(\\d+)\" target=._blank.>(.*?)</a>.*?(?:</b>)? - (.*?)<", Pattern.CASE_INSENSITIVE) .matcher(appsBody); compareFromMatcher(appsName, apps, m); } private void compareFromMatcher(ArrayList<String> appsName, ArrayList<AppItem> apps, Matcher m) { while (m.find()) { String id = m.group(1); AppItem app; while ((app = findById(apps, id)) != null) { if (isCancelled()) return; app.Ids.clear(); app.setId(id); app.setDescription(Html.fromHtml(m.group(3))); app.setFindedState(AppItem.STATE_NORMAL); } String normTitle = normalizeTitle(m.group(2)); for (int i = 0; i < appsName.size(); i++) { if (isCancelled()) return; if (normTitle.equals(appsName.get(i))) { app = apps.get(i); app.Ids.clear(); app.setId(id); app.setDescription(Html.fromHtml(m.group(3))); app.setFindedState(AppItem.STATE_NORMAL); appsName.set(i, null); } } } } private Boolean filterApp(ApplicationInfo info) { if ((info.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) { return true; } else if ((info.flags & ApplicationInfo.FLAG_SYSTEM) == 0) { return true; } return false; } private static final CharSequence normalizePattern = "\\d+|alpha|beta|pro|trial|free|plus|premium|donate|demo|paid|special|next|hd|ultimate|pc|lite|classic"; public static String normalizeTitle(CharSequence title) { return title.toString().toLowerCase().replaceAll("\\.?(" + normalizePattern + ")$|\\.?\\d+\\.?|\\s+", ""); } private static String normalizePackName(String packName) { return packName.toLowerCase().replaceAll("\\.?(" + normalizePattern + ")$", "").replaceAll("\\.(" + normalizePattern + ")\\.", "%"); } @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) { try { super.onCreateContextMenu(menu,v,menuInfo); AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo; if (info.id == -1) return; Object o = getAdapter().getItem((int) info.id); if (o == null) return; //if (TextUtils.isEmpty(topic.getId())) return; final AppItem appItem = (AppItem) o; menu.add(R.string.associate_with_theme).setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { public boolean onMenuItemClick(MenuItem menuItem) { MaterialDialog.Builder builder = new MaterialDialog.Builder(getContext()); builder.title(R.string.enter_url_theme); final EditText input = new EditText(getContext()); input.setInputType(InputType.TYPE_CLASS_TEXT); input.setText(appItem.getId()); builder.customView(input,true); builder.positiveText(android.R.string.ok); builder.negativeText(android.R.string.cancel); builder.callback(new MaterialDialog.ButtonCallback() { @Override public void onPositive(MaterialDialog dialog) { String text = input.getText() == null ? "" : input.getText().toString(); if (TextUtils.isEmpty(text)) { Toast.makeText(getContext(), R.string.empty_url, Toast.LENGTH_SHORT).show(); return; } Matcher m = Pattern.compile("showtopic=(\\d+)").matcher(text.trim()); if (!m.find()) { m = Pattern.compile("(\\d+)").matcher(text.trim()); if (m.find()) { if (m.group(1).length() != text.trim().length()) { Toast.makeText(getContext(), R.string.incorrect_url, Toast.LENGTH_SHORT).show(); return; } } else { Toast.makeText(getContext(), R.string.incorrect_url, Toast.LENGTH_SHORT).show(); return; } } ApplicationRelationsTable.addRealtion(appItem.getPackageName(), m.group(1)); appItem.setFindedState(AppItem.STATE_FINDED); appItem.setId(m.group(1)); mAdapter.notifyDataSetChanged(); } @Override public void onNegative(MaterialDialog dialog) { dialog.cancel(); } }); builder.show(); return true; } }); } catch (Throwable ex) { AppLog.e(getContext(), ex); } } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { menu.removeItem(settingItemId); } private AppItem findById(ArrayList<AppItem> apps, CharSequence id) { for (AppItem app : apps) { if (app.Ids.contains(id)) return app; } return null; } }