offload refers to the screen rendering process by bg SidekickService, without rendering ap, this will save power consumption, long standby watch increases, retaining only the basic functions of the motion sensor, the motion mode is not turned on / GPS / WIFI / HR lamp module , the power consumption can save about 10%.
Rendering a dial in the watch .WearOS offload mode, it is drawn by BG. Conditions that dial into the offload watch dial is in the dim light mode and in Decomposable.
In order to satisfy the above conditions, it is necessary to develop dial to do the following configuration:
a.manifest mera-data is increased DecompositionWatchFaceService
<meta-data
android:name="com.google.android.wearable.watchface.decomposable"
android:value="true" />
b.updateDecomposition。
UpdateDecomposition must be called to generate a valid WatchFaceDecomposition, otherwise the system is considered ordinary dial. It is a common method
1. direct successor DecompositionWatchFaceService achieve buildDecomposition method.
2 can also customize CanvasWatchFaceService, but must implement WatchFaceDecomposition displayable by updateDecomposition and notification system.
c. resource requirements.
Under offload mode dial display font, the string must be presented in the form of "picture matting", for example, you want to show the number 1, to be deducted from digital pictures 1 font resource (FontComponent), the string is first converted into display BG drawable through the drawing, thus involving the dial string translation suggestions with complex data, because the complex data itself contains drawable, Home drawable be converted into the display dial ImageComponent convenience. Resources must be a bitmap image format, and must be RGB332, the dial can display up to 16 colors, does not support carry serrated, anti-burn-in mechanisms to continue to take effect in this mode.
II. How to confirm whether the watch successfully entered offload mode.
See addition AmbientService, SidekickService the log, but also can directly see the system power wake status, such as:
# dumpsys power | grep -i wake
no_cached_wake_locks=true
mWakefulness=Dozing
mWakefulnessChanging=false
mWakeLockSummary=0x40
mLastWakeTime=45074118 (11793 ms ago)
mHoldingWakeLockSuspendBlocker=false
mWakeUpWhenPluggedOrUnpluggedConfig=true
mWakeUpWhenPluggedOrUnpluggedInTheaterModeConfig=false
mDrawWakeLockOverrideFromSidekick=true
mDoubleTapWakeEnabled=false
Wake Locks: size=1
DOZE_WAKE_LOCK 'DreamManagerService' ACQ=-1s396ms (uid=1000 pid=1752)
PowerManagerService.WakeLocks: ref count=0
mGravitySensor={Sensor name="gravity Non-wakeup", vendor="qualcomm", version=1, type=9, maxRange=1.0, resolution=0.1, power=0.515, minDelay=20000}
When SidekickService. MShouldControlDisplay is true, the value is also true, in a state of holding the screen STATE_DOZE_SUSPEND: The display is dozing in a suspended low power state; it is still on but the CPU is not updating it.
SidekickService calculates the buildDecomposition WatchFaceDecomposition returned used Components (), and parse each Components
of the display area, home to the last call replaceWatchFaceComponents update.
03-09 17:18:45.329 1752 1911 I SidekickService: endDisplayLocked()
03-09 17:18:45.359 1752 1911 D SidekickService: ... endDisplay returns void
03-09 17:18:51.765 2390 4681 I SidekickManager: clearWatchFace called:
03-09 17:18:51.765 1752 1775 D SidekickService: resetLocked()
03-09 17:18:51.989 2390 4681 I SidekickManager: sendWatchFaceImpl(): watchFace = com.google.android.clockwork.decomposablewatchface.WatchFaceDecomposition@6673f0c forTWM = false
03-09 17:18:52.099 1752 1775 D SidekickService: sendWatchFaceComponents called: watchFace = com.google.android.clockwork.decomposablewatchface.WatchFaceDecomposition@468521shouldReplace = true
03-09 17:18:52.100 1752 1775 D SidekickService: sendWatchFaceLocked(): shouldReplace = true, mSidekickIsControlling = false, 8 images, 0 fonts, 0 numbers, 0 proportionalFonts, 0 strings
03-09 17:18:52.101 1752 1775 D SidekickService: ISidekickGraphics#beginResources()...
03-09 17:18:52.122 1752 1775 D SidekickServiceUtils: bitmapFromDrawable: Returning bitmap directly
03-09 17:18:52.208 1752 1775 D SidekickService: sendBitmapsLocked(): bounds = RectF(0.0, 0.0, 1.0, 1.0), drawableInfo = {.id = 2, .width = 338, .height = 412, .display = true, .offsetX = 0.0, .offsetY = 0.0, .rotationInfo = {.hasRotation = false, .pivotX = 0.0, .pivotY = 0.0, .degreesPerDay = 0.0, .degreesPerStep = 0.0, .zeroDegreesTime = {.daysSinceLocalEpoch = 0, .msSinceMidnight = 0}}, .transformInfo = {.transformed = false, .flipX = false, .flipY = false, .flip45 = false, .scaleX = 0.0, .scaleY = 0.0}, .type = GENERIC, .blink = {.blinking = false, .periodOnMs = 0.0, .periodOffMs = 0.0, .startTime = {.daysSinceLocalEpoch = 0, .msSinceMidnight = 0}}, .zOrder = 2, .displayInTwm = true}, image.size() = 1462
03-09 17:18:52.270 1752 1775 D SidekickService: sendBitmapsLocked(): status = 0, bytesUsed = 840
03-09 17:18:52.274 1752 1775 D SidekickServiceUtils: bitmapFromDrawable: Returning bitmap directly
03-09 17:18:52.275 1752 1775 D SidekickService: sendBitmapsLocked(): bounds = RectF(0.0, 0.0, 0.088757396, 0.07281554), drawableInfo = {.id = 10, .width = 30, .height = 30, .display = true, .offsetX = 0.0, .offsetY = 0.0, .rotationInfo = {.hasRotation = false, .pivotX = 0.0, .pivotY = 0.0, .degreesPerDay = 0.0, .degreesPerStep = 0.0, .zeroDegreesTime = {.daysSinceLocalEpoch = 0, .msSinceMidnight = 0}}, .transformInfo = {.transformed = false, .flipX = false, .flipY = false, .flip45 = false, .scaleX = 0.0, .scaleY = 0.0}, .type = GENERIC, .blink = {.blinking = false, .periodOnMs = 0.0, .periodOffMs = 0.0, .startTime = {.daysSinceLocalEpoch = 0, .msSinceMidnight = 0}}, .zOrder = 3, .displayInTwm = true}, image.size() = 131
03-09 17:18:52.279 1752 1775 D SidekickService: sendBitmapsLocked(): status = 0, bytesUsed = 75
03-09 17:18:52.279 1752 1775 D SidekickServiceUtils: bitmapFromDrawable: Returning bitmap directly
03-09 17:18:52.281 1752 1775 D SidekickService: sendBitmapsLocked(): bounds = RectF(0.9112426, 0.0, 1.0, 0.07281554), drawableInfo = {.id = 11, .width = 30, .height = 30, .display = true, .offsetX = 308.0, .offsetY = 0.0, .rotationInfo = {.hasRotation = false, .pivotX = 0.0, .pivotY = 0.0, .degreesPerDay = 0.0, .degreesPerStep = 0.0, .zeroDegreesTime = {.daysSinceLocalEpoch = 0, .msSinceMidnight = 0}}, .transformInfo = {.transformed = false, .flipX = false, .flipY = false, .flip45 = false, .scaleX = 0.0, .scaleY = 0.0}, .type = GENERIC, .blink = {.blinking = false, .periodOnMs = 0.0, .periodOffMs = 0.0, .startTime = {.daysSinceLocalEpoch = 0, .msSinceMidnight = 0}}, .zOrder = 3, .displayInTwm = true}, image.size() = 131
03-09 17:18:52.282 1752 1775 D SidekickService: sendBitmapsLocked(): status = 0, bytesUsed = 75
03-09 17:18:52.283 1752 1775 D SidekickServiceUtils: bitmapFromDrawable: Returning bitmap directly
03-09 17:18:52.286 1752 1775 D SidekickService: sendBitmapsLocked(): bounds = RectF(0.0, 0.92718446, 0.088757396, 1.0), drawableInfo = {.id = 12, .width = 30, .height = 30, .display = true, .offsetX = 0.0, .offsetY = 382.0, .rotationInfo = {.hasRotation = false, .pivotX = 0.0, .pivotY = 0.0, .degreesPerDay = 0.0, .degreesPerStep = 0.0, .zeroDegreesTime = {.daysSinceLocalEpoch = 0, .msSinceMidnight = 0}}, .transformInfo = {.transformed = false, .flipX = false, .flipY = false, .flip45 = false, .scaleX = 0.0, .scaleY = 0.0}, .type = GENERIC, .blink = {.blinking = false, .periodOnMs = 0.0, .periodOffMs = 0.0, .startTime = {.daysSinceLocalEpoch = 0, .msSinceMidnight = 0}}, .zOrder = 3, .displayInTwm = true}, image.size() = 131
03-09 17:18:52.289 1752 1775 D SidekickService: sendBitmapsLocked(): status = 0, bytesUsed = 75
03-09 17:18:52.290 1752 1775 D SidekickServiceUtils: bitmapFromDrawable: Returning bitmap directly
03-09 17:18:52.291 1752 1775 D SidekickService: sendBitmapsLocked(): bounds = RectF(0.9112426, 0.92718446, 1.0, 1.0), drawableInfo = {.id = 13, .width = 30, .height = 30, .display = true, .offsetX = 308.0, .offsetY = 382.0, .rotationInfo = {.hasRotation = false, .pivotX = 0.0, .pivotY = 0.0, .degreesPerDay = 0.0, .degreesPerStep = 0.0, .zeroDegreesTime = {.daysSinceLocalEpoch = 0, .msSinceMidnight = 0}}, .transformInfo = {.transformed = false, .flipX = false, .flipY = false, .flip45 = false, .scaleX = 0.0, .scaleY = 0.0}, .type = GENERIC, .blink = {.blinking = false, .periodOnMs = 0.0, .periodOffMs = 0.0, .startTime = {.daysSinceLocalEpoch = 0, .msSinceMidnight = 0}}, .zOrder = 3, .displayInTwm = true}, image.size() = 131
03-09 17:18:52.293 1752 1775 D SidekickService: sendBitmapsLocked(): status = 0, bytesUsed = 75
03-09 17:18:52.295 1752 1775 D SidekickServiceUtils: bitmapFromDrawable: Returning bitmap directly
03-09 17:18:52.296 1752 1775 D SidekickService: sendBitmapsLocked(): bounds = RectF(0.4704142, 0.47572815, 0.5295858, 0.52427185), drawableInfo = {.id = 14, .width = 20, .height = 20, .display = true, .offsetX = 159.0, .offsetY = 196.0, .rotationInfo = {.hasRotation = false, .pivotX = 0.0, .pivotY = 0.0, .degreesPerDay = 0.0, .degreesPerStep = 0.0, .zeroDegreesTime = {.daysSinceLocalEpoch = 0, .msSinceMidnight = 0}}, .transformInfo = {.transformed = false, .flipX = false, .flipY = false, .flip45 = false, .scaleX = 0.0, .scaleY = 0.0}, .type = GENERIC, .blink = {.blinking = false, .periodOnMs = 0.0, .periodOffMs = 0.0, .startTime = {.daysSinceLocalEpoch = 0, .msSinceMidnight = 0}}, .zOrder = 3, .displayInTwm = true}, image.size() = 143
03-09 17:18:52.298 1752 1775 D SidekickService: sendBitmapsLocked(): status = 0, bytesUsed = 60
03-09 17:18:52.299 1752 1775 D SidekickServiceUtils: bitmapFromDrawable: Returning bitmap directly
03-09 17:18:52.303 1752 1775 D SidekickService: sendBitmapsLocked(): bounds = RectF(0.46745563, 0.2669903, 0.5325444, 0.526699), drawableInfo = {.id = 15, .width = 22, .height = 107, .display = true, .offsetX = 158.0, .offsetY = 110.0, .rotationInfo = {.hasRotation = true, .pivotX = 11.0, .pivotY = 96.0, .degreesPerDay = 518400.0, .degreesPerStep = 6.0, .zeroDegreesTime = {.daysSinceLocalEpoch = 0, .msSinceMidnight = 60000}}, .transformInfo = {.transformed = false, .flipX = false, .flipY = false, .flip45 = false, .scaleX = 0.0, .scaleY = 0.0}, .type = ROTATING, .blink = {.blinking = false, .periodOnMs = 0.0, .periodOffMs = 0.0, .startTime = {.daysSinceLocalEpoch = 0, .msSinceMidnight = 0}}, .zOrder = 4, .displayInTwm = true}, image.size() = 241
03-09 17:18:52.306 1752 1775 D SidekickService: sendBitmapsLocked(): status = 0, bytesUsed = 2897
03-09 17:18:52.307 1752 1775 D SidekickServiceUtils: bitmapFromDrawable: Returning bitmap directly
03-09 17:18:52.309 1752 1775 D SidekickService: sendBitmapsLocked(): bounds = RectF(0.0, 0.0, 0.0027173914, 0.002232143), drawableInfo = {.id = 100000, .width = 1, .height = 1, .display = true, .offsetX = 0.0, .offsetY = 0.0, .rotationInfo = {.hasRotation = false, .pivotX = 0.0, .pivotY = 0.0, .degreesPerDay = 0.0, .degreesPerStep = 0.0, .zeroDegreesTime = {.daysSinceLocalEpoch = 0, .msSinceMidnight = 0}}, .transformInfo = {.transformed = false, .flipX = false, .flipY = false, .flip45 = false, .scaleX = 0.0, .scaleY = 0.0}, .type = GENERIC, .blink = {.blinking = false, .periodOnMs = 0.0, .periodOffMs = 0.0, .startTime = {.daysSinceLocalEpoch = 0, .msSinceMidnight = 0}}, .zOrder = 5, .displayInTwm = true}, image.size() = 84
03-09 17:18:52.310 1752 1775 D SidekickService: sendBitmapsLocked(): status = 0, bytesUsed = 18
03-09 17:18:52.310 1752 1775 D SidekickService: ISidekickGraphics#endResources()...
03-09 17:21:32.580 1752 2548 D SidekickService: sendBitmapsLocked(): status = 0, bytesUsed = 155
03-09 17:21:32.580 1752 2548 D SidekickService: ISidekickGraphics#endResources()...
03-09 17:21:32.812 2390 2390 D SidekickManagerAsync: replaceWatchFaceComponents(): Callback#onResult(): 0
03-09 17:21:32.819 1752 2548 D SidekickService: setShouldControlDisplay called: true
03-09 17:21:32.875 1752 1911 I SidekickService: beginDisplayLocked(): DOZE_SUSPEND
03-09 17:21:32.965 1752 1911 D SidekickService: ... beginDisplay result: 0 for halPower: 1
(standard input):17378:03-09 17:21:26.048 1752 19744 I AmbientService: [6e93f94] Showing watch face in offload mode, canceling alarm.
replaceWatchFaceComponents resources will be checked if the resource format is wrong, there will be related error message prompts, such as
03-09 17:32:01.810 2390 2390 D SidekickManagerAsync: sendWatchFace(): Callback#onResult(): 2
03-09 17:32:09.808 1752 1752 D SidekickService: setShouldControlDisplay called: false
03-09 17:32:09.861 2390 7074 I SidekickManager: replaceWatchFaceComponentsImpl(): watchFace = com.google.android.clockwork.decomposablewatchface.WatchFaceDecomposition@f4d00e1
03-09 17:32:09.862 1752 26357 D SidekickService: sendWatchFaceComponents called: watchFace = com.google.android.clockwork.decomposablewatchface.WatchFaceDecomposition@dfbff84shouldReplace = false
03-09 17:32:09.864 1752 26357 W SidekickService: Ignoring partial update to an invalid watchface
03-09 17:32:09.923 2390 2390 D SidekickManagerAsync: replaceWatchFaceComponents(): Callback#onResult(): 2
replaceWatchFaceComponents (): Callback # onResult (): returns 2, indicates an invalid dial.
Question three .Decomposable display pointer of the dial.
Enter offload mode.
Only display picture (if provided with the original rectangular area pointer ImageComponent inconsistent, the display will not be enlarged / reduced), based on this rule, when the region is inconsistent with the original RECF imageComponent provided to only 1. Dial the coordinates of the upper left corner valid. This is described in the Google Wear Partner Doc_ Decomposable Watch Face API documentation.
2. The rotation of the pointer shaft is always the central position of the drawing region BG (BG five drawing reference herein). Based on this rule, when the development Decomposable Watchface dial, the pointer must be "spin" something BG secured to the center position.
3. Even if satisfying the above two points, found found, the pointer during rotation, "rotation" something is still visible position shifted. To reduce this problem, modify the shape of the pointer, the dial center position of a circular fixed ImageComponent circle, the circle placed above the hour and minute hands, a second hand into the top circle.
4. Because carry sawtooth mode does not support offload, the display vector can not only display the bitmap, there will inevitably rough edges, so that the UI showing, comprising circular, elliptical, circular arc as the arc gradient Some do fine. And try not to use color, find the measured color may be because the screen is dark, bright color screen, the easier the more flash.
When the pointer is displayed at 5.offload mode dial, you can not carry serrated, looks really bad, says Google may be able to optimize the version in the future, but at present can only be improved by adjusting the pointer display picture.
Fourth, the watch dial Decomposable product demand.
Because Decomposable dial can save power consumption, the project hopes to use Decomposable dial, but the pointer dial display effect is not good, after communication with the product, design, prefer the digital version of Decomposable dial. Issue digital version Decomposable dial to consider.
1. The need for basic information display, basically decided to show hours, date, Sunday.
2. Due to offload mode dial can only display ImageComponent, ComplicationComponent, FontComponent, NumberComponent. The presence of these component are drawable form, taking into account the watches international string translation issues, only to show the basis of the above information ComplicationComponent form.
3. The system comes with clock complex UI data is difficult to meet our requirements. If you want to meet product requirements, we need to customize complex data show the division, date, Sunday. To watch the development of the world clock, you can increase the complexity of the data in this app.
4. Verify that since we had to be able to define complex data refresh as expected.
Five, BG drawing area.
Ambient entering the watch, in order to prevent a region of the screen causes the screen to appear bad block Steady, high-pass provides a "burn-proof" mechanism, the principle of the mechanism is a smaller area in an original display, in 1 to 2 minutes movement of the region within the time. Display area size is adjustable, but the specific adjustment rule is unclear, only know
2 * (10 + 2-DISPLAY_BURNIN_PIXEL_WIDTH * 2 + 2 * DISPLAY_BURNIN_PIXEL_HEIGHT not be greater than 255, and wherein DISPLAY_BURNIN_PIXEL_WIDTH DISPLAY_BURNIN_PIXEL_HEIGHT respectively subtracted when the anti-burn width, height.
For example, the original screen resolution of 368 * 448, DISPLAY_BURNIN_PIXEL_WIDTH = 30, DISPLAY_BURNIN_PIXEL_HEIGHT = 36. So in
Under ambient mode the actual display resolution 338 * 412 (screen burn preventing enabled).
logcat.01:1044:03-09 19:10:10.950033 1691 1732 D SidekickService: SidekickService#getCapabilities()
logcat.01:1067:03-09 19:10:11.002619 413 1733 D SKGHAL : getCapabilities: Capabilities returned
logcat.01:1068:03-09 19:10:11.002643 413 1733 D SKGHAL : getCapabilities: RGB bits = [3,3,2]
logcat.01:1069:03-09 19:10:11.002663 413 1733 D SKGHAL : getCapabilities: paletteSize = 16
logcat.01:1070:03-09 19:10:11.002680 413 1733 D SKGHAL : getCapabilities: operations = 1102000b
logcat.01:1071:03-09 19:10:11.002698 413 1733 D SKGHAL : getCapabilities: availMemory = 49800
logcat.01:1072:03-09 19:10:11.002718 413 1733 D SKGHAL : getCapabilities: (x, y) = (338, 412)
logcat.01:1074:03-09 19:10:11.004113 1691 1732 D SidekickService: SidekickService#getCapabilities(): {.capabilities = 285343755, .displaySizeX = 338, .displaySizeY = 412}