152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project#!/usr/bin/ruby
252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project#
352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project# Find unused resources in all the apps found recursively under the current directory
452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project# Usage:
552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project#   find_unused_resources.rb [-html]
652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project#
752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project# If -html is specified, the output will be HTML, otherwise it will be plain text
852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project#
952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project# Author: cbeust@google.com
1052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
1152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectrequire 'find'
1252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
1352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectdebug = false
1452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
1552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project@@stringIdPattern = Regexp.new("name=\"([@_a-zA-Z0-9 ]*)\"")
1652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project@@layoutIdPattern = Regexp.new("android:id=\".*id/([_a-zA-Z0-9]*)\"")
1752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
1852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project@@stringXmlPatterns = [
1952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  Regexp.new("@string/([_a-zA-Z0-9]*)"),
2052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  Regexp.new("@array/([_a-zA-Z0-9]*)"),
2152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project]
2252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
2352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project@@javaIdPatterns = [
2452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  Regexp.new("R.id.([_a-zA-Z0-9]+)"),
2552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  Regexp.new("R.string.([_a-zA-Z0-9]+)"),
2652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  Regexp.new("R.array.([_a-zA-Z0-9]+)"),
2752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  Regexp.new("R.color.([_a-zA-Z0-9]+)"),
2852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  Regexp.new("R.configVarying.([_a-zA-Z0-9]+)"),
2952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  Regexp.new("R.dimen.([_a-zA-Z0-9]+)"),
3052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project]
3152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
3252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
3352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project@@appDir = "partner/google/apps/Gmail"
3452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
3552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectdef findResDirectories(root)
3652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  result = Array.new
3752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  Find.find(root) do |path|
3852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    if FileTest.directory?(path)
3952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project      if File.basename(path) == "res"
4052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        result << path
4152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project      else
4252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        next
4352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project      end
4452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    end
4552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  end
4652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  result
4752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectend
4852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
4952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectclass UnusedResources
5052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  attr_accessor :appDir, :unusedLayoutIds, :unusedStringIds
5152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectend
5252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
5352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectclass FilePosition
5452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  attr_accessor :file, :lineNumber
5552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
5652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  def initialize(f, ln)
5752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    @file = f
5852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    @lineNumber = ln
5952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  end
6052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
6152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  def to_s
6252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    "#{file}:#{lineNumber}"
6352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  end
6452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
6552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  def <=>(other)
6652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    if @file == other.file
6752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project      @lineNumber - other.lineNumber
6852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    else
6952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project      @file <=> other.file
7052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    end
7152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  end
7252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectend
7352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
7452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
7552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectdef findAllOccurrences(re, string)
7652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  result = Array.new
7752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
7852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  s = string
7952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  matchData = re.match(s)
8052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  while (matchData)
8152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    result << matchData[1].to_s
8252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    s = s[matchData.end(1) .. -1]
8352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    matchData = re.match(s)
8452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  end
8552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
8652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  result
8752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectend
8852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
8952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project@@globalJavaIdUses = Hash.new
9052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
9152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectdef recordJavaUses(glob)
9252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  Dir.glob(glob).each { |filename|
9352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    File.open(filename) { |file|
9452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project      file.each { |line|
9552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project	@@javaIdPatterns.each { |re|
9652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project          findAllOccurrences(re, line).each { |id|
9752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            @@globalJavaIdUses[id] = FilePosition.new(filename, file.lineno)
9852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project	  }
9952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        }
10052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project      }
10152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    }
10252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  }
10352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectend
10452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
10552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectdef findUnusedResources(dir)
10652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  javaIdUses = Hash.new
10752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  layouts = Hash.new
10852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  strings = Hash.new
10952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  xmlIdUses = Hash.new
11052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
11152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  Dir.glob("#{dir}/res/**/*.xml").each { |filename|
11252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    if ! (filename =~ /attrs.xml$/)
11352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project      File.open(filename) { |file|
11452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        file.each { |line|
11552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project          findAllOccurrences(@@stringIdPattern, line).each {|id|
11652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            strings[id] = FilePosition.new(filename, file.lineno)
11752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project          }
11852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project          findAllOccurrences(@@layoutIdPattern, line).each {|id|
11952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            layouts[id] = FilePosition.new(filename, file.lineno)
12052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project          }
12152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project          @@stringXmlPatterns.each { |re|
12252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            findAllOccurrences(re, line).each {|id|
12352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project              xmlIdUses[id] = FilePosition.new(filename, file.lineno)
12452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            }
12552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project          }
12652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        }
12752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project      }
12852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    end
12952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  }
13052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project 
13152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  Dir.glob("#{dir}/AndroidManifest.xml").each { |filename|
13252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    File.open(filename) { |file|
13352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project      file.each { |line|
13452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        @@stringXmlPatterns.each { |re|
13552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project          findAllOccurrences(re, line).each {|id|
13652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project            xmlIdUses[id] = FilePosition.new(filename, file.lineno)
13752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project          }
13852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project        }
13952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project      }
14052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    }
14152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  }
14252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
14352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  recordJavaUses("#{dir}/src/**/*.java")
14452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
14552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  @@globalJavaIdUses.each_pair { |id, file|
14652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    layouts.delete(id)
14752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    strings.delete(id)
14852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  }
14952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
15052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  javaIdUses.each_pair { |id, file|
15152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    layouts.delete(id)
15252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    strings.delete(id)
15352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  }
15452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
15552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  xmlIdUses.each_pair { |id, file|
15652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    layouts.delete(id)
15752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    strings.delete(id)
15852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  }
15952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
16052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  result = UnusedResources.new
16152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  result.appDir = dir
16252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  result.unusedLayoutIds = layouts
16352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  result.unusedStringIds = strings
16452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
16552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  result
16652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectend
16752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
16852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectdef findApps(dir)
16952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  result = Array.new
17052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  Dir.glob("#{dir}/**/res").each { |filename|
17152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    a = filename.split("/")
17252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    result << a.slice(0, a.size-1).join("/")
17352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  }
17452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  result
17552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectend
17652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
17752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectdef displayText(result)
17852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  result.each { |unusedResources|
17952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    puts "=== #{unusedResources.appDir}"
18052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
18152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    puts "----- Unused layout ids"
18252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    unusedResources.unusedLayoutIds.sort { |id, file| id[1] <=> file[1] }.each {|f|
18352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project      puts "    #{f[0]} #{f[1]}"
18452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    }
18552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
18652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project 
18752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    puts "----- Unused string ids"
18852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    unusedResources.unusedStringIds.sort { |id, file| id[1] <=> file[1] }.each {|f|
18952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project      puts "    #{f[0]} #{f[1]}"
19052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    }
19152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project 
19252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  }
19352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectend
19452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
19552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectdef displayHtmlUnused(unusedResourceIds, title)
19652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
19752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  puts "<h3>#{title}</h3>"
19852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  puts "<table border='1'>"
19952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  unusedResourceIds.sort { |id, file| id[1] <=> file[1] }.each {|f|
20052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    puts "<tr><td><b>#{f[0]}</b></td> <td>#{f[1]}</td></tr>"
20152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  }
20252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  puts "</table>"
20352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectend
20452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
20552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectdef displayHtml(result)
20652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  title = "Unused resources as of #{Time.now.localtime}"
20752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  puts "<html><header><title>#{title}</title></header><body>"
20852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
20952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  puts "<h1><p align=\"center\">#{title}</p></h1>"
21052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  result.each { |unusedResources|
21152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    puts "<h2>#{unusedResources.appDir}</h2>"
21252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    displayHtmlUnused(unusedResources.unusedLayoutIds, "Unused layout ids")
21352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    displayHtmlUnused(unusedResources.unusedStringIds, "Unused other ids")
21452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  }
21552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  puts "</body>"
21652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectend
21752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
21852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectresult = Array.new
21952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
22052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source ProjectrecordJavaUses("java/android/**/*.java")
22152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
22252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectif debug
22352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  result << findUnusedResources("apps/Browser")
22452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectelse 
22552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  findApps(".").each { |appDir|
22652d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project    result << findUnusedResources(appDir)
22752d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  }
22852d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectend
22952d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
23052d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectif ARGV[0] == "-html"
23152d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  displayHtml result
23252d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectelse
23352d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project  displayText result
23452d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Projectend
23552d4c30ca52320ec92d1d1ddc8db3f07f69c4f98The Android Open Source Project
236