/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package com.linkbubble.util; import android.app.Activity; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.res.Resources; import android.graphics.Canvas; import android.graphics.drawable.Drawable; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.ImageView; import android.widget.ListView; import android.widget.TextView; import com.linkbubble.BuildConfig; import com.linkbubble.Constant; import com.linkbubble.R; import com.linkbubble.Settings; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import se.emilsjolander.stickylistheaders.StickyListHeadersAdapter; import se.emilsjolander.stickylistheaders.StickyListHeadersListView; public class ActionItem { String mLabel; public Constant.ActionType mType; String mCategory; public String mPackageName; public String mActivityClassName; private Drawable mIcon; public ActionItem(Constant.ActionType type, Resources resources, String label, Drawable icon, String packageName, String activityClassName) { mType = type; mLabel = label; mCategory = resources.getString(type == Constant.ActionType.View ? R.string.consume_category_view : R.string.consume_category_share); mIcon = icon; mPackageName = packageName; mActivityClassName = activityClassName; } public String getLabel() { return mLabel; } public String getCategory() { return mCategory; } public interface OnActionItemSelectedListener { public void onSelected(ActionItem actionItem); } public interface OnActionItemDefaultSelectedListener { public void onSelected(ActionItem actionItem, boolean always); } private static ArrayList<ActionItem> getActionItems(Context context, boolean viewItems, boolean sendItems, boolean sharePicker) { final ArrayList<ActionItem> actionItems = new ArrayList<ActionItem>(); PackageManager packageManager = context.getPackageManager(); Resources resources = context.getResources(); if (viewItems) { List<ApplicationInfo> packages = packageManager.getInstalledApplications(PackageManager.GET_META_DATA); for (ApplicationInfo packageInfo : packages) { // Filter out system apps. Intent eachIntent = packageManager.getLaunchIntentForPackage(packageInfo.packageName); if (eachIntent == null) { continue; } // Ignore LinkBubble from this list if (Util.isValidBrowserPackageName(packageInfo.packageName)) { actionItems.add(new ActionItem(Constant.ActionType.View, resources, packageInfo.loadLabel(packageManager).toString(), packageInfo.loadIcon(packageManager), packageInfo.packageName, packageInfo.name)); } } } if (sendItems) { // Get list of handler apps that can send Intent intent = new Intent(Intent.ACTION_SEND); intent.setType("text/plain"); List<ResolveInfo> resolveInfos = packageManager.queryIntentActivities(intent, 0); for (ResolveInfo resolveInfo : resolveInfos) { if (resolveInfo.activityInfo.packageName.equals(BuildConfig.APPLICATION_ID) == false) { actionItems.add(new ActionItem(Constant.ActionType.Share, resources, resolveInfo.loadLabel(packageManager).toString(), resolveInfo.loadIcon(packageManager), resolveInfo.activityInfo.packageName, resolveInfo.activityInfo.name)); } } } if (sharePicker) { Intent intent = new Intent(Intent.ACTION_SEND); intent.setType("text/plain"); actionItems.add(new ActionItem(Constant.ActionType.Share, resources, context.getString(R.string.share_picker_label), context.getResources().getDrawable(R.drawable.ic_share_grey600_24dp), BuildConfig.APPLICATION_ID, Constant.SHARE_PICKER_NAME)); } Collections.sort(actionItems, new Comparator<ActionItem>() { @Override public int compare(ActionItem lhs, ActionItem rhs) { int categoryComparison = lhs.getCategory().compareTo(rhs.getCategory()); if (categoryComparison == 0) { return lhs.getLabel().compareTo(rhs.getLabel()); } return categoryComparison; } }); return actionItems; } public static AlertDialog getDefaultBrowserAlert(Context context, final OnActionItemSelectedListener onActionItemSelectedListener) { ArrayList<ActionItem> actionItems = getActionItems(context, true, false, false); ListView listView = new ListView(context); final AlertDialog alertDialog = new AlertDialog.Builder(context).create(); alertDialog.setIcon(Util.getAlertIcon(context)); alertDialog.setTitle(R.string.preference_default_browser); alertDialog.setView(listView); ActionItemAdapter adapter = new ActionItemAdapter(context, R.layout.action_picker_item, actionItems.toArray(new ActionItem[0])); listView.setAdapter(adapter); listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { Object tag = view.getTag(); if (tag instanceof ActionItem) { if (onActionItemSelectedListener != null) { onActionItemSelectedListener.onSelected((ActionItem) tag); } //Settings.get().setConsumeBubble(bubble, actionItem.mType, actionItem.getLabel(), // actionItem.mPackageName, actionItem.mActivityClassName); //preference.setSummary(Settings.get().getConsumeBubbleLabel(bubble)); alertDialog.dismiss(); } } }); return alertDialog; } public static AlertDialog getActionItemPickerAlert(Context context, final List<ResolveInfo> resolveInfos, int titleString, final OnActionItemDefaultSelectedListener onActionItemDefaultSelectedListener) { final ArrayList<ActionItem> actionItems = new ArrayList<ActionItem>(); Resources resources = context.getResources(); PackageManager packageManager = context.getPackageManager(); final int backgroundColorResourceId = Settings.get().getDarkThemeEnabled() ? R.color.color_list_background_dark : R.color.color_list_background_light; final int selectedBackgroundColorResourceId = Settings.get().getDarkThemeEnabled() ? R.color.color_list_selected_background_dark : R.color.color_list_selected_background_light; for (ResolveInfo resolveInfo : resolveInfos) { if (null == resolveInfo) { continue; } actionItems.add(new ActionItem(Constant.ActionType.View, resources, resolveInfo.loadLabel(packageManager).toString(), resolveInfo.loadIcon(packageManager), resolveInfo.activityInfo.packageName, resolveInfo.activityInfo.name)); } Collections.sort(actionItems, new Comparator<ActionItem>() { @Override public int compare(ActionItem lhs, ActionItem rhs) { int categoryComparison = lhs.getCategory().compareTo(rhs.getCategory()); if (categoryComparison == 0) { return lhs.getLabel().compareTo(rhs.getLabel()); } return categoryComparison; } }); class ActionItemListView extends ListView { boolean mDefaultSet = false; long mLastItemClickTime = -1; public ActionItemListView(Context context) { super(context); } @Override public void draw(Canvas canvas) { if (mDefaultSet == false) { Object tag = getTag(); if (tag != null && tag instanceof Integer) { int selectedIndex = (Integer)tag; if (getChildCount() > selectedIndex) { View child = getChildAt(selectedIndex); if (child != null) { child.setBackgroundResource(selectedBackgroundColorResourceId); mDefaultSet = true; } } } } super.draw(canvas); } } final ActionItemListView listView = new ActionItemListView(context); for (int i = 0; i < actionItems.size(); i++) { ActionItem actionItem = actionItems.get(i); if (actionItem.mPackageName.equals(context.getPackageName())) { continue; } // Set the first non-LinkBubble item as the current selection listView.setTag(i); break; } final AlertDialog alertDialog = new AlertDialog.Builder(context).create(); alertDialog.setIcon(Util.getAlertIcon(context)); alertDialog.setTitle(titleString); alertDialog.setView(listView); final ActionItemAdapter adapter = new ActionItemAdapter(context, R.layout.action_picker_item, actionItems.toArray(new ActionItem[0])); listView.setAdapter(adapter); listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { long currentTime = System.currentTimeMillis(); long clickDelta = currentTime - listView.mLastItemClickTime; // Check for a double-tap to emulate the behavior of the AOSP default app picker if (clickDelta < 350) { int selected = (Integer)listView.getTag(); if (selected == position) { ActionItem actionItem = actionItems.get(position); if (onActionItemDefaultSelectedListener != null) { onActionItemDefaultSelectedListener.onSelected(actionItem, false); } alertDialog.dismiss(); return; } } listView.mLastItemClickTime = currentTime; int viewChildCount = listView.getChildCount(); for (int i = 0; i < viewChildCount; i++) { View child = listView.getChildAt(i); child.setBackgroundResource(backgroundColorResourceId); } view.setBackgroundResource(selectedBackgroundColorResourceId); listView.setTag(position); /* Object tag = view.getTag(); if (tag instanceof ActionItem) { if (onActionItemDefaultSelectedListener != null) { onActionItemDefaultSelectedListener.onSelected((ActionItem) tag); } //Settings.get().setConsumeBubble(bubble, actionItem.mType, actionItem.getLabel(), // actionItem.mPackageName, actionItem.mActivityClassName); //preference.setSummary(Settings.get().getConsumeBubbleLabel(bubble)); alertDialog.dismiss(); }*/ } }); alertDialog.setButton(AlertDialog.BUTTON_POSITIVE, resources.getString(R.string.activity_resolver_use_once), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { try { int selectedItem = (Integer) listView.getTag(); ActionItem actionItem = actionItems.get(selectedItem); if (onActionItemDefaultSelectedListener != null) { onActionItemDefaultSelectedListener.onSelected(actionItem, false); } } catch (NullPointerException npe) { // XXX: ResolveInfos returning null in M preview releases. // See if we can remove this try/catch when M in final, but for now handle the crash. // Implemented in: 89b785a911f734e6ce6b0ecd1b7cb0ff75e88c25 CrashTracking.logHandledException(npe); } } }); alertDialog.setButton(AlertDialog.BUTTON_NEGATIVE, resources.getString(R.string.activity_resolver_use_always), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { try { int selectedItem = (Integer) listView.getTag(); ActionItem actionItem = actionItems.get(selectedItem); if (onActionItemDefaultSelectedListener != null) { onActionItemDefaultSelectedListener.onSelected(actionItem, true); } } catch (NullPointerException npe) { // XXX: ResolveInfos returning null in M preview releases. // See if we can remove this try/catch when M in final, but for now handle the crash. // Implemented in: 89b785a911f734e6ce6b0ecd1b7cb0ff75e88c25 CrashTracking.logHandledException(npe); } } }); return alertDialog; } public static AlertDialog getConfigureBubbleAlert(Context context, final OnActionItemSelectedListener onActionItemSelectedListener) { final ArrayList<ActionItem> actionItems = getActionItems(context, true, true, true); StickyListHeadersListView listView = new StickyListHeadersListView(context); final AlertDialog alertDialog = new AlertDialog.Builder(context).create(); alertDialog.setIcon(Util.getAlertIcon(context)); alertDialog.setTitle(R.string.preference_configure_bubble_title); alertDialog.setView(listView); ActionItemAdapter adapter = new ActionItemAdapter(context, R.layout.action_picker_item, actionItems.toArray(new ActionItem[0])); listView.setAdapter(adapter); listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { Object tag = view.getTag(); if (tag instanceof ActionItem) { if (onActionItemSelectedListener != null) { onActionItemSelectedListener.onSelected((ActionItem) tag); } alertDialog.dismiss(); } } }); alertDialog.setButton(AlertDialog.BUTTON_POSITIVE, context.getResources().getString(R.string.action_use_default), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { } }); alertDialog.setOnCancelListener(new DialogInterface.OnCancelListener() { @Override public void onCancel(DialogInterface dialog) { } }); return alertDialog; } public static AlertDialog getShareAlert(Context context, boolean showSharePicker, final OnActionItemSelectedListener onActionItemSelectedListener) { // Build the list of send applications AlertDialog.Builder builder = new AlertDialog.Builder(context); builder.setIcon(Util.getAlertIcon(context)); builder.setTitle(R.string.share_via); builder.setIcon(R.drawable.ic_launcher); final AlertDialog alertDialog = builder.create(); alertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); ArrayList<ActionItem> actionItems = getActionItems(context, false, true, showSharePicker); ActionItemAdapter adapter = new ActionItemAdapter(context, R.layout.action_picker_item, actionItems.toArray(new ActionItem[0])); ListView listView = new ListView(context); listView.setAdapter(adapter); listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { Object tag = view.getTag(); if (tag instanceof ActionItem) { if (onActionItemSelectedListener != null) { onActionItemSelectedListener.onSelected((ActionItem) tag); } alertDialog.dismiss(); } } }); alertDialog.setView(listView); return alertDialog; } private static class ActionItemAdapter extends ArrayAdapter<ActionItem> implements StickyListHeadersAdapter { Context mContext; int mLayoutResourceId; ActionItem mData[] = null; public ActionItemAdapter(Context context, int layoutResourceId, ActionItem[] data) { super(context, layoutResourceId, data); mLayoutResourceId = layoutResourceId; mContext = context; mData = data; } @Override public View getView(int position, View convertView, ViewGroup parent) { if(convertView==null){ LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); convertView = inflater.inflate(mLayoutResourceId, parent, false); } ActionItem actionItem = mData[position]; TextView label = (TextView) convertView.findViewById(R.id.label); label.setText(actionItem.getLabel()); ImageView icon = (ImageView) convertView.findViewById(R.id.icon); icon.setImageDrawable(actionItem.mIcon); convertView.setTag(actionItem); return convertView; } @Override public View getHeaderView(int position, View convertView, ViewGroup parent) { LayoutInflater inflater = ((Activity) mContext).getLayoutInflater(); convertView = inflater.inflate(R.layout.view_section_header, parent, false); ActionItem actionItem = mData[position]; TextView headerLabel = (TextView)convertView.findViewById(R.id.section_text); headerLabel.setText(actionItem.getCategory()); return convertView; } @Override public long getHeaderId(int position) { ActionItem actionItem = mData[position]; if (actionItem.mType == Constant.ActionType.View) { return 0; } else { return 1; } } } }