1 /**
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5  * use this file except in compliance with the License. You may obtain a copy of
6  * the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13  * License for the specific language governing permissions and limitations under
14  * the License.
15  */
16 package com.android.launcher3.util;
17 
18 
19 import android.text.TextUtils;
20 import android.util.Pair;
21 import android.util.Xml;
22 
23 import org.xmlpull.v1.XmlSerializer;
24 
25 import java.io.IOException;
26 import java.io.StringWriter;
27 import java.io.Writer;
28 import java.util.ArrayList;
29 import java.util.HashMap;
30 import java.util.Map;
31 
32 /**
33  * Helper class to build xml for Launcher Layout
34  */
35 public class LauncherLayoutBuilder {
36 
37     // Object Tags
38     private static final String TAG_WORKSPACE = "workspace";
39     private static final String TAG_AUTO_INSTALL = "autoinstall";
40     private static final String TAG_FOLDER = "folder";
41     private static final String TAG_APPWIDGET = "appwidget";
42     private static final String TAG_EXTRA = "extra";
43 
44     private static final String ATTR_CONTAINER = "container";
45     private static final String ATTR_RANK = "rank";
46 
47     private static final String ATTR_PACKAGE_NAME = "packageName";
48     private static final String ATTR_CLASS_NAME = "className";
49     private static final String ATTR_TITLE = "title";
50     private static final String ATTR_TITLE_TEXT = "titleText";
51     private static final String ATTR_SCREEN = "screen";
52 
53     // x and y can be specified as negative integers, in which case -1 represents the
54     // last row / column, -2 represents the second last, and so on.
55     private static final String ATTR_X = "x";
56     private static final String ATTR_Y = "y";
57     private static final String ATTR_SPAN_X = "spanX";
58     private static final String ATTR_SPAN_Y = "spanY";
59 
60     private static final String ATTR_CHILDREN = "children";
61 
62 
63     // Style attrs -- "Extra"
64     private static final String ATTR_KEY = "key";
65     private static final String ATTR_VALUE = "value";
66 
67     private static final String CONTAINER_DESKTOP = "desktop";
68     private static final String CONTAINER_HOTSEAT = "hotseat";
69 
70     private final ArrayList<Pair<String, HashMap<String, Object>>> mNodes = new ArrayList<>();
71 
atHotseat(int rank)72     public Location atHotseat(int rank) {
73         Location l = new Location();
74         l.items.put(ATTR_CONTAINER, CONTAINER_HOTSEAT);
75         l.items.put(ATTR_RANK, Integer.toString(rank));
76         return l;
77     }
78 
atWorkspace(int x, int y, int screen)79     public Location atWorkspace(int x, int y, int screen) {
80         Location l = new Location();
81         l.items.put(ATTR_CONTAINER, CONTAINER_DESKTOP);
82         l.items.put(ATTR_X, Integer.toString(x));
83         l.items.put(ATTR_Y, Integer.toString(y));
84         l.items.put(ATTR_SCREEN, Integer.toString(screen));
85         return l;
86     }
87 
build()88     public String build() throws IOException {
89         StringWriter writer = new StringWriter();
90         build(writer);
91         return writer.toString();
92     }
93 
build(Writer writer)94     public void build(Writer writer) throws IOException {
95         XmlSerializer serializer = Xml.newSerializer();
96         serializer.setOutput(writer);
97 
98         serializer.startDocument("UTF-8", true);
99         serializer.startTag(null, TAG_WORKSPACE);
100         writeNodes(serializer, mNodes);
101         serializer.endTag(null, TAG_WORKSPACE);
102         serializer.endDocument();
103         serializer.flush();
104     }
105 
writeNodes(XmlSerializer serializer, ArrayList<Pair<String, HashMap<String, Object>>> nodes)106     private static void writeNodes(XmlSerializer serializer,
107             ArrayList<Pair<String, HashMap<String, Object>>> nodes) throws IOException {
108         for (Pair<String, HashMap<String, Object>> node : nodes) {
109             ArrayList<Pair<String, HashMap<String, Object>>> children = null;
110 
111             serializer.startTag(null, node.first);
112             for (Map.Entry<String, Object> attr : node.second.entrySet()) {
113                 if (ATTR_CHILDREN.equals(attr.getKey())) {
114                     children = (ArrayList<Pair<String, HashMap<String, Object>>>) attr.getValue();
115                 } else {
116                     serializer.attribute(null, attr.getKey(), (String) attr.getValue());
117                 }
118             }
119 
120             if (children != null) {
121                 writeNodes(serializer, children);
122             }
123             serializer.endTag(null, node.first);
124         }
125     }
126 
127     public class Location {
128 
129         final HashMap<String, Object> items = new HashMap<>();
130 
putApp(String packageName, String className)131         public LauncherLayoutBuilder putApp(String packageName, String className) {
132             items.put(ATTR_PACKAGE_NAME, packageName);
133             items.put(ATTR_CLASS_NAME, TextUtils.isEmpty(className) ? packageName : className);
134             mNodes.add(Pair.create(TAG_AUTO_INSTALL, items));
135             return LauncherLayoutBuilder.this;
136         }
137 
putWidget(String packageName, String className, int spanX, int spanY)138         public LauncherLayoutBuilder putWidget(String packageName, String className,
139                 int spanX, int spanY) {
140             items.put(ATTR_PACKAGE_NAME, packageName);
141             items.put(ATTR_CLASS_NAME, className);
142             items.put(ATTR_SPAN_X, Integer.toString(spanX));
143             items.put(ATTR_SPAN_Y, Integer.toString(spanY));
144             mNodes.add(Pair.create(TAG_APPWIDGET, items));
145             return LauncherLayoutBuilder.this;
146         }
147 
putFolder(int titleResId)148         public FolderBuilder putFolder(int titleResId) {
149             items.put(ATTR_TITLE, Integer.toString(titleResId));
150             return putFolder();
151         }
152 
putFolder(String title)153         public FolderBuilder putFolder(String title) {
154             items.put(ATTR_TITLE_TEXT, title);
155             return putFolder();
156         }
157 
putFolder()158         private FolderBuilder putFolder() {
159             FolderBuilder folderBuilder = new FolderBuilder();
160             items.put(ATTR_CHILDREN, folderBuilder.mChildren);
161             mNodes.add(Pair.create(TAG_FOLDER, items));
162             return folderBuilder;
163         }
164     }
165 
166     public class FolderBuilder {
167 
168         final ArrayList<Pair<String, HashMap<String, Object>>> mChildren = new ArrayList<>();
169 
addApp(String packageName, String className)170         public FolderBuilder addApp(String packageName, String className) {
171             HashMap<String, Object> items = new HashMap<>();
172             items.put(ATTR_PACKAGE_NAME, packageName);
173             items.put(ATTR_CLASS_NAME, TextUtils.isEmpty(className) ? packageName : className);
174             mChildren.add(Pair.create(TAG_AUTO_INSTALL, items));
175             return this;
176         }
177 
build()178         public LauncherLayoutBuilder build() {
179             return LauncherLayoutBuilder.this;
180         }
181     }
182 }
183