|  | #!/usr/bin/env python2.5 | 
|  |  | 
|  | import cgi | 
|  | import os | 
|  | import shutil | 
|  | import sys | 
|  | import sqlite3 | 
|  |  | 
|  | SCREENS = 5 | 
|  | COLUMNS = 4 | 
|  | ROWS = 4 | 
|  | HOTSEAT_SIZE = 5 | 
|  | CELL_SIZE = 110 | 
|  |  | 
|  | DIR = "db_files" | 
|  | AUTO_FILE = DIR + "/launcher.db" | 
|  | INDEX_FILE = DIR + "/index.html" | 
|  |  | 
|  | def usage(): | 
|  | print "usage: print_db.py launcher.db -- prints a launcher.db" | 
|  | print "usage: print_db.py -- adb pulls a launcher.db from a device" | 
|  | print "       and prints it" | 
|  | print | 
|  | print "The dump will be created in a directory called db_files in cwd." | 
|  | print "This script will delete any db_files directory you have now" | 
|  |  | 
|  |  | 
|  | def make_dir(): | 
|  | shutil.rmtree(DIR, True) | 
|  | os.makedirs(DIR) | 
|  |  | 
|  | def pull_file(fn): | 
|  | print "pull_file: " + fn | 
|  | rv = os.system("adb pull" | 
|  | + " /data/data/com.android.launcher/databases/launcher.db" | 
|  | + " " + fn); | 
|  | if rv != 0: | 
|  | print "adb pull failed" | 
|  | sys.exit(1) | 
|  |  | 
|  | def get_favorites(conn): | 
|  | c = conn.cursor() | 
|  | c.execute("SELECT * FROM favorites") | 
|  | columns = [d[0] for d in c.description] | 
|  | rows = [] | 
|  | for row in c: | 
|  | rows.append(row) | 
|  | return columns,rows | 
|  |  | 
|  | def print_intent(out, id, i, cell): | 
|  | if cell: | 
|  | out.write("""<span class="intent" title="%s">shortcut</span>""" % ( | 
|  | cgi.escape(cell, True) | 
|  | )) | 
|  |  | 
|  |  | 
|  | def print_icon(out, id, i, cell): | 
|  | if cell: | 
|  | icon_fn = "icon_%d.png" % id | 
|  | out.write("""<img src="%s">""" % ( icon_fn )) | 
|  | f = file(DIR + "/" + icon_fn, "w") | 
|  | f.write(cell) | 
|  | f.close() | 
|  |  | 
|  | def print_cell(out, id, i, cell): | 
|  | if not cell is None: | 
|  | out.write(cgi.escape(str(cell))) | 
|  |  | 
|  | FUNCTIONS = { | 
|  | "intent": print_intent, | 
|  | "icon": print_icon | 
|  | } | 
|  |  | 
|  | def render_cell_info(out, cell, occupied): | 
|  | if cell is None: | 
|  | out.write("    <td width=%d height=%d></td>\n" % | 
|  | (CELL_SIZE, CELL_SIZE)) | 
|  | elif cell == occupied: | 
|  | pass | 
|  | else: | 
|  | cellX = cell["cellX"] | 
|  | cellY = cell["cellY"] | 
|  | spanX = cell["spanX"] | 
|  | spanY = cell["spanY"] | 
|  | intent = cell["intent"] | 
|  | if intent: | 
|  | title = "title=\"%s\"" % cgi.escape(cell["intent"], True) | 
|  | else: | 
|  | title = "" | 
|  | out.write(("    <td colspan=%d rowspan=%d width=%d height=%d" | 
|  | + " bgcolor=#dddddd align=center valign=middle %s>") % ( | 
|  | spanX, spanY, | 
|  | (CELL_SIZE*spanX), (CELL_SIZE*spanY), | 
|  | title)) | 
|  | itemType = cell["itemType"] | 
|  | if itemType == 0: | 
|  | out.write("""<img src="icon_%d.png">\n""" % ( cell["_id"] )) | 
|  | out.write("<br/>\n") | 
|  | out.write(cgi.escape(cell["title"]) + " <br/><i>(app)</i>") | 
|  | elif itemType == 1: | 
|  | out.write("""<img src="icon_%d.png">\n""" % ( cell["_id"] )) | 
|  | out.write("<br/>\n") | 
|  | out.write(cgi.escape(cell["title"]) + " <br/><i>(shortcut)</i>") | 
|  | elif itemType == 2: | 
|  | out.write("""<i>folder</i>""") | 
|  | elif itemType == 3: | 
|  | out.write("""<i>live folder</i>""") | 
|  | elif itemType == 4: | 
|  | out.write("<i>widget %d</i><br/>\n" % cell["appWidgetId"]) | 
|  | elif itemType == 1000: | 
|  | out.write("""<i>clock</i>""") | 
|  | elif itemType == 1001: | 
|  | out.write("""<i>search</i>""") | 
|  | elif itemType == 1002: | 
|  | out.write("""<i>photo frame</i>""") | 
|  | else: | 
|  | out.write("<b>unknown type: %d</b>" % itemType) | 
|  | out.write("</td>\n") | 
|  |  | 
|  | def process_file(fn): | 
|  | print "process_file: " + fn | 
|  | conn = sqlite3.connect(fn) | 
|  | columns,rows = get_favorites(conn) | 
|  | data = [dict(zip(columns,row)) for row in rows] | 
|  |  | 
|  | out = file(INDEX_FILE, "w") | 
|  | out.write("""<html> | 
|  | <head> | 
|  | <style type="text/css"> | 
|  | .intent { | 
|  | font-style: italic; | 
|  | } | 
|  | </style> | 
|  | </head> | 
|  | <body> | 
|  | """) | 
|  |  | 
|  | # Data table | 
|  | out.write("<b>Favorites table</b><br/>\n") | 
|  | out.write("""<html> | 
|  | <table border=1 cellspacing=0 cellpadding=4> | 
|  | <tr> | 
|  | """) | 
|  | print_functions = [] | 
|  | for col in columns: | 
|  | print_functions.append(FUNCTIONS.get(col, print_cell)) | 
|  | for i in range(0,len(columns)): | 
|  | col = columns[i] | 
|  | out.write("""  <th>%s</th> | 
|  | """ % ( col )) | 
|  | out.write(""" | 
|  | </tr> | 
|  | """) | 
|  | for row in rows: | 
|  | out.write("""<tr> | 
|  | """) | 
|  | for i in range(0,len(row)): | 
|  | cell = row[i] | 
|  | # row[0] is always _id | 
|  | out.write("""  <td>""") | 
|  | print_functions[i](out, row[0], row, cell) | 
|  | out.write("""</td> | 
|  | """) | 
|  | out.write("""</tr> | 
|  | """) | 
|  | out.write("""</table> | 
|  | """) | 
|  |  | 
|  | # Hotseat | 
|  | hotseat = [] | 
|  | for i in range(0, HOTSEAT_SIZE): | 
|  | hotseat.append(None) | 
|  | for row in data: | 
|  | if row["container"] != -101: | 
|  | continue | 
|  | screen = row["screen"] | 
|  | hotseat[screen] = row | 
|  | out.write("<br/><b>Hotseat</b><br/>\n") | 
|  | out.write("<table class=layout border=1 cellspacing=0 cellpadding=4>\n") | 
|  | for cell in hotseat: | 
|  | render_cell_info(out, cell, None) | 
|  | out.write("</table>\n") | 
|  |  | 
|  | # Pages | 
|  | screens = [] | 
|  | for i in range(0,SCREENS): | 
|  | screen = [] | 
|  | for j in range(0,ROWS): | 
|  | m = [] | 
|  | for k in range(0,COLUMNS): | 
|  | m.append(None) | 
|  | screen.append(m) | 
|  | screens.append(screen) | 
|  | occupied = "occupied" | 
|  | for row in data: | 
|  | screen = screens[row["screen"]] | 
|  | # desktop | 
|  | if row["container"] != -100: | 
|  | continue | 
|  | cellX = row["cellX"] | 
|  | cellY = row["cellY"] | 
|  | spanX = row["spanX"] | 
|  | spanY = row["spanY"] | 
|  | for j in range(cellY, cellY+spanY): | 
|  | for k in range(cellX, cellX+spanX): | 
|  | screen[j][k] = occupied | 
|  | screen[cellY][cellX] = row | 
|  | i=0 | 
|  | for screen in screens: | 
|  | out.write("<br/><b>Screen %d</b><br/>\n" % i) | 
|  | out.write("<table class=layout border=1 cellspacing=0 cellpadding=4>\n") | 
|  | for m in screen: | 
|  | out.write("  <tr>\n") | 
|  | for cell in m: | 
|  | render_cell_info(out, cell, occupied) | 
|  | out.write("</tr>\n") | 
|  | out.write("</table>\n") | 
|  | i=i+1 | 
|  |  | 
|  | out.write(""" | 
|  | </body> | 
|  | </html> | 
|  | """) | 
|  |  | 
|  | out.close() | 
|  |  | 
|  | def main(argv): | 
|  | if len(argv) == 1: | 
|  | make_dir() | 
|  | pull_file(AUTO_FILE) | 
|  | process_file(AUTO_FILE) | 
|  | elif len(argv) == 2: | 
|  | make_dir() | 
|  | process_file(argv[1]) | 
|  | else: | 
|  | usage() | 
|  |  | 
|  | if __name__=="__main__": | 
|  | main(sys.argv) |