diff options
35 files changed, 658 insertions, 142 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml index e81c4c96a..272f7c12c 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -70,7 +70,8 @@ android:launchMode="singleTask" android:clearTaskOnLaunch="true" android:stateNotNeeded="true" - android:theme="@style/Theme"> + android:theme="@style/Theme" + android:windowSoftInputMode="stateUnspecified|adjustPan"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.HOME"/> diff --git a/res/drawable/texture_brushed_steel.png b/res/drawable/texture_brushed_steel.png Binary files differnew file mode 100644 index 000000000..73b3dfe63 --- /dev/null +++ b/res/drawable/texture_brushed_steel.png diff --git a/res/layout-land/launcher.xml b/res/layout-land/launcher.xml index e92c8dc18..2b262c37e 100644 --- a/res/layout-land/launcher.xml +++ b/res/layout-land/launcher.xml @@ -66,7 +66,7 @@ android:layout_width="fill_parent" android:layout_height="fill_parent" - android:background="@color/grid_dark_background" + launcher:texture="@drawable/texture_brushed_steel" android:scrollbarStyle="outsideInset" android:drawSelectorOnTop="false" diff --git a/res/layout-port/application_boxed.xml b/res/layout-port/application_boxed.xml index 63d2254b4..e71a2e2d9 100644 --- a/res/layout-port/application_boxed.xml +++ b/res/layout-port/application_boxed.xml @@ -22,7 +22,7 @@ android:paddingTop="5dip" android:paddingBottom="2dip" android:drawablePadding="0dip" - + android:textSize="13dip" android:maxLines="2" android:ellipsize="marquee" diff --git a/res/layout-port/launcher.xml b/res/layout-port/launcher.xml index 1ba524b4d..0c249a344 100644 --- a/res/layout-port/launcher.xml +++ b/res/layout-port/launcher.xml @@ -66,7 +66,7 @@ android:layout_width="fill_parent" android:layout_height="fill_parent" - android:background="@color/grid_dark_background" + launcher:texture="@drawable/texture_brushed_steel" android:scrollbarStyle="outsideInset" android:drawSelectorOnTop="false" diff --git a/res/layout/widget_search.xml b/res/layout/widget_search.xml index dcc83a5bb..209716d52 100644 --- a/res/layout/widget_search.xml +++ b/res/layout/widget_search.xml @@ -26,7 +26,7 @@ android:layout_height="wrap_content" android:src="@drawable/google_logo" /> - <AutoCompleteTextView + <com.android.launcher.SearchAutoCompleteTextView android:id="@+id/input" android:layout_width="0dip" android:layout_weight="1" @@ -36,7 +36,8 @@ android:singleLine="true" android:selectAllOnFocus="true" android:completionThreshold="1" - android:inputType="textAutoComplete|textSearch" + android:inputType="textAutoComplete" + android:imeOptions="actionSearch" /> <ImageButton android:id="@+id/search_go_btn" diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml index ad5a30575..dea039f70 100644 --- a/res/values-cs/strings.xml +++ b/res/values-cs/strings.xml @@ -32,7 +32,6 @@ <string name="group_folder">"Složka"</string> <string name="group_live_folders">"Složka Live"</string> <string name="group_widgets">"Miniaplikace"</string> - <string name="group_gadgets">"Gadget"</string> <string name="group_wallpapers">"Tapeta"</string> <string name="add_folder">"Složka"</string> <string name="add_clock">"Hodiny"</string> @@ -55,5 +54,6 @@ <string name="permlab_write_settings">"zápis nastavení a odkazů plochy"</string> <string name="permdesc_write_settings">"Povoluje aplikaci změnit nastavení a odkazy plochy."</string> <string name="search_hint">"Vyhledávání Google"</string> - <string name="gadget_error_text">"Při načítání gadgetu došlo k problému"</string> + <!-- no translation found for gadget_error_text (8359351016167075858) --> + <skip /> </resources> diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml index 2b144da99..c40585215 100644 --- a/res/values-de/strings.xml +++ b/res/values-de/strings.xml @@ -32,7 +32,6 @@ <string name="group_folder">"Ordner"</string> <string name="group_live_folders">"Live-Ordner"</string> <string name="group_widgets">"Widget"</string> - <string name="group_gadgets">"Gadget"</string> <string name="group_wallpapers">"Hintergrund"</string> <string name="add_folder">"Ordner"</string> <string name="add_clock">"Uhr"</string> @@ -55,5 +54,6 @@ <string name="permlab_write_settings">"Einstellungen und Shortcuts für Startseite schreiben"</string> <string name="permdesc_write_settings">"Ermöglicht einer Anwendung, die Einstellungen und Shortcuts auf der Startseite zu ändern."</string> <string name="search_hint">"Google-Suche"</string> - <string name="gadget_error_text">"Problem beim Laden von Gadget"</string> + <!-- no translation found for gadget_error_text (8359351016167075858) --> + <skip /> </resources> diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml index 0cacbdafd..20d2605be 100644 --- a/res/values-es/strings.xml +++ b/res/values-es/strings.xml @@ -28,11 +28,10 @@ <string name="menu_item_add_item">"Añadir a pantalla de página principal"</string> <string name="group_applications">"Aplicación"</string> <string name="group_shortcuts">"Acceso directo"</string> - <string name="group_search">"Buscar"</string> + <string name="group_search">"Búsqueda"</string> <string name="group_folder">"Carpeta"</string> <string name="group_live_folders">"Carpeta activa"</string> <string name="group_widgets">"Widget"</string> - <string name="group_gadgets">"Gadget"</string> <string name="group_wallpapers">"Fondo de pantalla"</string> <string name="add_folder">"Carpeta"</string> <string name="add_clock">"Reloj"</string> @@ -43,7 +42,7 @@ <string name="title_select_live_folder">"Seleccionar carpeta activa"</string> <string name="menu_add">"Añadir"</string> <string name="menu_wallpaper">"Fondo de pantalla"</string> - <string name="menu_search">"Búsqueda de Google"</string> + <string name="menu_search">"Buscar con Google"</string> <string name="menu_notifications">"Notificaciones"</string> <string name="menu_settings">"Ajustes"</string> <string name="permlab_install_shortcut">"instalar accesos directos"</string> @@ -55,5 +54,6 @@ <string name="permlab_write_settings">"escribir información de accesos directos y de configuración de la página principal"</string> <string name="permdesc_write_settings">"Permite que una aplicación modifique la configuración y los accesos directos de la página principal."</string> <string name="search_hint">"Búsqueda de Google"</string> - <string name="gadget_error_text">"Problema la cargar gadget"</string> + <!-- no translation found for gadget_error_text (8359351016167075858) --> + <skip /> </resources> diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml index c25610922..c01ef47d2 100644 --- a/res/values-fr/strings.xml +++ b/res/values-fr/strings.xml @@ -17,9 +17,9 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="application_name">"Accueil"</string> <string name="folder_name">"Dossier"</string> - <string name="chooser_wallpaper">"Sélectionner l\'arrière-plan à partir de"</string> - <string name="wallpaper_instructions">"Configurer l\'arrière-plan"</string> - <string name="pick_wallpaper">"Galerie des arrière-plans"</string> + <string name="chooser_wallpaper">"Sélectionner à partir de..."</string> + <string name="wallpaper_instructions">"Sélectionner"</string> + <string name="pick_wallpaper">"Galerie"</string> <string name="activity_not_found">"L\'application n\'est pas installée sur votre téléphone."</string> <string name="rename_folder_label">"Nom du dossier"</string> <string name="rename_folder_title">"Renommer le dossier"</string> @@ -30,17 +30,16 @@ <string name="group_shortcuts">"Raccourci"</string> <string name="group_search">"Recherche"</string> <string name="group_folder">"Dossier"</string> - <string name="group_live_folders">"Dossier live"</string> + <string name="group_live_folders">"Dossier actif"</string> <string name="group_widgets">"Widget"</string> - <string name="group_gadgets">"Gadgets"</string> <string name="group_wallpapers">"Arrière-plan"</string> <string name="add_folder">"Dossier"</string> <string name="add_clock">"Horloge"</string> <string name="add_photo_frame">"Cadre d\'image"</string> <string name="add_search">"Rechercher"</string> - <string name="out_of_space">"Plus d\'espace libre sur l\'écran Accueil."</string> + <string name="out_of_space">"Plus d\'espace libre sur l\'écran d\'accueil."</string> <string name="title_select_shortcut">"Sélectionner un raccourci"</string> - <string name="title_select_live_folder">"Sélectionner Live Folder"</string> + <string name="title_select_live_folder">"Sélectionner dossier actif"</string> <string name="menu_add">"Ajouter"</string> <string name="menu_wallpaper">"Arrière-plan"</string> <string name="menu_search">"Rechercher"</string> @@ -50,10 +49,11 @@ <string name="permdesc_install_shortcut">"Permet à une application d\'ajouter des raccourcis sans l\'intervention de l\'utilisateur."</string> <string name="permlab_uninstall_shortcut">"désinstaller les raccourcis"</string> <string name="permdesc_uninstall_shortcut">"Permet à une application de supprimer les raccourcis sans l\'intervention de l\'utilisateur."</string> - <string name="permlab_read_settings">"lire les paramètres et les raccourcis de la page d\'accueil"</string> + <string name="permlab_read_settings">"Lire les paramètres et les raccourcis de la page d\'accueil"</string> <string name="permdesc_read_settings">"Permet à une application de lire les paramètres et raccourcis de la page d\'accueil."</string> - <string name="permlab_write_settings">"écrire les paramètres de la page d\'accueil et des raccourcis"</string> + <string name="permlab_write_settings">"Enregistrer les paramètres de la page d\'accueil et des raccourcis"</string> <string name="permdesc_write_settings">"Permet à une application de modifier les paramètres et les raccourcis de la page d\'accueil."</string> <string name="search_hint">"Recherche Google"</string> - <string name="gadget_error_text">"Problème lors du chargement du gadget"</string> + <!-- no translation found for gadget_error_text (8359351016167075858) --> + <skip /> </resources> diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml index a6895f993..47c6f9f79 100644 --- a/res/values-it/strings.xml +++ b/res/values-it/strings.xml @@ -27,12 +27,11 @@ <string name="cancel_action">"Annulla"</string> <string name="menu_item_add_item">"Aggiungi a schermata Home"</string> <string name="group_applications">"Applicazione"</string> - <string name="group_shortcuts">"Collegamento"</string> - <string name="group_search">"Cerca"</string> + <string name="group_shortcuts">"Scorciatoia"</string> + <string name="group_search">"Ricerca"</string> <string name="group_folder">"Cartella"</string> <string name="group_live_folders">"Cartella dinamica"</string> <string name="group_widgets">"Widget"</string> - <string name="group_gadgets">"Gadget"</string> <string name="group_wallpapers">"Sfondo"</string> <string name="add_folder">"Cartella"</string> <string name="add_clock">"Orologio"</string> @@ -46,14 +45,15 @@ <string name="menu_search">"Cerca"</string> <string name="menu_notifications">"Notifiche"</string> <string name="menu_settings">"Impostazioni"</string> - <string name="permlab_install_shortcut">"aggiungere collegamenti"</string> - <string name="permdesc_install_shortcut">"Consente a un\'applicazione di aggiungere collegamenti automaticamente."</string> - <string name="permlab_uninstall_shortcut">"eliminare collegamenti"</string> - <string name="permdesc_uninstall_shortcut">"Consente a un\'applicazione di rimuovere collegamenti automaticamente."</string> - <string name="permlab_read_settings">"leggere impostazioni e collegamenti in Home"</string> - <string name="permdesc_read_settings">"Consente a un\'applicazione di leggere le impostazioni e i collegamenti in Home."</string> - <string name="permlab_write_settings">"creare impostazioni e collegamenti in Home"</string> - <string name="permdesc_write_settings">"Consente a un\'applicazione di modificare le impostazioni e i collegamenti in Home."</string> + <string name="permlab_install_shortcut">"aggiungere scorciatorie"</string> + <string name="permdesc_install_shortcut">"Consente a un\'applicazione di aggiungere scorciatoie automaticamente."</string> + <string name="permlab_uninstall_shortcut">"eliminare scorciatoie"</string> + <string name="permdesc_uninstall_shortcut">"Consente a un\'applicazione di rimuovere scorciatoie automaticamente."</string> + <string name="permlab_read_settings">"leggere impostazioni e scorciatoie in Home"</string> + <string name="permdesc_read_settings">"Consente a un\'applicazione di leggere le impostazioni e le scorciatoie in Home."</string> + <string name="permlab_write_settings">"creare impostazioni e scorciatoie in Home"</string> + <string name="permdesc_write_settings">"Consente a un\'applicazione di modificare le impostazioni e le scorciatoie in Home."</string> <string name="search_hint">"Ricerca Google"</string> - <string name="gadget_error_text">"Errore durante caricamento del gadget"</string> + <!-- no translation found for gadget_error_text (8359351016167075858) --> + <skip /> </resources> diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml index 4c848828d..cf71c65a9 100644 --- a/res/values-ja/strings.xml +++ b/res/values-ja/strings.xml @@ -32,7 +32,6 @@ <string name="group_folder">"フォルダ"</string> <string name="group_live_folders">"ライブフォルダ"</string> <string name="group_widgets">"ウィジェット"</string> - <string name="group_gadgets">"ガジェット"</string> <string name="group_wallpapers">"壁紙"</string> <string name="add_folder">"フォルダ"</string> <string name="add_clock">"時計"</string> @@ -55,5 +54,6 @@ <string name="permlab_write_settings">"ホームの設定とショートカットの書き込み"</string> <string name="permdesc_write_settings">"ホームの設定とショートカットの変更をアプリケーションに許可します。"</string> <string name="search_hint">"Google検索"</string> - <string name="gadget_error_text">"ガジェットをロードできません"</string> + <!-- no translation found for gadget_error_text (8359351016167075858) --> + <skip /> </resources> diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml index 65f207972..75ad6d8a6 100644 --- a/res/values-ko/strings.xml +++ b/res/values-ko/strings.xml @@ -32,7 +32,6 @@ <string name="group_folder">"폴더"</string> <string name="group_live_folders">"라이브 폴더"</string> <string name="group_widgets">"위젯"</string> - <string name="group_gadgets">"가젯"</string> <string name="group_wallpapers">"배경화면"</string> <string name="add_folder">"폴더"</string> <string name="add_clock">"시계"</string> @@ -55,5 +54,6 @@ <string name="permlab_write_settings">"홈 설정 및 바로가기 쓰기"</string> <string name="permdesc_write_settings">"응용프로그램이 홈에 있는 설정 및 바로가기를 변경할 수 있습니다."</string> <string name="search_hint">"Google 검색"</string> - <string name="gadget_error_text">"가젯 로드 중 문제 발생"</string> + <!-- no translation found for gadget_error_text (8359351016167075858) --> + <skip /> </resources> diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml index c34acf387..b14a5da7b 100644 --- a/res/values-nb/strings.xml +++ b/res/values-nb/strings.xml @@ -32,7 +32,6 @@ <string name="group_folder">"Mappe"</string> <string name="group_live_folders">"Aktiv mappe"</string> <string name="group_widgets">"Skrivebordselement"</string> - <string name="group_gadgets">"Gadget"</string> <string name="group_wallpapers">"Bakgrunnsbilde"</string> <string name="add_folder">"Mappe"</string> <string name="add_clock">"Klokke"</string> @@ -55,5 +54,6 @@ <string name="permlab_write_settings">"skrive skrivebordsinnstillinger og -snarveier"</string> <string name="permdesc_write_settings">"Lar applikasjonen endre innstillinger og snarveier på skrivebordet."</string> <string name="search_hint">"Google-søk"</string> - <string name="gadget_error_text">"Problem under lasting av gadget"</string> + <!-- no translation found for gadget_error_text (8359351016167075858) --> + <skip /> </resources> diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml index 301d2747e..e4959c0db 100644 --- a/res/values-nl/strings.xml +++ b/res/values-nl/strings.xml @@ -32,7 +32,6 @@ <string name="group_folder">"Map"</string> <string name="group_live_folders">"Live map"</string> <string name="group_widgets">"Widget"</string> - <string name="group_gadgets">"Gadget"</string> <string name="group_wallpapers">"Achtergrond"</string> <string name="add_folder">"Map"</string> <string name="add_clock">"Klok"</string> @@ -54,6 +53,7 @@ <string name="permdesc_read_settings">"Hiermee kan een toepassing de instellingen en snelkoppelingen op de startpagina lezen."</string> <string name="permlab_write_settings">"instellingen en snelkoppelingen voor de startpagina schrijven"</string> <string name="permdesc_write_settings">"Hiermee kan een toepassing de instellingen en snelkoppelingen op de startpagina wijzigen."</string> - <string name="search_hint">"Zoeken met Google"</string> - <string name="gadget_error_text">"Probleem bij het laden van gadget"</string> + <string name="search_hint">"Google Zoeken"</string> + <!-- no translation found for gadget_error_text (8359351016167075858) --> + <skip /> </resources> diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml index adb5785a2..99718cb16 100644 --- a/res/values-pl/strings.xml +++ b/res/values-pl/strings.xml @@ -28,16 +28,15 @@ <string name="menu_item_add_item">"Dodaj do strony głównej"</string> <string name="group_applications">"Aplikacja"</string> <string name="group_shortcuts">"Skrót"</string> - <string name="group_search">"Szukaj"</string> + <string name="group_search">"Wyszukiwarka"</string> <string name="group_folder">"Folder"</string> - <string name="group_live_folders">"Folder Live"</string> + <string name="group_live_folders">"Folder aktywny"</string> <string name="group_widgets">"Widget"</string> - <string name="group_gadgets">"Gadżet"</string> <string name="group_wallpapers">"Tapeta"</string> <string name="add_folder">"Folder"</string> <string name="add_clock">"Zegar"</string> <string name="add_photo_frame">"Ramka obrazu"</string> - <string name="add_search">"Szukaj"</string> + <string name="add_search">"Wyszukiwarka"</string> <string name="out_of_space">"Brak miejsca na tej stronie głównej"</string> <string name="title_select_shortcut">"Wybierz skrót"</string> <string name="title_select_live_folder">"Wybierz folder aktywny"</string> @@ -55,5 +54,6 @@ <string name="permlab_write_settings">"zapisywanie ustawień i skrótów strony głównej"</string> <string name="permdesc_write_settings">"Umożliwia aplikacji zmianę ustawień i skrótów strony głównej."</string> <string name="search_hint">"Szukaj w Google"</string> - <string name="gadget_error_text">"Wystąpił problem podczas ładowania gadżetu"</string> + <!-- no translation found for gadget_error_text (8359351016167075858) --> + <skip /> </resources> diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml index d2ac07dcc..ab6120e9b 100644 --- a/res/values-ru/strings.xml +++ b/res/values-ru/strings.xml @@ -32,7 +32,6 @@ <string name="group_folder">"Папка"</string> <string name="group_live_folders">"Динамическая папка"</string> <string name="group_widgets">"Виджет"</string> - <string name="group_gadgets">"Гаджет"</string> <string name="group_wallpapers">"Фоновый рисунок"</string> <string name="add_folder">"Папка"</string> <string name="add_clock">"Часы"</string> @@ -55,5 +54,6 @@ <string name="permlab_write_settings">"записывать ярлыки и настройки главного экрана"</string> <string name="permdesc_write_settings">"Позволяет приложению изменять настройки и ярлыки на главном экране."</string> <string name="search_hint">"Поиск Google"</string> - <string name="gadget_error_text">"Проблема загрузки гаджета"</string> + <!-- no translation found for gadget_error_text (8359351016167075858) --> + <skip /> </resources> diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml index 8ea7b3f6b..f5d929d16 100644 --- a/res/values-zh-rCN/strings.xml +++ b/res/values-zh-rCN/strings.xml @@ -32,7 +32,6 @@ <string name="group_folder">"文件夹"</string> <string name="group_live_folders">"活动的文件夹"</string> <string name="group_widgets">"小工具"</string> - <string name="group_gadgets">"小工具"</string> <string name="group_wallpapers">"壁纸"</string> <string name="add_folder">"文件夹"</string> <string name="add_clock">"时钟"</string> @@ -55,5 +54,6 @@ <string name="permlab_write_settings">"写入“主页”设置和快捷键"</string> <string name="permdesc_write_settings">"允许应用程序更改“主页”中的设置和快捷键。"</string> <string name="search_hint">"Google 搜索"</string> - <string name="gadget_error_text">"载入小工具时出现问题"</string> + <!-- no translation found for gadget_error_text (8359351016167075858) --> + <skip /> </resources> diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml index b6559ffd6..326f2a232 100644 --- a/res/values-zh-rTW/strings.xml +++ b/res/values-zh-rTW/strings.xml @@ -32,7 +32,6 @@ <string name="group_folder">"資料夾"</string> <string name="group_live_folders">"使用中的資料夾"</string> <string name="group_widgets">"Widget"</string> - <string name="group_gadgets">"小工具"</string> <string name="group_wallpapers">"桌布"</string> <string name="add_folder">"資料夾"</string> <string name="add_clock">"時鐘"</string> @@ -55,5 +54,6 @@ <string name="permlab_write_settings">"寫入首頁設定和捷徑"</string> <string name="permdesc_write_settings">"允許應用程式變更首頁中的設定和捷徑。"</string> <string name="search_hint">"Google 搜尋"</string> - <string name="gadget_error_text">"載入小工具時發生問題"</string> + <!-- no translation found for gadget_error_text (8359351016167075858) --> + <skip /> </resources> diff --git a/res/values/attrs.xml b/res/values/attrs.xml index 87f5b788b..ab545aa76 100644 --- a/res/values/attrs.xml +++ b/res/values/attrs.xml @@ -69,4 +69,11 @@ <attr name="direction" /> </declare-styleable> + <!-- AllAppsGridView specific attributes. These attributes are used to customize + the list of all apps in XML files. --> + <declare-styleable name="AllAppsGridView"> + <!-- The background texture. --> + <attr name="texture" format="reference" /> + </declare-styleable> + </resources> diff --git a/res/values/strings.xml b/res/values/strings.xml index ff417987f..a7945cba7 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -58,10 +58,8 @@ <string name="group_folder">Folder</string> <!-- Options in "Add to Home" dialog box; Title of the group containing the list of all live folders --> <string name="group_live_folders">Live folder</string> - <!-- Options in "Add to Home" dialog box; Title of the group containing the list of all widgets --> + <!-- Options in "Add to Home" dialog box; Title of the group containing the list of all widgets/gadgets --> <string name="group_widgets">Widget</string> - <!-- Options in "Add to Home" dialog box; Title of the group containing the list of all gadgets --> - <string name="group_gadgets">Gadget</string> <!-- Options in "Add to Home" dialog box; Title of the group containing the list of apps that can set the wallpaper--> <string name="group_wallpapers">Wallpaper</string> <!-- Options in "Add to Home" dialog box; Name of the Folder widget--> @@ -115,6 +113,6 @@ <string name="search_hint">Google Search</string> <!-- Text to show user in place of a gadget when we can't display it properly --> - <string name="gadget_error_text">Problem loading gadget</string> + <string name="gadget_error_text">Problem loading widget</string> </resources> diff --git a/src/com/android/launcher/AddAdapter.java b/src/com/android/launcher/AddAdapter.java index 14107084e..18b36d5e2 100644 --- a/src/com/android/launcher/AddAdapter.java +++ b/src/com/android/launcher/AddAdapter.java @@ -82,7 +82,7 @@ public class AddAdapter extends BaseAdapter { mItems.add(new ListItem(res, R.string.group_search, R.drawable.ic_search_gadget, ITEM_SEARCH)); - mItems.add(new ListItem(res, R.string.group_gadgets, + mItems.add(new ListItem(res, R.string.group_widgets, R.drawable.ic_launcher_gadget, ITEM_GADGET)); mItems.add(new ListItem(res, R.string.group_live_folders, diff --git a/src/com/android/launcher/AllAppsGridView.java b/src/com/android/launcher/AllAppsGridView.java index a898c1a02..b8f79025f 100644 --- a/src/com/android/launcher/AllAppsGridView.java +++ b/src/com/android/launcher/AllAppsGridView.java @@ -19,25 +19,46 @@ package com.android.launcher; import android.widget.GridView; import android.widget.AdapterView; import android.content.Context; +import android.content.res.TypedArray; import android.util.AttributeSet; import android.view.View; +import android.graphics.BitmapFactory; +import android.graphics.Bitmap; +import android.graphics.Paint; +import android.graphics.Canvas; public class AllAppsGridView extends GridView implements AdapterView.OnItemClickListener, AdapterView.OnItemLongClickListener, DragSource { private DragController mDragger; private Launcher mLauncher; + private Bitmap mTexture; + private Paint mPaint; + private int mTextureWidth; + private int mTextureHeight; public AllAppsGridView(Context context) { super(context); } public AllAppsGridView(Context context, AttributeSet attrs) { - super(context, attrs); + this(context, attrs, com.android.internal.R.attr.gridViewStyle); } public AllAppsGridView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); + + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AllAppsGridView, defStyle, 0); + final int textureId = a.getResourceId(R.styleable.AllAppsGridView_texture, 0); + if (textureId != 0) { + mTexture = BitmapFactory.decodeResource(getResources(), textureId); + mTextureWidth = mTexture.getWidth(); + mTextureHeight = mTexture.getHeight(); + + mPaint = new Paint(); + mPaint.setDither(false); + } + a.recycle(); } @Override @@ -46,6 +67,32 @@ public class AllAppsGridView extends GridView implements AdapterView.OnItemClick setOnItemLongClickListener(this); } + @Override + public void draw(Canvas canvas) { + final Bitmap texture = mTexture; + final Paint paint = mPaint; + + final int width = getWidth(); + final int height = getHeight(); + + final int textureWidth = mTextureWidth; + final int textureHeight = mTextureHeight; + + int x = 0; + int y; + + while (x < width) { + y = 0; + while (y < height) { + canvas.drawBitmap(texture, x, y, paint); + y += textureHeight; + } + x += textureWidth; + } + + super.draw(canvas); + } + public void onItemClick(AdapterView parent, View v, int position, long id) { ApplicationInfo app = (ApplicationInfo) parent.getItemAtPosition(position); mLauncher.startActivitySafely(app.intent); diff --git a/src/com/android/launcher/DeleteZone.java b/src/com/android/launcher/DeleteZone.java index 6f67884db..f31a206c5 100644 --- a/src/com/android/launcher/DeleteZone.java +++ b/src/com/android/launcher/DeleteZone.java @@ -85,7 +85,11 @@ public class DeleteZone extends ImageView implements DropTarget, DragController. final LauncherModel model = Launcher.getModel(); if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) { - model.removeDesktopItem(item); + if (item instanceof LauncherGadgetInfo) { + model.removeDesktopGadget((LauncherGadgetInfo) item); + } else { + model.removeDesktopItem(item); + } } else { if (source instanceof UserFolder) { final UserFolder userFolder = (UserFolder) source; diff --git a/src/com/android/launcher/DragLayer.java b/src/com/android/launcher/DragLayer.java index aa6615a22..b542de62a 100644 --- a/src/com/android/launcher/DragLayer.java +++ b/src/com/android/launcher/DragLayer.java @@ -32,6 +32,7 @@ import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.KeyEvent; +import android.view.inputmethod.InputMethodManager; import android.widget.FrameLayout; /** @@ -127,6 +128,8 @@ public class DragLayer extends FrameLayout implements DragController { private int mAnimationType; private int mAnimationState = ANIMATION_STATE_DONE; + private InputMethodManager mInputMethodManager; + /** * Used to create a new DragLayer from XML. * @@ -144,7 +147,14 @@ public class DragLayer extends FrameLayout implements DragController { if (PROFILE_DRAWING_DURING_DRAG) { android.os.Debug.startMethodTracing("Launcher"); } - + + // Hide soft keyboard, if visible + if (mInputMethodManager == null) { + mInputMethodManager = (InputMethodManager) + getContext().getSystemService(Context.INPUT_METHOD_SERVICE); + } + mInputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0); + if (mListener != null) { mListener.onDragStart(v, source, dragInfo, dragAction); } diff --git a/src/com/android/launcher/Launcher.java b/src/com/android/launcher/Launcher.java index 58fcd5a28..e88e55ebf 100644 --- a/src/com/android/launcher/Launcher.java +++ b/src/com/android/launcher/Launcher.java @@ -40,6 +40,7 @@ import android.database.ContentObserver; import android.gadget.GadgetProviderInfo; import android.gadget.GadgetManager; import android.graphics.Bitmap; +import android.graphics.Rect; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.TransitionDrawable; @@ -86,6 +87,7 @@ import java.util.ArrayList; */ public final class Launcher extends Activity implements View.OnClickListener, OnLongClickListener { static final String LOG_TAG = "Launcher"; + static final boolean LOGD = false; private static final boolean PROFILE_STARTUP = false; private static final boolean DEBUG_USER_INTERFACE = false; @@ -169,7 +171,7 @@ public final class Launcher extends Activity implements View.OnClickListener, On private GadgetManager mGadgetManager; private LauncherGadgetHost mGadgetHost; - private static final int GADGET_HOST_ID = 1024; + static final int GADGET_HOST_ID = 1024; private CellLayout.CellInfo mAddItemCellInfo; private CellLayout.CellInfo mMenuAddInfo; @@ -191,6 +193,8 @@ public final class Launcher extends Activity implements View.OnClickListener, On private boolean mWaitingForResult; private boolean mLocaleChanged; + private Bundle mSavedInstanceState; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -201,8 +205,6 @@ public final class Launcher extends Activity implements View.OnClickListener, On mGadgetHost = new LauncherGadgetHost(this, GADGET_HOST_ID); mGadgetHost.startListening(); - // TODO: figure out if this is first launch and correctly clear GadgetHost database - if (PROFILE_STARTUP) { android.os.Debug.startMethodTracing("/sdcard/launcher"); } @@ -355,15 +357,11 @@ public final class Launcher extends Activity implements View.OnClickListener, On } return handled; } + private boolean acceptFilter() { - final Configuration configuration = getResources().getConfiguration(); - final boolean keyboardShowing = configuration.keyboardHidden != - Configuration.KEYBOARDHIDDEN_YES; - final boolean hasKeyboard = configuration.keyboard != Configuration.KEYBOARD_NOKEYS; final InputMethodManager inputManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); - return (hasKeyboard && keyboardShowing) || - (!hasKeyboard && !inputManager.isFullscreenMode()); + return !inputManager.isFullscreenMode(); } @Override @@ -633,7 +631,7 @@ public final class Launcher extends Activity implements View.OnClickListener, On mWorkspace.getCurrentScreen(), xy[0], xy[1], false); if (!mRestoring) { - sModel.addDesktopItem(launcherInfo); + sModel.addDesktopGadget(launcherInfo); // Perform actual inflation because we're live launcherInfo.hostView = mGadgetHost.createView(this, gadgetId, gadgetInfo); @@ -644,7 +642,7 @@ public final class Launcher extends Activity implements View.OnClickListener, On mWorkspace.addInCurrentScreen(launcherInfo.hostView, xy[0], xy[1], launcherInfo.spanX, launcherInfo.spanY, insertAtFirst); } else if (sModel.isDesktopLoaded()) { - sModel.addDesktopItem(launcherInfo); + sModel.addDesktopGadget(launcherInfo); } } @@ -746,6 +744,12 @@ public final class Launcher extends Activity implements View.OnClickListener, On } @Override + protected void onRestoreInstanceState(Bundle savedInstanceState) { + // Do not call super here + mSavedInstanceState = savedInstanceState; + } + + @Override protected void onSaveInstanceState(Bundle outState) { outState.putInt(RUNTIME_STATE_CURRENT_SCREEN, mWorkspace.getCurrentScreen()); @@ -793,7 +797,11 @@ public final class Launcher extends Activity implements View.OnClickListener, On super.onDestroy(); - mGadgetHost.stopListening(); + try { + mGadgetHost.stopListening(); + } catch (NullPointerException ex) { + Log.w(LOG_TAG, "problem while stopping GadgetHost during Launcher destruction", ex); + } TextKeyListener.getInstance().release(); @@ -1156,8 +1164,8 @@ public final class Launcher extends Activity implements View.OnClickListener, On void onDesktopItemsLoaded() { if (mDestroyed) return; - bindDesktopItems(); mAllAppsGrid.setAdapter(Launcher.getModel().getApplicationsAdapter()); + bindDesktopItems(); } /** @@ -1165,7 +1173,8 @@ public final class Launcher extends Activity implements View.OnClickListener, On */ private void bindDesktopItems() { final ArrayList<ItemInfo> shortcuts = sModel.getDesktopItems(); - if (shortcuts == null) { + final ArrayList<LauncherGadgetInfo> gadgets = sModel.getDesktopGadgets(); + if (shortcuts == null || gadgets == null) { return; } @@ -1187,19 +1196,17 @@ public final class Launcher extends Activity implements View.OnClickListener, On }); } - count = shortcuts.size(); - - final DesktopItemsBinder binder = new DesktopItemsBinder(this, shortcuts); - binder.obtainMessage(DesktopItemsBinder.MESSAGE_BIND_ITEMS, 0, count).sendToTarget(); + final DesktopBinder binder = new DesktopBinder(this, shortcuts, gadgets); + binder.startBindingItems(); } - private void bindItems(Launcher.DesktopItemsBinder binder, + private void bindItems(Launcher.DesktopBinder binder, ArrayList<ItemInfo> shortcuts, int start, int count) { final Workspace workspace = mWorkspace; final boolean desktopLocked = mDesktopLocked; - final int end = Math.min(start + DesktopItemsBinder.ITEMS_COUNT, count); + final int end = Math.min(start + DesktopBinder.ITEMS_COUNT, count); int i = start; for ( ; i < end; i++) { @@ -1226,21 +1233,6 @@ public final class Launcher extends Activity implements View.OnClickListener, On workspace.addInScreen(newLiveFolder, item.screen, item.cellX, item.cellY, 1, 1, !desktopLocked); break; - case LauncherSettings.Favorites.ITEM_TYPE_GADGET: - final LauncherGadgetInfo launcherInfo = (LauncherGadgetInfo) item; - - final int gadgetId = launcherInfo.gadgetId; - GadgetProviderInfo gadgetInfo = mGadgetManager.getGadgetInfo(gadgetId); - launcherInfo.hostView = mGadgetHost.createView(this, gadgetId, gadgetInfo); - - Log.d(LOG_TAG, "about to setGadget for id="+gadgetId+", info="+gadgetInfo); - launcherInfo.hostView.setGadget(gadgetId, gadgetInfo); - launcherInfo.hostView.setTag(launcherInfo); - - workspace.addInScreen(launcherInfo.hostView, item.screen, item.cellX, - item.cellY, item.spanX, item.spanY, !desktopLocked); - - break; case LauncherSettings.Favorites.ITEM_TYPE_WIDGET_SEARCH: final int screen = workspace.getCurrentScreen(); final View view = mInflater.inflate(R.layout.widget_search, @@ -1258,14 +1250,17 @@ public final class Launcher extends Activity implements View.OnClickListener, On if (end >= count) { finishBindDesktopItems(); + binder.startBindingGadgets(); } else { - binder.obtainMessage(DesktopItemsBinder.MESSAGE_BIND_ITEMS, i, count).sendToTarget(); + binder.obtainMessage(DesktopBinder.MESSAGE_BIND_ITEMS, i, count).sendToTarget(); } } private void finishBindDesktopItems() { if (mSavedState != null) { - mWorkspace.getChildAt(mWorkspace.getCurrentScreen()).requestFocus(); + if (!mWorkspace.hasFocus()) { + mWorkspace.getChildAt(mWorkspace.getCurrentScreen()).requestFocus(); + } final long[] userFolders = mSavedState.getLongArray(RUNTIME_STATE_USER_FOLDERS); if (userFolders != null) { @@ -1278,24 +1273,67 @@ public final class Launcher extends Activity implements View.OnClickListener, On final Folder openFolder = mWorkspace.getOpenFolder(); if (openFolder != null) { openFolder.requestFocus(); - } else { - mWorkspace.getChildAt(mWorkspace.getCurrentScreen()).requestFocus(); } } final boolean allApps = mSavedState.getBoolean(RUNTIME_STATE_ALL_APPS_FOLDER, false); if (allApps) { mDrawer.open(); - mDrawer.requestFocus(); } mSavedState = null; } + if (mSavedInstanceState != null) { + super.onRestoreInstanceState(mSavedInstanceState); + mSavedInstanceState = null; + } + + if (mDrawer.isOpened() && !mDrawer.hasFocus()) { + mDrawer.requestFocus(); + } + mDesktopLocked = false; mDrawer.unlock(); } + private void bindGadgets(Launcher.DesktopBinder binder, + ArrayList<LauncherGadgetInfo> gadgets, int start, int count) { + + final Workspace workspace = mWorkspace; + final boolean desktopLocked = mDesktopLocked; + + final int end = Math.min(start + DesktopBinder.GADGETS_COUNT, count); + int i = start; + + for ( ; i < end; i++) { + final LauncherGadgetInfo item = gadgets.get(i); + + final int gadgetId = item.gadgetId; + final GadgetProviderInfo gadgetInfo = mGadgetManager.getGadgetInfo(gadgetId); + item.hostView = mGadgetHost.createView(this, gadgetId, gadgetInfo); + + if (LOGD) Log.d(LOG_TAG, String.format("about to setGadget for id=%d, info=%s", gadgetId, gadgetInfo)); + + item.hostView.setGadget(gadgetId, gadgetInfo); + item.hostView.setTag(item); + + workspace.addInScreen(item.hostView, item.screen, item.cellX, + item.cellY, item.spanX, item.spanY, !desktopLocked); + } + + workspace.requestLayout(); + + if (end >= count) { + finishBindDesktopGadgets(); + } else { + binder.obtainMessage(DesktopBinder.MESSAGE_BIND_GADGETS, i, count).sendToTarget(); + } + } + + private void finishBindDesktopGadgets() { + } + DragController getDragController() { return mDragLayer; } @@ -1419,7 +1457,7 @@ public final class Launcher extends Activity implements View.OnClickListener, On // This happens when long clicking an item with the dpad/trackball if (cellInfo == null) { - return false; + return true; } if (mWorkspace.allowLongPress()) { @@ -1450,6 +1488,10 @@ public final class Launcher extends Activity implements View.OnClickListener, On return !mDrawer.isMoving() && !mDrawer.isOpened(); } + boolean isDrawerUp() { + return mDrawer.isOpened() && !mDrawer.isMoving(); + } + Workspace getWorkspace() { return mWorkspace; } @@ -1766,6 +1808,16 @@ public final class Launcher extends Activity implements View.OnClickListener, On public void onDrawerOpened() { if (!mOpen) { mHandleIcon.reverseTransition(150); + final Rect bounds = mWorkspace.mDrawerBounds; + + View view = mAllAppsGrid; + view.getDrawingRect(bounds); + + while (view != mDragLayer) { + bounds.offset(view.getLeft(), view.getTop()); + view = (View) view.getParent(); + } + mOpen = true; } } @@ -1773,41 +1825,63 @@ public final class Launcher extends Activity implements View.OnClickListener, On public void onDrawerClosed() { if (mOpen) { mHandleIcon.reverseTransition(150); + mWorkspace.mDrawerBounds.setEmpty(); mOpen = false; } mAllAppsGrid.setSelection(0); mAllAppsGrid.clearTextFilter(); - mWorkspace.clearChildrenCache(); } public void onScrollStarted() { - mWorkspace.enableChildrenCache(); } public void onScrollEnded() { } } - private static class DesktopItemsBinder extends Handler { + private static class DesktopBinder extends Handler { static final int MESSAGE_BIND_ITEMS = 0x1; + static final int MESSAGE_BIND_GADGETS = 0x2; // Number of items to bind in every pass static final int ITEMS_COUNT = 6; + static final int GADGETS_COUNT = 1; private final ArrayList<ItemInfo> mShortcuts; + private final ArrayList<LauncherGadgetInfo> mGadgets; private final WeakReference<Launcher> mLauncher; - DesktopItemsBinder(Launcher launcher, ArrayList<ItemInfo> shortcuts) { + DesktopBinder(Launcher launcher, ArrayList<ItemInfo> shortcuts, + ArrayList<LauncherGadgetInfo> gadgets) { + mLauncher = new WeakReference<Launcher>(launcher); mShortcuts = shortcuts; + mGadgets = gadgets; + } + + public void startBindingItems() { + obtainMessage(MESSAGE_BIND_ITEMS, 0, mShortcuts.size()).sendToTarget(); } + public void startBindingGadgets() { + obtainMessage(MESSAGE_BIND_GADGETS, 0, mGadgets.size()).sendToTarget(); + } + @Override public void handleMessage(Message msg) { + Launcher launcher = mLauncher.get(); + if (launcher == null) { + return; + } + switch (msg.what) { - case MESSAGE_BIND_ITEMS: - Launcher launcher = mLauncher.get(); - if (launcher != null) launcher.bindItems(this, mShortcuts, msg.arg1, msg.arg2); + case MESSAGE_BIND_ITEMS: { + launcher.bindItems(this, mShortcuts, msg.arg1, msg.arg2); + break; + } + case MESSAGE_BIND_GADGETS: { + launcher.bindGadgets(this, mGadgets, msg.arg1, msg.arg2); break; + } } } } diff --git a/src/com/android/launcher/LauncherGadgetHostView.java b/src/com/android/launcher/LauncherGadgetHostView.java index dd098aac2..2b5f7f7f4 100644 --- a/src/com/android/launcher/LauncherGadgetHostView.java +++ b/src/com/android/launcher/LauncherGadgetHostView.java @@ -58,13 +58,13 @@ public class LauncherGadgetHostView extends GadgetHostView { break; } - case MotionEvent.ACTION_UP: { + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_CANCEL: mHasPerformedLongPress = false; if (mPendingCheckForLongPress != null) { removeCallbacks(mPendingCheckForLongPress); } break; - } } // Otherwise continue letting touch events fall through to children diff --git a/src/com/android/launcher/LauncherModel.java b/src/com/android/launcher/LauncherModel.java index 783eef2db..40b5402c0 100644 --- a/src/com/android/launcher/LauncherModel.java +++ b/src/com/android/launcher/LauncherModel.java @@ -57,6 +57,7 @@ public class LauncherModel { private boolean mDesktopItemsLoaded; private ArrayList<ItemInfo> mDesktopItems; + private ArrayList<LauncherGadgetInfo> mDesktopGadgets; private HashMap<Long, FolderInfo> mFolders; private ArrayList<ApplicationInfo> mApplications; @@ -202,6 +203,7 @@ public class LauncherModel { final ApplicationsAdapter applicationList = mApplicationList; final int count = buffer.size(); + applicationList.setNotifyOnChange(false); applicationList.clear(); for (int i = 0; i < count; i++) { applicationList.setNotifyOnChange(false); @@ -222,7 +224,7 @@ public class LauncherModel { } boolean isDesktopLoaded() { - return mDesktopItems != null && mDesktopItemsLoaded; + return mDesktopItems != null && mDesktopGadgets != null && mDesktopItemsLoaded; } /** @@ -232,7 +234,7 @@ public class LauncherModel { void loadUserItems(boolean isLaunching, Launcher launcher, boolean localeChanged, boolean loadApplications) { - if (isLaunching && mDesktopItems != null && mDesktopItemsLoaded) { + if (isLaunching && isDesktopLoaded()) { if (loadApplications) startApplicationsLoader(launcher); // We have already loaded our data from the DB launcher.onDesktopItemsLoaded(); @@ -358,9 +360,11 @@ public class LauncherModel { } mDesktopItems = new ArrayList<ItemInfo>(); + mDesktopGadgets = new ArrayList<LauncherGadgetInfo>(); mFolders = new HashMap<Long, FolderInfo>(); final ArrayList<ItemInfo> desktopItems = mDesktopItems; + final ArrayList<LauncherGadgetInfo> desktopGadgets = mDesktopGadgets; final Cursor c = contentResolver.query( LauncherSettings.Favorites.CONTENT_URI, null, null, null, null); @@ -386,8 +390,8 @@ public class LauncherModel { ApplicationInfo info; String intentDescription; - Widget widgetInfo = null; - LauncherGadgetInfo gadgetInfo = null; + Widget widgetInfo; + LauncherGadgetInfo gadgetInfo; int container; long id; Intent intent; @@ -536,7 +540,7 @@ public class LauncherModel { } gadgetInfo.container = c.getInt(containerIndex); - desktopItems.add(gadgetInfo); + desktopGadgets.add(gadgetInfo); break; } } catch (Exception e) { @@ -643,6 +647,7 @@ public class LauncherModel { mApplicationsAdapter = null; unbindAppDrawables(mApplications); unbindDrawables(mDesktopItems); + unbindGadgetHostViews(mDesktopGadgets); } /** @@ -658,6 +663,7 @@ public class LauncherModel { case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION: case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT: ((ApplicationInfo)item).icon.setCallback(null); + break; } } } @@ -677,6 +683,19 @@ public class LauncherModel { } /** + * Remove any {@link LauncherGadgetHostView} references in our gadgets. + */ + private void unbindGadgetHostViews(ArrayList<LauncherGadgetInfo> gadgets) { + if (gadgets != null) { + final int count = gadgets.size(); + for (int i = 0; i < count; i++) { + LauncherGadgetInfo launcherInfo = gadgets.get(i); + launcherInfo.hostView = null; + } + } + } + + /** * @return The current list of applications */ public ArrayList<ApplicationInfo> getApplications() { @@ -696,6 +715,13 @@ public class LauncherModel { public ArrayList<ItemInfo> getDesktopItems() { return mDesktopItems; } + + /** + * @return The current list of desktop items + */ + public ArrayList<LauncherGadgetInfo> getDesktopGadgets() { + return mDesktopGadgets; + } /** * Add an item to the desktop @@ -716,6 +742,20 @@ public class LauncherModel { } /** + * Add a gadget to the desktop + */ + public void addDesktopGadget(LauncherGadgetInfo info) { + mDesktopGadgets.add(info); + } + + /** + * Remove a gadget from the desktop + */ + public void removeDesktopGadget(LauncherGadgetInfo info) { + mDesktopGadgets.remove(info); + } + + /** * Make an ApplicationInfo object for an application */ private static ApplicationInfo getApplicationInfo(PackageManager manager, Intent intent) { diff --git a/src/com/android/launcher/LauncherProvider.java b/src/com/android/launcher/LauncherProvider.java index 47db647e4..539d5ae44 100644 --- a/src/com/android/launcher/LauncherProvider.java +++ b/src/com/android/launcher/LauncherProvider.java @@ -30,6 +30,7 @@ import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteQueryBuilder; import android.database.Cursor; import android.database.SQLException; +import android.gadget.GadgetHost; import android.util.Log; import android.util.Xml; import android.net.Uri; @@ -41,19 +42,25 @@ import java.io.FileReader; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; +import java.util.ArrayList; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import com.android.internal.util.XmlUtils; +import com.android.launcher.LauncherSettings.Favorites; public class LauncherProvider extends ContentProvider { - private static final String LOG_TAG = "LauncherSettingsProvider"; + private static final String LOG_TAG = "LauncherProvider"; + private static final boolean LOGD = true; private static final String DATABASE_NAME = "launcher.db"; private static final int DATABASE_VERSION = 2; static final String AUTHORITY = "com.android.launcher.settings"; + + static final String EXTRA_BIND_SOURCES = "com.android.launcher.settings.bindsources"; + static final String EXTRA_BIND_TARGETS = "com.android.launcher.settings.bindtargets"; static final String TABLE_FAVORITES = "favorites"; static final String PARAMETER_NOTIFY = "notify"; @@ -170,14 +177,18 @@ public class LauncherProvider extends ContentProvider { private static final String ATTRIBUTE_Y = "y"; private final Context mContext; + private final GadgetHost mGadgetHost; DatabaseHelper(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); mContext = context; + mGadgetHost = new GadgetHost(context, Launcher.GADGET_HOST_ID); } @Override public void onCreate(SQLiteDatabase db) { + if (LOGD) Log.d(LOG_TAG, "creating new launcher database"); + db.execSQL("CREATE TABLE favorites (" + "_id INTEGER PRIMARY KEY," + "title TEXT," + @@ -199,11 +210,11 @@ public class LauncherProvider extends ContentProvider { "displayMode INTEGER" + ");"); - // TODO: During first database creation, trigger wipe of any gadgets that - // might have been left around during a wipe-data. -// GadgetManager gadgetManager = GadgetManager.getInstance(mContext); - - + // Database was just created, so wipe any previous gadgets + if (mGadgetHost != null) { + mGadgetHost.deleteHost(); + } + if (!convertDatabase(db)) { // Populate favorites table with initial favorites loadFavorites(db, DEFAULT_FAVORITES_PATH); @@ -211,6 +222,7 @@ public class LauncherProvider extends ContentProvider { } private boolean convertDatabase(SQLiteDatabase db) { + if (LOGD) Log.d(LOG_TAG, "converting database from an older format, but not onUpgrade"); boolean converted = false; final Uri uri = Uri.parse("content://" + Settings.AUTHORITY + @@ -236,6 +248,12 @@ public class LauncherProvider extends ContentProvider { resolver.delete(uri, null, null); } } + + if (converted) { + // Convert widgets from this import into gadgets + if (LOGD) Log.d(LOG_TAG, "converted and now triggering widget upgrade"); + convertWidgets(db); + } return converted; } @@ -299,16 +317,16 @@ public class LauncherProvider extends ContentProvider { @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + if (LOGD) Log.d(LOG_TAG, "onUpgrade triggered"); + int version = oldVersion; if (version == 1) { // upgrade 1 -> 2 added gadgetId column db.beginTransaction(); try { - // TODO: convert any existing widgets for search and clock - // this might involve a FORCE_ADD_GADGET permission in GadgetManager that - // Launcher could then use to add these gadgets without user interaction + // Insert new column for holding gadgetIds db.execSQL("ALTER TABLE favorites " + - "ADD COLUMN gadgetId INTEGER NOT NULL DEFAULT -1;"); + "ADD COLUMN gadgetId INTEGER NOT NULL DEFAULT -1;"); db.setTransactionSuccessful(); version = 2; } catch (SQLException ex) { @@ -317,6 +335,11 @@ public class LauncherProvider extends ContentProvider { } finally { db.endTransaction(); } + + // Convert existing widgets only if table upgrade was successful + if (version == 2) { + convertWidgets(db); + } } if (version != DATABASE_VERSION) { @@ -325,8 +348,99 @@ public class LauncherProvider extends ContentProvider { onCreate(db); } } + + /** + * Upgrade existing clock and photo frame widgets into their new gadget + * equivalents. This method allocates gadgetIds, and then hands off to + * LauncherGadgetBinder to finish the actual binding. + */ + private void convertWidgets(SQLiteDatabase db) { + final int[] bindSources = new int[] { + Favorites.ITEM_TYPE_WIDGET_CLOCK, + Favorites.ITEM_TYPE_WIDGET_PHOTO_FRAME, + }; + + final ArrayList<ComponentName> bindTargets = new ArrayList<ComponentName>(); + bindTargets.add(new ComponentName("com.android.alarmclock", + "com.android.alarmclock.AnalogGadgetProvider")); + bindTargets.add(new ComponentName("com.android.camera", + "com.android.camera.PhotoGadgetProvider")); + + final String selectWhere = buildOrWhereString(Favorites.ITEM_TYPE, bindSources); + + Cursor c = null; + boolean allocatedGadgets = false; + + db.beginTransaction(); + try { + // Select and iterate through each matching widget + c = db.query(TABLE_FAVORITES, new String[] { Favorites._ID }, + selectWhere, null, null, null, null); + + if (LOGD) Log.d(LOG_TAG, "found upgrade cursor count="+c.getCount()); + + final ContentValues values = new ContentValues(); + while (c != null && c.moveToNext()) { + long favoriteId = c.getLong(0); + + // Allocate and update database with new gadgetId + try { + int gadgetId = mGadgetHost.allocateGadgetId(); + + if (LOGD) Log.d(LOG_TAG, "allocated gadgetId="+gadgetId+" for favoriteId="+favoriteId); + + values.clear(); + values.put(LauncherSettings.Favorites.GADGET_ID, gadgetId); + + // Original widgets might not have valid spans when upgrading + values.put(LauncherSettings.Favorites.SPANX, 2); + values.put(LauncherSettings.Favorites.SPANY, 2); + + String updateWhere = Favorites._ID + "=" + favoriteId; + db.update(TABLE_FAVORITES, values, updateWhere, null); + + allocatedGadgets = true; + } catch (RuntimeException ex) { + Log.e(LOG_TAG, "Problem allocating gadgetId", ex); + } + } + + db.setTransactionSuccessful(); + } catch (SQLException ex) { + Log.w(LOG_TAG, "Problem while allocating gadgetIds for existing widgets", ex); + } finally { + db.endTransaction(); + if (c != null) { + c.close(); + } + } + + // If any gadgetIds allocated, then launch over to binder + if (allocatedGadgets) { + launchGadgetBinder(bindSources, bindTargets); + } + } - + /** + * Launch the gadget binder that walks through the Launcher database, + * binding any matching widgets to the corresponding targets. We can't + * bind ourselves because our parent process can't obtain the + * BIND_GADGET permission. + */ + private void launchGadgetBinder(int[] bindSources, ArrayList<ComponentName> bindTargets) { + final Intent intent = new Intent(); + intent.setComponent(new ComponentName("com.android.settings", + "com.android.settings.LauncherGadgetBinder")); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + + final Bundle extras = new Bundle(); + extras.putIntArray(EXTRA_BIND_SOURCES, bindSources); + extras.putParcelableArrayList(EXTRA_BIND_TARGETS, bindTargets); + intent.putExtras(extras); + + mContext.startActivity(intent); + } + /** * Loads the default set of favorite packages from an xml file. * @@ -413,13 +527,62 @@ public class LauncherProvider extends ContentProvider { values.put(LauncherSettings.Favorites.SPANY, 1); db.insert(TABLE_FAVORITES, null, values); - // TODO: automatically add clock and search gadget to - // default locations. this might need the FORCE permission mentioned above + final int[] bindSources = new int[] { + Favorites.ITEM_TYPE_WIDGET_CLOCK, + }; + + final ArrayList<ComponentName> bindTargets = new ArrayList<ComponentName>(); + bindTargets.add(new ComponentName("com.android.alarmclock", + "com.android.alarmclock.AnalogGadgetProvider")); + + boolean allocatedGadgets = false; + + // Try binding to an analog clock gadget + try { + int gadgetId = mGadgetHost.allocateGadgetId(); + + values.clear(); + values.put(LauncherSettings.Favorites.CONTAINER, + LauncherSettings.Favorites.CONTAINER_DESKTOP); + values.put(LauncherSettings.Favorites.ITEM_TYPE, + LauncherSettings.Favorites.ITEM_TYPE_WIDGET_CLOCK); + values.put(LauncherSettings.Favorites.SCREEN, 1); + values.put(LauncherSettings.Favorites.CELLX, 1); + values.put(LauncherSettings.Favorites.CELLY, 0); + values.put(LauncherSettings.Favorites.SPANX, 2); + values.put(LauncherSettings.Favorites.SPANY, 2); + values.put(LauncherSettings.Favorites.GADGET_ID, gadgetId); + db.insert(TABLE_FAVORITES, null, values); + + allocatedGadgets = true; + } catch (RuntimeException ex) { + Log.e(LOG_TAG, "Problem allocating gadgetId", ex); + } + // If any gadgetIds allocated, then launch over to binder + if (allocatedGadgets) { + launchGadgetBinder(bindSources, bindTargets); + } + return i; } } + /** + * Build a query string that will match any row where the column matches + * anything in the values list. + */ + static String buildOrWhereString(String column, int[] values) { + StringBuilder selectWhere = new StringBuilder(); + for (int i = values.length - 1; i >= 0; i--) { + selectWhere.append(column).append("=").append(values[i]); + if (i > 0) { + selectWhere.append(" OR "); + } + } + return selectWhere.toString(); + } + static class SqlArguments { public final String table; public final String where; diff --git a/src/com/android/launcher/LauncherSettings.java b/src/com/android/launcher/LauncherSettings.java index 77bdc73fe..461cca4fe 100644 --- a/src/com/android/launcher/LauncherSettings.java +++ b/src/com/android/launcher/LauncherSettings.java @@ -24,7 +24,8 @@ import android.net.Uri; */ class LauncherSettings { /** - * Favorites. + * Favorites. When changing these values, be sure to update + * {@link com.android.settings.LauncherGadgetBinder} as needed. */ static final class Favorites implements BaseColumns { /** diff --git a/src/com/android/launcher/LiveFolder.java b/src/com/android/launcher/LiveFolder.java index 37b98e0f7..5d727f830 100644 --- a/src/com/android/launcher/LiveFolder.java +++ b/src/com/android/launcher/LiveFolder.java @@ -24,8 +24,14 @@ import android.view.View; import android.widget.AdapterView; import android.net.Uri; import android.provider.LiveFolders; +import android.os.AsyncTask; +import android.database.Cursor; + +import java.lang.ref.WeakReference; public class LiveFolder extends Folder { + private AsyncTask<LiveFolderInfo,Void,Cursor> mLoadingTask; + public LiveFolder(Context context, AttributeSet attrs) { super(context, attrs); } @@ -66,7 +72,10 @@ public class LiveFolder extends Folder { void bind(FolderInfo info) { super.bind(info); - setContentAdapter(new LiveFolderAdapter(mLauncher, (LiveFolderInfo) info)); + if (mLoadingTask != null && mLoadingTask.getStatus() == AsyncTask.Status.RUNNING) { + mLoadingTask.cancel(true); + } + mLoadingTask = new FolderLoadingTask(this).execute((LiveFolderInfo) info); } @Override @@ -78,6 +87,42 @@ public class LiveFolder extends Folder { @Override void onClose() { super.onClose(); + if (mLoadingTask != null && mLoadingTask.getStatus() == AsyncTask.Status.RUNNING) { + mLoadingTask.cancel(true); + } ((LiveFolderAdapter) mContent.getAdapter()).cleanup(); } + + static class FolderLoadingTask extends AsyncTask<LiveFolderInfo, Void, Cursor> { + private final WeakReference<LiveFolder> mFolder; + private LiveFolderInfo mInfo; + + FolderLoadingTask(LiveFolder folder) { + mFolder = new WeakReference<LiveFolder>(folder); + } + + protected Cursor doInBackground(LiveFolderInfo... params) { + final LiveFolder folder = mFolder.get(); + if (folder != null) { + mInfo = params[0]; + return LiveFolderAdapter.query(folder.mLauncher, mInfo); + } + return null; + } + + @Override + protected void onPostExecute(Cursor cursor) { + if (!isCancelled()) { + if (cursor != null) { + final LiveFolder folder = mFolder.get(); + if (folder != null) { + final Launcher launcher = folder.mLauncher; + folder.setContentAdapter(new LiveFolderAdapter(launcher, mInfo, cursor)); + } + } + } else if (cursor != null) { + cursor.close(); + } + } + } } diff --git a/src/com/android/launcher/LiveFolderAdapter.java b/src/com/android/launcher/LiveFolderAdapter.java index 71ed85d34..4a5c077c8 100644 --- a/src/com/android/launcher/LiveFolderAdapter.java +++ b/src/com/android/launcher/LiveFolderAdapter.java @@ -45,8 +45,8 @@ class LiveFolderAdapter extends CursorAdapter { new HashMap<Long, SoftReference<Drawable>>(); private final Launcher mLauncher; - LiveFolderAdapter(Launcher launcher, LiveFolderInfo info) { - super(launcher, query(launcher, info), true); + LiveFolderAdapter(Launcher launcher, LiveFolderInfo info, Cursor cursor) { + super(launcher, cursor, true); mIsList = info.displayMode == LiveFolders.DISPLAY_MODE_LIST; mInflater = LayoutInflater.from(launcher); mLauncher = launcher; @@ -54,8 +54,9 @@ class LiveFolderAdapter extends CursorAdapter { mLauncher.startManagingCursor(getCursor()); } - private static Cursor query(Context context, LiveFolderInfo info) { - return context.getContentResolver().query(info.uri, null, null, null, LiveFolders.NAME + " ASC"); + static Cursor query(Context context, LiveFolderInfo info) { + return context.getContentResolver().query(info.uri, null, null, + null, LiveFolders.NAME + " ASC"); } public View newView(Context context, Cursor cursor, ViewGroup parent) { diff --git a/src/com/android/launcher/Search.java b/src/com/android/launcher/Search.java index d33fd69fa..522a43262 100644 --- a/src/com/android/launcher/Search.java +++ b/src/com/android/launcher/Search.java @@ -57,8 +57,6 @@ import android.widget.TextView; import android.widget.AdapterView.OnItemClickListener; import android.widget.AdapterView.OnItemSelectedListener; -import java.util.List; - public class Search extends LinearLayout implements OnClickListener, OnKeyListener, OnLongClickListener, TextWatcher, OnItemClickListener, OnItemSelectedListener { @@ -81,6 +79,7 @@ public class Search extends LinearLayout implements OnClickListener, OnKeyListen private Intent mVoiceSearchIntent; private Rect mTempRect = new Rect(); + private boolean mRestoreFocus = false; /** * Used to inflate the Workspace from XML. @@ -170,7 +169,26 @@ public class Search extends LinearLayout implements OnClickListener, OnKeyListen getContext().startActivity(launcher); } - + + @Override + public void onWindowFocusChanged(boolean hasWindowFocus) { + if (!hasWindowFocus && hasFocus()) { + mRestoreFocus = true; + } + + super.onWindowFocusChanged(hasWindowFocus); + + if (hasWindowFocus && mRestoreFocus) { + if (isInTouchMode()) { + final AutoCompleteTextView searchText = mSearchText; + searchText.setSelectAllOnFocus(false); + searchText.requestFocusFromTouch(); + searchText.setSelectAllOnFocus(true); + } + mRestoreFocus = false; + } + } + /** * Implements TextWatcher (for EditText) */ @@ -371,6 +389,18 @@ public class Search extends LinearLayout implements OnClickListener, OnKeyListen } /** + * Remove internal cursor references when detaching from window which + * prevents {@link Context} leaks. + */ + @Override + public void onDetachedFromWindow() { + if (mSuggestionsAdapter != null) { + mSuggestionsAdapter.changeCursor(null); + mSuggestionsAdapter = null; + } + } + + /** * Implements OnItemClickListener */ public void onItemClick(AdapterView<?> parent, View view, int position, long id) { diff --git a/src/com/android/launcher/SearchAutoCompleteTextView.java b/src/com/android/launcher/SearchAutoCompleteTextView.java new file mode 100644 index 000000000..18a464a5c --- /dev/null +++ b/src/com/android/launcher/SearchAutoCompleteTextView.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.launcher; + +import android.widget.AutoCompleteTextView; +import android.content.Context; +import android.util.AttributeSet; +import android.graphics.Rect; +import android.view.WindowManager; +import android.view.inputmethod.InputMethodManager; +import android.app.Activity; + +/** + * This class is not for the faint of heart. Home works in the pan & scan + * soft input mode. However, this mode gets rid of the soft keyboard on rotation, + * which is a probelm when the Search widget has focus. This special class + * changes Home's soft input method temporarily as long as the Search widget holds + * the focus. This way, the soft keyboard remains after rotation. + */ +public class SearchAutoCompleteTextView extends AutoCompleteTextView { + public SearchAutoCompleteTextView(Context context) { + super(context); + } + + public SearchAutoCompleteTextView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public SearchAutoCompleteTextView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + @Override + protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) { + super.onFocusChanged(gainFocus, direction, previouslyFocusedRect); + + final WindowManager.LayoutParams lp = ((Activity) getContext()).getWindow().getAttributes(); + if (gainFocus) { + lp.softInputMode = + (lp.softInputMode & ~WindowManager.LayoutParams.SOFT_INPUT_MASK_STATE) | + WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED; + } else { + //noinspection PointlessBitwiseExpression + lp.softInputMode = + (lp.softInputMode & ~WindowManager.LayoutParams.SOFT_INPUT_MASK_STATE) | + WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED; + + // Hide the soft keyboard when the search widget loses the focus + InputMethodManager.peekInstance().hideSoftInputFromWindow(getWindowToken(), 0); + } + + final WindowManager manager = (WindowManager) + getContext().getSystemService(Context.WINDOW_SERVICE); + manager.updateViewLayout(getRootView(), lp); + } +} diff --git a/src/com/android/launcher/Workspace.java b/src/com/android/launcher/Workspace.java index 6d8eef5f1..d93fe1436 100644 --- a/src/com/android/launcher/Workspace.java +++ b/src/com/android/launcher/Workspace.java @@ -17,6 +17,8 @@ package com.android.launcher; import android.content.Context; +import android.content.Intent; +import android.content.ComponentName; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.Canvas; @@ -91,6 +93,9 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag private int mTouchSlop; + final Rect mDrawerBounds = new Rect(); + final Rect mClipBounds = new Rect(); + /** * Used to inflate the Workspace from XML. * @@ -437,6 +442,18 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag @Override protected void dispatchDraw(Canvas canvas) { + // If the all apps drawer is open and the drawing region for the workspace + // is contained within the drawer's bounds, we skip the drawing. This requires + // the drawer to be fully opaque. + if (mLauncher.isDrawerUp()) { + final Rect clipBounds = mClipBounds; + canvas.getClipBounds(clipBounds); + clipBounds.offset(-mScrollX, -mScrollY); + if (mDrawerBounds.contains(clipBounds)) { + return; + } + } + float x = mScrollX * mWallpaperOffset; if (x + mWallpaperWidth < mRight - mLeft) { x = mRight - mLeft - mWallpaperWidth; @@ -673,6 +690,7 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag // Release the drag clearChildrenCache(); mTouchState = TOUCH_STATE_REST; + mAllowLongPress = false; break; } @@ -1152,7 +1170,13 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag Object tag = view.getTag(); if (tag instanceof ApplicationInfo) { ApplicationInfo info = (ApplicationInfo) tag; - if (packageName.equals(info.intent.getComponent().getPackageName())) { + // We need to check for ACTION_MAIN otherwise getComponent() might + // return null for some shortcuts (for instance, for shortcuts to + // web pages.) + final Intent intent = info.intent; + final ComponentName name = intent.getComponent(); + if (Intent.ACTION_MAIN.equals(intent.getAction()) && + name != null && packageName.equals(name.getPackageName())) { model.removeDesktopItem(info); LauncherModel.deleteItemFromDatabase(mLauncher, info); childrenToRemove.add(view); |