print_db.py revision d64d1763c590b1c954b759156683abf39ff22945
1#!/usr/bin/env python2.5
2
3import cgi
4import codecs
5import os
6import pprint
7import shutil
8import sys
9import sqlite3
10
11SCREENS = 0
12COLUMNS = 4
13ROWS = 4
14HOTSEAT_SIZE = 4
15CELL_SIZE = 110
16
17CONTAINER_DESKTOP = -100
18CONTAINER_HOTSEAT = -101
19
20DIR = "db_files"
21AUTO_FILE = DIR + "/launcher.db"
22INDEX_FILE = DIR + "/index.html"
23
24def usage():
25  print "usage: print_db.py launcher.db <sw600|sw720> -- prints a launcher.db"
26  print "usage: print_db.py <sw600|sw720> -- adb pulls a launcher.db from a device"
27  print "       and prints it"
28  print
29  print "The dump will be created in a directory called db_files in cwd."
30  print "This script will delete any db_files directory you have now"
31
32
33def make_dir():
34  shutil.rmtree(DIR, True)
35  os.makedirs(DIR)
36
37def adb_root_remount():
38  os.system("adb root")
39  os.system("adb remount")
40
41def pull_file(fn):
42  print "pull_file: " + fn
43  rv = os.system("adb pull"
44    + " /data/data/com.google.android.googlequicksearchbox/databases/launcher.db"
45    + " " + fn);
46  if rv != 0:
47    print "adb pull failed"
48    sys.exit(1)
49
50def get_favorites(conn):
51  c = conn.cursor()
52  c.execute("SELECT * FROM favorites")
53  columns = [d[0] for d in c.description]
54  rows = []
55  for row in c:
56    rows.append(row)
57  return columns,rows
58
59def get_screens(conn):
60  c = conn.cursor()
61  c.execute("SELECT * FROM workspaceScreens")
62  columns = [d[0] for d in c.description]
63  rows = []
64  for row in c:
65    rows.append(row)
66  return columns,rows
67
68def print_intent(out, id, i, cell):
69  if cell:
70    out.write("""<span class="intent" title="%s">shortcut</span>""" % (
71        cgi.escape(cell, True)
72      ))
73
74
75def print_icon(out, id, i, cell):
76  if cell:
77    icon_fn = "icon_%d.png" % id
78    out.write("""<img style="width: 3em; height: 3em;" src="%s">""" % ( icon_fn ))
79    f = file(DIR + "/" + icon_fn, "w")
80    f.write(cell)
81    f.close()
82
83def print_icon_type(out, id, i, cell):
84  if cell == 0:
85    out.write("Application (%d)" % cell)
86  elif cell == 1:
87    out.write("Shortcut (%d)" % cell)
88  elif cell == 2:
89    out.write("Folder (%d)" % cell)
90  elif cell == 4:
91    out.write("Widget (%d)" % cell)
92  elif cell:
93    out.write("%d" % cell)
94
95def print_cell(out, id, i, cell):
96  if not cell is None:
97    out.write(cgi.escape(unicode(cell)))
98
99FUNCTIONS = {
100  "intent": print_intent,
101  "icon": print_icon,
102  "iconType": print_icon_type
103}
104
105def render_cell_info(out, cell, occupied):
106  if cell is None:
107    out.write("    <td width=%d height=%d></td>\n" %
108        (CELL_SIZE, CELL_SIZE))
109  elif cell == occupied:
110    pass
111  else:
112    cellX = cell["cellX"]
113    cellY = cell["cellY"]
114    spanX = cell["spanX"]
115    spanY = cell["spanY"]
116    intent = cell["intent"]
117    if intent:
118      title = "title=\"%s\"" % cgi.escape(cell["intent"], True)
119    else:
120      title = ""
121    out.write(("    <td colspan=%d rowspan=%d width=%d height=%d"
122        + " bgcolor=#dddddd align=center valign=middle %s>") % (
123          spanX, spanY,
124          (CELL_SIZE*spanX), (CELL_SIZE*spanY),
125          title))
126    itemType = cell["itemType"]
127    if itemType == 0:
128      out.write("""<img style="width: 4em; height: 4em;" src="icon_%d.png">\n""" % ( cell["_id"] ))
129      out.write("<br/>\n")
130      out.write(cgi.escape(cell["title"]) + " <br/><i>(app)</i>")
131    elif itemType == 1:
132      out.write("""<img style="width: 4em; height: 4em;" src="icon_%d.png">\n""" % ( cell["_id"] ))
133      out.write("<br/>\n")
134      out.write(cgi.escape(cell["title"]) + " <br/><i>(shortcut)</i>")
135    elif itemType == 2:
136      out.write("""<i>folder</i>""")
137    elif itemType == 4:
138      out.write("<i>widget %d</i><br/>\n" % cell["appWidgetId"])
139    else:
140      out.write("<b>unknown type: %d</b>" % itemType)
141    out.write("</td>\n")
142
143def render_screen_info(out, screen):
144  out.write("<tr>")
145  out.write("<td>%s</td>" % (screen["_id"]))
146  out.write("<td>%s</td>" % (screen["screenRank"]))
147  out.write("</tr>")
148
149def process_file(fn):
150  global SCREENS, COLUMNS, ROWS, HOTSEAT_SIZE
151  print "process_file: " + fn
152  conn = sqlite3.connect(fn)
153  columns,rows = get_favorites(conn)
154  screenCols, screenRows = get_screens(conn)
155
156  data = [dict(zip(columns,row)) for row in rows]
157  screenData = [dict(zip(screenCols, screenRow)) for screenRow in screenRows]
158
159  # Calculate the proper number of screens, columns, and rows in this db
160  screensIdMap = []
161  hotseatIdMap = []
162  HOTSEAT_SIZE = 0
163  for d in data:
164    if d["spanX"] is None:
165      d["spanX"] = 1
166    if d["spanY"] is None:
167      d["spanY"] = 1
168    if d["container"] == CONTAINER_DESKTOP:
169      if d["screen"] not in screensIdMap:
170        screensIdMap.append(d["screen"])
171      COLUMNS = max(COLUMNS, d["cellX"] + d["spanX"])
172      ROWS = max(ROWS, d["cellX"] + d["spanX"])
173    elif d["container"] == CONTAINER_HOTSEAT:
174      hotseatIdMap.append(d["screen"])
175      HOTSEAT_SIZE = max(HOTSEAT_SIZE, d["screen"] + 1)
176  SCREENS = len(screensIdMap)
177
178  out = codecs.open(INDEX_FILE, encoding="utf-8", mode="w")
179  out.write("""<html>
180<head>
181<style type="text/css">
182.intent {
183  font-style: italic;
184}
185</style>
186</head>
187<body>
188""")
189
190  # Data table
191  out.write("<b>Favorites table</b><br/>\n")
192  out.write("""<html>
193<table border=1 cellspacing=0 cellpadding=4>
194<tr>
195""")
196  print_functions = []
197  for col in columns:
198    print_functions.append(FUNCTIONS.get(col, print_cell))
199  for i in range(0,len(columns)):
200    col = columns[i]
201    out.write("""  <th>%s</th>
202""" % ( col ))
203  out.write("""
204</tr>
205""")
206
207  for row in rows:
208    out.write("""<tr>
209""")
210    for i in range(0,len(row)):
211      cell = row[i]
212      # row[0] is always _id
213      out.write("""  <td>""")
214      print_functions[i](out, row[0], row, cell)
215      out.write("""</td>
216""")
217    out.write("""</tr>
218""")
219  out.write("""</table>
220""")
221
222  # Screens
223  out.write("<br/><b>Screens</b><br/>\n")
224  out.write("<table class=layout border=1 cellspacing=0 cellpadding=4>\n")
225  out.write("<tr><td>Screen ID</td><td>Rank</td></tr>\n")
226  for screen in screenData:
227    render_screen_info(out, screen)
228  out.write("</table>\n")
229
230  # Hotseat
231  hotseat = []
232  for i in range(0, HOTSEAT_SIZE):
233    hotseat.append(None)
234  for row in data:
235    if row["container"] != CONTAINER_HOTSEAT:
236      continue
237    screen = row["screen"]
238    hotseat[screen] = row
239  out.write("<br/><b>Hotseat</b><br/>\n")
240  out.write("<table class=layout border=1 cellspacing=0 cellpadding=4>\n")
241  for cell in hotseat:
242    render_cell_info(out, cell, None)
243  out.write("</table>\n")
244
245  # Pages
246  screens = []
247  for i in range(0,SCREENS):
248    screen = []
249    for j in range(0,ROWS):
250      m = []
251      for k in range(0,COLUMNS):
252        m.append(None)
253      screen.append(m)
254    screens.append(screen)
255  occupied = "occupied"
256  for row in data:
257    # desktop
258    if row["container"] != CONTAINER_DESKTOP:
259      continue
260    screen = screens[screensIdMap.index(row["screen"])]
261    cellX = row["cellX"]
262    cellY = row["cellY"]
263    spanX = row["spanX"]
264    spanY = row["spanY"]
265    for j in range(cellY, cellY+spanY):
266      for k in range(cellX, cellX+spanX):
267        screen[j][k] = occupied
268    screen[cellY][cellX] = row
269  i=0
270  for screen in screens:
271    out.write("<br/><b>Screen %d</b><br/>\n" % i)
272    out.write("<table class=layout border=1 cellspacing=0 cellpadding=4>\n")
273    for m in screen:
274      out.write("  <tr>\n")
275      for cell in m:
276        render_cell_info(out, cell, occupied)
277      out.write("</tr>\n")
278    out.write("</table>\n")
279    i=i+1
280
281  out.write("""
282</body>
283</html>
284""")
285
286  out.close()
287
288def updateDeviceClassConstants(str):
289  global SCREENS, COLUMNS, ROWS, HOTSEAT_SIZE
290  devClass = str.lower()
291  if devClass == "sw600":
292    COLUMNS = 6
293    ROWS = 6
294    HOTSEAT_SIZE = 6
295    return True
296  elif devClass == "sw720":
297    COLUMNS = 8
298    ROWS = 6
299    HOTSEAT_SIZE = 8
300    return True
301  return False
302
303def main(argv):
304  if len(argv) == 1 or (len(argv) == 2 and updateDeviceClassConstants(argv[1])):
305    make_dir()
306    adb_root_remount()
307    pull_file(AUTO_FILE)
308    process_file(AUTO_FILE)
309  elif len(argv) == 2 or (len(argv) == 3 and updateDeviceClassConstants(argv[2])):
310    make_dir()
311    process_file(argv[1])
312  else:
313    usage()
314
315if __name__=="__main__":
316  main(sys.argv)
317