merge in nyc-release history after reset to master
diff --git a/interlace-frames.py b/interlace-frames.py
index 243e565..3e777b4 100644
--- a/interlace-frames.py
+++ b/interlace-frames.py
@@ -12,42 +12,69 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Script to take a set of frames (PNG files) for a recovery animation
-and turn it into a single output image which contains the input frames
-interlaced by row.  Run with the names of all the input frames on the
-command line, in order, followed by the name of the output file."""
+"""
+Script to take a set of frames (PNG files) for a recovery animation and turn
+it into a single output image which contains the input frames interlaced by
+row. Run with the names of all the input frames on the command line. Specify
+the name of the output file with -o (or --output), and optionally specify the
+number of frames per second (FPS) with --fps (default: 20).
 
+e.g.
+interlace-frames.py --fps 20 --output output.png frame0.png frame1.png frame3.png
+"""
+
+from __future__ import print_function
+
+import argparse
 import sys
 try:
   import Image
   import PngImagePlugin
 except ImportError:
-  print "This script requires the Python Imaging Library to be installed."
+  print("This script requires the Python Imaging Library to be installed.")
   sys.exit(1)
 
-frames = [Image.open(fn).convert("RGB") for fn in sys.argv[1:-1]]
-assert len(frames) > 0, "Must have at least one input frame."
-sizes = set()
-for fr in frames:
-  sizes.add(fr.size)
 
-assert len(sizes) == 1, "All input images must have the same size."
-w, h = sizes.pop()
-N = len(frames)
+def interlace(output, fps, inputs):
+  frames = [Image.open(fn).convert("RGB") for fn in inputs]
+  assert len(frames) > 0, "Must have at least one input frame."
+  sizes = set()
+  for fr in frames:
+    sizes.add(fr.size)
 
-out = Image.new("RGB", (w, h*N))
-for j in range(h):
-  for i in range(w):
-    for fn, f in enumerate(frames):
-      out.putpixel((i, j*N+fn), f.getpixel((i, j)))
+  assert len(sizes) == 1, "All input images must have the same size."
+  w, h = sizes.pop()
+  N = len(frames)
 
-# When loading this image, the graphics library expects to find a text
-# chunk that specifies how many frames this animation represents.  If
-# you post-process the output of this script with some kind of
-# optimizer tool (eg pngcrush or zopflipng) make sure that your
-# optimizer preserves this text chunk.
+  out = Image.new("RGB", (w, h*N))
+  for j in range(h):
+    for i in range(w):
+      for fn, f in enumerate(frames):
+        out.putpixel((i, j*N+fn), f.getpixel((i, j)))
 
-meta = PngImagePlugin.PngInfo()
-meta.add_text("Frames", str(N))
+  # When loading this image, the graphics library expects to find a text
+  # chunk that specifies how many frames this animation represents.  If
+  # you post-process the output of this script with some kind of
+  # optimizer tool (eg pngcrush or zopflipng) make sure that your
+  # optimizer preserves this text chunk.
 
-out.save(sys.argv[-1], pnginfo=meta)
+  meta = PngImagePlugin.PngInfo()
+  meta.add_text("Frames", str(N))
+  meta.add_text("FPS", str(fps))
+
+  out.save(output, pnginfo=meta)
+
+
+def main(argv):
+  parser = argparse.ArgumentParser()
+  parser.add_argument('--fps', default=20)
+  parser.add_argument('--output', '-o', required=True)
+  parser.add_argument('input', nargs='+')
+  args = parser.parse_args(argv)
+
+  interlace(args.output, args.fps, args.input)
+
+
+if __name__ == '__main__':
+  main(sys.argv[1:])
+
diff --git a/minui/minui.h b/minui/minui.h
index bdde083..e3bc005 100644
--- a/minui/minui.h
+++ b/minui/minui.h
@@ -101,8 +101,8 @@
 // should have a 'Frames' text chunk whose value is the number of
 // frames this image represents.  The pixel data itself is interlaced
 // by row.
-int res_create_multi_display_surface(const char* name,
-                                     int* frames, GRSurface*** pSurface);
+int res_create_multi_display_surface(const char* name, int* frames,
+                                     int* fps, GRSurface*** pSurface);
 
 // Load a single alpha surface from a grayscale PNG image.
 int res_create_alpha_surface(const char* name, GRSurface** pSurface);
diff --git a/minui/resources.cpp b/minui/resources.cpp
index 5e47892..63a0dff 100644
--- a/minui/resources.cpp
+++ b/minui/resources.cpp
@@ -237,14 +237,14 @@
     return result;
 }
 
-int res_create_multi_display_surface(const char* name, int* frames, GRSurface*** pSurface) {
+int res_create_multi_display_surface(const char* name, int* frames, int* fps,
+        GRSurface*** pSurface) {
     GRSurface** surface = NULL;
     int result = 0;
     png_structp png_ptr = NULL;
     png_infop info_ptr = NULL;
     png_uint_32 width, height;
     png_byte channels;
-    int i;
     png_textp text;
     int num_text;
     unsigned char* p_row;
@@ -257,14 +257,23 @@
     if (result < 0) return result;
 
     *frames = 1;
+    *fps = 20;
     if (png_get_text(png_ptr, info_ptr, &text, &num_text)) {
-        for (i = 0; i < num_text; ++i) {
+        for (int i = 0; i < num_text; ++i) {
             if (text[i].key && strcmp(text[i].key, "Frames") == 0 && text[i].text) {
                 *frames = atoi(text[i].text);
-                break;
+            } else if (text[i].key && strcmp(text[i].key, "FPS") == 0 && text[i].text) {
+                *fps = atoi(text[i].text);
             }
         }
         printf("  found frames = %d\n", *frames);
+        printf("  found fps = %d\n", *fps);
+    }
+
+    if (frames <= 0 || fps <= 0) {
+        printf("bad number of frames (%d) and/or FPS (%d)\n", *frames, *fps);
+        result = -10;
+        goto exit;
     }
 
     if (height % *frames != 0) {
@@ -278,7 +287,7 @@
         result = -8;
         goto exit;
     }
-    for (i = 0; i < *frames; ++i) {
+    for (int i = 0; i < *frames; ++i) {
         surface[i] = init_display_surface(width, height / *frames);
         if (surface[i] == NULL) {
             result = -8;
@@ -307,7 +316,7 @@
 
     if (result < 0) {
         if (surface) {
-            for (i = 0; i < *frames; ++i) {
+            for (int i = 0; i < *frames; ++i) {
                 if (surface[i]) free(surface[i]);
             }
             free(surface);
diff --git a/res-hdpi/images/icon_installing.png b/res-hdpi/images/icon_installing.png
index c2c0201..0fcfbc2 100644
--- a/res-hdpi/images/icon_installing.png
+++ b/res-hdpi/images/icon_installing.png
Binary files differ
diff --git a/res-mdpi/images/icon_installing.png b/res-mdpi/images/icon_installing.png
index c2c0201..0fcfbc2 100644
--- a/res-mdpi/images/icon_installing.png
+++ b/res-mdpi/images/icon_installing.png
Binary files differ
diff --git a/res-xhdpi/images/icon_installing.png b/res-xhdpi/images/icon_installing.png
index c2c0201..0fcfbc2 100644
--- a/res-xhdpi/images/icon_installing.png
+++ b/res-xhdpi/images/icon_installing.png
Binary files differ
diff --git a/res-xxhdpi/images/icon_installing.png b/res-xxhdpi/images/icon_installing.png
index c2c0201..0fcfbc2 100644
--- a/res-xxhdpi/images/icon_installing.png
+++ b/res-xxhdpi/images/icon_installing.png
Binary files differ
diff --git a/res-xxxhdpi/images/icon_installing.png b/res-xxxhdpi/images/icon_installing.png
index c2c0201..0fcfbc2 100644
--- a/res-xxxhdpi/images/icon_installing.png
+++ b/res-xxxhdpi/images/icon_installing.png
Binary files differ
diff --git a/screen_ui.cpp b/screen_ui.cpp
index 23fc901..522aa6b 100644
--- a/screen_ui.cpp
+++ b/screen_ui.cpp
@@ -73,7 +73,7 @@
     menu_items(0),
     menu_sel(0),
     file_viewer_text_(nullptr),
-    animation_fps(20),
+    animation_fps(-1),
     installing_frames(-1),
     stage(-1),
     max_stage(-1) {
@@ -367,8 +367,9 @@
     }
 }
 
-void ScreenRecoveryUI::LoadBitmapArray(const char* filename, int* frames, GRSurface*** surface) {
-    int result = res_create_multi_display_surface(filename, frames, surface);
+void ScreenRecoveryUI::LoadBitmapArray(const char* filename, int* frames, int* fps,
+        GRSurface*** surface) {
+    int result = res_create_multi_display_surface(filename, frames, fps, surface);
     if (result < 0) {
         LOGE("missing bitmap %s\n(Code %d)\n", filename, result);
     }
@@ -405,7 +406,7 @@
     text_top_ = 1;
 
     backgroundIcon[NONE] = nullptr;
-    LoadBitmapArray("icon_installing", &installing_frames, &installation);
+    LoadBitmapArray("icon_installing", &installing_frames, &animation_fps, &installation);
     backgroundIcon[INSTALLING_UPDATE] = installing_frames ? installation[0] : nullptr;
     backgroundIcon[ERASING] = backgroundIcon[INSTALLING_UPDATE];
     LoadBitmap("icon_error", &backgroundIcon[ERROR]);
diff --git a/screen_ui.h b/screen_ui.h
index 8e18864..08a5f44 100644
--- a/screen_ui.h
+++ b/screen_ui.h
@@ -109,6 +109,8 @@
 
     pthread_t progress_thread_;
 
+    // The following two are parsed from the image file
+    // (e.g. '/res/images/icon_installing.png').
     int animation_fps;
     int installing_frames;
 
@@ -135,7 +137,7 @@
     void DrawTextLines(int* y, const char* const* lines);
 
     void LoadBitmap(const char* filename, GRSurface** surface);
-    void LoadBitmapArray(const char* filename, int* frames, GRSurface*** surface);
+    void LoadBitmapArray(const char* filename, int* frames, int* fps, GRSurface*** surface);
     void LoadLocalizedBitmap(const char* filename, GRSurface** surface);
 };
 
diff --git a/wear_ui.cpp b/wear_ui.cpp
index 3ee38e8..50aeb38 100644
--- a/wear_ui.cpp
+++ b/wear_ui.cpp
@@ -61,10 +61,10 @@
     menu_unusable_rows(0),
     intro_frames(22),
     loop_frames(60),
+    animation_fps(30),
     currentIcon(NONE),
     intro_done(false),
     current_frame(0),
-    animation_fps(30),
     rtl_locale(false),
     progressBarType(EMPTY),
     progressScopeStart(0),
diff --git a/wear_ui.h b/wear_ui.h
index 839a264..63c1b6e 100644
--- a/wear_ui.h
+++ b/wear_ui.h
@@ -79,6 +79,9 @@
     int intro_frames;
     int loop_frames;
 
+    // Number of frames per sec (default: 30) for both of intro and loop.
+    int animation_fps;
+
   private:
     Icon currentIcon;
 
@@ -86,8 +89,6 @@
 
     int current_frame;
 
-    int animation_fps;
-
     bool rtl_locale;
 
     pthread_mutex_t updateMutex;