Merge "Deprecate DexEncodedMethod#isStaticMethod."
diff --git a/build.gradle b/build.gradle
index 7a44d6d..eed9769 100644
--- a/build.gradle
+++ b/build.gradle
@@ -342,6 +342,7 @@
         "youtube/youtube.android_12.10",
         "youtube/youtube.android_12.17",
         "youtube/youtube.android_12.22",
+        "youtube/youtube.android_13.37",
         "proguardsettings",
         "proguard/proguard_internal_159423826",
         "framework",
diff --git a/src/main/java/com/android/tools/r8/ExtractMarker.java b/src/main/java/com/android/tools/r8/ExtractMarker.java
index 100105f..6fd04b6 100644
--- a/src/main/java/com/android/tools/r8/ExtractMarker.java
+++ b/src/main/java/com/android/tools/r8/ExtractMarker.java
@@ -121,7 +121,7 @@
             "Failed to read dex/vdex file `" + programFile + "`: '" + e.getMessage() + "'");
         continue;
       }
-      System.out.print("In file: " + cwd.relativize(programFile));
+      System.out.print("In file: " + cwd.toAbsolutePath().relativize(programFile.toAbsolutePath()));
       System.out.println(", " + extractDexSize(programFile) + " bytes:");
       for (Marker marker : markers) {
         if (marker == null) {
diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java
index dc94041..78a9d3f 100644
--- a/src/main/java/com/android/tools/r8/R8Command.java
+++ b/src/main/java/com/android/tools/r8/R8Command.java
@@ -362,9 +362,8 @@
         mainDexKeepRules = parser.getConfig().getRules();
       }
 
-      ProguardConfigurationParser parser = new ProguardConfigurationParser(
-          factory, reporter,
-          !allowPartiallyImplementedProguardOptions, allowTestProguardOptions);
+      ProguardConfigurationParser parser =
+          new ProguardConfigurationParser(factory, reporter, allowTestProguardOptions);
       if (!proguardConfigs.isEmpty()) {
         parser.parse(proguardConfigs);
       }
diff --git a/src/main/java/com/android/tools/r8/graph/JarCode.java b/src/main/java/com/android/tools/r8/graph/JarCode.java
index f974aca..0a1ee94 100644
--- a/src/main/java/com/android/tools/r8/graph/JarCode.java
+++ b/src/main/java/com/android/tools/r8/graph/JarCode.java
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.graph;
 
+import com.android.tools.r8.errors.CompilationError;
 import com.android.tools.r8.errors.InvalidDebugInfoException;
 import com.android.tools.r8.graph.JarClassFileReader.ReparseContext;
 import com.android.tools.r8.ir.code.IRCode;
@@ -241,7 +242,12 @@
 
   private void parseCode(ReparseContext context, boolean useJsrInliner) {
     SecondVisitor classVisitor = new SecondVisitor(createCodeLocator(context), useJsrInliner);
-    new ClassReader(context.classCache).accept(classVisitor, ClassReader.SKIP_FRAMES);
+    try {
+      new ClassReader(context.classCache).accept(classVisitor, ClassReader.SKIP_FRAMES);
+    } catch (Exception exception) {
+      throw new CompilationError(
+          "Unable to parse method `" + method.toSourceString() + "`", exception);
+    }
   }
 
   protected BiFunction<String, String, JarCode> createCodeLocator(ReparseContext context) {
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
index a49c15c..faf5317 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
@@ -49,7 +49,6 @@
   private final DexItemFactory dexItemFactory;
 
   private final Reporter reporter;
-  private final boolean failOnPartiallyImplementedOptions;
   private final boolean allowTestOptions;
 
   private static final List<String> IGNORED_SINGLE_ARG_OPTIONS = ImmutableList.of(
@@ -102,17 +101,15 @@
 
   public ProguardConfigurationParser(
       DexItemFactory dexItemFactory, Reporter reporter) {
-    this(dexItemFactory, reporter, true, false);
+    this(dexItemFactory, reporter, false);
   }
 
   public ProguardConfigurationParser(
-      DexItemFactory dexItemFactory, Reporter reporter, boolean failOnPartiallyImplementedOptions,
-      boolean allowTestOptions) {
+      DexItemFactory dexItemFactory, Reporter reporter, boolean allowTestOptions) {
     this.dexItemFactory = dexItemFactory;
     configurationBuilder = ProguardConfiguration.builder(dexItemFactory, reporter);
 
     this.reporter = reporter;
-    this.failOnPartiallyImplementedOptions = failOnPartiallyImplementedOptions;
     this.allowTestOptions = allowTestOptions;
   }
 
diff --git a/src/test/java/com/android/tools/r8/debug/LocalsLiveAtBlockEntryDebugTest.java b/src/test/java/com/android/tools/r8/debug/LocalsLiveAtBlockEntryDebugTest.java
index 09a46e5..85749ab 100644
--- a/src/test/java/com/android/tools/r8/debug/LocalsLiveAtBlockEntryDebugTest.java
+++ b/src/test/java/com/android/tools/r8/debug/LocalsLiveAtBlockEntryDebugTest.java
@@ -6,6 +6,9 @@
 import static org.junit.Assert.assertTrue;
 
 import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.VmTestRunner;
+import com.android.tools.r8.VmTestRunner.IgnoreIfVmOlderThan;
 import com.android.tools.r8.jasmin.JasminBuilder;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -14,10 +17,10 @@
 import java.nio.file.Path;
 import java.util.Collections;
 import java.util.List;
-import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
 
 /**
  * Test to check that locals that are introduced in a block that is not hit, still start in the
@@ -25,6 +28,7 @@
  *
  * <p>See b/75251251 or b/78617758
  */
+@RunWith(VmTestRunner.class)
 public class LocalsLiveAtBlockEntryDebugTest extends DebugTestBase {
 
   final String className = "LocalsLiveAtEntry";
@@ -45,7 +49,7 @@
   }
 
   @Test
-  @Ignore("b/78617758")
+  @IgnoreIfVmOlderThan(Version.V7_0_0)
   public void testD8() throws Throwable {
     JasminBuilder builder = getBuilderForTest(className, methodName);
     List<Path> outputs = builder.writeClassFiles(temp.newFolder().toPath());
diff --git a/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java b/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
index 3f66921..f8907d6 100644
--- a/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
@@ -154,17 +154,10 @@
   }
 
   @Before
-  public void resetAllowPartiallyImplementedOptions() {
-    handler = new KeepingDiagnosticHandler();
-    reporter = new Reporter(handler);
-    parser = new ProguardConfigurationParser(new DexItemFactory(), reporter, false, false);
-  }
-
-  @Before
   public void resetAllowTestOptions() {
     handler = new KeepingDiagnosticHandler();
     reporter = new Reporter(handler);
-    parser = new ProguardConfigurationParser(new DexItemFactory(), reporter, true, true);
+    parser = new ProguardConfigurationParser(new DexItemFactory(), reporter, true);
   }
 
   @Test
@@ -901,7 +894,7 @@
   @Test
   public void parseKeepdirectories() throws Exception {
     ProguardConfigurationParser parser =
-        new ProguardConfigurationParser(new DexItemFactory(), reporter, false, false);
+        new ProguardConfigurationParser(new DexItemFactory(), reporter, false);
     parser.parse(Paths.get(KEEPDIRECTORIES));
     verifyParserEndsCleanly();
   }
@@ -1317,7 +1310,6 @@
 
   @Test
   public void parse_adaptresourcexxx_keepdirectories_noArguments1() {
-    resetAllowPartiallyImplementedOptions();
     ProguardConfiguration config = parseAndVerifyParserEndsCleanly(ImmutableList.of(
         "-adaptresourcefilenames",
         "-adaptresourcefilecontents",
@@ -1330,7 +1322,6 @@
 
   @Test
   public void parse_adaptresourcexxx_keepdirectories_noArguments2() {
-    resetAllowPartiallyImplementedOptions();
     ProguardConfiguration config = parseAndVerifyParserEndsCleanly(ImmutableList.of(
         "-keepdirectories",
         "-adaptresourcefilenames",
@@ -1343,7 +1334,6 @@
 
   @Test
   public void parse_adaptresourcexxx_keepdirectories_noArguments3() {
-    resetAllowPartiallyImplementedOptions();
     ProguardConfiguration config = parseAndVerifyParserEndsCleanly(ImmutableList.of(
         "-adaptresourcefilecontents",
         "-keepdirectories",
@@ -1365,7 +1355,6 @@
 
   @Test
   public void parse_adaptresourcexxx_keepdirectories_singleArgument() {
-    resetAllowPartiallyImplementedOptions();
     ProguardConfiguration config = parseAndVerifyParserEndsCleanly(ImmutableList.of(
         "-adaptresourcefilenames " + FILE_FILTER_SINGLE,
         "-adaptresourcefilecontents " + FILE_FILTER_SINGLE,
@@ -1398,7 +1387,6 @@
 
   @Test
   public void parse_adaptresourcexxx_keepdirectories_multipleArgument() {
-    resetAllowPartiallyImplementedOptions();
     ProguardConfiguration config = parseAndVerifyParserEndsCleanly(ImmutableList.of(
         "-adaptresourcefilenames " + FILE_FILTER_MULTIPLE,
         "-adaptresourcefilecontents " + FILE_FILTER_MULTIPLE,
@@ -1415,7 +1403,7 @@
         "-adaptresourcefilenames", "-adaptresourcefilecontents", "-keepdirectories");
     for (String option : options) {
       try {
-        resetAllowPartiallyImplementedOptions();
+        reset();
         parser.parse(createConfigurationForTesting(ImmutableList.of(option + " ,")));
         fail("Expect to fail due to the lack of path filter.");
       } catch (AbortException e) {
@@ -1430,7 +1418,7 @@
         "-adaptresourcefilenames", "-adaptresourcefilecontents", "-keepdirectories");
     for (String option : options) {
       try {
-        resetAllowPartiallyImplementedOptions();
+        reset();
         parser.parse(createConfigurationForTesting(ImmutableList.of(option + " xxx,,yyy")));
         fail("Expect to fail due to the lack of path filter.");
       } catch (AbortException e) {
@@ -1445,7 +1433,7 @@
         "-adaptresourcefilenames", "-adaptresourcefilecontents", "-keepdirectories");
     for (String option : options) {
       try {
-        resetAllowPartiallyImplementedOptions();
+        reset();
         parser.parse(createConfigurationForTesting(ImmutableList.of(option + " xxx,")));
         fail("Expect to fail due to the lack of path filter.");
       } catch (AbortException e) {
diff --git a/third_party/youtube/youtube.android_13.37.tar.gz.sha1 b/third_party/youtube/youtube.android_13.37.tar.gz.sha1
new file mode 100644
index 0000000..ffc92a8
--- /dev/null
+++ b/third_party/youtube/youtube.android_13.37.tar.gz.sha1
@@ -0,0 +1 @@
+533819c8e988bfbcdd7bc3dbd17e0d374c4ba9ab
\ No newline at end of file
diff --git a/tools/internal_test.py b/tools/internal_test.py
index 0cb9019..e040f80 100755
--- a/tools/internal_test.py
+++ b/tools/internal_test.py
@@ -4,6 +4,30 @@
 # BSD-style license that can be found in the LICENSE file.
 
 # Run all internal tests, archive result to cloud storage.
+# In the continuous operation flow we have a tester continuously checking
+# a specific cloud storage location for a file with a git hash.
+# If the file is there, the tester will remove the file, and add another
+# file stating that this is now being run. After successfully running,
+# the tester will add yet another file, and remove the last one.
+# Complete flow with states:
+# 1:
+#   BOT:
+#     Add file READY_FOR_TESTING (contains git hash)
+#     Wait until file TESTING_COMPLETE exists (contains git hash)
+#     Timeout if no progress for RUN_TIMEOUT
+#       Cleanup READY_FOR_TESTING and TESTING
+# 2:
+#   TESTER:
+#     Replace file READY_FOR_TESTING by TESTING (contains git hash)
+#     Run tests for git hash
+#     Upload commit specific logs if failures
+#     Upload git specific overall status file (failed or succeeded)
+#     Replace file TESTING by TESTING_COMPLETE (contains git hash)
+# 3:
+#   BOT:
+#     Read overall status
+#     Delete TESTING_COMPLETE
+#     Exit based on status
 
 import optparse
 import os
@@ -12,18 +36,36 @@
 import time
 import utils
 
-# How often to pull the git repo, in seconds.
-PULL_DELAY = 25
+# How often the bot/tester should check state
+PULL_DELAY = 30
 # Command timeout, in seconds.
 RUN_TIMEOUT = 3600
+# Add some extra time for the bot, since the tester might not start immediately.
+BOT_RUN_TIMEOUT = 4000
 BUCKET = 'r8-test-results'
 TEST_RESULT_DIR = 'internal'
 
+# Magic files
+READY_FOR_TESTING = 'READY_FOR_TESTING'
+TESTING = 'TESTING'
+TESTING_COMPLETE = 'TESTING_COMPLETE'
+
+ALL_MAGIC = [READY_FOR_TESTING, TESTING, TESTING_COMPLETE]
+
+# Log file names
+STDERR = 'stderr'
+STDOUT = 'stdout'
+EXITCODE = 'exitcode'
+TIMED_OUT = 'timed_out'
+
 def ParseOptions():
   result = optparse.OptionParser()
   result.add_option('--continuous',
       help='Continuously run internal tests and post results to GCS.',
       default=False, action='store_true')
+  result.add_option('--bot',
+      help='Run in bot mode, i.e., scheduling runs.',
+      default=False, action='store_true')
   result.add_option('--archive',
        help='Post result to GCS, implied by --continuous',
        default=False, action='store_true')
@@ -39,22 +81,40 @@
     print('Restarting tools/internal_test.py, content changed')
     os.execv(sys.argv[0], sys.argv)
 
-def git_pull():
+def ensure_git_clean():
   # Ensure clean git repo.
   diff = subprocess.check_output(['git', 'diff'])
   if len(diff) > 0:
     print('Local modifications to the git repo, exiting')
     sys.exit(1)
+
+def git_pull():
+  ensure_git_clean()
+  subprocess.check_call(['git', 'checkout', 'master'])
   subprocess.check_call(['git', 'pull'])
   return utils.get_HEAD_sha1()
 
+def git_checkout(git_hash):
+  ensure_git_clean()
+  # Ensure that we are up to date to get the commit.
+  git_pull()
+  subprocess.check_call(['git', 'checkout', git_hash])
+  return utils.get_HEAD_sha1()
+
+def get_test_result_dir():
+  return os.path.join(BUCKET, TEST_RESULT_DIR)
+
 def get_sha_destination(sha):
-  return os.path.join(BUCKET, TEST_RESULT_DIR, sha)
+  return os.path.join(get_test_result_dir(), sha)
 
 def archive_status(failed):
   gs_destination = 'gs://%s' % get_sha_destination(utils.get_HEAD_sha1())
   archive_value('status', gs_destination, failed)
 
+def get_status(sha):
+  gs_destination = 'gs://%s/status' % get_sha_destination(sha)
+  return utils.cat_file_on_cloud_storage(gs_destination)
+
 def archive_file(name, gs_dir, src_file):
   gs_file = '%s/%s' % (gs_dir, name)
   utils.upload_file_to_cloud_storage(src_file, gs_file, public_read=False)
@@ -68,30 +128,97 @@
 
 def archive_log(stdout, stderr, exitcode, timed_out, cmd):
   sha = utils.get_HEAD_sha1()
-  cmd_dir = cmd.replace(' ', '_')
+  cmd_dir = cmd.replace(' ', '_').replace('/', '_')
   destination = os.path.join(get_sha_destination(sha), cmd_dir)
   gs_destination = 'gs://%s' % destination
   url = 'https://storage.cloud.google.com/%s' % destination
   print('Archiving logs to: %s' % gs_destination)
-  archive_value('exitcode', gs_destination, exitcode)
-  archive_value('timed_out', gs_destination, timed_out)
-  archive_file('stdout', gs_destination, stdout)
-  archive_file('stderr', gs_destination, stderr)
+  archive_value(EXITCODE, gs_destination, exitcode)
+  archive_value(TIMED_OUT, gs_destination, timed_out)
+  archive_file(STDOUT, gs_destination, stdout)
+  archive_file(STDERR, gs_destination, stderr)
   print('Logs available at: %s' % url)
 
+def get_magic_file_base_path():
+  return 'gs://%s/magic' % get_test_result_dir()
+
+def get_magic_file_gs_path(name):
+  return '%s/%s' % (get_magic_file_base_path(), name)
+
+def get_magic_file_exists(name):
+  return utils.file_exists_on_cloud_storage(get_magic_file_gs_path(name))
+
+def delete_magic_file(name):
+  utils.delete_file_from_cloud_storage(get_magic_file_gs_path(name))
+
+def put_magic_file(name, sha):
+  archive_value(name, get_magic_file_base_path(), sha)
+
+def get_magic_file_content(name, ignore_errors=False):
+  return utils.cat_file_on_cloud_storage(get_magic_file_gs_path(name),
+                                         ignore_errors=ignore_errors)
+
+def print_magic_file_state():
+  print('Magic file status:')
+  for magic in ALL_MAGIC:
+    if get_magic_file_exists(magic):
+      content = get_magic_file_content(magic, ignore_errors=True)
+      print('%s content: %s' % (magic, content))
+
+def run_bot():
+  print_magic_file_state()
+  # Ensure that there is nothing currently scheduled (broken/stopped run)
+  for magic in ALL_MAGIC:
+    if get_magic_file_exists(magic):
+      print('ERROR: Synchronizing file %s exists, cleaning up' % magic)
+      delete_magic_file(magic)
+  print_magic_file_state()
+  assert not get_magic_file_exists(READY_FOR_TESTING)
+  git_hash = utils.get_HEAD_sha1()
+  put_magic_file(READY_FOR_TESTING, git_hash)
+  begin = time.time()
+  while True:
+    if time.time() - begin > BOT_RUN_TIMEOUT:
+      print('Timeout exceeded')
+      raise Exception('Bot timeout')
+    if get_magic_file_exists(TESTING_COMPLETE):
+      if get_magic_file_content(TESTING_COMPLETE) == git_hash:
+        break
+      else:
+        raise Exception('Non matching git hashes %s and %s' % (
+            get_magic_file_content(TESTING_COMPLETE), git_hash))
+    print('Still waiting for test result')
+    print_magic_file_state()
+    time.sleep(PULL_DELAY)
+  total_time = time.time()-begin
+  print('Done running test for %s in %ss' % (git_hash, total_time))
+  test_status = get_status(git_hash)
+  delete_magic_file(TESTING_COMPLETE)
+  print('Test status is: %s' % test_status)
+  if test_status != '0':
+    return 1
+
 def run_continuously():
   # If this script changes, we will restart ourselves
   own_content = get_own_file_content()
-  git_hash = utils.get_HEAD_sha1()
   while True:
     restart_if_new_version(own_content)
-    print('Running with hash: %s' % git_hash)
-    exitcode = run_once(archive=True)
-    git_pull()
-    while git_pull() == git_hash:
-      print('Still on same git hash: %s' % git_hash)
-      time.sleep(PULL_DELAY)
-    git_hash = utils.get_HEAD_sha1()
+    print_magic_file_state()
+    if get_magic_file_exists(READY_FOR_TESTING):
+      git_hash = get_magic_file_content(READY_FOR_TESTING)
+      checked_out = git_checkout(git_hash)
+      # Sanity check, if this does not succeed stop.
+      if checked_out != git_hash:
+        print('Inconsistent state: %s %s' % (git_hash, checked_out))
+        sys.exit(1)
+      put_magic_file(TESTING, git_hash)
+      delete_magic_file(READY_FOR_TESTING)
+      print('Running with hash: %s' % git_hash)
+      exitcode = run_once(archive=True)
+      print('Running finished with exit code %s' % exitcode)
+      put_magic_file(TESTING_COMPLETE, git_hash)
+      delete_magic_file(TESTING)
+    time.sleep(PULL_DELAY)
 
 def handle_output(archive, stderr, stdout, exitcode, timed_out, cmd):
   if archive:
@@ -147,17 +274,21 @@
   if execute(cmd, archive):
     failed = True
   # Ensure that all internal apps compile.
-  cmd = ['tools/run_on_app.py', '--run-all', '--out=out']
+  cmd = ['tools/run_on_app.py', '--ignore-java-version','--run-all',
+         '--out=out']
   if execute(cmd, archive):
     failed = True
   archive_status(1 if failed else 0)
+  return failed
 
 def Main():
   (options, args) = ParseOptions()
   if options.continuous:
     run_continuously()
+  elif options.bot:
+    return run_bot()
   else:
-    run_once(options.archive)
+    return run_once(options.archive)
 
 if __name__ == '__main__':
   sys.exit(Main())
diff --git a/tools/run_on_app.py b/tools/run_on_app.py
index 0667abe..bab9b32 100755
--- a/tools/run_on_app.py
+++ b/tools/run_on_app.py
@@ -49,6 +49,10 @@
                     help='Running on golem, do not build or download',
                     default=False,
                     action='store_true')
+  result.add_option('--ignore-java-version',
+                    help='Do not check java version',
+                    default=False,
+                    action='store_true')
   result.add_option('--no-libraries',
                     help='Do not pass in libraries, even if they exist in conf',
                     default=False,
@@ -115,7 +119,8 @@
 # do Bug: #BUG in the commit message of disabling to ensure re-enabling
 DISABLED_PERMUTATIONS = [
     ('youtube', '12.10', 'dex'), # b/116089492
-    ('youtube', '12.22', 'deploy') # b/116093710
+    ('youtube', '12.10', 'proguarded'), # b/116089492
+    ('gmscore', 'latest', 'deploy') # b/116575775
 ]
 
 def get_permutations():
@@ -150,8 +155,10 @@
       exit(exit_code)
 
 def main(argv):
-  utils.check_java_version()
   (options, args) = ParseOptions(argv)
+  if not options.ignore_java_version:
+    utils.check_java_version()
+
   if options.run_all:
     return run_all(options, args)
   return run_with_options(options, args)
diff --git a/tools/utils.py b/tools/utils.py
index d96151d..20ba093 100644
--- a/tools/utils.py
+++ b/tools/utils.py
@@ -106,6 +106,27 @@
   PrintCmd(cmd)
   subprocess.check_call(cmd)
 
+def delete_file_from_cloud_storage(destination):
+  cmd = ['gsutil.py', 'rm', destination]
+  PrintCmd(cmd)
+  subprocess.check_call(cmd)
+
+def cat_file_on_cloud_storage(destination, ignore_errors=False):
+  cmd = ['gsutil.py', 'cat', destination]
+  PrintCmd(cmd)
+  try:
+    return subprocess.check_output(cmd)
+  except subprocess.CalledProcessError as e:
+    if ignore_errors:
+      return ''
+    else:
+      raise e
+
+def file_exists_on_cloud_storage(destination):
+  cmd = ['gsutil.py', 'ls', destination]
+  PrintCmd(cmd)
+  return subprocess.call(cmd) == 0
+
 def download_file_from_cloud_storage(source, destination):
   cmd = ['gsutil.py', 'cp', source, destination]
   PrintCmd(cmd)
diff --git a/tools/youtube_data.py b/tools/youtube_data.py
index b7f1ee7..6fdf63a 100644
--- a/tools/youtube_data.py
+++ b/tools/youtube_data.py
@@ -19,6 +19,9 @@
 V12_22_BASE = os.path.join(BASE, 'youtube.android_12.22')
 V12_22_PREFIX = os.path.join(V12_22_BASE, 'YouTubeRelease')
 
+V13_37_BASE = os.path.join(BASE, 'youtube.android_13.37')
+V13_37_PREFIX = os.path.join(V13_37_BASE, 'YouTubeRelease')
+
 # NOTE: we always use android.jar for SDK v25, later we might want to revise it
 #       to use proper android.jar version for each of youtube version separately.
 ANDROID_JAR = os.path.join(THIRD_PARTY, 'android_jar', 'lib-v25', 'android.jar')
@@ -85,4 +88,30 @@
       'min-api' : ANDROID_L_API,
     }
   },
+  '13.37': {
+    'dex' : {
+      'inputs': [os.path.join(V13_37_BASE, 'YouTubeRelease_unsigned.apk')],
+      'pgmap': '%s_proguard.map' % V13_37_PREFIX,
+      'libraries' : [ANDROID_JAR],
+      'min-api' : ANDROID_L_API,
+    },
+    'deploy' : {
+      'inputs': ['%s_deploy.jar' % V13_37_PREFIX],
+      'pgconf': [
+          '%s_proguard.config' % V13_37_PREFIX,
+          '%s/proguardsettings/YouTubeRelease_proguard.config' % THIRD_PARTY],
+      # Build for native multi dex, as Currently R8 cannot meet the main-dex
+      # constraints.
+      #'maindexrules' : [
+      #    os.path.join(V13_37_BASE, 'mainDexClasses.rules'),
+      #    os.path.join(V13_37_BASE, 'main-dex-classes-release-optimized.cfg'),
+      #    os.path.join(V13_37_BASE, 'main_dex_YouTubeRelease_proguard.cfg')],
+      'min-api' : ANDROID_L_API,
+    },
+    'proguarded' : {
+      'inputs': ['%s_proguard.jar' % V13_37_PREFIX],
+      'pgmap': '%s_proguard.map' % V13_37_PREFIX,
+      'min-api' : ANDROID_L_API,
+    }
+  },
 }