def build_and_run(self, install, avd_id, keystore=None, keystore_pass='******', keystore_alias='tidev', dist_dir=None):
		deploy_type = 'development'
		if install:
			if keystore == None:
				deploy_type = 'test'
			else:
				deploy_type = 'production'
				
		aapt = os.path.join(self.tools_dir,'aapt')
		jar = os.path.join(self.platform_dir,'android.jar')
		dx = os.path.join(self.tools_dir,'dx')
		apkbuilder = os.path.join(self.sdk,'tools','apkbuilder')
		if platform.system() == "Windows":
			aapt += ".exe"
			dx += ".bat"
			apkbuilder += ".bat"
		
		if keystore==None:
			keystore = os.path.join(self.support_dir,'dev_keystore')
		
		curdir = os.getcwd()
		tijar = os.path.join(self.support_dir,'titanium.jar')
		timapjar = os.path.join(self.support_dir,'titanium-map.jar')
		
		try:
			os.chdir(self.project_dir)
			
			if os.path.exists('bin'):
				shutil.rmtree('bin')
			os.makedirs('bin')
			
			if os.path.exists('lib'):
				shutil.copy(tijar,'lib')

			resources_dir = os.path.join(self.top_dir,'Resources')
			assets_dir = os.path.join('bin','assets')
			asset_resource_dir = os.path.join(assets_dir,'Resources')

			# we re-run the create each time through in case any of our key files
			# have changed
			android = Android(self.name,self.app_id,self.sdk)
			android.create(os.path.abspath(os.path.join(self.top_dir,'..')),True)

			# transform resources
			def strip_slash(s):
				if s[0:1]=='/' or s[0:1]=='\\': return s[1:]
				return s
			def recursive_cp(dir,dest):
				for root, dirs, files in os.walk(dir):
					# Remove file from the list of files copied
					# that shouldn't appear in the binaries
					for name in ignoreFiles:
						if name in files:
							files.remove(name);
					for name in ignoreDirs:
						if name in dirs:
							dirs.remove(name)
					# Copy remaining files
					relative = strip_slash(root.replace(dir,''))
					relative_dest = os.path.join(dest,relative)
					if not os.path.exists(relative_dest):
						os.makedirs(relative_dest)
					for f in files:
						fullpath = os.path.join(root,f)
						relativedest = os.path.join(dest,relative,f)
						print "[TRACE] COPYING: %s => %s" %(fullpath,relativedest)
						shutil.copy(fullpath,relativedest)

			if os.path.exists(asset_resource_dir):
				shutil.rmtree(asset_resource_dir)
			os.makedirs(asset_resource_dir)
			recursive_cp(resources_dir,asset_resource_dir)
			if os.path.exists(os.path.join(asset_resource_dir,'iphone')):
				shutil.rmtree(os.path.join(asset_resource_dir,'iphone'))
			if os.path.exists(os.path.join(resources_dir,'android')):
				recursive_cp(os.path.join(resources_dir,'android'),asset_resource_dir)		
				shutil.rmtree(os.path.join(asset_resource_dir,'android'))
				


			sys.stdout.flush()

			if not os.path.exists(assets_dir):
				os.makedirs(assets_dir)
				
			my_avd = None	
			google_apis_supported = False
				
			# find the AVD we've selected and determine if we support Google APIs
			for avd_props in avd.get_avds(self.sdk):
				if avd_props['id'] == avd_id:
					my_avd = avd_props
					google_apis_supported = (my_avd['name'].find('Google')!=-1)
					break

			# compile resources
			full_resource_dir = os.path.join(self.project_dir,asset_resource_dir)
			compiler = Compiler(self.app_id,full_resource_dir,False)
			compiler.compile()
			
			# Android SDK version --- FIXME: this is hardcoded until i hook in Nolan's code from Developer
			android_sdk_version = '3'
			
			# NOTE: these are built-in permissions we need -- we probably need to refine when these are needed too
			permissions_required = ['INTERNET','ACCESS_WIFI_STATE','ACCESS_NETWORK_STATE']
			
			GEO_PERMISSION = [ 'ACCESS_COARSE_LOCATION', 'ACCESS_FINE_LOCATION', 'ACCESS_MOCK_LOCATION']
			CONTACTS_PERMISSION = ['READ_CONTACTS']
			VIBRATE_PERMISSION = ['VIBRATE']
			CAMERA_PERMISSION = ['CAMERA']
			
			# this is our module method to permission(s) trigger - for each method on the left, require the permission(s) on the right
			permission_mapping = {
				# GEO
				'Geolocation.watchPosition' : GEO_PERMISSION,
				'Geolocation.getCurrentPosition' : GEO_PERMISSION,
				'Geolocation.watchHeading' : GEO_PERMISSION,
				'Geolocation.getCurrentHeading' : GEO_PERMISSION,
				
				# MEDIA
				'Media.vibrate' : VIBRATE_PERMISSION,
				'Media.createVideoPlayer' : CAMERA_PERMISSION,
				'Media.showCamera' : CAMERA_PERMISSION,
				
				# CONTACTS
				'Contacts.createContact' : CONTACTS_PERMISSION,
				'Contacts.saveContact' : CONTACTS_PERMISSION,
				'Contacts.removeContact' : CONTACTS_PERMISSION,
				'Contacts.addContact' : CONTACTS_PERMISSION,
				'Contacts.getAllContacts' : CONTACTS_PERMISSION,
				'Contacts.showContactPicker' : CONTACTS_PERMISSION,
			}
			
			VIDEO_ACTIVITY = """<activity
			android:name="org.appcelerator.titanium.TitaniumVideoActivity"
			android:configChanges="keyboardHidden|orientation"
			android:launchMode="singleTask"
	    	/>"""
	
			MAP_ACTIVITY = """<activity
	    		android:name="org.appcelerator.titanium.module.map.TitaniumMapActivity"
	    		android:configChanges="keyboardHidden|orientation"
	    		android:launchMode="singleTask"
	    	/>
		<uses-library android:name="com.google.android.maps" />"""
	
			FACEBOOK_ACTIVITY = """<activity 
			android:name="org.appcelerator.titanium.module.facebook.FBActivity"
			android:theme="@android:style/Theme.Translucent.NoTitleBar"
        />"""
			
			activity_mapping = {
			
				# MEDIA
				'Media.createVideoPlayer' : VIDEO_ACTIVITY,
				
				# MAPS
				'Map.createView' : MAP_ACTIVITY,
		    	
				# FACEBOOK
				'Facebook.setup' : FACEBOOK_ACTIVITY,
				'Facebook.login' : FACEBOOK_ACTIVITY,
				'Facebook.createLoginButton' : FACEBOOK_ACTIVITY,
			}
			
			# this is a map of our APIs to ones that require Google APIs to be available on the device
			google_apis = {
				"Map.createView" : True
			}
			
			activities = []
			
			# figure out which permissions we need based on the used module methods
			for mn in compiler.module_methods:
				try:
					perms = permission_mapping[mn]
					if perms:
						for perm in perms: 
							try:
								permissions_required.index(perm)
							except:
								permissions_required.append(perm)
				except:
					pass
				try:
					mappings = activity_mapping[mn]
					try:
						if google_apis[mn] and not google_apis_supported:
							print "[WARN] Google APIs detected but a device has been selected that doesn't support them. The API call to Titanium.%s will fail using '%s'" % (mn,my_avd['name'])
							sys.stdout.flush()
							continue
					except:
						pass
					try:
						activities.index(mappings)
					except:
						activities.append(mappings)
				except:
					pass
			
			# build the permissions XML based on the permissions detected
			permissions_required_xml = ""
			for p in permissions_required:
				permissions_required_xml+="<uses-permission android:name=\"android.permission.%s\"/>\n\t" % p				
			
			# copy any module image directories
			for module in compiler.modules:
				if module.lower() == 'map' and google_apis_supported:
					tijar = timapjar
					print "[INFO] Detected Google Maps dependency. Using Titanium + Maps"
				img_dir = os.path.abspath(os.path.join(template_dir,'modules',module.lower(),'images'))
				if os.path.exists(img_dir):
					dest_img_dir = os.path.join(full_resource_dir,'modules',module.lower(),'images')
					if os.path.exists(dest_img_dir):
						shutil.rmtree(dest_img_dir)
					os.makedirs(dest_img_dir)
					copy_resources(img_dir,dest_img_dir)
				

			shutil.copy(os.path.join(self.top_dir,'tiapp.xml'), assets_dir)
			
			tiapp = open(os.path.join(assets_dir, 'tiapp.xml')).read()
			
			finalxml = os.path.join(assets_dir,'tiapp.xml')
			tiapp = TiAppXML(finalxml)
			tiapp.setDeployType(deploy_type)
			
			iconname = tiapp.properties['icon']
			iconpath = os.path.join(asset_resource_dir,iconname)
			iconext = os.path.splitext(iconpath)[1]
			if not os.path.exists(os.path.join('res','drawable')):
				os.makedirs(os.path.join('res','drawable'))
				
			existingicon = os.path.join('res','drawable','appicon%s' % iconext)	
			if os.path.exists(existingicon):	
				os.remove(existingicon)
			if os.path.exists(iconpath):
				shutil.copy(iconpath,existingicon)

			# make our Titanium theme for our icon
			resfiledir = os.path.join('res','values')
			if not os.path.exists(resfiledir):
				os.makedirs(resfiledir)
			resfilepath = os.path.join(resfiledir,'theme.xml')
			if not os.path.exists(resfilepath):
				resfile = open(resfilepath,'w')
				TITANIUM_THEME="""<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="Theme.Titanium" parent="android:Theme">
        <item name="android:windowBackground">@drawable/background</item>
    </style>
</resources>
	"""
				resfile.write(TITANIUM_THEME)
				resfile.close()
			
			# create our background image which acts as splash screen during load	
			splashimage = os.path.join(asset_resource_dir,'default.png')
			if os.path.exists(splashimage):
				print "[DEBUG] found splash screen at %s" % os.path.abspath(splashimage)
				shutil.copy(splashimage,os.path.join('res','drawable','background.png'))
			
			

			src_dir = os.path.join(self.project_dir, 'src')
			android_manifest = os.path.join(self.project_dir, 'AndroidManifest.xml')
			
			android_manifest_to_read = android_manifest

			# NOTE: allow the user to use their own custom AndroidManifest if they put a file named
			# AndroidManifest.custom.xml in their android project directory in which case all bets are
			# off
			android_custom_manifest = os.path.join(self.project_dir, 'AndroidManifest.custom.xml')
			if os.path.exists(android_custom_manifest):
				android_manifest_to_read = android_custom_manifest
				print "[INFO] Detected custom ApplicationManifest.xml -- no Titanium version migration supported"
			
			# we need to write out the new manifest
			manifest_contents = open(android_manifest_to_read,'r').read()
			manifest_contents = manifest_contents.replace('<!-- TI_ACTIVITIES -->',"\n\n\t\t".join(activities))
			manifest_contents = manifest_contents.replace('<!-- TI_PERMISSIONS -->',permissions_required_xml)
			manifest_contents = manifest_contents.replace('<uses-sdk android:minSdkVersion="3" />', '<uses-sdk android:minSdkVersion="%s" />' % android_sdk_version)

			# write out the new manifest
			amf = open(android_manifest,'w')
			amf.write(manifest_contents)
			amf.close()
			
			res_dir = os.path.join(self.project_dir, 'res')
			output = run.run([aapt, 'package', '-m', '-J', src_dir, '-M', android_manifest, '-S', res_dir, '-I', jar])
			if output == None:
				sys.exit(1)
			success = re.findall(r'ERROR (.*)',output)
			if len(success) > 0:
				print "[ERROR] %s" % success[0]
				sys.exit(1)
			
			srclist = []
			jarlist = []
						
			for root, dirs, files in os.walk(os.path.join(self.project_dir,'src')):
				# Strip out directories we shouldn't traverse
				for name in ignoreDirs:
					if name in dirs:
						dirs.remove(name)
						
				if len(files) > 0:
					for f in files:
						if f in ignoreFiles : continue
						path = root + os.sep + f
						srclist.append(path)
		
			project_module_dir = os.path.join(self.top_dir,'modules','android')
			if os.path.exists(project_module_dir):
				for root, dirs, files in os.walk(project_module_dir):
					# Strip out directories we shouldn't traverse
					for name in ignoreDirs:
						if name in dirs:
							dirs.remove(name)

					if len(files) > 0:
						for f in files:
							path = root + os.sep + f
							ext = splitext(f)[-1]
							if ext in ('.java'):
								srclist.append(path)
							elif ext in ('.jar'):
								jarlist.append(path) 
				
		
			classes_dir = os.path.join(self.project_dir, 'bin', 'classes')	
			if not os.path.exists(classes_dir):
				os.makedirs(classes_dir)

			jarsigner = "jarsigner"	
			javac = "javac"
			if platform.system() == "Windows":
				if os.environ.has_key("JAVA_HOME"):
					home_jarsigner = os.path.join(os.environ["JAVA_HOME"], "bin", "jarsigner.exe")
					home_javac = os.path.join(os.environ["JAVA_HOME"], "bin", "javac.exe")
					if os.path.exists(home_jarsigner):
						jarsigner = home_jarsigner
					if os.path.exists(home_javac):
						javac = home_javac
				else:
					found = False
					for path in os.environ['PATH'].split(os.pathsep):
						if os.path.exists(os.path.join(path, 'jarsigner.exe')) and os.path.exists(os.path.join(path, 'javac.exe')):
							jarsigner = os.path.join(path, 'jarsigner.exe')
							javac = os.path.join(path, 'javac.exe')
							found = True
							break
					if not found:
						print "[ERROR] Error locating JDK: set $JAVA_HOME or put javac and jarsigner on your $PATH"
						sys.exit(1)
						
			# see if the user has app data and if so, compile in the user data
			# such that it can be accessed automatically using Titanium.App.Properties.getString
			app_data_cfg = os.path.join(self.top_dir,"appdata.cfg")
			if os.path.exists(app_data_cfg):
				props = read_properties(open(app_data_cfg,"r"))
				module_data = ''
				for key in props.keys():
					data = props[key]
					module_data+="properties.setString(\"%s\",\"%s\");\n   " % (key,data)
					print("[DEBUG] detected user application data at = %s"% app_data_cfg)
					sys.stdout.flush()
					dtf = os.path.join(src_dir,"AppUserData.java")
					if os.path.exists(dtf):
						os.remove(dtf)
					ctf = open(dtf,"w")
					cf_template = open(os.path.join(template_dir,'templates','AppUserData.java'),'r').read()
					cf_template = cf_template.replace('__MODULE_BODY__',module_data)
					ctf.write(cf_template)
					ctf.close()
					srclist.append(dtf)
						
			classpath = jar + os.pathsep + tijar + os.pathsep.join(jarlist)
			
			javac_command = [javac, '-classpath', classpath, '-d', classes_dir, '-sourcepath', src_dir]
			javac_command += srclist
			print "[DEBUG] %s" % javac_command
			sys.stdout.flush()
			out = run.run(javac_command)
			
		
			classes_dex = os.path.join(self.project_dir, 'bin', 'classes.dex')	
			if platform.system() == "Windows":
				run.run([dx, '--dex', '--output='+classes_dex, classes_dir, tijar])
			else:
				run.run([dx, '-JXmx512M', '--dex', '--output='+classes_dex, classes_dir, tijar])
										
			ap_ = os.path.join(self.project_dir, 'bin', 'app.ap_')	
			run.run([aapt, 'package', '-f', '-M', 'AndroidManifest.xml', '-A', assets_dir, '-S', 'res', '-I', jar, '-I', tijar, '-F', ap_])
		
			unsigned_apk = os.path.join(self.project_dir, 'bin', 'app-unsigned.apk')	
			run.run([apkbuilder, unsigned_apk, '-u', '-z', ap_, '-f', classes_dex, '-rf', src_dir, '-rj', tijar])
	
			if dist_dir:
				app_apk = os.path.join(dist_dir, project_name + '.apk')	
			else:
				app_apk = os.path.join(self.project_dir, 'bin', 'app.apk')	

			output = run.run([jarsigner, '-storepass', keystore_pass, '-keystore', keystore, '-signedjar', app_apk, unsigned_apk, keystore_alias])
			success = re.findall(r'RuntimeException: (.*)',output)
			if len(success) > 0:
				print "[ERROR] %s " %success[0]
				sys.exit(1)
				
			# NOTE: we can't zipalign until we officially support 1.6+
			# # attempt to zipalign -- this only exists in 1.6 and above so be nice
			# zipalign = os.path.join(self.tools_dir,'zipalign')
			# if platform.system() == "Windows":
			# 	zipalign+=".exe"
			# 	
			# if os.path.exists(zipalign):
			# 	#zipalign -v 4 source.apk destination.apk
			# 	run.run([zipalign, '-v', '4', app_apk, app_apk+'z'])
			# 	os.rename(app_apk+'z',app_apk)

			if dist_dir:
				sys.exit(0)			

			out = subprocess.Popen([self.adb,'get-state'], stderr=subprocess.PIPE, stdout=subprocess.PIPE).communicate()[0]
			out = str(out).strip()
			
			# try a few times as sometimes it fails waiting on boot
			attempts = 0
			launched = False
			launch_failed = False
			while attempts < 5:
				try:
					cmd = [self.adb]
					if install:
						self.wait_for_device('d')
						print "[INFO] Installing application on emulator"
						cmd += ['-d', 'install', '-r', app_apk]
					else:
						self.wait_for_device('e')
						print "[INFO] Installing application on device"
						cmd += ['-e', 'install', '-r', app_apk]
					if run.run(cmd)==None:
						launch_failed = True
					elif not install:
						launched = True
					break
				except:
					time.sleep(3)
					attempts+=1

			if launched:
				print "[INFO] Launching application ... %s" % self.name
				sys.stdout.flush()
				run.run([self.adb, '-e' , 'shell', 'am', 'start', '-a', 'android.intent.action.MAIN', '-c','android.intent.category.LAUNCHER', '-n', '%s/.%sActivity' % (self.app_id , self.classname)])
				print "[INFO] Deployed %s ... Application should be running." % self.name
			elif launch_failed==False:
				print "[INFO] Application installed. Launch from drawer on Home Screen"

		finally:
			os.chdir(curdir)
			sys.stdout.flush()