<commit_before>/**
 * 
 */
package org.commcare.android.util;

import java.util.HashSet;
import java.util.Hashtable;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import java.util.Vector;

import org.commcare.android.models.User;
import org.commcare.dalvik.R;
import org.commcare.suite.model.Detail;
import org.commcare.suite.model.Entry;
import org.commcare.suite.model.SessionDatum;
import org.commcare.suite.model.Suite;
import org.commcare.suite.model.Text;
import org.commcare.util.CommCareSession;
import org.javarosa.core.model.condition.EvaluationContext;
import org.javarosa.core.model.instance.TreeReference;

import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
import android.telephony.PhoneNumberUtils;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.util.Pair;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;

/**
 * @author ctsims
 *
 */
public class CallInPhoneListener extends PhoneStateListener {
	
	private Context context;
	private AndroidCommCarePlatform platform;
	
	private Hashtable<String, String[]> cachedNumbers;
	private User user;
	
	private Toast currentToast;
	
	private Timer toastTimer;
	
	private boolean running = false;
	
	public CallInPhoneListener(Context context, AndroidCommCarePlatform platform, User user) {
		this.context = context;
		this.platform = platform;
		cachedNumbers = new Hashtable<String, String[]>();
		this.user = user;
		toastTimer = new Timer("toastTimer");
	}

	
	@Override
	public void onCallStateChanged(int state, String incomingNumber) {
		super.onCallStateChanged(state, incomingNumber);
		if(state == TelephonyManager.CALL_STATE_RINGING) {
			String caller = getCaller(incomingNumber);
			if(caller != null) {
				LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
				View layout = inflater.inflate(R.layout.call_toast, null);
				TextView textView = (TextView)layout.findViewById(R.id.incoming_call_text);
				textView.setText("Incoming Call From: " + caller);
				
				currentToast = new Toast(context);
				currentToast.setDuration(Toast.LENGTH_LONG);
				
				currentToast.setView(layout);
				currentToast.setGravity(Gravity.BOTTOM, 0,0);
				running = true;
				startToastLoop();
			}
		} else {
			running = false;
		}
	}
	
	public void startToastLoop() {
		
		synchronized(toastTimer) {
			toastTimer.schedule(
					new TimerTask() {
						int runtimes = 0;
						public void run() {
							if(runtimes > 100 || running == false) {
								this.cancel();
							} else {
								runtimes++;
								currentToast.show();
							}
						}
					}, 0, 200);
		}
	}


	public void startCache() {
		
		AsyncTask<Void, Void, Void> loader = new AsyncTask<Void, Void, Void>() {

			@Override
			protected Void doInBackground(Void... params) {
				try {
					synchronized(cachedNumbers) {
						Hashtable<String,Pair<String, TreeReference>> detailSources = new Hashtable<String,Pair<String, TreeReference>>();
						Set<Detail> details = new HashSet<Detail>();
						
						
						//To fan this out, we first need to find the appropriate long detail screens
						//then determine what nodeset to use to iterate over it
						
						//First, collect the details we need to use.
						for(Suite s : platform.getInstalledSuites() ){
							for(Entry e : s.getEntries().values()) {
								//We won't bother trying to handle the situation where there's more than one
								//thing to collect, just yet. In the future, we'll fan out the whole thing.
								if(e.getSessionDataReqs().size() !=1) {
									continue;
								}
								SessionDatum datum = e.getSessionDataReqs().firstElement();
								String detailId = datum.getLongDetail();
								
								for(String form : s.getDetail(detailId).getTemplateForms()) {
									if("phone".equals(form)) {
										//Found some numbers! 
										
										//Check to see if we've already got a detail for this 
										if(detailSources.containsKey(detailId)) {
											
											//Ok. So in the future we should possibly run all of the details
											//we can where ID's don't match, but for now, we'll stick with the smallest<commit_msg>Apps without long details were not playing nice with the call listener<commit_after>/**
 * 
 */
package org.commcare.android.util;

import java.util.HashSet;
import java.util.Hashtable;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import java.util.Vector;

import org.commcare.android.models.User;
import org.commcare.dalvik.R;
import org.commcare.suite.model.Detail;
import org.commcare.suite.model.Entry;
import org.commcare.suite.model.SessionDatum;
import org.commcare.suite.model.Suite;
import org.commcare.suite.model.Text;
import org.commcare.util.CommCareSession;
import org.javarosa.core.model.condition.EvaluationContext;
import org.javarosa.core.model.instance.TreeReference;

import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
import android.telephony.PhoneNumberUtils;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.util.Pair;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;

/**
 * @author ctsims
 *
 */
public class CallInPhoneListener extends PhoneStateListener {
	
	private Context context;
	private AndroidCommCarePlatform platform;
	
	private Hashtable<String, String[]> cachedNumbers;
	private User user;
	
	private Toast currentToast;
	
	private Timer toastTimer;
	
	private boolean running = false;
	
	public CallInPhoneListener(Context context, AndroidCommCarePlatform platform, User user) {
		this.context = context;
		this.platform = platform;
		cachedNumbers = new Hashtable<String, String[]>();
		this.user = user;
		toastTimer = new Timer("toastTimer");
	}

	
	@Override
	public void onCallStateChanged(int state, String incomingNumber) {
		super.onCallStateChanged(state, incomingNumber);
		if(state == TelephonyManager.CALL_STATE_RINGING) {
			String caller = getCaller(incomingNumber);
			if(caller != null) {
				LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
				View layout = inflater.inflate(R.layout.call_toast, null);
				TextView textView = (TextView)layout.findViewById(R.id.incoming_call_text);
				textView.setText("Incoming Call From: " + caller);
				
				currentToast = new Toast(context);
				currentToast.setDuration(Toast.LENGTH_LONG);
				
				currentToast.setView(layout);
				currentToast.setGravity(Gravity.BOTTOM, 0,0);
				running = true;
				startToastLoop();
			}
		} else {
			running = false;
		}
	}
	
	public void startToastLoop() {
		
		synchronized(toastTimer) {
			toastTimer.schedule(
					new TimerTask() {
						int runtimes = 0;
						public void run() {
							if(runtimes > 100 || running == false) {
								this.cancel();
							} else {
								runtimes++;
								currentToast.show();
							}
						}
					}, 0, 200);
		}
	}


	public void startCache() {
		
		AsyncTask<Void, Void, Void> loader = new AsyncTask<Void, Void, Void>() {

			@Override
			protected Void doInBackground(Void... params) {
				try {
					synchronized(cachedNumbers) {
						Hashtable<String,Pair<String, TreeReference>> detailSources = new Hashtable<String,Pair<String, TreeReference>>();
						Set<Detail> details = new HashSet<Detail>();
						
						
						//To fan this out, we first need to find the appropriate long detail screens
						//then determine what nodeset to use to iterate over it
						
						//First, collect the details we need to use.
						for(Suite s : platform.getInstalledSuites() ){
							for(Entry e : s.getEntries().values()) {
								//We won't bother trying to handle the situation where there's more than one
								//thing to collect, just yet. In the future, we'll fan out the whole thing.
								if(e.getSessionDataReqs().size() !=1) {
									continue;
								}
								SessionDatum datum = e.getSessionDataReqs().firstElement();
								String detailId = datum.getLongDetail();
								if(detailId == null) { continue; }
								
								for(String form : s.getDetail(detailId).getTemplateForms()) {
									if("phone".equals(form)) {
										//Found some numbers! 
										
										//Check to see if we've already got a detail for this 
										if(detailSources.containsKey(detailId)) {
											
											//Ok. So in the future we should possibly run all of the details
											//we can where ID's don't match, but for now, we'll stick with the smallest
{'fraction_non_alphanumeric': 0.1050056882821388, 'fraction_numerical': 0.002502844141069397, 'mean_word_length': 3.3998998998999, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2766031', 'n_tokens_mistral': 3339, 'n_tokens_neox': 2557, 'n_words': 659}