Merge "s/product-services/product_services/g"
diff --git a/healthd/healthd_draw.cpp b/healthd/healthd_draw.cpp
index 30f2cf3..706dc80 100644
--- a/healthd/healthd_draw.cpp
+++ b/healthd/healthd_draw.cpp
@@ -173,7 +173,7 @@
         cur_level = 100;
     }
 
-    if (cur_level <= 0) return;
+    if (cur_level < 0) return;
 
     const animation::text_field& field = anim->text_percent;
     if (field.font == nullptr || field.font->char_width == 0 || field.font->char_height == 0) {
diff --git a/healthd/healthd_mode_charger.cpp b/healthd/healthd_mode_charger.cpp
index 56a9f86..2eb5497 100644
--- a/healthd/healthd_mode_charger.cpp
+++ b/healthd/healthd_mode_charger.cpp
@@ -72,6 +72,7 @@
 #define BATTERY_UNKNOWN_TIME (2 * MSEC_PER_SEC)
 #define POWER_ON_KEY_TIME (2 * MSEC_PER_SEC)
 #define UNPLUGGED_SHUTDOWN_TIME (10 * MSEC_PER_SEC)
+#define UNPLUGGED_DISPLAY_TIME (3 * MSEC_PER_SEC)
 
 #define LAST_KMSG_MAX_SZ (32 * 1024)
 
@@ -91,6 +92,7 @@
 struct charger {
     bool have_battery_state;
     bool charger_connected;
+    bool screen_blanked;
     int64_t next_screen_transition;
     int64_t next_key_check;
     int64_t next_pwr_check;
@@ -293,6 +295,7 @@
 
 #ifndef CHARGER_DISABLE_INIT_BLANK
         healthd_draw->blank_screen(true);
+        charger->screen_blanked = true;
 #endif
     }
 
@@ -301,6 +304,7 @@
         reset_animation(batt_anim);
         charger->next_screen_transition = -1;
         healthd_draw->blank_screen(true);
+        charger->screen_blanked = true;
         LOGV("[%" PRId64 "] animation done\n", now);
         if (charger->charger_connected) request_suspend(true);
         return;
@@ -308,8 +312,10 @@
 
     disp_time = batt_anim->frames[batt_anim->cur_frame].disp_time;
 
-    /* unblank the screen on first cycle and first frame */
-    if (batt_anim->cur_cycle == 0 && batt_anim->cur_frame == 0) healthd_draw->blank_screen(false);
+    if (charger->screen_blanked) {
+        healthd_draw->blank_screen(false);
+        charger->screen_blanked = false;
+    }
 
     /* animation starting, set up the animation */
     if (batt_anim->cur_frame == 0) {
@@ -327,9 +333,15 @@
                     }
                 }
 
-                // repeat the first frame first_frame_repeats times
-                disp_time = batt_anim->frames[batt_anim->cur_frame].disp_time *
-                            batt_anim->first_frame_repeats;
+                if (charger->charger_connected) {
+                    // repeat the first frame first_frame_repeats times
+                    disp_time = batt_anim->frames[batt_anim->cur_frame].disp_time *
+                                batt_anim->first_frame_repeats;
+                } else {
+                    disp_time = UNPLUGGED_DISPLAY_TIME / batt_anim->num_cycles;
+                }
+
+                LOGV("cur_frame=%d disp_time=%d\n", batt_anim->cur_frame, disp_time);
             }
         }
     }
@@ -348,7 +360,7 @@
     }
 
     /* schedule next screen transition */
-    charger->next_screen_transition = now + disp_time;
+    charger->next_screen_transition = curr_time_ms() + disp_time;
 
     /* advance frame cntr to the next valid frame only if we are charging
      * if necessary, advance cycle cntr, and reset frame cntr
@@ -458,6 +470,7 @@
             /* if the power key got released, force screen state cycle */
             if (key->pending) {
                 kick_animation(charger->batt_anim);
+                request_suspend(false);
             }
         }
     }
@@ -476,12 +489,18 @@
     if (!charger->have_battery_state) return;
 
     if (!charger->charger_connected) {
-        /* Last cycle would have stopped at the extreme top of battery-icon
-         * Need to show the correct level corresponding to capacity.
-         */
-        kick_animation(charger->batt_anim);
         request_suspend(false);
         if (charger->next_pwr_check == -1) {
+            /* Last cycle would have stopped at the extreme top of battery-icon
+             * Need to show the correct level corresponding to capacity.
+             *
+             * Reset next_screen_transition to update screen immediately.
+             * Reset & kick animation to show complete animation cycles
+             * when charger disconnected.
+             */
+            charger->next_screen_transition = now - 1;
+            reset_animation(charger->batt_anim);
+            kick_animation(charger->batt_anim);
             charger->next_pwr_check = now + UNPLUGGED_SHUTDOWN_TIME;
             LOGW("[%" PRId64 "] device unplugged: shutting down in %" PRId64 " (@ %" PRId64 ")\n",
                  now, (int64_t)UNPLUGGED_SHUTDOWN_TIME, charger->next_pwr_check);
@@ -494,8 +513,15 @@
     } else {
         /* online supply present, reset shutdown timer if set */
         if (charger->next_pwr_check != -1) {
-            LOGW("[%" PRId64 "] device plugged in: shutdown cancelled\n", now);
+            /* Reset next_screen_transition to update screen immediately.
+             * Reset & kick animation to show complete animation cycles
+             * when charger connected again.
+             */
+            request_suspend(false);
+            charger->next_screen_transition = now - 1;
+            reset_animation(charger->batt_anim);
             kick_animation(charger->batt_anim);
+            LOGW("[%" PRId64 "] device plugged in: shutdown cancelled\n", now);
         }
         charger->next_pwr_check = -1;
     }
@@ -523,6 +549,7 @@
     if (!charger->have_battery_state) {
         charger->have_battery_state = true;
         charger->next_screen_transition = curr_time_ms() - 1;
+        request_suspend(false);
         reset_animation(charger->batt_anim);
         kick_animation(charger->batt_anim);
     }
diff --git a/libutils/Unicode.cpp b/libutils/Unicode.cpp
index e00fb81..82f650d 100644
--- a/libutils/Unicode.cpp
+++ b/libutils/Unicode.cpp
@@ -340,27 +340,6 @@
            : 0);
 }
 
-int strzcmp16_h_n(const char16_t *s1H, size_t n1, const char16_t *s2N, size_t n2)
-{
-    const char16_t* e1 = s1H+n1;
-    const char16_t* e2 = s2N+n2;
-
-    while (s1H < e1 && s2N < e2) {
-        const char16_t c2 = ntohs(*s2N);
-        const int d = (int)*s1H++ - (int)c2;
-        s2N++;
-        if (d) {
-            return d;
-        }
-    }
-
-    return n1 < n2
-        ? (0 - (int)ntohs(*s2N))
-        : (n1 > n2
-           ? ((int)*s1H - 0)
-           : 0);
-}
-
 void utf16_to_utf8(const char16_t* src, size_t src_len, char* dst, size_t dst_len)
 {
     if (src == nullptr || src_len == 0 || dst == nullptr) {
diff --git a/libutils/include/utils/StrongPointer.h b/libutils/include/utils/StrongPointer.h
index 360fce5..3abce17 100644
--- a/libutils/include/utils/StrongPointer.h
+++ b/libutils/include/utils/StrongPointer.h
@@ -228,8 +228,10 @@
 
 template<typename T>
 void sp<T>::clear() {
-    if (m_ptr) {
-        m_ptr->decStrong(this);
+    T* oldPtr(*const_cast<T* volatile*>(&m_ptr));
+    if (oldPtr) {
+        oldPtr->decStrong(this);
+        if (oldPtr != *const_cast<T* volatile*>(&m_ptr)) sp_report_race();
         m_ptr = nullptr;
     }
 }
diff --git a/libutils/include/utils/Unicode.h b/libutils/include/utils/Unicode.h
index 666b70f..61a1b4f 100644
--- a/libutils/include/utils/Unicode.h
+++ b/libutils/include/utils/Unicode.h
@@ -40,9 +40,6 @@
 // equivalent result as strcmp16 (unlike strncmp16).
 int strzcmp16(const char16_t *s1, size_t n1, const char16_t *s2, size_t n2);
 
-// Version of strzcmp16 for comparing strings in different endianness.
-int strzcmp16_h_n(const char16_t *s1H, size_t n1, const char16_t *s2N, size_t n2);
-
 // Standard string functions on char32_t strings.
 size_t strlen32(const char32_t *);
 size_t strnlen32(const char32_t *, size_t);
diff --git a/rootdir/etc/OWNERS b/rootdir/etc/OWNERS
new file mode 100644
index 0000000..8a65b23
--- /dev/null
+++ b/rootdir/etc/OWNERS
@@ -0,0 +1,4 @@
+danalbert@google.com
+enh@google.com
+jiyong@google.com
+rprichard@google.com