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 |
Winson | 787e3fb | 2015-09-14 11:51:41 -0700 | [diff] [blame] | 7 | import re |
Joe Onorato | 6f9d4bd | 2010-09-29 17:43:46 -0700 | [diff] [blame] | 8 | import shutil |
| 9 | import sys |
| 10 | import sqlite3 |
| 11 | |
Winson Chung | 8838173 | 2013-07-12 13:41:18 -0700 | [diff] [blame] | 12 | SCREENS = 0 |
Joe Onorato | 6f9d4bd | 2010-09-29 17:43:46 -0700 | [diff] [blame] | 13 | COLUMNS = 4 |
| 14 | ROWS = 4 |
Winson Chung | 8838173 | 2013-07-12 13:41:18 -0700 | [diff] [blame] | 15 | HOTSEAT_SIZE = 4 |
Joe Onorato | 6f9d4bd | 2010-09-29 17:43:46 -0700 | [diff] [blame] | 16 | CELL_SIZE = 110 |
| 17 | |
Winson Chung | 8838173 | 2013-07-12 13:41:18 -0700 | [diff] [blame] | 18 | CONTAINER_DESKTOP = -100 |
| 19 | CONTAINER_HOTSEAT = -101 |
| 20 | |
Joe Onorato | 6f9d4bd | 2010-09-29 17:43:46 -0700 | [diff] [blame] | 21 | DIR = "db_files" |
| 22 | AUTO_FILE = DIR + "/launcher.db" |
| 23 | INDEX_FILE = DIR + "/index.html" |
| 24 | |
| 25 | def usage(): |
Winson | 787e3fb | 2015-09-14 11:51:41 -0700 | [diff] [blame] | 26 | 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 Onorato | 6f9d4bd | 2010-09-29 17:43:46 -0700 | [diff] [blame] | 30 | 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 | |
| 35 | def make_dir(): |
| 36 | shutil.rmtree(DIR, True) |
| 37 | os.makedirs(DIR) |
| 38 | |
Winson Chung | d64d176 | 2013-08-20 14:37:16 -0700 | [diff] [blame] | 39 | def adb_root_remount(): |
| 40 | os.system("adb root") |
| 41 | os.system("adb remount") |
| 42 | |
Joe Onorato | 6f9d4bd | 2010-09-29 17:43:46 -0700 | [diff] [blame] | 43 | def pull_file(fn): |
| 44 | print "pull_file: " + fn |
| 45 | rv = os.system("adb pull" |
Winson | 787e3fb | 2015-09-14 11:51:41 -0700 | [diff] [blame] | 46 | + " /data/data/com.android.launcher3/databases/launcher.db" |
Joe Onorato | 6f9d4bd | 2010-09-29 17:43:46 -0700 | [diff] [blame] | 47 | + " " + fn); |
| 48 | if rv != 0: |
| 49 | print "adb pull failed" |
| 50 | sys.exit(1) |
| 51 | |
| 52 | def 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 Chung | d64d176 | 2013-08-20 14:37:16 -0700 | [diff] [blame] | 61 | def 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 Onorato | 6f9d4bd | 2010-09-29 17:43:46 -0700 | [diff] [blame] | 70 | def 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 | |
| 77 | def print_icon(out, id, i, cell): |
| 78 | if cell: |
| 79 | icon_fn = "icon_%d.png" % id |
Winson Chung | 8838173 | 2013-07-12 13:41:18 -0700 | [diff] [blame] | 80 | out.write("""<img style="width: 3em; height: 3em;" src="%s">""" % ( icon_fn )) |
Joe Onorato | 6f9d4bd | 2010-09-29 17:43:46 -0700 | [diff] [blame] | 81 | f = file(DIR + "/" + icon_fn, "w") |
| 82 | f.write(cell) |
| 83 | f.close() |
| 84 | |
Winson Chung | 8838173 | 2013-07-12 13:41:18 -0700 | [diff] [blame] | 85 | def 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 Onorato | 6f9d4bd | 2010-09-29 17:43:46 -0700 | [diff] [blame] | 97 | def print_cell(out, id, i, cell): |
| 98 | if not cell is None: |
Winson Chung | 8838173 | 2013-07-12 13:41:18 -0700 | [diff] [blame] | 99 | out.write(cgi.escape(unicode(cell))) |
Joe Onorato | 6f9d4bd | 2010-09-29 17:43:46 -0700 | [diff] [blame] | 100 | |
| 101 | FUNCTIONS = { |
| 102 | "intent": print_intent, |
Winson Chung | 8838173 | 2013-07-12 13:41:18 -0700 | [diff] [blame] | 103 | "icon": print_icon, |
| 104 | "iconType": print_icon_type |
Joe Onorato | 6f9d4bd | 2010-09-29 17:43:46 -0700 | [diff] [blame] | 105 | } |
| 106 | |
Winson Chung | bfc003a | 2011-08-24 11:32:02 -0700 | [diff] [blame] | 107 | def 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 Chung | 8838173 | 2013-07-12 13:41:18 -0700 | [diff] [blame] | 130 | 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] | 131 | out.write("<br/>\n") |
| 132 | out.write(cgi.escape(cell["title"]) + " <br/><i>(app)</i>") |
| 133 | elif itemType == 1: |
Winson Chung | 8838173 | 2013-07-12 13:41:18 -0700 | [diff] [blame] | 134 | 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] | 135 | 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 Chung | bfc003a | 2011-08-24 11:32:02 -0700 | [diff] [blame] | 139 | elif itemType == 4: |
| 140 | out.write("<i>widget %d</i><br/>\n" % cell["appWidgetId"]) |
Winson Chung | bfc003a | 2011-08-24 11:32:02 -0700 | [diff] [blame] | 141 | else: |
| 142 | out.write("<b>unknown type: %d</b>" % itemType) |
| 143 | out.write("</td>\n") |
| 144 | |
Winson Chung | d64d176 | 2013-08-20 14:37:16 -0700 | [diff] [blame] | 145 | def 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 Onorato | 6f9d4bd | 2010-09-29 17:43:46 -0700 | [diff] [blame] | 151 | def process_file(fn): |
Winson Chung | 8838173 | 2013-07-12 13:41:18 -0700 | [diff] [blame] | 152 | global SCREENS, COLUMNS, ROWS, HOTSEAT_SIZE |
Joe Onorato | 6f9d4bd | 2010-09-29 17:43:46 -0700 | [diff] [blame] | 153 | print "process_file: " + fn |
| 154 | conn = sqlite3.connect(fn) |
| 155 | columns,rows = get_favorites(conn) |
Winson Chung | d64d176 | 2013-08-20 14:37:16 -0700 | [diff] [blame] | 156 | screenCols, screenRows = get_screens(conn) |
Winson Chung | 8838173 | 2013-07-12 13:41:18 -0700 | [diff] [blame] | 157 | |
Joe Onorato | 6f9d4bd | 2010-09-29 17:43:46 -0700 | [diff] [blame] | 158 | data = [dict(zip(columns,row)) for row in rows] |
Winson Chung | d64d176 | 2013-08-20 14:37:16 -0700 | [diff] [blame] | 159 | screenData = [dict(zip(screenCols, screenRow)) for screenRow in screenRows] |
Joe Onorato | 6f9d4bd | 2010-09-29 17:43:46 -0700 | [diff] [blame] | 160 | |
Winson Chung | 8838173 | 2013-07-12 13:41:18 -0700 | [diff] [blame] | 161 | # 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 Chung | 8481e32 | 2013-08-09 16:06:38 -0700 | [diff] [blame] | 166 | if d["spanX"] is None: |
| 167 | d["spanX"] = 1 |
| 168 | if d["spanY"] is None: |
| 169 | d["spanY"] = 1 |
Winson Chung | 8838173 | 2013-07-12 13:41:18 -0700 | [diff] [blame] | 170 | 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 Onorato | 6f9d4bd | 2010-09-29 17:43:46 -0700 | [diff] [blame] | 181 | 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 Chung | 8838173 | 2013-07-12 13:41:18 -0700 | [diff] [blame] | 208 | |
Joe Onorato | 6f9d4bd | 2010-09-29 17:43:46 -0700 | [diff] [blame] | 209 | 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 Chung | d64d176 | 2013-08-20 14:37:16 -0700 | [diff] [blame] | 224 | # 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 Chung | bfc003a | 2011-08-24 11:32:02 -0700 | [diff] [blame] | 232 | # Hotseat |
| 233 | hotseat = [] |
| 234 | for i in range(0, HOTSEAT_SIZE): |
| 235 | hotseat.append(None) |
| 236 | for row in data: |
Winson Chung | 8838173 | 2013-07-12 13:41:18 -0700 | [diff] [blame] | 237 | if row["container"] != CONTAINER_HOTSEAT: |
Winson Chung | bfc003a | 2011-08-24 11:32:02 -0700 | [diff] [blame] | 238 | 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 Onorato | 6f9d4bd | 2010-09-29 17:43:46 -0700 | [diff] [blame] | 247 | # 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 Onorato | 6f9d4bd | 2010-09-29 17:43:46 -0700 | [diff] [blame] | 259 | # desktop |
Winson Chung | 8838173 | 2013-07-12 13:41:18 -0700 | [diff] [blame] | 260 | if row["container"] != CONTAINER_DESKTOP: |
Joe Onorato | 6f9d4bd | 2010-09-29 17:43:46 -0700 | [diff] [blame] | 261 | continue |
Winson Chung | 8838173 | 2013-07-12 13:41:18 -0700 | [diff] [blame] | 262 | screen = screens[screensIdMap.index(row["screen"])] |
Joe Onorato | 6f9d4bd | 2010-09-29 17:43:46 -0700 | [diff] [blame] | 263 | 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 Chung | bfc003a | 2011-08-24 11:32:02 -0700 | [diff] [blame] | 278 | render_cell_info(out, cell, occupied) |
Joe Onorato | 6f9d4bd | 2010-09-29 17:43:46 -0700 | [diff] [blame] | 279 | 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 Chung | 8838173 | 2013-07-12 13:41:18 -0700 | [diff] [blame] | 290 | def updateDeviceClassConstants(str): |
| 291 | global SCREENS, COLUMNS, ROWS, HOTSEAT_SIZE |
Winson | 787e3fb | 2015-09-14 11:51:41 -0700 | [diff] [blame] | 292 | 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 Chung | 8838173 | 2013-07-12 13:41:18 -0700 | [diff] [blame] | 297 | return True |
| 298 | return False |
| 299 | |
Joe Onorato | 6f9d4bd | 2010-09-29 17:43:46 -0700 | [diff] [blame] | 300 | def main(argv): |
Winson Chung | 8838173 | 2013-07-12 13:41:18 -0700 | [diff] [blame] | 301 | if len(argv) == 1 or (len(argv) == 2 and updateDeviceClassConstants(argv[1])): |
Joe Onorato | 6f9d4bd | 2010-09-29 17:43:46 -0700 | [diff] [blame] | 302 | make_dir() |
Winson Chung | d64d176 | 2013-08-20 14:37:16 -0700 | [diff] [blame] | 303 | adb_root_remount() |
Joe Onorato | 6f9d4bd | 2010-09-29 17:43:46 -0700 | [diff] [blame] | 304 | pull_file(AUTO_FILE) |
| 305 | process_file(AUTO_FILE) |
Winson Chung | 8838173 | 2013-07-12 13:41:18 -0700 | [diff] [blame] | 306 | elif len(argv) == 2 or (len(argv) == 3 and updateDeviceClassConstants(argv[2])): |
Joe Onorato | 6f9d4bd | 2010-09-29 17:43:46 -0700 | [diff] [blame] | 307 | make_dir() |
| 308 | process_file(argv[1]) |
| 309 | else: |
| 310 | usage() |
| 311 | |
| 312 | if __name__=="__main__": |
| 313 | main(sys.argv) |