package org.witness.informacam.app.screens.popups; import info.guardianproject.iocipher.File; import info.guardianproject.iocipher.camera.io.IOCipherContentProvider; import info.guardianproject.netcipher.proxy.OrbotHelper; import java.io.IOException; import java.security.NoSuchAlgorithmException; import java.security.SignatureException; import java.util.ArrayList; import java.util.List; import org.javarosa.core.services.Logger; import org.spongycastle.openpgp.PGPException; import org.witness.informacam.InformaCam; import org.witness.informacam.app.R; import org.witness.informacam.app.utils.Constants.App; import org.witness.informacam.app.utils.UIHelpers; import org.witness.informacam.models.media.IMedia; import org.witness.informacam.models.organizations.IInstalledOrganizations; import org.witness.informacam.models.organizations.IOrganization; import org.witness.informacam.utils.Constants.Codes; import org.witness.informacam.utils.Constants.Models; import android.annotation.SuppressLint; import android.app.Activity; import android.app.Dialog; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.Window; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.ArrayAdapter; import android.widget.LinearLayout; import android.widget.ListAdapter; import android.widget.ListView; import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonElement; import com.google.gson.JsonParser; public class SharePopup { LayoutInflater li; ArrayList<IMedia> mediaList; ArrayList<Uri> mediaListUri; int exportCounter = 0; protected final static String LOG = App.Home.LOG; InformaCam informaCam; View tvTitleShareOrg, divider1, tvTitleShare, divider2; ListView mLvItems; ListView mLvItemsOrg; ProgressBar inProgressBar; LinearLayout inProgressRoot; List<IOrganization> organizations; HandlerIntent sendTo = null; IOrganization encryptTo = null; Activity a; Handler h; private final Dialog alert; private boolean isLocalShare = false; private int shareType = SHARE_TYPE_MEDIA; public final static int SHARE_TYPE_MEDIA = 0; public final static int SHARE_TYPE_J3M = 1; public final static int SHARE_TYPE_CSV = 2; public SharePopup(Activity a, final ArrayList<IMedia> mediaList, boolean isLocalShare) { this(a, mediaList, false, SHARE_TYPE_MEDIA, isLocalShare); } @SuppressLint("HandlerLeak") public SharePopup(final Activity a, final ArrayList<IMedia> mediaList, boolean startsInforma, int shareType, boolean isLocalShare) { this.a = a; alert = new Dialog(a); alert.requestWindowFeature(Window.FEATURE_NO_TITLE); alert.setContentView(R.layout.popup_share); this.mediaList = mediaList; this.shareType = shareType; this.isLocalShare = isLocalShare; mediaListUri = new ArrayList<Uri>(); informaCam = InformaCam.getInstance(); mLvItems = (ListView) alert.findViewById(R.id.lvItems); mLvItemsOrg = (ListView) alert.findViewById(R.id.lvItemsOrg); inProgressRoot = (LinearLayout) alert .findViewById(R.id.share_in_progress_root); inProgressBar = (ProgressBar) alert .findViewById(R.id.share_in_progress_bar); tvTitleShare = alert.findViewById(R.id.tvTitleShare); tvTitleShareOrg = alert.findViewById(R.id.tvTitleShareOrg); divider1 = alert.findViewById(R.id.divider1); divider2 = alert.findViewById(R.id.divider2); li = LayoutInflater.from(a); try { initLayout(); } catch (Exception e) { Log.e("Share Popup","error setting up popup layout",e); return; } h = new Handler() { @Override public void handleMessage(Message msg) { Bundle b = msg.getData(); if(b.containsKey(Models.IMedia.VERSION)) { java.io.File fileShare = new java.io.File(b.getString(Models.IMedia.VERSION)); if (fileShare.exists()) //this is an external, unencrypted share { mediaListUri.add(Uri.fromFile(fileShare)); } else { String sharePath = b.getString(Models.IMedia.VERSION); String uriPath = IOCipherContentProvider.addShare(sharePath,"org.witness.informacam"); mediaListUri.add(Uri.parse(uriPath)); } exportCounter++; if (exportCounter == mediaList.size()) { inProgressBar.setProgress(100); alert.cancel(); if (sendTo != null && b.getString(Models.IMedia.VERSION) != null) { sendTo.intent.setClassName( sendTo.resolveInfo.activityInfo.packageName, sendTo.resolveInfo.activityInfo.name); sendTo.intent.setType("*/*"); if (mediaListUri.size() > 1) { String title = a.getString(R.string.share_from_) + a.getString(R.string.app_name); // sendTo.intent.putExtra(Intent.EXTRA_TITLE, title); sendTo.intent.putExtra(Intent.EXTRA_SUBJECT, title); sendTo.intent.setAction(Intent.ACTION_SEND_MULTIPLE); sendTo.intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, mediaListUri); } else { String title = a.getString(R.string.share_from_) + a.getString(R.string.app_name) + ' ' + fileShare.getName(); // sendTo.intent.putExtra(Intent.EXTRA_TITLE, title); sendTo.intent.putExtra(Intent.EXTRA_SUBJECT, title); //if a google app like gmail, hangouts or drive is being used, then add the extra_text if (sendTo.resolveInfo.activityInfo.packageName.startsWith("com.google")) { try { String value = generateJ3MSummary(a, b.getString(Models.IMedia._ID)); sendTo.intent.putExtra(Intent.EXTRA_TEXT, value); } catch (Exception ioe) { Log.e("Export","error generate j3M",ioe); } } sendTo.intent.setData(mediaListUri.get(0)); sendTo.intent.putExtra(Intent.EXTRA_STREAM, mediaListUri.get(0)); sendTo.intent.setAction(Intent.ACTION_SEND); } a.startActivity(sendTo.intent); } } else { inProgressBar.setProgress((int)(100*(((float)exportCounter)/((float)mediaList.size())))); } } else if(b.containsKey(Codes.Keys.UI.PROGRESS)) { //inProgressBar.setProgress(b.getInt(Codes.Keys.UI.PROGRESS)); } else if (msg.what == -1) { inProgressBar.setProgress(100); alert.cancel(); String errMsg = b.getString("msg"); Toast.makeText(a,errMsg, Toast.LENGTH_LONG).show(); } else if (msg.what == Codes.Messages.Transport.ORBOT_UNINSTALLED) { Intent intent = OrbotHelper.getOrbotInstallIntent(informaCam); informaCam.startActivity(intent); } else if (msg.what == Codes.Messages.Transport.ORBOT_NOT_RUNNING) { OrbotHelper.requestStartTor(informaCam); } } }; alert.show(); alert.getWindow().setBackgroundDrawable( new ColorDrawable(android.graphics.Color.TRANSPARENT)); } public String generateJ3MSummary (Context context, String id) throws InstantiationException, IllegalAccessException, NoSuchAlgorithmException, SignatureException, PGPException, IOException { IMedia media = informaCam.mediaManifest.getById(id); //String j3m = ((IMedia) media).buildJ3M(context, signData, null); //Gson gson = new GsonBuilder().setPrettyPrinting().create(); //JsonParser jp = new JsonParser(); //JsonElement je = jp.parse(j3m); //String prettyJsonString = gson.toJson(je); String prettyString = ((IMedia) media).buildSummary(context, null); return prettyString; } private void initLayout() throws IllegalAccessException, InstantiationException, IOException { initData(); } private void initData() throws IllegalAccessException, InstantiationException, IOException { informaCam = InformaCam.getInstance(); ListAdapter adapter = null; ArrayList<Object> shareDestinations = new ArrayList<Object>(); /* * //REMOVE SPECIFIC ORG SHARING FOR NOW IInstalledOrganizations installedOrganizations = (IInstalledOrganizations) informaCam.getModel(new IInstalledOrganizations()); // Add organizations if(installedOrganizations.organizations != null && installedOrganizations.organizations.size() > 0) { organizations = installedOrganizations.organizations; for(IOrganization org : organizations) { shareDestinations.add(org); } } ListAdapter adapter = new HandlerIntentListAdapter(a, shareDestinations.toArray(new Object[shareDestinations.size()])); mLvItemsOrg.setAdapter(adapter); */ // Add other handlers shareDestinations.clear(); Intent intent = new Intent(Intent.ACTION_SEND); intent.setType("*/*"); getHandlersForIntent(intent, shareDestinations); adapter = new HandlerIntentListAdapter(a, shareDestinations.toArray(new Object[shareDestinations.size()])); mLvItems.setAdapter(adapter); OnItemClickListener listener = new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { Object handler = parent.getAdapter().getItem(position); if (handler instanceof IOrganization) { encryptTo = organizations.get(position); sendTo = null; Log.d(LOG, "now exporting to " + encryptTo.organizationName); export(); } else if (handler instanceof HandlerIntent) { encryptTo = null; sendTo = (HandlerIntent) handler; Log.d(LOG, "now sending to " + sendTo.toString()); export(); } } }; mLvItems.setOnItemClickListener(listener); mLvItemsOrg.setOnItemClickListener(listener); } private void export() { mLvItemsOrg.setVisibility(View.GONE); mLvItems.setVisibility(View.GONE); inProgressRoot.setVisibility(View.VISIBLE); if (sendTo != null) { tvTitleShareOrg.setVisibility(View.GONE); divider1.setVisibility(View.GONE); } else { tvTitleShare.setVisibility(View.GONE); divider2.setVisibility(View.GONE); } new Thread(new Runnable() { @Override public void run() { try { boolean doSendTo = sendTo != null; for (IMedia media : mediaList) { if (shareType == SHARE_TYPE_J3M) media.exportJ3M(a, h, encryptTo, doSendTo); else if (shareType == SHARE_TYPE_CSV) media.exportCSV(a, h, encryptTo, doSendTo); else media.export(a, h, null, true, isLocalShare, false); } } catch (Exception e) { Logger.exception(LOG, e); Message msg = new Message(); msg.what = -1; msg.getData().putString("msg", "Error exporting metadata: " + e.getMessage()); h.sendMessage(msg); } } }).start(); } private class HandlerIntent { public final Intent intent; public final ResolveInfo resolveInfo; public HandlerIntent(Intent intent, ResolveInfo resolveInfo) { this.intent = intent; this.resolveInfo = resolveInfo; } } private class HandlerIntentListAdapter extends ArrayAdapter<Object> { public HandlerIntentListAdapter(Context context, Object[] intents) { super(context, android.R.layout.select_dialog_item, android.R.id.text1, intents); } @Override public View getView(int position, View convertView, ViewGroup parent) { // User super class to create the View View v = super.getView(position, convertView, parent); TextView tv = (TextView) v.findViewById(android.R.id.text1); Object handler = getItem(position); int iconSize = UIHelpers.dpToPx(32, getContext()); if (handler instanceof IOrganization) { IOrganization org = (IOrganization) handler; tv.setText(org.organizationName); //todo load the org's icon from bundle or remote site //Drawable icon = a.getResources().getDrawable( // R.drawable.ic_share_iba); //icon.setBounds(0, 0, iconSize, iconSize); //tv.setCompoundDrawables(icon, null, null, null); tv.setCompoundDrawablePadding(UIHelpers.dpToPx(10, getContext())); } else if (handler instanceof HandlerIntent) { HandlerIntent handlerIntent = (HandlerIntent) handler; ResolveInfo info = handlerIntent.resolveInfo; PackageManager pm = getContext().getPackageManager(); tv.setText(info.loadLabel(pm)); Drawable icon = info.loadIcon(pm); icon.setBounds(0, 0, iconSize, iconSize); // Put the image on the TextView tv.setCompoundDrawables(icon, null, null, null); tv.setCompoundDrawablePadding(UIHelpers.dpToPx(10, getContext())); } // Add margin between image and text (support various screen // densities) int dp5 = (int) (5 * a.getResources().getDisplayMetrics().density + 0.5f); tv.setCompoundDrawablePadding(dp5); return v; } }; private void getHandlersForIntent(Intent intent, ArrayList<Object> rgIntents) { PackageManager pm = a.getPackageManager(); List<ResolveInfo> resInfos = pm.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY); for (ResolveInfo resInfo : resInfos) { rgIntents.add(new HandlerIntent(intent, resInfo)); } } }