package yuku.alkitab.base.ac; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.LabeledIntent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.graphics.drawable.Drawable; import android.os.AsyncTask; import android.os.Bundle; import android.support.v7.app.ActionBar; import android.support.v7.widget.Toolbar; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.ListView; import android.widget.TextView; import com.afollestad.materialdialogs.MaterialDialog; import yuku.afw.V; import yuku.alkitab.base.App; import yuku.alkitab.base.ac.base.BaseActivity; import yuku.alkitab.debug.R; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; public class ShareActivity extends BaseActivity { public static final String TAG = ShareActivity.class.getSimpleName(); PackageManager mPm; ResolveListAdapter mAdapter; ListView lsIntent; public static Intent createIntent(Intent intent, String title) { Intent res = new Intent(App.context, ShareActivity.class); res.putExtra(Intent.EXTRA_INTENT, intent); res.putExtra(Intent.EXTRA_TITLE, title); return res; } public static class Result { public Intent chosenIntent; } public static Result obtainResult(Intent data) { if (data == null) return null; Result res = new Result(); res.chosenIntent = data.getParcelableExtra(Intent.EXTRA_INTENT); return res; } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_share); final Toolbar toolbar = V.get(this, R.id.toolbar); setSupportActionBar(toolbar); final ActionBar ab = getSupportActionBar(); assert ab != null; ab.setDisplayHomeAsUpEnabled(true); String title = getIntent().getStringExtra(Intent.EXTRA_TITLE); setTitle(title); final Intent intent = getIntent().getParcelableExtra(Intent.EXTRA_INTENT); final Intent[] initialIntents = null; final List<ResolveInfo> rList = null; lsIntent = V.get(this, R.id.lsIntent); // fix for memory leak: // https://github.com/square/leakcanary/blob/master/leakcanary-android/src/main/java/com/squareup/leakcanary/AndroidExcludedRefs.java // // UserManager has a static sInstance field that creates an instance and caches it the first // time UserManager.get() is called. This instance is created with the outer context (which // is an activity base context). // Tracked here: https://code.google.com/p/android/issues/detail?id=173789 // Introduced by: https://github.com/android/platform_frameworks_base/commit // /27db46850b708070452c0ce49daf5f79503fbde6 // Fix: trigger a call to UserManager.get() in Application.onCreate(), so that the // UserManager instance gets cached with a reference to the application context. // // This fix: instead of calling this.getPackageManager(), call getPackageManager // using the app context. mPm = getApplicationContext().getPackageManager(); intent.setComponent(null); // show progress dialog so that it does not appear to be hang final MaterialDialog pd = new MaterialDialog.Builder(this) .content(R.string.please_wait_titik3) .cancelable(false) .progress(true, 0) .show(); new AsyncTask<Void, Void, Void>() { @Override public Void doInBackground(Void... params) { mAdapter = new ResolveListAdapter(ShareActivity.this, intent, initialIntents, rList); return null; } @Override protected void onPostExecute(Void result) { lsIntent.setAdapter(mAdapter); pd.dismiss(); } }.execute(); lsIntent.setOnItemClickListener(lsIntent_itemClick); } private OnItemClickListener lsIntent_itemClick = new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { Intent intent = mAdapter.intentForPosition(position); Intent data = new Intent(); data.putExtra(Intent.EXTRA_INTENT, intent); setResult(RESULT_OK, data); finish(); } }; private final class DisplayResolveInfo { ResolveInfo ri; CharSequence displayLabel; Drawable displayIcon; CharSequence extendedInfo; Intent origIntent; List<ImageView> loadedListeners; DisplayResolveInfo(ResolveInfo pri, CharSequence pLabel, CharSequence pInfo, Intent pOrigIntent) { ri = pri; displayLabel = pLabel; extendedInfo = pInfo; origIntent = pOrigIntent; } } private final class ResolveListAdapter extends BaseAdapter { private final Intent mIntent; private final LayoutInflater mInflater; private List<DisplayResolveInfo> mList; public ResolveListAdapter(Context context, Intent intent, Intent[] initialIntents, List<ResolveInfo> rList) { mIntent = new Intent(intent); mIntent.setComponent(null); mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); if (rList == null) { rList = mPm.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY); } int N; if ((rList != null) && ((N = rList.size()) > 0)) { // Only display the first matches that are either of equal // priority or have asked to be default options. ResolveInfo r0 = rList.get(0); for (int i = 1; i < N; i++) { ResolveInfo ri = rList.get(i); if (r0.priority != ri.priority || r0.isDefault != ri.isDefault) { while (i < N) { rList.remove(i); N--; } } } if (N > 1) { ResolveInfo.DisplayNameComparator rComparator = new ResolveInfo.DisplayNameComparator(mPm); Collections.sort(rList, rComparator); } mList = new ArrayList<>(); // First put the initial items at the top. if (initialIntents != null) { for (Intent ii : initialIntents) { if (ii == null) { continue; } ActivityInfo ai = ii.resolveActivityInfo(getPackageManager(), 0); if (ai == null) { Log.w("ResolverActivity", "No activity found for " + ii); continue; } ResolveInfo ri = new ResolveInfo(); ri.activityInfo = ai; if (ii instanceof LabeledIntent) { LabeledIntent li = (LabeledIntent) ii; ri.resolvePackageName = li.getSourcePackage(); ri.labelRes = li.getLabelResource(); ri.nonLocalizedLabel = li.getNonLocalizedLabel(); ri.icon = li.getIconResource(); } mList.add(new DisplayResolveInfo(ri, ri.loadLabel(getPackageManager()), null, ii)); } } // Check for applications with same name and use application name or // package name if necessary r0 = rList.get(0); int start = 0; CharSequence r0Label = r0.loadLabel(mPm); for (int i = 1; i < N; i++) { if (r0Label == null) { r0Label = r0.activityInfo.packageName; } ResolveInfo ri = rList.get(i); CharSequence riLabel = ri.loadLabel(mPm); if (riLabel == null) { riLabel = ri.activityInfo.packageName; } if (riLabel.equals(r0Label)) { continue; } processGroup(rList, start, (i - 1), r0, r0Label); r0 = ri; r0Label = riLabel; start = i; } // Process last group processGroup(rList, start, (N - 1), r0, r0Label); } } private void processGroup(List<ResolveInfo> rList, int start, int end, ResolveInfo ro, CharSequence roLabel) { // Process labels from start to i int num = end - start + 1; if (num == 1) { // No duplicate labels. Use label for entry at start mList.add(new DisplayResolveInfo(ro, roLabel, null, null)); } else { boolean usePkg = false; CharSequence startApp = ro.activityInfo.applicationInfo.loadLabel(mPm); if (startApp == null) { usePkg = true; } if (!usePkg) { // Use HashSet to track duplicates HashSet<CharSequence> duplicates = new HashSet<>(); duplicates.add(startApp); for (int j = start + 1; j <= end; j++) { ResolveInfo jRi = rList.get(j); CharSequence jApp = jRi.activityInfo.applicationInfo.loadLabel(mPm); if ((jApp == null) || (duplicates.contains(jApp))) { usePkg = true; break; } else { duplicates.add(jApp); } } // Clear HashSet for later use duplicates.clear(); } for (int k = start; k <= end; k++) { ResolveInfo add = rList.get(k); if (usePkg) { // Use application name for all entries from start to end-1 mList.add(new DisplayResolveInfo(add, roLabel, add.activityInfo.packageName, null)); } else { // Use package name for all entries from start to end-1 mList.add(new DisplayResolveInfo(add, roLabel, add.activityInfo.applicationInfo.loadLabel(mPm), null)); } } } } public Intent intentForPosition(int position) { if (mList == null) { return null; } DisplayResolveInfo dri = mList.get(position); Intent intent = new Intent(dri.origIntent != null ? dri.origIntent : mIntent); // removed by yuku because we return the chosen intent instead of starting activity from here: // intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT | Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP); ActivityInfo ai = dri.ri.activityInfo; intent.setComponent(new ComponentName(ai.applicationInfo.packageName, ai.name)); return intent; } @Override public int getCount() { return mList != null ? mList.size() : 0; } @Override public Object getItem(int position) { return position; } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { View view; if (convertView == null) { view = mInflater.inflate(R.layout.item_share_intent, parent, false); } else { view = convertView; } bindView(view, mList.get(position)); return view; } private void bindView(View view, final DisplayResolveInfo info) { TextView text = (TextView) view.findViewById(android.R.id.text1); TextView text2 = (TextView) view.findViewById(android.R.id.text2); final ImageView icon = (ImageView) view.findViewById(R.id.icon); text.setText(info.displayLabel); if (info.extendedInfo != null) { text2.setVisibility(View.VISIBLE); text2.setText(info.extendedInfo); } else { text2.setVisibility(View.GONE); } // patch by yuku: load icon in the background so app does not hang icon.setTag(info); if (info.displayIcon != null) { icon.setImageDrawable(info.displayIcon); } else { icon.setImageDrawable(null); // kosongin dulu if (info.loadedListeners == null) { info.loadedListeners = new ArrayList<>(); info.loadedListeners.add(icon); new AsyncTask<Void, Void, Drawable>() { @Override protected Drawable doInBackground(Void... params) { Drawable res = info.ri.loadIcon(mPm); info.displayIcon = res; // set data only return res; } @Override protected void onPostExecute(Drawable result) { // set drawable if icon still refers to this info for (ImageView listener: info.loadedListeners) { if (listener.getTag() == info) { listener.setImageDrawable(result); } } // clear listeners info.loadedListeners = null; } }.execute(); } else { // it's already loading, just add listener. info.loadedListeners.add(icon); } } } } }