Home | History | Annotate | Download | only in Launcher3
      1 #!/usr/bin/env python2.5
      2 
      3 import cgi
      4 import codecs
      5 import os
      6 import pprint
      7 import shutil
      8 import sys
      9 import sqlite3
     10 
     11 SCREENS = 0
     12 COLUMNS = 4
     13 ROWS = 4
     14 HOTSEAT_SIZE = 4
     15 CELL_SIZE = 110
     16 
     17 CONTAINER_DESKTOP = -100
     18 CONTAINER_HOTSEAT = -101
     19 
     20 DIR = "db_files"
     21 AUTO_FILE = DIR + "/launcher.db"
     22 INDEX_FILE = DIR + "/index.html"
     23 
     24 def 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 
     33 def make_dir():
     34   shutil.rmtree(DIR, True)
     35   os.makedirs(DIR)
     36 
     37 def adb_root_remount():
     38   os.system("adb root")
     39   os.system("adb remount")
     40 
     41 def 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 
     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 
     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 
     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
     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 
     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 
     95 def print_cell(out, id, i, cell):
     96   if not cell is None:
     97     out.write(cgi.escape(unicode(cell)))
     98 
     99 FUNCTIONS = {
    100   "intent": print_intent,
    101   "icon": print_icon,
    102   "iconType": print_icon_type
    103 }
    104 
    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:
    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 
    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 
    149 def 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 
    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 
    303 def 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 
    315 if __name__=="__main__":
    316   main(sys.argv)
    317