--- /dev/null
+# Clock Plugins
+
+## Introduction
+
+The clock appearing on the lock screen and always on display (AOD) can be
+customized via the ClockPlugin plugin interface.
+
+## System Health
+
+Clocks are high risk for battery consumption and screen burn-in because they
+modify the UI of AOD.
+
+To reduce battery consumption, it is recommended to
+target a maximum on-pixel-ratio (OPR) of 5%. Clocks that are composed of
+large blocks of color that cause the OPR to exceed 5% should be avoided.
+
+To prevent screen burn-in, clocks should not be composed of large solid
+blocks of color, and the clock should be moved around the screen to
+distribute the on pixels across a large number of pixels. Software
+burn-in testing is a good starting point to assess the pixel shifting
+(clock movement) scheme and shape of the clock.
+
+### Software Burn-In Test
+
+The goal is to look for bright spots in the luminosity average over a period of
+time. It is difficult to define a threshold where burn-in will occur. It is,
+therefore, recommended to compare against an element on AOD that is known not
+to cause problems.
+
+For clock face that contain color, it is recommended to use an all white
+version of the face. Since white has the highest luminosity, this version of
+the clock face represents the worst case scenario.
+
+To start, generate a sequence of screenshots for each minute over a 12 hr interval.
+
+```
+serial = '84TY004MS' # serial number for the device
+count = 1
+t = datetime.datetime(2019, 1, 1)
+stop = t + datetime.timedelta(hours=12)
+if not os.path.exists(OUTPUT_FOLDER):
+ raise RuntimeError('output folder "%s" does not exist' % OUTPUT_FOLDER)
+while t <= stop:
+ os.system("adb -s %s shell 'date %s ; am broadcast -a android.intent.action.TIME_SET'" % (serial, t.strftime('%m%d%H%M%Y.%S')))
+ os.system('adb -s %s shell screencap -p > %s/screencap_%06d.png' % (serial, OUTPUT_FOLDER, count))
+ t += datetime.timedelta(minutes=1)
+ count += 1
+```
+
+Average the luminosity of the screenshots.
+
+```
+#!python
+import numpy
+import scipy.ndimage
+from imageio import imread, imwrite
+import matplotlib.pylab as plt
+import os
+import os.path
+
+def images(path):
+ return [os.path.join(path, name) for name in os.listdir(path) if name.endswith('.png')]
+
+def average(images):
+ AVG = None
+ for name in images:
+ IM = scipy.ndimage.imread(name, mode='L')
+ A = numpy.array(IM, dtype=numpy.double)
+ if AVG is None:
+ AVG = A
+ else:
+ AVG += A
+ AVG /= len(images)
+ return numpy.array(AVG, dtype=numpy.uint8)
+
+def main(path):
+ ims = images(path)
+ if len(ims) == 0:
+ raise ValueError("folder '%s' doesn't contain any png files" % path)
+ AVG = average(ims)
+ imwrite('average.png', AVG)
+ plt.imshow(AVG)
+ plt.show()
+
+if __name__=='__main__':
+ import sys
+ main(sys.argv[1])
+```
+
+Look for bright spots in the luminosity average. If bright spots are found,
+action should be taken to change the shape of the clock face or increase the
+amount of pixel shifting.