Joe Onorato | 6f9d4bd | 2010-09-29 17:43:46 -0700 | [diff] [blame] | 1 | #!/usr/bin/env python2.5 |
| 2 | |
| 3 | import cgi |
Winson Chung | 8838173 | 2013-07-12 13:41:18 -0700 | [diff] [blame] | 4 | import codecs |
Joe Onorato | 6f9d4bd | 2010-09-29 17:43:46 -0700 | [diff] [blame] | 5 | import os |
Winson Chung | 8838173 | 2013-07-12 13:41:18 -0700 | [diff] [blame] | 6 | import pprint |
Joe Onorato | 6f9d4bd | 2010-09-29 17:43:46 -0700 | [diff] [blame] | 7 | import shutil |
| 8 | import sys |
| 9 | import sqlite3 |
| 10 | |
Winson Chung | 8838173 | 2013-07-12 13:41:18 -0700 | [diff] [blame] | 11 | SCREENS = 0 |
Joe Onorato | 6f9d4bd | 2010-09-29 17:43:46 -0700 | [diff] [blame] | 12 | COLUMNS = 4 |
| 13 | ROWS = 4 |
Winson Chung | 8838173 | 2013-07-12 13:41:18 -0700 | [diff] [blame] | 14 | HOTSEAT_SIZE = 4 |
Joe Onorato | 6f9d4bd | 2010-09-29 17:43:46 -0700 | [diff] [blame] | 15 | CELL_SIZE = 110 |
| 16 | |
Winson Chung | 8838173 | 2013-07-12 13:41:18 -0700 | [diff] [blame] | 17 | CONTAINER_DESKTOP = -100 |
| 18 | CONTAINER_HOTSEAT = -101 |
| 19 | |
Joe Onorato | 6f9d4bd | 2010-09-29 17:43:46 -0700 | [diff] [blame] | 20 | DIR = "db_files" |
| 21 | AUTO_FILE = DIR + "/launcher.db" |
| 22 | INDEX_FILE = DIR + "/index.html" |
| 23 | |
| 24 | def usage(): |
Winson Chung | 8838173 | 2013-07-12 13:41:18 -0700 | [diff] [blame] | 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" |
Joe Onorato | 6f9d4bd | 2010-09-29 17:43:46 -0700 | [diff] [blame] | 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 | |
| 33 | def make_dir(): |
| 34 | shutil.rmtree(DIR, True) |
| 35 | os.makedirs(DIR) |
| 36 | |
Winson Chung | d64d176 | 2013-08-20 14:37:16 -0700 | [diff] [blame] | 37 | def adb_root_remount(): |
| 38 | os.system("adb root") |
| 39 | os.system("adb remount") |
| 40 | |
Joe Onorato | 6f9d4bd | 2010-09-29 17:43:46 -0700 | [diff] [blame] | 41 | def pull_file(fn): |
| 42 | print "pull_file: " + fn |
| 43 | rv = os.system("adb pull" |
Winson Chung | 8838173 | 2013-07-12 13:41:18 -0700 | [diff] [blame] | 44 | + " /data/data/com.google.android.googlequicksearchbox/databases/launcher.db" |
Joe Onorato | 6f9d4bd | 2010-09-29 17:43:46 -0700 | [diff] [blame] | 45 | + " " + fn); |
| 46 | if rv != 0: |
| 47 | print "adb pull failed" |
| 48 | sys.exit(1) |
| 49 | |
| 50 | def 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 | |
Winson Chung | d64d176 | 2013-08-20 14:37:16 -0700 | [diff] [blame] | 59 | def 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 | |
Joe Onorato | 6f9d4bd | 2010-09-29 17:43:46 -0700 | [diff] [blame] | 68 | def 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 | |
| 75 | def print_icon(out, id, i, cell): |
| 76 | if cell: |
| 77 | icon_fn = "icon_%d.png" % id |
Winson Chung | 8838173 | 2013-07-12 13:41:18 -0700 | [diff] [blame] | 78 | out.write("""<img style="width: 3em; height: 3em;" src="%s">""" % ( icon_fn )) |
Joe Onorato | 6f9d4bd | 2010-09-29 17:43:46 -0700 | [diff] [blame] | 79 | f = file(DIR + "/" + icon_fn, "w") |
| 80 | f.write(cell) |
| 81 | f.close() |
| 82 | |
Winson Chung | 8838173 | 2013-07-12 13:41:18 -0700 | [diff] [blame] | 83 | def 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 | |
Joe Onorato | 6f9d4bd | 2010-09-29 17:43:46 -0700 | [diff] [blame] | 95 | def print_cell(out, id, i, cell): |
| 96 | if not cell is None: |
Winson Chung | 8838173 | 2013-07-12 13:41:18 -0700 | [diff] [blame] | 97 | out.write(cgi.escape(unicode(cell))) |
Joe Onorato | 6f9d4bd | 2010-09-29 17:43:46 -0700 | [diff] [blame] | 98 | |
| 99 | FUNCTIONS = { |
| 100 | "intent": print_intent, |
Winson Chung | 8838173 | 2013-07-12 13:41:18 -0700 | [diff] [blame] | 101 | "icon": print_icon, |
| 102 | "iconType": print_icon_type |
Joe Onorato | 6f9d4bd | 2010-09-29 17:43:46 -0700 | [diff] [blame] | 103 | } |
| 104 | |
Winson Chung | bfc003a | 2011-08-24 11:32:02 -0700 | [diff] [blame] | 105 | def 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: |
Winson Chung | 8838173 | 2013-07-12 13:41:18 -0700 | [diff] [blame] | 128 | out.write("""<img style="width: 4em; height: 4em;" src="icon_%d.png">\n""" % ( cell["_id"] )) |
Winson Chung | bfc003a | 2011-08-24 11:32:02 -0700 | [diff] [blame] | 129 | out.write("<br/>\n") |
| 130 | out.write(cgi.escape(cell["title"]) + " <br/><i>(app)</i>") |
| 131 | elif itemType == 1: |
Winson Chung | 8838173 | 2013-07-12 13:41:18 -0700 | [diff] [blame] | 132 | out.write("""<img style="width: 4em; height: 4em;" src="icon_%d.png">\n""" % ( cell["_id"] )) |
Winson Chung | bfc003a | 2011-08-24 11:32:02 -0700 | [diff] [blame] | 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>""") |
Winson Chung | bfc003a | 2011-08-24 11:32:02 -0700 | [diff] [blame] | 137 | elif itemType == 4: |
| 138 | out.write("<i>widget %d</i><br/>\n" % cell["appWidgetId"]) |
Winson Chung | bfc003a | 2011-08-24 11:32:02 -0700 | [diff] [blame] | 139 | else: |
| 140 | out.write("<b>unknown type: %d</b>" % itemType) |
| 141 | out.write("</td>\n") |
| 142 | |
Winson Chung | d64d176 | 2013-08-20 14:37:16 -0700 | [diff] [blame] | 143 | def 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 | |
Joe Onorato | 6f9d4bd | 2010-09-29 17:43:46 -0700 | [diff] [blame] | 149 | def process_file(fn): |
Winson Chung | 8838173 | 2013-07-12 13:41:18 -0700 | [diff] [blame] | 150 | global SCREENS, COLUMNS, ROWS, HOTSEAT_SIZE |
Joe Onorato | 6f9d4bd | 2010-09-29 17:43:46 -0700 | [diff] [blame] | 151 | print "process_file: " + fn |
| 152 | conn = sqlite3.connect(fn) |
| 153 | columns,rows = get_favorites(conn) |
Winson Chung | d64d176 | 2013-08-20 14:37:16 -0700 | [diff] [blame] | 154 | screenCols, screenRows = get_screens(conn) |
Winson Chung | 8838173 | 2013-07-12 13:41:18 -0700 | [diff] [blame] | 155 | |
Joe Onorato | 6f9d4bd | 2010-09-29 17:43:46 -0700 | [diff] [blame] | 156 | data = [dict(zip(columns,row)) for row in rows] |
Winson Chung | d64d176 | 2013-08-20 14:37:16 -0700 | [diff] [blame] | 157 | screenData = [dict(zip(screenCols, screenRow)) for screenRow in screenRows] |
Joe Onorato | 6f9d4bd | 2010-09-29 17:43:46 -0700 | [diff] [blame] | 158 | |
Winson Chung | 8838173 | 2013-07-12 13:41:18 -0700 | [diff] [blame] | 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: |
Winson Chung | 8481e32 | 2013-08-09 16:06:38 -0700 | [diff] [blame] | 164 | if d["spanX"] is None: |
| 165 | d["spanX"] = 1 |
| 166 | if d["spanY"] is None: |
| 167 | d["spanY"] = 1 |
Winson Chung | 8838173 | 2013-07-12 13:41:18 -0700 | [diff] [blame] | 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") |
Joe Onorato | 6f9d4bd | 2010-09-29 17:43:46 -0700 | [diff] [blame] | 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 | """) |
Winson Chung | 8838173 | 2013-07-12 13:41:18 -0700 | [diff] [blame] | 206 | |
Joe Onorato | 6f9d4bd | 2010-09-29 17:43:46 -0700 | [diff] [blame] | 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 | |
Winson Chung | d64d176 | 2013-08-20 14:37:16 -0700 | [diff] [blame] | 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 | |
Winson Chung | bfc003a | 2011-08-24 11:32:02 -0700 | [diff] [blame] | 230 | # Hotseat |
| 231 | hotseat = [] |
| 232 | for i in range(0, HOTSEAT_SIZE): |
| 233 | hotseat.append(None) |
| 234 | for row in data: |
Winson Chung | 8838173 | 2013-07-12 13:41:18 -0700 | [diff] [blame] | 235 | if row["container"] != CONTAINER_HOTSEAT: |
Winson Chung | bfc003a | 2011-08-24 11:32:02 -0700 | [diff] [blame] | 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 | |
Joe Onorato | 6f9d4bd | 2010-09-29 17:43:46 -0700 | [diff] [blame] | 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: |
Joe Onorato | 6f9d4bd | 2010-09-29 17:43:46 -0700 | [diff] [blame] | 257 | # desktop |
Winson Chung | 8838173 | 2013-07-12 13:41:18 -0700 | [diff] [blame] | 258 | if row["container"] != CONTAINER_DESKTOP: |
Joe Onorato | 6f9d4bd | 2010-09-29 17:43:46 -0700 | [diff] [blame] | 259 | continue |
Winson Chung | 8838173 | 2013-07-12 13:41:18 -0700 | [diff] [blame] | 260 | screen = screens[screensIdMap.index(row["screen"])] |
Joe Onorato | 6f9d4bd | 2010-09-29 17:43:46 -0700 | [diff] [blame] | 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: |
Winson Chung | bfc003a | 2011-08-24 11:32:02 -0700 | [diff] [blame] | 276 | render_cell_info(out, cell, occupied) |
Joe Onorato | 6f9d4bd | 2010-09-29 17:43:46 -0700 | [diff] [blame] | 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 | |
Winson Chung | 8838173 | 2013-07-12 13:41:18 -0700 | [diff] [blame] | 288 | def 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 | |
Joe Onorato | 6f9d4bd | 2010-09-29 17:43:46 -0700 | [diff] [blame] | 303 | def main(argv): |
Winson Chung | 8838173 | 2013-07-12 13:41:18 -0700 | [diff] [blame] | 304 | if len(argv) == 1 or (len(argv) == 2 and updateDeviceClassConstants(argv[1])): |
Joe Onorato | 6f9d4bd | 2010-09-29 17:43:46 -0700 | [diff] [blame] | 305 | make_dir() |
Winson Chung | d64d176 | 2013-08-20 14:37:16 -0700 | [diff] [blame] | 306 | adb_root_remount() |
Joe Onorato | 6f9d4bd | 2010-09-29 17:43:46 -0700 | [diff] [blame] | 307 | pull_file(AUTO_FILE) |
| 308 | process_file(AUTO_FILE) |
Winson Chung | 8838173 | 2013-07-12 13:41:18 -0700 | [diff] [blame] | 309 | elif len(argv) == 2 or (len(argv) == 3 and updateDeviceClassConstants(argv[2])): |
Joe Onorato | 6f9d4bd | 2010-09-29 17:43:46 -0700 | [diff] [blame] | 310 | make_dir() |
| 311 | process_file(argv[1]) |
| 312 | else: |
| 313 | usage() |
| 314 | |
| 315 | if __name__=="__main__": |
| 316 | main(sys.argv) |