[Samsung Galaxy Watch] Zeuserx:
This is from the GWD file : C:\Program Files (x86)\GearWatchDesigner\plugins\com.samsung.gwd_1.6.2.201810300802.jar

This is a Java package. When looking inside with a "Java decompiler" (free download), find the loadXml.class and you'll see the following code. Once we analyze this, I think we can kind of figure out the schema.

package com.samsung.gwd;

import com.samsung.gwd.gef.models.ActionConfig;
import com.samsung.gwd.gef.models.ActionConfigEnum.ACTION_STATE;
import com.samsung.gwd.gef.models.Condition;
import com.samsung.gwd.gef.models.ModelAnimation;
import com.samsung.gwd.gef.models.ModelBackground;
import com.samsung.gwd.gef.models.ModelComponent;
import com.samsung.gwd.gef.models.ModelDigitalclock;
import com.samsung.gwd.gef.models.ModelGroup;
import com.samsung.gwd.gef.models.ModelHand;
import com.samsung.gwd.gef.models.ModelImage;
import com.samsung.gwd.gef.models.ModelIndex;
import com.samsung.gwd.gef.models.ModelRoot;
import com.samsung.gwd.gef.models.ModelText;
import com.samsung.gwd.source.Source;
import com.samsung.gwd.ui.dialog.bitmapfont.BitmapFont;
import com.samsung.gwd.utils.RM;
import com.samsung.gwd.utils.Util;
import java.awt.Color;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.log4j.Logger;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
import org.xml.sax.SAXException;

public class LoadXml
{
public static final int TIME_ONE_MINUTE = 900;
public static final int TIME_ONE_HOUR = 54000;
public static final double PLATFORM_HOUR_MINUTE_CORRECTION = 0.005D;
Project project;
ModelRoot root;
String path;
Document doc;
String projectDir;
int width;
int height;

public LoadXml(String path, String name, Project project)
{
this.path = path;
File file = new File(path + name);

this.project = project;

this.projectDir = project.getProjectDir();
if (file.isFile())
{
DocumentBuilderFactory docBuildFact = DocumentBuilderFactory.newInstance();
try
{
DocumentBuilder docBuild = docBuildFact.newDocumentBuilder();
this.doc = docBuild.parse(file);
this.doc.getDocumentElement().normalize();

NodeList watchface = this.doc.getElementsByTagName("watchface");
Node watchfaceNode = watchface.item(0);
this.width = Integer.parseInt(((Element)watchfaceNode).getAttribute("width"));
this.height = Integer.parseInt(((Element)watchfaceNode).getAttribute("height"));

NodeList groupsList = this.doc.getElementsByTagName("groups");
for (int i = 0; i < groupsList.getLength(); i++)
{
Node groupsNode = groupsList.item(i);
processGroups((Element)groupsNode);
}
}
catch (ParserConfigurationException e)
{
e.printStackTrace();
}
catch (SAXException e)
{
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}
}
else
{
Application.LOGGER.error("Loading XML failed : " + path + name);
}
}

void processGroups(Element groupsElmt)
{
if (groupsElmt.getAttribute("type").equals("ambient"))
{
this.project.initLowBitAmbientMode();
this.root = this.project.getAmbientLowRoot();
}
else if (groupsElmt.getAttribute("type").equals("ambient-fullcolor"))
{
this.project.initHighColorAmbientMode();
this.root = this.project.getAmbientHighRoot();
}
else if (groupsElmt.getAttribute("type").equals("current"))
{
this.root = this.project.getModelRoot();
}
else
{
this.root = this.project.getNormalRoot();
}
NodeList groupList = groupsElmt.getElementsByTagName("group");
for (int j = 0; j < groupList.getLength(); j++)
{
Node groupNode = groupList.item(j);
processGroup((Element)groupNode);
}
}

void processGroup(Element groupElm)
{
ModelGroup group = null;
ActionConfig actionConf = null;

String tmpStr = groupElm.getAttribute("x");
if (!groupElm.getAttribute("name").startsWith("__DEFAULT_GROUP")) {
if (!tmpStr.isEmpty())
{
group = new ModelGroup(this.root);
group.setRect(Integer.parseInt(groupElm.getAttribute("x")), Integer.parseInt(groupElm.getAttribute("y")),
Integer.parseInt(groupElm.getAttribute("width")), Integer.parseInt(groupElm.getAttribute("height")));
}
else
{
group = new ModelGroup(this.root);
group.setRect(0, 0, this.width, this.height);
}
}
Point groupLoc;
Point groupLoc;
if (!groupElm.getAttribute("x").isEmpty()) {
groupLoc = new Point(Integer.parseInt(groupElm.getAttribute("x")), Integer.parseInt(groupElm.getAttribute("y")));
} else {
groupLoc = new Point(0, 0);
}
NodeList groupChildList = groupElm.getChildNodes();
for (int i = 0; i < groupChildList.getLength(); i++)
{
Node childNode = groupChildList.item(i);
if ((childNode.getNodeType() == 1) && (childNode.getNodeName().equals("action")))
{
Element childElm = (Element)childNode;

String on_event = childElm.getAttribute("on_event");
if (on_event.equals("tap"))
{
String type = childElm.getAttribute("type");
if (type.equals("launch"))
{
NodeList launchList = childElm.getElementsByTagName("launch");
if (launchList.getLength() != 0)
{
Node launchNode = launchList.item(0);

String appid = ((Element)launchNode).getAttribute("app_id");
if (appid.isEmpty()) {
appid = ((Element)launchNode).getAttribute("preset");
}
if (actionConf != null) {
break;
}
actionConf = new ActionConfig(DeviceSpec.GEAR_S2.getOpenAppTable());
actionConf.setActionState("Open App");
actionConf.setSelectAppId(appid);
}
}
else if (type.equals("image-set-show-next"))
{
if (actionConf != null) {
break;
}
actionConf = new ActionConfig(DeviceSpec.GEAR_S2.getOpenAppTable());
actionConf.setActionState("Change Image");
}
}
}
}
for (int i = 0; i < groupChildList.getLength(); i++)
{
Node childNode = groupChildList.item(i);
if (childNode.getNodeType() == 1)
{
Element childElmnt = (Element)childNode;
if (childNode.getNodeName().equals("part"))
{
ModelComponent model = processPart(childElmnt, group, actionConf);
if (model != null)
{
model.setLocation(model.getLocation().x + groupLoc.x, model.getLocation().y + groupLoc.y);
try
{
if (actionConf == null) {
break;
}
actionConf.setModel(model);
model.setActionConfig(actionConf);
model.setButton(true);
}
catch (Exception e)
{
e.printStackTrace();
if (group == null)
{
this.root.removeChild(model); continue;
}
group.removeChild(model);

continue;
}
}
}
else if (childNode.getNodeName().equals("condition"))
{
ModelComponent model = processCondition(childElmnt, group, 0, 0, null, actionConf);
if (model != null)
{
model.setLocation(model.getLocation().x + groupLoc.x, model.getLocation().y + groupLoc.y);
try
{
if (group == null) {
this.root.addChild(model);
} else {
group.addChild(model);
}
if (actionConf == null) {
break;
}
actionConf.setModel(model);
model.setActionConfig(actionConf);
model.setButton(true);
}
catch (Exception e)
{
e.printStackTrace();
if (group == null) {
this.root.removeChild(model);
} else {
group.removeChild(model);
}
}
}
}
}
}
}

ModelComponent processPart(Element partElmt, ModelGroup group, ActionConfig actionConf)
{
Rectangle partRect = null;

String tmpStr = partElmt.getAttribute("x");
if (!tmpStr.isEmpty()) {
partRect = new Rectangle(Integer.parseInt(tmpStr),
Integer.parseInt(partElmt.getAttribute("y")),
Integer.parseInt(partElmt.getAttribute("width")),
Integer.parseInt(partElmt.getAttribute("height")));
}
String type = partElmt.getAttribute("type");
if (type.equals("image")) {
return processPartImage(partElmt, group, partRect, actionConf);
}
if (type.equals("text")) {
return processPartText(partElmt, group, partRect);
}
if (!type.equals("draw")) {
Application.LOGGER.error("Not supporeted part type : " + type);
}
return null;
}

ModelComponent processPartImage(Element partElmt, ModelGroup group, Rectangle partRect, ActionConfig actionConf)
{
ModelImage obj = null;
boolean isHands = false;
boolean isBackground = false;
boolean isIndex = false;
ModelComponent parent;
ModelComponent parent;
if (group != null) {
parent = group;
} else {
parent = this.root;
}
NodeList partAttrList = null;
Node partAttrNode = null;
Element partAttrElmnt = null;
Element metaElmnt = null;

partAttrList = partElmt.getElementsByTagName("metadata");
if (partAttrList.getLength() != 0)
{
for (int i = 0; i < partAttrList.getLength(); i++)
{
partAttrNode = partAttrList.item(i);
metaElmnt = (Element)partAttrNode;

String tmpStr = metaElmnt.getAttribute("type");
if (tmpStr.equals("hands")) {
isHands = true;
} else if (tmpStr.equals("background")) {
isBackground = true;
} else if (tmpStr.equals("index")) {
isIndex = true;
}
}
}
else
{
partAttrList = partElmt.getElementsByTagName("rotation");
if (partAttrList.getLength() != 0)
{
partAttrNode = partAttrList.item(0);
partAttrElmnt = (Element)partAttrNode;
if ((partAttrElmnt.getAttribute("source").equals("hour0-23.minute")) ||
(partAttrElmnt.getAttribute("source").equals("minute"))) {
isHands = true;
}
}
}
partAttrList = partElmt.getElementsByTagName("image-set");
if ((partAttrList.getLength() == 0) || ((actionConf != null) && (actionConf.getActionState() == ActionConfigEnum.ACTION_STATE.CHANGE_IMAGE)))
{
String baseName = null;
if ((actionConf != null) && (actionConf.getActionState() == ActionConfigEnum.ACTION_STATE.CHANGE_IMAGE))
{
String projResDir = new String(this.project.getProjectDir() + BuildConfig.PATH_XML);
partAttrList = partElmt.getElementsByTagName("image-set");
if (partAttrList.getLength() != 0)
{
int changeNum = 0;
NodeList imageSetChildList = partAttrList.item(0).getChildNodes();
for (int nodeIndex = 0; nodeIndex < imageSetChildList.getLength(); nodeIndex++)
{
Node imageSetChildNode = imageSetChildList.item(nodeIndex);
if (imageSetChildNode.getNodeType() == 1) {
if (imageSetChildNode.getNodeName().equals("image"))
{
Element imageElmnt = (Element)imageSetChildNode;
if (nodeIndex == 0)
{
baseName = imageElmnt.getTextContent();
}
else
{
if ((imageElmnt.getTextContent() == "") || (imageElmnt.getTextContent().compareTo(baseName) == 0))
{
actionConf.setChangeImage(null, changeNum, null);
}
else
{
String str_des = new String(imageElmnt.getTextContent());
if (System.getProperty("os.name").contains("Windows")) {
while (str_des.contains("/")) {
str_des = str_des.replace("/", File.separator);
}
}
actionConf.setChangeImage(RM.getImage(projResDir + str_des),
changeNum, projResDir + str_des);
}
changeNum++;
}
}
}
}
}
Rectangle tempRect = new Rectangle(partRect);
if (isHands) {
obj = new ModelHand(parent, this.path, baseName);
} else if (isBackground) {
obj = new ModelBackground(parent, this.path, baseName);
} else {
obj = new ModelImage(parent, this.path, baseName);
}
obj.setRect(tempRect);
}
else
{
partAttrList = partElmt.getElementsByTagName("image");

partAttrNode = partAttrList.item(0);
partAttrElmnt = (Element)partAttrNode;

NodeList partAttrChildList = partAttrNode.getChildNodes();
Rectangle tempRect = new Rectangle(partRect);
if (partAttrChildList.getLength() == 1)
{
if (isHands)
{
obj = new ModelHand(parent, this.path, partAttrElmnt.getTextContent());
obj.setRect(tempRect);
}
else if (isBackground)
{
obj = new ModelBackground(parent, this.path, partAttrElmnt.getTextContent());
obj.setRect(tempRect);
}
else if (isIndex)
{
String tmpStr = metaElmnt.getAttribute("image");
if (!tmpStr.isEmpty())
{
obj = new ModelIndex(parent, this.path, tmpStr);
obj.setRect(tempRect);
((ModelIndex)obj).setOriginalRect(new Rectangle(Integer.parseInt(metaElmnt.getAttribute("x")),
Integer.parseInt(metaElmnt.getAttribute("y")),
Integer.parseInt(metaElmnt.getAttribute("width")),
Integer.parseInt(metaElmnt.getAttribute("height"))));
}
else
{
obj = new ModelIndex(parent, this.path, partAttrElmnt.getTextContent());
obj.setRect(tempRect);
}
tmpStr = metaElmnt.getAttribute("range");
if (tmpStr.isEmpty()) {
return null;
}
((ModelIndex)obj).setRange(0.0D, Integer.parseInt(tmpStr));

tmpStr = metaElmnt.getAttribute("number");

((ModelIndex)obj).setNumber(Integer.parseInt(tmpStr));
((ModelIndex)obj).apply();

((ModelIndex)obj).setRect(tempRect);
}
else
{
obj = new ModelImage(parent, this.path, partAttrElmnt.getTextContent());
obj.setRect(tempRect);
}
}
else {
Application.LOGGER.error("LoadXml : Implement me - image condition, length=" + partAttrChildList.getLength());
}
}
if (obj != null)
{
partAttrList = partElmt.getElementsByTagName("color");
if (partAttrList.getLength() != 0)
{
partAttrNode = partAttrList.item(0);
partAttrElmnt = (Element)partAttrNode;

String tmpStr = partAttrElmnt.getAttribute("a");
if (!tmpStr.isEmpty())
{
tmpStr = partAttrElmnt.getAttribute("r");
if (!tmpStr.isEmpty())
{
obj.setFilterEnable(true);
float[] hsl = Color.RGBtoHSB(Integer.parseInt(partAttrElmnt.getAttribute("r")),
Integer.parseInt(partAttrElmnt.getAttribute("g")),
Integer.parseInt(partAttrElmnt.getAttribute("b")), null);

obj.setHue((int)(hsl[0] * 360.0F - 180.0F));
obj.setSaturation((int)(hsl[1] * 200.0F - 100.0F));
obj.setLightness((int)(hsl[2] * 200.0F - 100.0F));

obj.setAlpha(Integer.parseInt(partAttrElmnt.getAttribute("a")));
}
else
{
obj.setAlpha(Integer.parseInt(partAttrElmnt.getAttribute("a")));
}
}
}
partAttrList = partElmt.getElementsByTagName("rotation");
if (partAttrList.getLength() != 0)
{
partAttrNode = partAttrList.item(0);
partAttrElmnt = (Element)partAttrNode;

String source = partAttrElmnt.getAttribute("source");
if (!source.isEmpty())
{
if (isHands)
{
ModelHand hand = (ModelHand)obj;
hand.setSource(Source.findById(source));
if (!partElmt.getAttribute("x").isEmpty())
{
hand.setPivot(Integer.parseInt(partAttrElmnt.getAttribute("center_x")) +
Integer.parseInt(partElmt.getAttribute("x")),
Integer.parseInt(partAttrElmnt.getAttribute("center_y")) +
Integer.parseInt(partElmt.getAttribute("y")));

hand.setStartAngle(Double.parseDouble(partAttrElmnt.getAttribute("start_angle")));
hand.setEndAngle(Double.parseDouble(partAttrElmnt.getAttribute("end_angle")));
hand.setStartValue(Double.parseDouble(partAttrElmnt.getAttribute("start_value")));
hand.setEndValue(Double.parseDouble(partAttrElmnt.getAttribute("end_value")));
}
else
{
if (group == null) {
hand.setPivot(Integer.parseInt(partAttrElmnt.getAttribute("center_x")),
Integer.parseInt(partAttrElmnt.getAttribute("center_y")));
}
hand.setStartAngle(Double.parseDouble(partAttrElmnt.getAttribute("start_angle")));
hand.setEndAngle(Double.parseDouble(partAttrElmnt.getAttribute("end_angle")));
hand.setStartValue(Double.parseDouble(partAttrElmnt.getAttribute("start_value")));
hand.setEndValue(Double.parseDouble(partAttrElmnt.getAttribute("end_value")));
}
if (partAttrElmnt.getAttribute("animation").equals("tick"))
{
hand.setTensionFrame(Integer.parseInt(partAttrElmnt.getAttribute("tick_frame")) / 2);
hand.setTensionAngle(Double.parseDouble(partAttrElmnt.getAttribute("tick_angle")));
hand.setTension((int)(hand.getTensionAngle() * 100.0D / 6.0D));
hand.setTensionEnabled(true);
}
if (source.equals("hour0-11.minute"))
{
hand.setSource(Source.findById("hour0-23.minute"));
if (hand.getStartAngle() < hand.getEndAngle()) {
hand.setEndAngle(hand.getEndAngle() + 360.0D);
} else {
hand.setEndAngle(hand.getEndAngle() - 360.0D);
}
}
}
}
else if (!partAttrElmnt.getAttribute("angle").isEmpty()) {
if (Util.checkExprTag(partAttrElmnt.getAttribute("angle"))) {
obj.setAngle(Util.removeExprTag(partAttrElmnt.getAttribute("angle")));
} else {
obj.setAngle(Double.parseDouble(partAttrElmnt.getAttribute("angle")));
}
}
}
}
}
else
{
partAttrList = partElmt.getElementsByTagName("image-set");
if (partAttrList.getLength() != 0)
{
ModelAnimation ani = new ModelAnimation(parent);
int frameNum = 0;
ani.setRect(partRect);

NodeList imageSetChildList = partAttrList.item(0).getChildNodes();
for (int nodeIndex = 0; nodeIndex < imageSetChildList.getLength(); nodeIndex++)
{
Node imageSetChildNode = imageSetChildList.item(nodeIndex);
if (imageSetChildNode.getNodeType() == 1)
{
if (imageSetChildNode.getNodeName().equals("image"))
{
Element imageElmnt = (Element)imageSetChildNode;

ModelImage frameItem = new ModelImage(ani, this.path, imageElmnt.getTextContent());
frameItem.setRect(0, 0, partRect.width, partRect.height);
frameItem.setId("Frame " + (nodeIndex + 1));

frameItem.getCondition().deleteAll();
frameItem.getCondition().addItem(frameNum, frameNum + 1);
}
frameNum++;
}
}
partAttrList = partElmt.getElementsByTagName("color");
if (partAttrList.getLength() != 0)
{
partAttrNode = partAttrList.item(0);
partAttrElmnt = (Element)partAttrNode;

String tmpStr = partAttrElmnt.getAttribute("a");
if (!tmpStr.isEmpty()) {
ani.setAlpha(Integer.parseInt(partAttrElmnt.getAttribute("a")));
}
}
partAttrList = partElmt.getElementsByTagName("rotation");
if (partAttrList.getLength() != 0)
{
partAttrElmnt = (Element)partAttrList.item(0);
if (!partAttrElmnt.getAttribute("angle").isEmpty()) {
if (Util.checkExprTag(partAttrElmnt.getAttribute("angle"))) {
ani.setAngle(Util.removeExprTag(partAttrElmnt.getAttribute("angle")));
} else {
ani.setAngle(Double.parseDouble(partAttrElmnt.getAttribute("angle")));
}
}
}
return ani;
}
}
return obj;
}