blob: 7257a12c24f46d7e205b7a32d313f089d31ef652 [file] [log] [blame]
Joe Onorato6f9d4bd2010-09-29 17:43:46 -07001#!/usr/bin/env python2.5
2
3import cgi
Winson Chung88381732013-07-12 13:41:18 -07004import codecs
Joe Onorato6f9d4bd2010-09-29 17:43:46 -07005import os
Winson Chung88381732013-07-12 13:41:18 -07006import pprint
Winson787e3fb2015-09-14 11:51:41 -07007import re
Joe Onorato6f9d4bd2010-09-29 17:43:46 -07008import shutil
9import sys
10import sqlite3
11
Winson Chung88381732013-07-12 13:41:18 -070012SCREENS = 0
Joe Onorato6f9d4bd2010-09-29 17:43:46 -070013COLUMNS = 4
14ROWS = 4
Winson Chung88381732013-07-12 13:41:18 -070015HOTSEAT_SIZE = 4
Joe Onorato6f9d4bd2010-09-29 17:43:46 -070016CELL_SIZE = 110
17
Winson Chung88381732013-07-12 13:41:18 -070018CONTAINER_DESKTOP = -100
19CONTAINER_HOTSEAT = -101
20
Joe Onorato6f9d4bd2010-09-29 17:43:46 -070021DIR = "db_files"
22AUTO_FILE = DIR + "/launcher.db"
23INDEX_FILE = DIR + "/index.html"
24
25def usage():
Winson787e3fb2015-09-14 11:51:41 -070026 print "usage: print_db.py launcher.db <4x4|5x5|5x6|...> -- prints a launcher.db with"
27 print " the specified grid size (rows x cols)"
28 print "usage: print_db.py <4x4|5x5|5x6|...> -- adb pulls a launcher.db from a device"
29 print " and prints it with the specified grid size (rows x cols)"
Joe Onorato6f9d4bd2010-09-29 17:43:46 -070030 print
31 print "The dump will be created in a directory called db_files in cwd."
32 print "This script will delete any db_files directory you have now"
33
34
35def make_dir():
36 shutil.rmtree(DIR, True)
37 os.makedirs(DIR)
38
Winson Chungd64d1762013-08-20 14:37:16 -070039def adb_root_remount():
40 os.system("adb root")
41 os.system("adb remount")
42
Joe Onorato6f9d4bd2010-09-29 17:43:46 -070043def pull_file(fn):
44 print "pull_file: " + fn
45 rv = os.system("adb pull"
Winson787e3fb2015-09-14 11:51:41 -070046 + " /data/data/com.android.launcher3/databases/launcher.db"
Joe Onorato6f9d4bd2010-09-29 17:43:46 -070047 + " " + fn);
48 if rv != 0:
49 print "adb pull failed"
50 sys.exit(1)
51
52def get_favorites(conn):
53 c = conn.cursor()
54 c.execute("SELECT * FROM favorites")
55 columns = [d[0] for d in c.description]
56 rows = []
57 for row in c:
58 rows.append(row)
59 return columns,rows
60
Winson Chungd64d1762013-08-20 14:37:16 -070061def get_screens(conn):
62 c = conn.cursor()
63 c.execute("SELECT * FROM workspaceScreens")
64 columns = [d[0] for d in c.description]
65 rows = []
66 for row in c:
67 rows.append(row)
68 return columns,rows
69
Joe Onorato6f9d4bd2010-09-29 17:43:46 -070070def print_intent(out, id, i, cell):
71 if cell:
72 out.write("""<span class="intent" title="%s">shortcut</span>""" % (
73 cgi.escape(cell, True)
74 ))
75
76
77def print_icon(out, id, i, cell):
78 if cell:
79 icon_fn = "icon_%d.png" % id
Winson Chung88381732013-07-12 13:41:18 -070080 out.write("""<img style="width: 3em; height: 3em;" src="%s">""" % ( icon_fn ))
Joe Onorato6f9d4bd2010-09-29 17:43:46 -070081 f = file(DIR + "/" + icon_fn, "w")
82 f.write(cell)
83 f.close()
84
Winson Chung88381732013-07-12 13:41:18 -070085def print_icon_type(out, id, i, cell):
86 if cell == 0:
87 out.write("Application (%d)" % cell)
88 elif cell == 1:
89 out.write("Shortcut (%d)" % cell)
90 elif cell == 2:
91 out.write("Folder (%d)" % cell)
92 elif cell == 4:
93 out.write("Widget (%d)" % cell)
94 elif cell:
95 out.write("%d" % cell)
96
Joe Onorato6f9d4bd2010-09-29 17:43:46 -070097def print_cell(out, id, i, cell):
98 if not cell is None:
Winson Chung88381732013-07-12 13:41:18 -070099 out.write(cgi.escape(unicode(cell)))
Joe Onorato6f9d4bd2010-09-29 17:43:46 -0700100
101FUNCTIONS = {
102 "intent": print_intent,
Winson Chung88381732013-07-12 13:41:18 -0700103 "icon": print_icon,
104 "iconType": print_icon_type
Joe Onorato6f9d4bd2010-09-29 17:43:46 -0700105}
106
Winson Chungbfc003a2011-08-24 11:32:02 -0700107def render_cell_info(out, cell, occupied):
108 if cell is None:
109 out.write(" <td width=%d height=%d></td>\n" %
110 (CELL_SIZE, CELL_SIZE))
111 elif cell == occupied:
112 pass
113 else:
114 cellX = cell["cellX"]
115 cellY = cell["cellY"]
116 spanX = cell["spanX"]
117 spanY = cell["spanY"]
118 intent = cell["intent"]
119 if intent:
120 title = "title=\"%s\"" % cgi.escape(cell["intent"], True)
121 else:
122 title = ""
123 out.write((" <td colspan=%d rowspan=%d width=%d height=%d"
124 + " bgcolor=#dddddd align=center valign=middle %s>") % (
125 spanX, spanY,
126 (CELL_SIZE*spanX), (CELL_SIZE*spanY),
127 title))
128 itemType = cell["itemType"]
129 if itemType == 0:
Winson Chung88381732013-07-12 13:41:18 -0700130 out.write("""<img style="width: 4em; height: 4em;" src="icon_%d.png">\n""" % ( cell["_id"] ))
Winson Chungbfc003a2011-08-24 11:32:02 -0700131 out.write("<br/>\n")
132 out.write(cgi.escape(cell["title"]) + " <br/><i>(app)</i>")
133 elif itemType == 1:
Winson Chung88381732013-07-12 13:41:18 -0700134 out.write("""<img style="width: 4em; height: 4em;" src="icon_%d.png">\n""" % ( cell["_id"] ))
Winson Chungbfc003a2011-08-24 11:32:02 -0700135 out.write("<br/>\n")
136 out.write(cgi.escape(cell["title"]) + " <br/><i>(shortcut)</i>")
137 elif itemType == 2:
138 out.write("""<i>folder</i>""")
Winson Chungbfc003a2011-08-24 11:32:02 -0700139 elif itemType == 4:
140 out.write("<i>widget %d</i><br/>\n" % cell["appWidgetId"])
Winson Chungbfc003a2011-08-24 11:32:02 -0700141 else:
142 out.write("<b>unknown type: %d</b>" % itemType)
143 out.write("</td>\n")
144
Winson Chungd64d1762013-08-20 14:37:16 -0700145def render_screen_info(out, screen):
146 out.write("<tr>")
147 out.write("<td>%s</td>" % (screen["_id"]))
148 out.write("<td>%s</td>" % (screen["screenRank"]))
149 out.write("</tr>")
150
Joe Onorato6f9d4bd2010-09-29 17:43:46 -0700151def process_file(fn):
Winson Chung88381732013-07-12 13:41:18 -0700152 global SCREENS, COLUMNS, ROWS, HOTSEAT_SIZE
Joe Onorato6f9d4bd2010-09-29 17:43:46 -0700153 print "process_file: " + fn
154 conn = sqlite3.connect(fn)
155 columns,rows = get_favorites(conn)
Winson Chungd64d1762013-08-20 14:37:16 -0700156 screenCols, screenRows = get_screens(conn)
Winson Chung88381732013-07-12 13:41:18 -0700157
Joe Onorato6f9d4bd2010-09-29 17:43:46 -0700158 data = [dict(zip(columns,row)) for row in rows]
Winson Chungd64d1762013-08-20 14:37:16 -0700159 screenData = [dict(zip(screenCols, screenRow)) for screenRow in screenRows]
Joe Onorato6f9d4bd2010-09-29 17:43:46 -0700160
Winson Chung88381732013-07-12 13:41:18 -0700161 # Calculate the proper number of screens, columns, and rows in this db
162 screensIdMap = []
163 hotseatIdMap = []
164 HOTSEAT_SIZE = 0
165 for d in data:
Winson Chung8481e322013-08-09 16:06:38 -0700166 if d["spanX"] is None:
167 d["spanX"] = 1
168 if d["spanY"] is None:
169 d["spanY"] = 1
Winson Chung88381732013-07-12 13:41:18 -0700170 if d["container"] == CONTAINER_DESKTOP:
171 if d["screen"] not in screensIdMap:
172 screensIdMap.append(d["screen"])
173 COLUMNS = max(COLUMNS, d["cellX"] + d["spanX"])
174 ROWS = max(ROWS, d["cellX"] + d["spanX"])
175 elif d["container"] == CONTAINER_HOTSEAT:
176 hotseatIdMap.append(d["screen"])
177 HOTSEAT_SIZE = max(HOTSEAT_SIZE, d["screen"] + 1)
178 SCREENS = len(screensIdMap)
179
180 out = codecs.open(INDEX_FILE, encoding="utf-8", mode="w")
Joe Onorato6f9d4bd2010-09-29 17:43:46 -0700181 out.write("""<html>
182<head>
183<style type="text/css">
184.intent {
185 font-style: italic;
186}
187</style>
188</head>
189<body>
190""")
191
192 # Data table
193 out.write("<b>Favorites table</b><br/>\n")
194 out.write("""<html>
195<table border=1 cellspacing=0 cellpadding=4>
196<tr>
197""")
198 print_functions = []
199 for col in columns:
200 print_functions.append(FUNCTIONS.get(col, print_cell))
201 for i in range(0,len(columns)):
202 col = columns[i]
203 out.write(""" <th>%s</th>
204""" % ( col ))
205 out.write("""
206</tr>
207""")
Winson Chung88381732013-07-12 13:41:18 -0700208
Joe Onorato6f9d4bd2010-09-29 17:43:46 -0700209 for row in rows:
210 out.write("""<tr>
211""")
212 for i in range(0,len(row)):
213 cell = row[i]
214 # row[0] is always _id
215 out.write(""" <td>""")
216 print_functions[i](out, row[0], row, cell)
217 out.write("""</td>
218""")
219 out.write("""</tr>
220""")
221 out.write("""</table>
222""")
223
Winson Chungd64d1762013-08-20 14:37:16 -0700224 # Screens
225 out.write("<br/><b>Screens</b><br/>\n")
226 out.write("<table class=layout border=1 cellspacing=0 cellpadding=4>\n")
227 out.write("<tr><td>Screen ID</td><td>Rank</td></tr>\n")
228 for screen in screenData:
229 render_screen_info(out, screen)
230 out.write("</table>\n")
231
Winson Chungbfc003a2011-08-24 11:32:02 -0700232 # Hotseat
233 hotseat = []
234 for i in range(0, HOTSEAT_SIZE):
235 hotseat.append(None)
236 for row in data:
Winson Chung88381732013-07-12 13:41:18 -0700237 if row["container"] != CONTAINER_HOTSEAT:
Winson Chungbfc003a2011-08-24 11:32:02 -0700238 continue
239 screen = row["screen"]
240 hotseat[screen] = row
241 out.write("<br/><b>Hotseat</b><br/>\n")
242 out.write("<table class=layout border=1 cellspacing=0 cellpadding=4>\n")
243 for cell in hotseat:
244 render_cell_info(out, cell, None)
245 out.write("</table>\n")
246
Joe Onorato6f9d4bd2010-09-29 17:43:46 -0700247 # Pages
248 screens = []
249 for i in range(0,SCREENS):
250 screen = []
251 for j in range(0,ROWS):
252 m = []
253 for k in range(0,COLUMNS):
254 m.append(None)
255 screen.append(m)
256 screens.append(screen)
257 occupied = "occupied"
258 for row in data:
Joe Onorato6f9d4bd2010-09-29 17:43:46 -0700259 # desktop
Winson Chung88381732013-07-12 13:41:18 -0700260 if row["container"] != CONTAINER_DESKTOP:
Joe Onorato6f9d4bd2010-09-29 17:43:46 -0700261 continue
Winson Chung88381732013-07-12 13:41:18 -0700262 screen = screens[screensIdMap.index(row["screen"])]
Joe Onorato6f9d4bd2010-09-29 17:43:46 -0700263 cellX = row["cellX"]
264 cellY = row["cellY"]
265 spanX = row["spanX"]
266 spanY = row["spanY"]
267 for j in range(cellY, cellY+spanY):
268 for k in range(cellX, cellX+spanX):
269 screen[j][k] = occupied
270 screen[cellY][cellX] = row
271 i=0
272 for screen in screens:
273 out.write("<br/><b>Screen %d</b><br/>\n" % i)
274 out.write("<table class=layout border=1 cellspacing=0 cellpadding=4>\n")
275 for m in screen:
276 out.write(" <tr>\n")
277 for cell in m:
Winson Chungbfc003a2011-08-24 11:32:02 -0700278 render_cell_info(out, cell, occupied)
Joe Onorato6f9d4bd2010-09-29 17:43:46 -0700279 out.write("</tr>\n")
280 out.write("</table>\n")
281 i=i+1
282
283 out.write("""
284</body>
285</html>
286""")
287
288 out.close()
289
Winson Chung88381732013-07-12 13:41:18 -0700290def updateDeviceClassConstants(str):
291 global SCREENS, COLUMNS, ROWS, HOTSEAT_SIZE
Winson787e3fb2015-09-14 11:51:41 -0700292 match = re.search(r"(\d+)x(\d+)", str)
293 if match:
294 COLUMNS = int(match.group(1))
295 ROWS = int(match.group(2))
296 HOTSEAT_SIZE = 2 * int(COLUMNS / 2)
Winson Chung88381732013-07-12 13:41:18 -0700297 return True
298 return False
299
Joe Onorato6f9d4bd2010-09-29 17:43:46 -0700300def main(argv):
Winson Chung88381732013-07-12 13:41:18 -0700301 if len(argv) == 1 or (len(argv) == 2 and updateDeviceClassConstants(argv[1])):
Joe Onorato6f9d4bd2010-09-29 17:43:46 -0700302 make_dir()
Winson Chungd64d1762013-08-20 14:37:16 -0700303 adb_root_remount()
Joe Onorato6f9d4bd2010-09-29 17:43:46 -0700304 pull_file(AUTO_FILE)
305 process_file(AUTO_FILE)
Winson Chung88381732013-07-12 13:41:18 -0700306 elif len(argv) == 2 or (len(argv) == 3 and updateDeviceClassConstants(argv[2])):
Joe Onorato6f9d4bd2010-09-29 17:43:46 -0700307 make_dir()
308 process_file(argv[1])
309 else:
310 usage()
311
312if __name__=="__main__":
313 main(sys.argv)