Merge commit 'korg/cupcake'
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 272f7c1..4b11343 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -71,6 +71,7 @@
android:clearTaskOnLaunch="true"
android:stateNotNeeded="true"
android:theme="@style/Theme"
+ android:screenOrientation="nosensor"
android:windowSoftInputMode="stateUnspecified|adjustPan">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
diff --git a/res/drawable-land/delete_handle.png b/res/drawable-land/delete_handle.png
index 5784c26..43a9081 100644
--- a/res/drawable-land/delete_handle.png
+++ b/res/drawable-land/delete_handle.png
Binary files differ
diff --git a/res/drawable-land/delete_handle_normal.png b/res/drawable-land/delete_handle_normal.png
index d3a8dba..bc11ff8 100644
--- a/res/drawable-land/delete_handle_normal.png
+++ b/res/drawable-land/delete_handle_normal.png
Binary files differ
diff --git a/res/drawable-land/ic_delete.png b/res/drawable-land/ic_delete.png
index 58871fd..7b0f768 100644
--- a/res/drawable-land/ic_delete.png
+++ b/res/drawable-land/ic_delete.png
Binary files differ
diff --git a/res/drawable-land/ic_tray_collapse.png b/res/drawable-land/ic_tray_collapse.png
index 15c6257..c11f8b3 100644
--- a/res/drawable-land/ic_tray_collapse.png
+++ b/res/drawable-land/ic_tray_collapse.png
Binary files differ
diff --git a/res/drawable-land/ic_tray_expand.png b/res/drawable-land/ic_tray_expand.png
index 38836af..cd3e5a4 100644
--- a/res/drawable-land/ic_tray_expand.png
+++ b/res/drawable-land/ic_tray_expand.png
Binary files differ
diff --git a/res/drawable-land/search_bg.9.png b/res/drawable-land/search_bg.9.png
index 9b11d42..7f105bd 100644
--- a/res/drawable-land/search_bg.9.png
+++ b/res/drawable-land/search_bg.9.png
Binary files differ
diff --git a/res/drawable-land/tray_handle_normal.png b/res/drawable-land/tray_handle_normal.png
index 93b8597..0cd2146 100644
--- a/res/drawable-land/tray_handle_normal.png
+++ b/res/drawable-land/tray_handle_normal.png
Binary files differ
diff --git a/res/drawable-land/tray_handle_pressed.png b/res/drawable-land/tray_handle_pressed.png
index e2cae0e..c875617 100644
--- a/res/drawable-land/tray_handle_pressed.png
+++ b/res/drawable-land/tray_handle_pressed.png
Binary files differ
diff --git a/res/drawable-land/tray_handle_selected.png b/res/drawable-land/tray_handle_selected.png
index 106c8f4..1dfdf1e 100644
--- a/res/drawable-land/tray_handle_selected.png
+++ b/res/drawable-land/tray_handle_selected.png
Binary files differ
diff --git a/res/drawable-port/delete_handle.png b/res/drawable-port/delete_handle.png
index 9ce0924..94a5cd0 100644
--- a/res/drawable-port/delete_handle.png
+++ b/res/drawable-port/delete_handle.png
Binary files differ
diff --git a/res/drawable-port/delete_handle_normal.png b/res/drawable-port/delete_handle_normal.png
index 1f0a7ac..95b3da7 100644
--- a/res/drawable-port/delete_handle_normal.png
+++ b/res/drawable-port/delete_handle_normal.png
Binary files differ
diff --git a/res/drawable-port/ic_delete.png b/res/drawable-port/ic_delete.png
index 88330e7..382cba9 100644
--- a/res/drawable-port/ic_delete.png
+++ b/res/drawable-port/ic_delete.png
Binary files differ
diff --git a/res/drawable-port/ic_tray_collapse.png b/res/drawable-port/ic_tray_collapse.png
index b6b8a77..712d189 100644
--- a/res/drawable-port/ic_tray_collapse.png
+++ b/res/drawable-port/ic_tray_collapse.png
Binary files differ
diff --git a/res/drawable-port/ic_tray_expand.png b/res/drawable-port/ic_tray_expand.png
index d2bbbd0..753a4c9 100644
--- a/res/drawable-port/ic_tray_expand.png
+++ b/res/drawable-port/ic_tray_expand.png
Binary files differ
diff --git a/res/drawable-port/search_bg.9.png b/res/drawable-port/search_bg.9.png
index 4293159..b55b545 100644
--- a/res/drawable-port/search_bg.9.png
+++ b/res/drawable-port/search_bg.9.png
Binary files differ
diff --git a/res/drawable-port/tray_handle_normal.png b/res/drawable-port/tray_handle_normal.png
index bf82049..e989645 100644
--- a/res/drawable-port/tray_handle_normal.png
+++ b/res/drawable-port/tray_handle_normal.png
Binary files differ
diff --git a/res/drawable-port/tray_handle_pressed.png b/res/drawable-port/tray_handle_pressed.png
index b9d8e02..bc6e03f 100644
--- a/res/drawable-port/tray_handle_pressed.png
+++ b/res/drawable-port/tray_handle_pressed.png
Binary files differ
diff --git a/res/drawable-port/tray_handle_selected.png b/res/drawable-port/tray_handle_selected.png
index 01c2522..b319c8d 100644
--- a/res/drawable-port/tray_handle_selected.png
+++ b/res/drawable-port/tray_handle_selected.png
Binary files differ
diff --git a/res/drawable/box_launcher_bottom.9.png b/res/drawable/box_launcher_bottom.9.png
index f4cc1fa..1c99c50 100755
--- a/res/drawable/box_launcher_bottom.9.png
+++ b/res/drawable/box_launcher_bottom.9.png
Binary files differ
diff --git a/res/drawable/box_launcher_top_normal.9.png b/res/drawable/box_launcher_top_normal.9.png
index abaff95..30b17b2 100644
--- a/res/drawable/box_launcher_top_normal.9.png
+++ b/res/drawable/box_launcher_top_normal.9.png
Binary files differ
diff --git a/res/drawable/box_launcher_top_pressed.9.png b/res/drawable/box_launcher_top_pressed.9.png
index 4e163d4..033cd48 100644
--- a/res/drawable/box_launcher_top_pressed.9.png
+++ b/res/drawable/box_launcher_top_pressed.9.png
Binary files differ
diff --git a/res/drawable/box_launcher_top_selected.9.png b/res/drawable/box_launcher_top_selected.9.png
index 01b1c4e..3ef394c 100644
--- a/res/drawable/box_launcher_top_selected.9.png
+++ b/res/drawable/box_launcher_top_selected.9.png
Binary files differ
diff --git a/res/drawable/ic_launcher_application.png b/res/drawable/ic_launcher_application.png
index 7502484..3b28cc6 100644
--- a/res/drawable/ic_launcher_application.png
+++ b/res/drawable/ic_launcher_application.png
Binary files differ
diff --git a/res/drawable/ic_launcher_empty.png b/res/drawable/ic_launcher_empty.png
deleted file mode 100644
index 59bb6c5..0000000
--- a/res/drawable/ic_launcher_empty.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable/ic_launcher_folder_live.png b/res/drawable/ic_launcher_folder_live.png
new file mode 100644
index 0000000..2145747
--- /dev/null
+++ b/res/drawable/ic_launcher_folder_live.png
Binary files differ
diff --git a/res/drawable/ic_launcher_shortcut.png b/res/drawable/ic_launcher_shortcut.png
new file mode 100644
index 0000000..d6c0ef4
--- /dev/null
+++ b/res/drawable/ic_launcher_shortcut.png
Binary files differ
diff --git a/res/drawable/ic_search_widget.png b/res/drawable/ic_search_widget.png
index 0a4d8f4..37bf77e 100644
--- a/res/drawable/ic_search_widget.png
+++ b/res/drawable/ic_search_widget.png
Binary files differ
diff --git a/res/drawable/pattern_carbon_fiber_dark.png b/res/drawable/pattern_carbon_fiber_dark.png
new file mode 100644
index 0000000..44e050f
--- /dev/null
+++ b/res/drawable/pattern_carbon_fiber_dark.png
Binary files differ
diff --git a/res/drawable/texture_brushed_steel.png b/res/drawable/texture_brushed_steel.png
deleted file mode 100644
index 73b3dfe..0000000
--- a/res/drawable/texture_brushed_steel.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable/wallpaper_dale_chihuly.jpg b/res/drawable/wallpaper_dale_chihuly.jpg
deleted file mode 100644
index e69de29..0000000
--- a/res/drawable/wallpaper_dale_chihuly.jpg
+++ /dev/null
diff --git a/res/drawable/wallpaper_dale_chihuly_small.jpg b/res/drawable/wallpaper_dale_chihuly_small.jpg
deleted file mode 100644
index e69de29..0000000
--- a/res/drawable/wallpaper_dale_chihuly_small.jpg
+++ /dev/null
diff --git a/res/drawable/wallpaper_john_maeda.jpg b/res/drawable/wallpaper_john_maeda.jpg
deleted file mode 100644
index e69de29..0000000
--- a/res/drawable/wallpaper_john_maeda.jpg
+++ /dev/null
diff --git a/res/drawable/wallpaper_john_maeda_small.jpg b/res/drawable/wallpaper_john_maeda_small.jpg
deleted file mode 100644
index e69de29..0000000
--- a/res/drawable/wallpaper_john_maeda_small.jpg
+++ /dev/null
diff --git a/res/drawable/wallpaper_marc_ecko.jpg b/res/drawable/wallpaper_marc_ecko.jpg
deleted file mode 100644
index e69de29..0000000
--- a/res/drawable/wallpaper_marc_ecko.jpg
+++ /dev/null
diff --git a/res/drawable/wallpaper_marc_ecko_small.jpg b/res/drawable/wallpaper_marc_ecko_small.jpg
deleted file mode 100644
index e69de29..0000000
--- a/res/drawable/wallpaper_marc_ecko_small.jpg
+++ /dev/null
diff --git a/res/layout-land/launcher.xml b/res/layout-land/launcher.xml
index 2b262c3..8214863 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"
- launcher:texture="@drawable/texture_brushed_steel"
+ launcher:texture="@drawable/pattern_carbon_fiber_dark"
android:scrollbarStyle="outsideInset"
android:drawSelectorOnTop="false"
diff --git a/res/layout-port/launcher.xml b/res/layout-port/launcher.xml
index 0c249a3..7dcacd6 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"
- launcher:texture="@drawable/texture_brushed_steel"
+ launcher:texture="@drawable/pattern_carbon_fiber_dark"
android:scrollbarStyle="outsideInset"
android:drawSelectorOnTop="false"
diff --git a/res/layout/create_shortcut_group_item.xml b/res/layout/create_shortcut_group_item.xml
deleted file mode 100644
index 8004633..0000000
--- a/res/layout/create_shortcut_group_item.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 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.
-*/
--->
-
-<TextView xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/title"
- android:layout_width="fill_parent"
- android:layout_height="?android:attr/listPreferredItemHeight"
- android:minHeight="?android:attr/listPreferredItemHeight"
- android:textAppearance="?android:attr/textAppearanceLargeInverse"
- android:gravity="center_vertical"
- android:paddingRight="15dip"
- android:paddingLeft="?android:attr/expandableListPreferredItemPaddingLeft" />
-
diff --git a/res/layout/create_shortcut_list.xml b/res/layout/create_shortcut_list.xml
deleted file mode 100644
index aa16733..0000000
--- a/res/layout/create_shortcut_list.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 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.
-*/
--->
-<ListView xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:layout_marginTop="5dip"
- android:cacheColorHint="@null"
- android:divider="@android:drawable/divider_horizontal_bright"
- android:scrollbars="vertical" />
diff --git a/res/layout/create_shortcut_list_item.xml b/res/layout/create_shortcut_list_item.xml
deleted file mode 100644
index a6975f8..0000000
--- a/res/layout/create_shortcut_list_item.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 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.
-*/
--->
-<TextView xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/title"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:minHeight="?android:attr/listPreferredItemHeight"
- android:textAppearance="?android:attr/textAppearanceLargeInverse"
- android:gravity="center_vertical"
- android:drawablePadding="14dip"
- android:paddingLeft="?android:attr/expandableListPreferredChildPaddingLeft"
- android:paddingRight="15dip" />
-
-
diff --git a/res/layout/widget_search.xml b/res/layout/widget_search.xml
index 209716d..b4c455c 100644
--- a/res/layout/widget_search.xml
+++ b/res/layout/widget_search.xml
@@ -19,11 +19,13 @@
android:layout_height="fill_parent"
android:orientation="horizontal"
android:background="@drawable/search_bg"
- android:gravity="center_vertical">
+ android:gravity="center_vertical"
+ >
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:paddingRight="3dip"
android:src="@drawable/google_logo" />
<com.android.launcher.SearchAutoCompleteTextView
@@ -31,6 +33,7 @@
android:layout_width="0dip"
android:layout_weight="1"
android:layout_height="wrap_content"
+ android:layout_marginTop="1dip"
android:hint="@string/search_hint"
android:focusableInTouchMode="false"
android:singleLine="true"
@@ -38,16 +41,18 @@
android:completionThreshold="1"
android:inputType="textAutoComplete"
android:imeOptions="actionSearch"
+ android:lines="1"
/>
<ImageButton android:id="@+id/search_go_btn"
- android:layout_marginLeft="1dip"
+ android:layout_marginLeft="4dip"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@*android:drawable/ic_btn_search"
/>
<ImageButton android:id="@+id/search_voice_btn"
+ android:layout_marginLeft="2dip"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@android:drawable/ic_btn_speak_now"
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index dea039f..ecf6792 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -54,6 +54,5 @@
<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>
- <!-- no translation found for gadget_error_text (8359351016167075858) -->
- <skip />
+ <string name="gadget_error_text">"Problém s načtením widgetu"</string>
</resources>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index c405852..ca07fc6 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -54,6 +54,5 @@
<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>
- <!-- no translation found for gadget_error_text (8359351016167075858) -->
- <skip />
+ <string name="gadget_error_text">"Problem beim Laden des Widgets"</string>
</resources>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index 20d2605..ecfdd98 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -54,6 +54,5 @@
<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>
- <!-- no translation found for gadget_error_text (8359351016167075858) -->
- <skip />
+ <string name="gadget_error_text">"Problema al cargar el widget"</string>
</resources>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index c01ef47..203c37b 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -54,6 +54,5 @@
<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>
- <!-- no translation found for gadget_error_text (8359351016167075858) -->
- <skip />
+ <string name="gadget_error_text">"Problème lors du chargement du widget"</string>
</resources>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index 47c6f9f..c061ce7 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -54,6 +54,5 @@
<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>
- <!-- no translation found for gadget_error_text (8359351016167075858) -->
- <skip />
+ <string name="gadget_error_text">"Errore durante il caricamento del widget"</string>
</resources>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index cf71c65..ccde597 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -26,20 +26,27 @@
<string name="rename_action">"OK"</string>
<string name="cancel_action">"キャンセル"</string>
<string name="menu_item_add_item">"ホーム画面に追加"</string>
- <string name="group_applications">"アプリケーション"</string>
- <string name="group_shortcuts">"ショートカット"</string>
+ <!-- no translation found for group_applications (4118484163419674240) -->
+ <skip />
+ <!-- no translation found for group_shortcuts (9133529424900391877) -->
+ <skip />
<string name="group_search">"検索"</string>
- <string name="group_folder">"フォルダ"</string>
- <string name="group_live_folders">"ライブフォルダ"</string>
- <string name="group_widgets">"ウィジェット"</string>
- <string name="group_wallpapers">"壁紙"</string>
+ <!-- no translation found for group_folder (5143593791798929193) -->
+ <skip />
+ <!-- no translation found for group_live_folders (2664945399140647217) -->
+ <skip />
+ <!-- no translation found for group_widgets (6704978494073105844) -->
+ <skip />
+ <!-- no translation found for group_wallpapers (1568191644272224858) -->
+ <skip />
<string name="add_folder">"フォルダ"</string>
<string name="add_clock">"時計"</string>
<string name="add_photo_frame">"写真フレーム"</string>
<string name="add_search">"検索"</string>
<string name="out_of_space">"ホーム画面に空きスペースがありません。"</string>
<string name="title_select_shortcut">"ショートカットを選択"</string>
- <string name="title_select_live_folder">"ライブフォルダを選択"</string>
+ <!-- no translation found for title_select_live_folder (3753447798805166749) -->
+ <skip />
<string name="menu_add">"追加"</string>
<string name="menu_wallpaper">"壁紙"</string>
<string name="menu_search">"検索"</string>
@@ -54,6 +61,5 @@
<string name="permlab_write_settings">"ホームの設定とショートカットの書き込み"</string>
<string name="permdesc_write_settings">"ホームの設定とショートカットの変更をアプリケーションに許可します。"</string>
<string name="search_hint">"Google検索"</string>
- <!-- no translation found for gadget_error_text (8359351016167075858) -->
- <skip />
+ <string name="gadget_error_text">"ウィジェットを表示できません"</string>
</resources>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index 75ad6d8..52c7df5 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -54,6 +54,5 @@
<string name="permlab_write_settings">"홈 설정 및 바로가기 쓰기"</string>
<string name="permdesc_write_settings">"응용프로그램이 홈에 있는 설정 및 바로가기를 변경할 수 있습니다."</string>
<string name="search_hint">"Google 검색"</string>
- <!-- no translation found for gadget_error_text (8359351016167075858) -->
- <skip />
+ <string name="gadget_error_text">"위젯을 로드하는 중 문제가 발생했습니다."</string>
</resources>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index b14a5da..8fdb342 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -54,6 +54,5 @@
<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>
- <!-- no translation found for gadget_error_text (8359351016167075858) -->
- <skip />
+ <string name="gadget_error_text">"Problem under lasting av gadget"</string>
</resources>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index e4959c0..1a07fa6 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -54,6 +54,5 @@
<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">"Google Zoeken"</string>
- <!-- no translation found for gadget_error_text (8359351016167075858) -->
- <skip />
+ <string name="gadget_error_text">"Probleem bij het laden van widget"</string>
</resources>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index 99718cb..e26d723 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -54,6 +54,5 @@
<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>
- <!-- no translation found for gadget_error_text (8359351016167075858) -->
- <skip />
+ <string name="gadget_error_text">"Problem podczas ładowania widżetu"</string>
</resources>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index ab6120e..2546503 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -54,6 +54,5 @@
<string name="permlab_write_settings">"записывать ярлыки и настройки главного экрана"</string>
<string name="permdesc_write_settings">"Позволяет приложению изменять настройки и ярлыки на главном экране."</string>
<string name="search_hint">"Поиск Google"</string>
- <!-- no translation found for gadget_error_text (8359351016167075858) -->
- <skip />
+ <string name="gadget_error_text">"Не удалось загрузить виджет"</string>
</resources>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index f5d929d..a71bb3a 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -54,6 +54,5 @@
<string name="permlab_write_settings">"写入“主页”设置和快捷键"</string>
<string name="permdesc_write_settings">"允许应用程序更改“主页”中的设置和快捷键。"</string>
<string name="search_hint">"Google 搜索"</string>
- <!-- no translation found for gadget_error_text (8359351016167075858) -->
- <skip />
+ <string name="gadget_error_text">"载入窗口小部件时出现问题"</string>
</resources>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index 326f2a2..217444e 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -54,6 +54,5 @@
<string name="permlab_write_settings">"寫入首頁設定和捷徑"</string>
<string name="permdesc_write_settings">"允許應用程式變更首頁中的設定和捷徑。"</string>
<string name="search_hint">"Google 搜尋"</string>
- <!-- no translation found for gadget_error_text (8359351016167075858) -->
- <skip />
+ <string name="gadget_error_text">"載入小工具時發生問題"</string>
</resources>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index ab545aa..1fcad81 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -76,4 +76,12 @@
<attr name="texture" format="reference" />
</declare-styleable>
+ <!-- XML attributes used by default_workspace.xml -->
+ <declare-styleable name="Favorite">
+ <attr name="className" format="string" />
+ <attr name="packageName" format="string" />
+ <attr name="screen" format="string" />
+ <attr name="x" format="string" />
+ <attr name="y" format="string" />
+ </declare-styleable>
</resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index a7945cb..b0421b2 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -49,19 +49,19 @@
<!-- Title of dialog box -->
<string name="menu_item_add_item">Add to Home screen</string>
<!-- Options in "Add to Home" dialog box; Title of the group containing the list of all apps -->
- <string name="group_applications">Application</string>
+ <string name="group_applications">Applications</string>
<!-- Options in "Add to Home" dialog box; Title of the group containing the list of all shortcuts -->
- <string name="group_shortcuts">Shortcut</string>
+ <string name="group_shortcuts">Shortcuts</string>
<!-- Options in "Add to Home" dialog box; Title of the search gadget -->
<string name="group_search">Search</string>
<!-- Options in "Add to Home" dialog box; Title of the folder gadget -->
- <string name="group_folder">Folder</string>
+ <string name="group_folder">New 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>
+ <string name="group_live_folders">Folders</string>
<!-- Options in "Add to Home" dialog box; Title of the group containing the list of all widgets/gadgets -->
- <string name="group_widgets">Widget</string>
+ <string name="group_widgets">Widgets</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>
+ <string name="group_wallpapers">Wallpapers</string>
<!-- Options in "Add to Home" dialog box; Name of the Folder widget-->
<string name="add_folder">Folder</string>
<!-- Options in "Add to Home" dialog box; Name of the Clock widget-->
@@ -76,7 +76,7 @@
<!-- Title of dialog when user is selecting shortcut to add to homescreen -->
<string name="title_select_shortcut">Select shortcut</string>
<!-- Title of dialog when user is selecting live folder to add to homescreen -->
- <string name="title_select_live_folder">Select live folder</string>
+ <string name="title_select_live_folder">Select folder</string>
<!-- Menus items: -->
<skip />
diff --git a/res/xml/default_workspace.xml b/res/xml/default_workspace.xml
new file mode 100644
index 0000000..fd7adf7
--- /dev/null
+++ b/res/xml/default_workspace.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 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.
+-->
+
+<favorites xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher">
+
+ <clock
+ launcher:screen="1"
+ launcher:x="1"
+ launcher:y="0" />
+
+ <search
+ launcher:screen="2"
+ launcher:x="0"
+ launcher:y="0" />
+
+ <favorite
+ launcher:packageName="com.android.contacts"
+ launcher:className="com.android.contacts.DialtactsActivity"
+ launcher:screen="1"
+ launcher:x="0"
+ launcher:y="3" />
+
+ <favorite
+ launcher:packageName="com.android.contacts"
+ launcher:className="com.android.contacts.DialtactsContactsEntryActivity"
+ launcher:screen="1"
+ launcher:x="1"
+ launcher:y="3" />
+
+ <favorite
+ launcher:packageName="com.android.browser"
+ launcher:className="com.android.browser.BrowserActivity"
+ launcher:screen="1"
+ launcher:x="2"
+ launcher:y="3" />
+
+ <favorite
+ launcher:packageName="com.google.android.apps.maps"
+ launcher:className="com.google.android.maps.MapsActivity"
+ launcher:screen="1"
+ launcher:x="3"
+ launcher:y="3" />
+
+ <favorite
+ launcher:packageName="com.android.mms"
+ launcher:className="com.android.mms.ui.ConversationList"
+ launcher:screen="1"
+ launcher:x="0"
+ launcher:y="2" />
+
+ <favorite
+ launcher:packageName="com.android.vending"
+ launcher:className="com.android.vending.AssetBrowserActivity"
+ launcher:screen="1"
+ launcher:x="3"
+ launcher:y="2" />
+
+</favorites>
diff --git a/src/com/android/launcher/AddAdapter.java b/src/com/android/launcher/AddAdapter.java
index cbcb338..a6c889e 100644
--- a/src/com/android/launcher/AddAdapter.java
+++ b/src/com/android/launcher/AddAdapter.java
@@ -31,19 +31,15 @@
* Adapter showing the types of items that can be added to a {@link Workspace}.
*/
public class AddAdapter extends BaseAdapter {
-
- private final Launcher mLauncher;
+
private final LayoutInflater mInflater;
private final ArrayList<ListItem> mItems = new ArrayList<ListItem>();
- public static final int ITEM_APPLICATION = 0;
- public static final int ITEM_SHORTCUT = 1;
- public static final int ITEM_SEARCH = 2;
- public static final int ITEM_APPWIDGET = 3;
- public static final int ITEM_LIVE_FOLDER = 4;
- public static final int ITEM_FOLDER = 5;
- public static final int ITEM_WALLPAPER = 6;
+ public static final int ITEM_SHORTCUT = 0;
+ public static final int ITEM_APPWIDGET = 1;
+ public static final int ITEM_LIVE_FOLDER = 2;
+ public static final int ITEM_WALLPAPER = 3;
/**
* Specific item in our list.
@@ -66,30 +62,20 @@
public AddAdapter(Launcher launcher) {
super();
-
- mLauncher = launcher;
- mInflater = (LayoutInflater) mLauncher.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+
+ mInflater = (LayoutInflater) launcher.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
// Create default actions
Resources res = launcher.getResources();
- mItems.add(new ListItem(res, R.string.group_applications,
- R.drawable.ic_launcher_application, ITEM_APPLICATION));
-
mItems.add(new ListItem(res, R.string.group_shortcuts,
- R.drawable.ic_launcher_empty, ITEM_SHORTCUT));
-
- mItems.add(new ListItem(res, R.string.group_search,
- R.drawable.ic_search_widget, ITEM_SEARCH));
-
+ R.drawable.ic_launcher_shortcut, ITEM_SHORTCUT));
+
mItems.add(new ListItem(res, R.string.group_widgets,
R.drawable.ic_launcher_appwidget, ITEM_APPWIDGET));
mItems.add(new ListItem(res, R.string.group_live_folders,
- R.drawable.ic_launcher_empty, ITEM_LIVE_FOLDER));
-
- mItems.add(new ListItem(res, R.string.group_folder,
- R.drawable.ic_launcher_folder, ITEM_FOLDER));
+ R.drawable.ic_launcher_folder_live, ITEM_LIVE_FOLDER));
mItems.add(new ListItem(res, R.string.group_wallpapers,
R.drawable.ic_launcher_gallery, ITEM_WALLPAPER));
diff --git a/src/com/android/launcher/Launcher.java b/src/com/android/launcher/Launcher.java
index 17f16a7..7b7802e 100644
--- a/src/com/android/launcher/Launcher.java
+++ b/src/com/android/launcher/Launcher.java
@@ -31,6 +31,7 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
+import android.content.Intent.ShortcutIconResource;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
@@ -46,6 +47,8 @@
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
+import android.os.Looper;
+import android.os.MessageQueue;
import android.os.Parcelable;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -57,20 +60,17 @@
import android.text.TextUtils;
import android.text.method.TextKeyListener;
import android.util.Log;
+import static android.util.Log.*;
import android.view.Display;
-import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
-import android.view.WindowManager;
import android.view.View.OnLongClickListener;
import android.view.inputmethod.InputMethodManager;
-import android.widget.AdapterView;
import android.widget.EditText;
-import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.GridView;
@@ -81,6 +81,7 @@
import java.lang.ref.WeakReference;
import java.util.ArrayList;
+import java.util.LinkedList;
/**
* Default launcher application.
@@ -91,6 +92,7 @@
private static final boolean PROFILE_STARTUP = false;
private static final boolean PROFILE_DRAWER = false;
+ private static final boolean PROFILE_ROTATE = false;
private static final boolean DEBUG_USER_INTERFACE = false;
private static final int WALLPAPER_SCREENS_SPAN = 2;
@@ -112,6 +114,9 @@
static final String EXTRA_SHORTCUT_DUPLICATE = "duplicate";
+ static final String EXTRA_CUSTOM_WIDGET = "custom_widget";
+ static final String SEARCH_WIDGET = "search_widget";
+
static final int SCREEN_COUNT = 3;
static final int DEFAULT_SCREN = 1;
static final int NUMBER_CELLS_X = 4;
@@ -197,6 +202,8 @@
private Bundle mSavedInstanceState;
+ private DesktopBinder mBinder;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -352,6 +359,19 @@
super.onPause();
closeDrawer(false);
}
+
+ @Override
+ public Object onRetainNonConfigurationInstance() {
+ // Flag any binder to stop early before switching
+ if (mBinder != null) {
+ mBinder.mTerminate = true;
+ }
+
+ if (PROFILE_ROTATE) {
+ android.os.Debug.startMethodTracing("/sdcard/launcher-rotate");
+ }
+ return null;
+ }
private boolean acceptFilter() {
final InputMethodManager inputManager = (InputMethodManager)
@@ -385,7 +405,8 @@
intent.putExtra(Contacts.Intents.UI.FILTER_TEXT_EXTRA_KEY, str);
}
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
try {
startActivity(intent);
@@ -603,7 +624,7 @@
Bundle extras = data.getExtras();
int appWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);
- Log.d(LOG_TAG, "dumping extras content="+extras.toString());
+ d(LOG_TAG, "dumping extras content="+extras.toString());
AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
@@ -671,7 +692,7 @@
final int id = resources.getIdentifier(iconResource.resourceName, null, null);
icon = resources.getDrawable(id);
} catch (Exception e) {
- Log.w(LOG_TAG, "Could not load shortcut icon: " + extra);
+ w(LOG_TAG, "Could not load shortcut icon: " + extra);
}
}
}
@@ -794,7 +815,7 @@
try {
mAppWidgetHost.stopListening();
} catch (NullPointerException ex) {
- Log.w(LOG_TAG, "problem while stopping AppWidgetHost during Launcher destruction", ex);
+ w(LOG_TAG, "problem while stopping AppWidgetHost during Launcher destruction", ex);
}
TextKeyListener.getInstance().release();
@@ -903,21 +924,36 @@
}
}
+ private void updateShortcutsForPackage(String packageName) {
+ if (packageName != null && packageName.length() > 0) {
+ mWorkspace.updateShortcutsForPackage(packageName);
+ }
+ }
+
void addAppWidget(Intent data) {
// TODO: catch bad widget exception when sent
int appWidgetId = data.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);
- AppWidgetProviderInfo appWidget = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
- if (appWidget.configure != null) {
- // Launch over to configure widget, if needed
- Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_CONFIGURE);
- intent.setComponent(appWidget.configure);
- intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
-
- startActivityForResult(intent, REQUEST_CREATE_APPWIDGET);
+ String customWidget = data.getStringExtra(EXTRA_CUSTOM_WIDGET);
+ if (SEARCH_WIDGET.equals(customWidget)) {
+ // We don't need this any more, since this isn't a real app widget.
+ mAppWidgetHost.deleteAppWidgetId(appWidgetId);
+ // add the search widget
+ addSearch();
} else {
- // Otherwise just add it
- onActivityResult(REQUEST_CREATE_APPWIDGET, Activity.RESULT_OK, data);
+ AppWidgetProviderInfo appWidget = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
+
+ if (appWidget.configure != null) {
+ // Launch over to configure widget, if needed
+ Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_CONFIGURE);
+ intent.setComponent(appWidget.configure);
+ intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
+
+ startActivityForResult(intent, REQUEST_CREATE_APPWIDGET);
+ } else {
+ // Otherwise just add it
+ onActivityResult(REQUEST_CREATE_APPWIDGET, Activity.RESULT_OK, data);
+ }
}
}
@@ -942,11 +978,32 @@
}
void addShortcut(Intent intent) {
- startActivityForResult(intent, REQUEST_CREATE_SHORTCUT);
+ // Handle case where user selected "Applications"
+ String applicationName = getResources().getString(R.string.group_applications);
+ String shortcutName = intent.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);
+
+ if (applicationName != null && applicationName.equals(shortcutName)) {
+ Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
+ mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
+
+ Intent pickIntent = new Intent(Intent.ACTION_PICK_ACTIVITY);
+ pickIntent.putExtra(Intent.EXTRA_INTENT, mainIntent);
+ startActivityForResult(pickIntent, REQUEST_PICK_APPLICATION);
+ } else {
+ startActivityForResult(intent, REQUEST_CREATE_SHORTCUT);
+ }
}
void addLiveFolder(Intent intent) {
- startActivityForResult(intent, REQUEST_CREATE_LIVE_FOLDER);
+ // Handle case where user selected "Folder"
+ String folderName = getResources().getString(R.string.group_folder);
+ String shortcutName = intent.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);
+
+ if (folderName != null && folderName.equals(shortcutName)) {
+ addFolder(!mDesktopLocked);
+ } else {
+ startActivityForResult(intent, REQUEST_CREATE_LIVE_FOLDER);
+ }
}
void addFolder(boolean insertAtFirst) {
@@ -1008,7 +1065,7 @@
final int id = resources.getIdentifier(iconResource.resourceName, null, null);
icon = resources.getDrawable(id);
} catch (Exception e) {
- Log.w(LOG_TAG, "Could not load live folder icon: " + extra);
+ w(LOG_TAG, "Could not load live folder icon: " + extra);
}
}
@@ -1107,8 +1164,11 @@
switch (event.getKeyCode()) {
case KeyEvent.KEYCODE_BACK:
mWorkspace.dispatchKeyEvent(event);
- closeFolder();
- closeDrawer();
+ if (mDrawer.isOpened()) {
+ closeDrawer();
+ } else {
+ closeFolder();
+ }
return true;
case KeyEvent.KEYCODE_HOME:
return true;
@@ -1163,21 +1223,22 @@
void onDesktopItemsLoaded() {
if (mDestroyed) return;
-android.util.Log.d("Home", "setting grid adapter");
- mAllAppsGrid.setAdapter(sModel.getApplicationsAdapter());
bindDesktopItems();
}
-
+
/**
* Refreshes the shortcuts shown on the workspace.
*/
private void bindDesktopItems() {
final ArrayList<ItemInfo> shortcuts = sModel.getDesktopItems();
final ArrayList<LauncherAppWidgetInfo> appWidgets = sModel.getDesktopAppWidgets();
- if (shortcuts == null || appWidgets == null) {
+ final ApplicationsAdapter drawerAdapter = sModel.getApplicationsAdapter();
+ if (shortcuts == null || appWidgets == null || drawerAdapter == null) {
return;
}
+ mAllAppsGrid.setAdapter(drawerAdapter);
+
final Workspace workspace = mWorkspace;
int count = workspace.getChildCount();
for (int i = 0; i < count; i++) {
@@ -1195,9 +1256,14 @@
}
});
}
-
- final DesktopBinder binder = new DesktopBinder(this, shortcuts, appWidgets);
- binder.startBindingItems();
+
+ // Flag any old binder to terminate early
+ if (mBinder != null) {
+ mBinder.mTerminate = true;
+ }
+
+ mBinder = new DesktopBinder(this, shortcuts, appWidgets);
+ mBinder.startBindingItems();
}
private void bindItems(Launcher.DesktopBinder binder,
@@ -1250,7 +1316,7 @@
if (end >= count) {
finishBindDesktopItems();
- binder.startBindingAppWidgets();
+ binder.startBindingAppWidgetsWhenIdle();
} else {
binder.obtainMessage(DesktopBinder.MESSAGE_BIND_ITEMS, i, count).sendToTarget();
}
@@ -1296,44 +1362,44 @@
mDesktopLocked = false;
mDrawer.unlock();
}
-
+
private void bindAppWidgets(Launcher.DesktopBinder binder,
- ArrayList<LauncherAppWidgetInfo> appWidgets, int start, int count) {
-
+ LinkedList<LauncherAppWidgetInfo> appWidgets) {
+
final Workspace workspace = mWorkspace;
final boolean desktopLocked = mDesktopLocked;
- final int end = Math.min(start + DesktopBinder.APPWIDGETS_COUNT, count);
- int i = start;
-
- for ( ; i < end; i++) {
- final LauncherAppWidgetInfo item = appWidgets.get(i);
-
+ if (!appWidgets.isEmpty()) {
+ final LauncherAppWidgetInfo item = appWidgets.removeFirst();
+
final int appWidgetId = item.appWidgetId;
- final AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
+ final AppWidgetProviderInfo appWidgetInfo =
+ mAppWidgetManager.getAppWidgetInfo(appWidgetId);
item.hostView = mAppWidgetHost.createView(this, appWidgetId, appWidgetInfo);
- if (LOGD) Log.d(LOG_TAG, String.format("about to setAppWidget for id=%d, info=%s", appWidgetId, appWidgetInfo));
+ if (LOGD) {
+ d(LOG_TAG, String.format("about to setAppWidget for id=%d, info=%s",
+ appWidgetId, appWidgetInfo));
+ }
item.hostView.setAppWidget(appWidgetId, appWidgetInfo);
item.hostView.setTag(item);
workspace.addInScreen(item.hostView, item.screen, item.cellX,
item.cellY, item.spanX, item.spanY, !desktopLocked);
+
+ workspace.requestLayout();
}
- workspace.requestLayout();
-
- if (end >= count) {
- finishBindDesktopAppWidgets();
+ if (appWidgets.isEmpty()) {
+ if (PROFILE_ROTATE) {
+ android.os.Debug.stopMethodTracing();
+ }
} else {
- binder.obtainMessage(DesktopBinder.MESSAGE_BIND_APPWIDGETS, i, count).sendToTarget();
+ binder.obtainMessage(DesktopBinder.MESSAGE_BIND_APPWIDGETS).sendToTarget();
}
}
-
- private void finishBindDesktopAppWidgets() {
- }
-
+
DragController getDragController() {
return mDragLayer;
}
@@ -1623,11 +1689,10 @@
* Displays the shortcut creation dialog and launches, if necessary, the
* appropriate activity.
*/
- private class CreateShortcut implements AdapterView.OnItemClickListener,
+ private class CreateShortcut implements DialogInterface.OnClickListener,
DialogInterface.OnCancelListener {
private AddAdapter mAdapter;
- private ListView mList;
-
+
Dialog createDialog() {
mWaitingForResult = true;
@@ -1635,22 +1700,13 @@
final AlertDialog.Builder builder = new AlertDialog.Builder(Launcher.this);
builder.setTitle(getString(R.string.menu_item_add_item));
- builder.setIcon(0);
-
- mList = (ListView)
- View.inflate(Launcher.this, R.layout.create_shortcut_list, null);
- mList.setAdapter(mAdapter);
- mList.setOnItemClickListener(this);
- builder.setView(mList);
+ builder.setAdapter(mAdapter, this);
+
builder.setInverseBackgroundForced(true);
AlertDialog dialog = builder.create();
dialog.setOnCancelListener(this);
- WindowManager.LayoutParams attributes = dialog.getWindow().getAttributes();
- attributes.gravity = Gravity.TOP;
- dialog.onWindowAttributesChanged(attributes);
-
return dialog;
}
@@ -1664,74 +1720,94 @@
dismissDialog(DIALOG_CREATE_SHORTCUT);
}
- public void onItemClick(AdapterView parent, View view, int position, long id) {
- // handle which item was clicked based on position
- // this will launch off pick intent
+ /**
+ * Handle the action clicked in the "Add to home" dialog.
+ */
+ public void onClick(DialogInterface dialog, int which) {
+ Resources res = getResources();
+ cleanup();
- Object tag = view.getTag();
- if (tag instanceof AddAdapter.ListItem) {
- AddAdapter.ListItem item = (AddAdapter.ListItem) tag;
- cleanup();
- switch (item.actionTag) {
- case AddAdapter.ITEM_APPLICATION: {
- Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
- mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
-
- Intent pickIntent = new Intent(Intent.ACTION_PICK_ACTIVITY);
- pickIntent.putExtra(Intent.EXTRA_INTENT, mainIntent);
- startActivityForResult(pickIntent, REQUEST_PICK_APPLICATION);
- break;
- }
-
- case AddAdapter.ITEM_SHORTCUT: {
- Intent shortcutIntent = new Intent(Intent.ACTION_CREATE_SHORTCUT);
-
- Intent pickIntent = new Intent(Intent.ACTION_PICK_ACTIVITY);
- pickIntent.putExtra(Intent.EXTRA_INTENT, shortcutIntent);
- pickIntent.putExtra(Intent.EXTRA_TITLE,
- getText(R.string.title_select_shortcut));
- startActivityForResult(pickIntent, REQUEST_PICK_SHORTCUT);
- break;
- }
+ switch (which) {
+ case AddAdapter.ITEM_SHORTCUT: {
+ // Insert extra item to handle picking application
+ Bundle bundle = new Bundle();
- case AddAdapter.ITEM_SEARCH: {
- addSearch();
- break;
- }
+ ArrayList<String> shortcutNames = new ArrayList<String>();
+ shortcutNames.add(res.getString(R.string.group_applications));
+ bundle.putStringArrayList(Intent.EXTRA_SHORTCUT_NAME, shortcutNames);
- case AddAdapter.ITEM_APPWIDGET: {
- int appWidgetId = Launcher.this.mAppWidgetHost.allocateAppWidgetId();
-
- Intent pickIntent = new Intent(AppWidgetManager.ACTION_APPWIDGET_PICK);
- pickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
- startActivityForResult(pickIntent, REQUEST_PICK_APPWIDGET);
- break;
- }
+ ArrayList<ShortcutIconResource> shortcutIcons =
+ new ArrayList<ShortcutIconResource>();
+ shortcutIcons.add(ShortcutIconResource.fromContext(Launcher.this,
+ R.drawable.ic_launcher_application));
+ bundle.putParcelableArrayList(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, shortcutIcons);
- case AddAdapter.ITEM_LIVE_FOLDER: {
- Intent liveFolderIntent = new Intent(LiveFolders.ACTION_CREATE_LIVE_FOLDER);
-
- Intent pickIntent = new Intent(Intent.ACTION_PICK_ACTIVITY);
- pickIntent.putExtra(Intent.EXTRA_INTENT, liveFolderIntent);
- pickIntent.putExtra(Intent.EXTRA_TITLE,
- getText(R.string.title_select_live_folder));
- startActivityForResult(pickIntent, REQUEST_PICK_LIVE_FOLDER);
- break;
- }
-
- case AddAdapter.ITEM_FOLDER: {
- addFolder(!mDesktopLocked);
- dismissDialog(DIALOG_CREATE_SHORTCUT);
- break;
- }
-
- case AddAdapter.ITEM_WALLPAPER: {
- startWallpaper();
- break;
- }
-
- }
+ Intent pickIntent = new Intent(Intent.ACTION_PICK_ACTIVITY);
+ pickIntent.putExtra(Intent.EXTRA_INTENT,
+ new Intent(Intent.ACTION_CREATE_SHORTCUT));
+ pickIntent.putExtra(Intent.EXTRA_TITLE,
+ getText(R.string.title_select_shortcut));
+ pickIntent.putExtras(bundle);
+
+ startActivityForResult(pickIntent, REQUEST_PICK_SHORTCUT);
+ break;
+ }
+ case AddAdapter.ITEM_APPWIDGET: {
+ int appWidgetId = Launcher.this.mAppWidgetHost.allocateAppWidgetId();
+
+ Intent pickIntent = new Intent(AppWidgetManager.ACTION_APPWIDGET_PICK);
+ pickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
+ // add the search widget
+ ArrayList<AppWidgetProviderInfo> customInfo =
+ new ArrayList<AppWidgetProviderInfo>();
+ AppWidgetProviderInfo info = new AppWidgetProviderInfo();
+ info.provider = new ComponentName(getPackageName(), "XXX.YYY");
+ info.label = getString(R.string.group_search);
+ info.icon = R.drawable.ic_search_widget;
+ customInfo.add(info);
+ pickIntent.putParcelableArrayListExtra(
+ AppWidgetManager.EXTRA_CUSTOM_INFO, customInfo);
+ ArrayList<Bundle> customExtras = new ArrayList<Bundle>();
+ Bundle b = new Bundle();
+ b.putString(EXTRA_CUSTOM_WIDGET, SEARCH_WIDGET);
+ customExtras.add(b);
+ pickIntent.putParcelableArrayListExtra(
+ AppWidgetManager.EXTRA_CUSTOM_EXTRAS, customExtras);
+ // start the pick activity
+ startActivityForResult(pickIntent, REQUEST_PICK_APPWIDGET);
+ break;
+ }
+
+ case AddAdapter.ITEM_LIVE_FOLDER: {
+ // Insert extra item to handle inserting folder
+ Bundle bundle = new Bundle();
+
+ ArrayList<String> shortcutNames = new ArrayList<String>();
+ shortcutNames.add(res.getString(R.string.group_folder));
+ bundle.putStringArrayList(Intent.EXTRA_SHORTCUT_NAME, shortcutNames);
+
+ ArrayList<ShortcutIconResource> shortcutIcons =
+ new ArrayList<ShortcutIconResource>();
+ shortcutIcons.add(ShortcutIconResource.fromContext(Launcher.this,
+ R.drawable.ic_launcher_folder));
+ bundle.putParcelableArrayList(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, shortcutIcons);
+
+ Intent pickIntent = new Intent(Intent.ACTION_PICK_ACTIVITY);
+ pickIntent.putExtra(Intent.EXTRA_INTENT,
+ new Intent(LiveFolders.ACTION_CREATE_LIVE_FOLDER));
+ pickIntent.putExtra(Intent.EXTRA_TITLE,
+ getText(R.string.title_select_live_folder));
+ pickIntent.putExtras(bundle);
+
+ startActivityForResult(pickIntent, REQUEST_PICK_LIVE_FOLDER);
+ break;
+ }
+
+ case AddAdapter.ITEM_WALLPAPER: {
+ startWallpaper();
+ break;
+ }
}
}
}
@@ -1742,23 +1818,47 @@
private class ApplicationsIntentReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
- boolean reloadWorkspace = false;
-android.util.Log.d("Home", "application intent received: " + intent.getAction());
-android.util.Log.d("Home", " --> " + intent.getData());
- if (Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())) {
- if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
- removeShortcutsForPackage(intent.getData().getSchemeSpecificPart());
- } else {
- reloadWorkspace = true;
- }
+ final String action = intent.getAction();
+ final String packageName = intent.getData().getSchemeSpecificPart();
+ final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
+
+ if (LauncherModel.DEBUG_LOADERS) {
+ d(LauncherModel.LOG_TAG, "application intent received: " + action +
+ ", replacing=" + replacing);
+ d(LauncherModel.LOG_TAG, " --> " + intent.getData());
}
- removeDialog(DIALOG_CREATE_SHORTCUT);
- if (!reloadWorkspace) {
-android.util.Log.d("Home", " --> loading apps");
- sModel.loadApplications(false, Launcher.this, false);
+
+ if (!Intent.ACTION_PACKAGE_CHANGED.equals(action)) {
+ if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
+ if (!replacing) {
+ removeShortcutsForPackage(packageName);
+ if (LauncherModel.DEBUG_LOADERS) {
+ d(LauncherModel.LOG_TAG, " --> remove package");
+ }
+ sModel.removePackage(Launcher.this, packageName);
+ }
+ // else, we are replacing the package, so a PACKAGE_ADDED will be sent
+ // later, we will update the package at this time
+ } else {
+ if (!replacing) {
+ if (LauncherModel.DEBUG_LOADERS) {
+ d(LauncherModel.LOG_TAG, " --> add package");
+ }
+ sModel.addPackage(Launcher.this, packageName);
+ } else {
+ if (LauncherModel.DEBUG_LOADERS) {
+ d(LauncherModel.LOG_TAG, " --> update package " + packageName);
+ }
+ sModel.updatePackage(Launcher.this, packageName);
+ updateShortcutsForPackage(packageName);
+ }
+ }
+ removeDialog(DIALOG_CREATE_SHORTCUT);
} else {
-android.util.Log.d("Home", " --> loading workspace");
- sModel.loadUserItems(false, Launcher.this, false, true);
+ if (LauncherModel.DEBUG_LOADERS) {
+ d(LauncherModel.LOG_TAG, " --> sync package " + packageName);
+ }
+ sModel.syncPackage(Launcher.this, packageName);
}
}
}
@@ -1865,37 +1965,64 @@
}
}
- private static class DesktopBinder extends Handler {
+ private static class DesktopBinder extends Handler implements MessageQueue.IdleHandler {
static final int MESSAGE_BIND_ITEMS = 0x1;
static final int MESSAGE_BIND_APPWIDGETS = 0x2;
+
// Number of items to bind in every pass
static final int ITEMS_COUNT = 6;
- static final int APPWIDGETS_COUNT = 1;
private final ArrayList<ItemInfo> mShortcuts;
- private final ArrayList<LauncherAppWidgetInfo> mAppWidgets;
+ private final LinkedList<LauncherAppWidgetInfo> mAppWidgets;
private final WeakReference<Launcher> mLauncher;
+
+ public volatile boolean mTerminate = false;
DesktopBinder(Launcher launcher, ArrayList<ItemInfo> shortcuts,
ArrayList<LauncherAppWidgetInfo> appWidgets) {
mLauncher = new WeakReference<Launcher>(launcher);
mShortcuts = shortcuts;
- mAppWidgets = appWidgets;
+
+ // Sort widgets so active workspace is bound first
+ final int currentScreen = launcher.mWorkspace.getCurrentScreen();
+ final int size = appWidgets.size();
+ mAppWidgets = new LinkedList<LauncherAppWidgetInfo>();
+
+ for (int i = 0; i < size; i++) {
+ LauncherAppWidgetInfo appWidgetInfo = appWidgets.get(i);
+ if (appWidgetInfo.screen == currentScreen) {
+ mAppWidgets.addFirst(appWidgetInfo);
+ } else {
+ mAppWidgets.addLast(appWidgetInfo);
+ }
+ }
}
public void startBindingItems() {
obtainMessage(MESSAGE_BIND_ITEMS, 0, mShortcuts.size()).sendToTarget();
}
-
- public void startBindingAppWidgets() {
- obtainMessage(MESSAGE_BIND_APPWIDGETS, 0, mAppWidgets.size()).sendToTarget();
+
+ public void startBindingAppWidgetsWhenIdle() {
+ // Ask for notification when message queue becomes idle
+ final MessageQueue messageQueue = Looper.myQueue();
+ messageQueue.addIdleHandler(this);
}
+ public boolean queueIdle() {
+ // Queue is idle, so start binding items
+ startBindingAppWidgets();
+ return false;
+ }
+
+ public void startBindingAppWidgets() {
+ obtainMessage(MESSAGE_BIND_APPWIDGETS).sendToTarget();
+ }
+
@Override
public void handleMessage(Message msg) {
Launcher launcher = mLauncher.get();
- if (launcher == null) {
+ if (launcher == null || mTerminate) {
return;
}
@@ -1905,7 +2032,7 @@
break;
}
case MESSAGE_BIND_APPWIDGETS: {
- launcher.bindAppWidgets(this, mAppWidgets, msg.arg1, msg.arg2);
+ launcher.bindAppWidgets(this, mAppWidgets);
break;
}
}
diff --git a/src/com/android/launcher/LauncherModel.java b/src/com/android/launcher/LauncherModel.java
index 70b4c10..e302081 100644
--- a/src/com/android/launcher/LauncherModel.java
+++ b/src/com/android/launcher/LauncherModel.java
@@ -28,8 +28,9 @@
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
+import android.graphics.drawable.Drawable;
import android.net.Uri;
-import android.util.Log;
+import static android.util.Log.*;
import android.os.Process;
import java.util.ArrayList;
@@ -46,13 +47,14 @@
* for the Launcher.
*/
public class LauncherModel {
+ static final boolean DEBUG_LOADERS = true;
+ static final String LOG_TAG = "HomeLoaders";
+
private static final int UI_NOTIFICATION_RATE = 4;
private static final int DEFAULT_APPLICATIONS_NUMBER = 42;
private static final long APPLICATION_NOT_RESPONDING_TIMEOUT = 5000;
private static final int INITIAL_ICON_CACHE_CAPACITY = 50;
- private static final boolean DEBUG = false;
-
private static final Collator sCollator = Collator.getInstance();
private boolean mApplicationsLoaded;
@@ -101,14 +103,16 @@
*/
synchronized boolean loadApplications(boolean isLaunching, Launcher launcher,
boolean localeChanged) {
-android.util.Log.d("Home", "load applications");
+
+ if (DEBUG_LOADERS) d(LOG_TAG, "load applications");
+
if (isLaunching && mApplicationsLoaded && !localeChanged) {
mApplicationsAdapter = new ApplicationsAdapter(launcher, mApplications);
-android.util.Log.d("Home", " --> applications loaded, return");
+ if (DEBUG_LOADERS) d(LOG_TAG, " --> applications loaded, return");
return false;
}
- waitForApplicationsLoader();
+ stopAndWaitForApplicationsLoader();
if (localeChanged) {
dropApplicationCache();
@@ -129,9 +133,9 @@
return true;
}
- private synchronized void waitForApplicationsLoader() {
+ private synchronized void stopAndWaitForApplicationsLoader() {
if (mApplicationsLoader != null && mApplicationsLoader.isRunning()) {
- android.util.Log.d("Home", " --> wait for applications loader");
+ if (DEBUG_LOADERS) d(LOG_TAG, " --> wait for applications loader");
mApplicationsLoader.stop();
// Wait for the currently running thread to finish, this can take a little
@@ -145,14 +149,310 @@
}
private synchronized void startApplicationsLoader(Launcher launcher) {
-android.util.Log.d("Home", " --> starting applications loader");
- waitForApplicationsLoader();
+ if (DEBUG_LOADERS) d(LOG_TAG, " --> starting applications loader");
+
+ stopAndWaitForApplicationsLoader();
mApplicationsLoader = new ApplicationsLoader(launcher);
mApplicationsLoaderThread = new Thread(mApplicationsLoader, "Applications Loader");
mApplicationsLoaderThread.start();
}
+ synchronized void addPackage(Launcher launcher, String packageName) {
+ if (mApplicationsLoader != null && mApplicationsLoader.isRunning()) {
+ startApplicationsLoader(launcher);
+ return;
+ }
+
+ if (packageName != null && packageName.length() > 0) {
+ final PackageManager packageManager = launcher.getPackageManager();
+ final List<ResolveInfo> matches = findActivitiesForPackage(packageManager, packageName);
+
+ if (matches.size() > 0) {
+ final ApplicationsAdapter adapter = mApplicationsAdapter;
+ final HashMap<ComponentName, ApplicationInfo> cache = mAppInfoCache;
+
+ for (ResolveInfo info : matches) {
+ adapter.setNotifyOnChange(false);
+ adapter.add(makeAndCacheApplicationInfo(packageManager, cache, info));
+ }
+
+ adapter.sort(new ApplicationInfoComparator());
+ adapter.notifyDataSetChanged();
+ }
+ }
+ }
+
+ synchronized void removePackage(Launcher launcher, String packageName) {
+ if (mApplicationsLoader != null && mApplicationsLoader.isRunning()) {
+ dropApplicationCache(); // TODO: this could be optimized
+ startApplicationsLoader(launcher);
+ return;
+ }
+
+ if (packageName != null && packageName.length() > 0) {
+ final ApplicationsAdapter adapter = mApplicationsAdapter;
+
+ final List<ApplicationInfo> toRemove = new ArrayList<ApplicationInfo>();
+ final int count = adapter.getCount();
+
+ for (int i = 0; i < count; i++) {
+ final ApplicationInfo applicationInfo = adapter.getItem(i);
+ final Intent intent = applicationInfo.intent;
+ final ComponentName component = intent.getComponent();
+ if (packageName.equals(component.getPackageName())) {
+ toRemove.add(applicationInfo);
+ }
+ }
+
+ final HashMap<ComponentName, ApplicationInfo> cache = mAppInfoCache;
+ for (ApplicationInfo info : toRemove) {
+ adapter.setNotifyOnChange(false);
+ adapter.remove(info);
+ cache.remove(info.intent.getComponent());
+ }
+
+ if (toRemove.size() > 0) {
+ adapter.sort(new ApplicationInfoComparator());
+ adapter.notifyDataSetChanged();
+ }
+ }
+ }
+
+ synchronized void updatePackage(Launcher launcher, String packageName) {
+ if (mApplicationsLoader != null && mApplicationsLoader.isRunning()) {
+ startApplicationsLoader(launcher);
+ return;
+ }
+
+ if (packageName != null && packageName.length() > 0) {
+ final PackageManager packageManager = launcher.getPackageManager();
+ final ApplicationsAdapter adapter = mApplicationsAdapter;
+
+ final List<ResolveInfo> matches = findActivitiesForPackage(packageManager, packageName);
+ final int count = matches.size();
+
+ boolean changed = false;
+
+ for (int i = 0; i < count; i++) {
+ final ResolveInfo info = matches.get(i);
+ final ApplicationInfo applicationInfo = findIntent(adapter,
+ info.activityInfo.applicationInfo.packageName, info.activityInfo.name);
+ if (applicationInfo != null) {
+ updateAndCacheApplicationInfo(packageManager, info, applicationInfo);
+ changed = true;
+ }
+ }
+
+ if (changed) {
+ adapter.sort(new ApplicationInfoComparator());
+ adapter.notifyDataSetChanged();
+ }
+ }
+ }
+
+ private void updateAndCacheApplicationInfo(PackageManager packageManager, ResolveInfo info,
+ ApplicationInfo applicationInfo) {
+
+ updateApplicationInfoTitleAndIcon(packageManager, info, applicationInfo);
+
+ ComponentName componentName = new ComponentName(
+ info.activityInfo.applicationInfo.packageName, info.activityInfo.name);
+ mAppInfoCache.put(componentName, applicationInfo);
+ }
+
+ synchronized void syncPackage(Launcher launcher, String packageName) {
+ if (mApplicationsLoader != null && mApplicationsLoader.isRunning()) {
+ startApplicationsLoader(launcher);
+ return;
+ }
+
+ if (packageName != null && packageName.length() > 0) {
+ final PackageManager packageManager = launcher.getPackageManager();
+ final List<ResolveInfo> matches = findActivitiesForPackage(packageManager, packageName);
+
+ if (matches.size() > 0) {
+ final ApplicationsAdapter adapter = mApplicationsAdapter;
+
+ // Find disabled activities and remove them from the adapter
+ boolean removed = removeDisabledActivities(packageName, matches, adapter);
+ // Find enable activities and add them to the adapter
+ // Also updates existing activities with new labels/icons
+ boolean added = addEnabledAndUpdateActivities(matches, adapter, launcher);
+
+ if (added || removed) {
+ adapter.sort(new ApplicationInfoComparator());
+ adapter.notifyDataSetChanged();
+ }
+ }
+ }
+ }
+
+ private static List<ResolveInfo> findActivitiesForPackage(PackageManager packageManager,
+ String packageName) {
+
+ final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
+ mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
+
+ final List<ResolveInfo> apps = packageManager.queryIntentActivities(mainIntent, 0);
+ final List<ResolveInfo> matches = new ArrayList<ResolveInfo>();
+
+ if (apps != null) {
+ // Find all activities that match the packageName
+ int count = apps.size();
+ for (int i = 0; i < count; i++) {
+ final ResolveInfo info = apps.get(i);
+ final ActivityInfo activityInfo = info.activityInfo;
+ if (packageName.equals(activityInfo.packageName)) {
+ matches.add(info);
+ }
+ }
+ }
+
+ return matches;
+ }
+
+ private boolean addEnabledAndUpdateActivities(List<ResolveInfo> matches,
+ ApplicationsAdapter adapter, Launcher launcher) {
+
+ final List<ApplicationInfo> toAdd = new ArrayList<ApplicationInfo>();
+ final int count = matches.size();
+
+ boolean changed = false;
+
+ for (int i = 0; i < count; i++) {
+ final ResolveInfo info = matches.get(i);
+ final ApplicationInfo applicationInfo = findIntent(adapter,
+ info.activityInfo.applicationInfo.packageName, info.activityInfo.name);
+ if (applicationInfo == null) {
+ toAdd.add(makeAndCacheApplicationInfo(launcher.getPackageManager(),
+ mAppInfoCache, info));
+ changed = true;
+ } else {
+ updateAndCacheApplicationInfo(launcher.getPackageManager(), info, applicationInfo);
+ changed = true;
+ }
+ }
+
+ for (ApplicationInfo info : toAdd) {
+ adapter.setNotifyOnChange(false);
+ adapter.add(info);
+ }
+
+ return changed;
+ }
+
+ private boolean removeDisabledActivities(String packageName, List<ResolveInfo> matches,
+ ApplicationsAdapter adapter) {
+
+ final List<ApplicationInfo> toRemove = new ArrayList<ApplicationInfo>();
+ final int count = adapter.getCount();
+
+ boolean changed = false;
+
+ for (int i = 0; i < count; i++) {
+ final ApplicationInfo applicationInfo = adapter.getItem(i);
+ final Intent intent = applicationInfo.intent;
+ final ComponentName component = intent.getComponent();
+ if (packageName.equals(component.getPackageName())) {
+ if (!findIntent(matches, component)) {
+ toRemove.add(applicationInfo);
+ changed = true;
+ }
+ }
+ }
+
+ final HashMap<ComponentName, ApplicationInfo> cache = mAppInfoCache;
+ for (ApplicationInfo info : toRemove) {
+ adapter.setNotifyOnChange(false);
+ adapter.remove(info);
+ cache.remove(info.intent.getComponent());
+ }
+
+ return changed;
+ }
+
+ private static ApplicationInfo findIntent(ApplicationsAdapter adapter, String packageName,
+ String name) {
+
+ final int count = adapter.getCount();
+ for (int i = 0; i < count; i++) {
+ final ApplicationInfo applicationInfo = adapter.getItem(i);
+ final Intent intent = applicationInfo.intent;
+ final ComponentName component = intent.getComponent();
+ if (packageName.equals(component.getPackageName()) &&
+ name.equals(component.getClassName())) {
+ return applicationInfo;
+ }
+ }
+
+ return null;
+ }
+
+ private static boolean findIntent(List<ResolveInfo> apps, ComponentName component) {
+ final String className = component.getClassName();
+ for (ResolveInfo info : apps) {
+ final ActivityInfo activityInfo = info.activityInfo;
+ if (activityInfo.name.equals(className)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ Drawable getApplicationInfoIcon(PackageManager manager, ApplicationInfo info) {
+ final ResolveInfo resolveInfo = manager.resolveActivity(info.intent, 0);
+ if (resolveInfo == null) {
+ return null;
+ }
+
+ ComponentName componentName = new ComponentName(
+ resolveInfo.activityInfo.applicationInfo.packageName,
+ resolveInfo.activityInfo.name);
+ ApplicationInfo application = mAppInfoCache.get(componentName);
+
+ if (application == null) {
+ return resolveInfo.activityInfo.loadIcon(manager);
+ }
+
+ return application.icon;
+ }
+
+ private static ApplicationInfo makeAndCacheApplicationInfo(PackageManager manager,
+ HashMap<ComponentName, ApplicationInfo> appInfoCache, ResolveInfo info) {
+
+ ComponentName componentName = new ComponentName(
+ info.activityInfo.applicationInfo.packageName,
+ info.activityInfo.name);
+ ApplicationInfo application = appInfoCache.get(componentName);
+
+ if (application == null) {
+ application = new ApplicationInfo();
+ application.container = ItemInfo.NO_ID;
+
+ updateApplicationInfoTitleAndIcon(manager, info, application);
+
+ application.setActivity(componentName,
+ Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+
+ appInfoCache.put(componentName, application);
+ }
+
+ return application;
+ }
+
+ private static void updateApplicationInfoTitleAndIcon(PackageManager manager, ResolveInfo info,
+ ApplicationInfo application) {
+
+ application.title = info.loadLabel(manager);
+ if (application.title == null) {
+ application.title = info.activityInfo.name;
+ }
+
+ application.icon = info.activityInfo.loadIcon(manager);
+ application.filtered = false;
+ }
+
private class ApplicationsLoader implements Runnable {
private final WeakReference<Launcher> mLauncher;
@@ -176,7 +476,7 @@
android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
- Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
+ final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
final Launcher launcher = mLauncher.get();
@@ -185,6 +485,8 @@
if (apps != null && !mStopped) {
final int count = apps.size();
+ // Can be set to null on the UI thread by the unbind() method
+ // Do not access without checking for null first
final ApplicationsAdapter applicationList = mApplicationsAdapter;
ChangeNotifier action = new ChangeNotifier(applicationList, true);
@@ -192,28 +494,10 @@
for (int i = 0; i < count && !mStopped; i++) {
ResolveInfo info = apps.get(i);
- ComponentName componentName = new ComponentName(
- info.activityInfo.applicationInfo.packageName,
- info.activityInfo.name);
- ApplicationInfo application = appInfoCache.get(componentName);
- if (application == null) {
- application = new ApplicationInfo();
- application.title = info.loadLabel(manager);
- if (application.title == null) {
- application.title = info.activityInfo.name;
- }
- application.setActivity(componentName,
- Intent.FLAG_ACTIVITY_NEW_TASK |
- Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
- application.container = ItemInfo.NO_ID;
- application.icon = info.activityInfo.loadIcon(manager);
- if (DEBUG) {
- Log.d(Launcher.LOG_TAG, "Loaded ApplicationInfo for " + componentName);
- }
- appInfoCache.put(componentName, application);
- }
+ ApplicationInfo application =
+ makeAndCacheApplicationInfo(manager, appInfoCache, info);
- if (action.add(application)) {
+ if (action.add(application) && !mStopped) {
launcher.runOnUiThread(action);
action = new ChangeNotifier(applicationList, false);
}
@@ -229,7 +513,7 @@
}
}
- private static class ChangeNotifier implements Runnable, Comparator<ApplicationInfo> {
+ private static class ChangeNotifier implements Runnable {
private final ApplicationsAdapter mApplicationList;
private final ArrayList<ApplicationInfo> mBuffer;
@@ -243,6 +527,8 @@
public void run() {
final ApplicationsAdapter applicationList = mApplicationList;
+ // Can be set to null on the UI thread by the unbind() method
+ if (applicationList == null) return;
if (mFirst) {
applicationList.setNotifyOnChange(false);
@@ -260,7 +546,7 @@
buffer.clear();
- applicationList.sort(this);
+ applicationList.sort(new ApplicationInfoComparator());
applicationList.notifyDataSetChanged();
}
@@ -269,7 +555,9 @@
buffer.add(application);
return buffer.size() >= UI_NOTIFICATION_RATE;
}
+ }
+ private static class ApplicationInfoComparator implements Comparator<ApplicationInfo> {
public final int compare(ApplicationInfo a, ApplicationInfo b) {
return sCollator.compare(a.title.toString(), b.title.toString());
}
@@ -285,10 +573,10 @@
*/
void loadUserItems(boolean isLaunching, Launcher launcher, boolean localeChanged,
boolean loadApplications) {
-android.util.Log.d("Home", "loading user items");
+ if (DEBUG_LOADERS) d(LOG_TAG, "loading user items");
if (isLaunching && isDesktopLoaded()) {
-android.util.Log.d("Home", " --> items loaded, return");
+ if (DEBUG_LOADERS) d(LOG_TAG, " --> items loaded, return");
if (loadApplications) startApplicationsLoader(launcher);
// We have already loaded our data from the DB
launcher.onDesktopItemsLoaded();
@@ -306,7 +594,7 @@
}
}
-android.util.Log.d("Home", " --> starting workspace loader");
+ if (DEBUG_LOADERS) d(LOG_TAG, " --> starting workspace loader");
mDesktopItemsLoaded = false;
mDesktopItemsLoader = new DesktopItemsLoader(launcher, localeChanged, loadApplications);
mDesktopLoaderThread = new Thread(mDesktopItemsLoader, "Desktop Items Loader");
@@ -563,7 +851,7 @@
container = c.getInt(containerIndex);
if (container != LauncherSettings.Favorites.CONTAINER_DESKTOP) {
- Log.e(Launcher.LOG_TAG, "Widget found where container "
+ e(Launcher.LOG_TAG, "Widget found where container "
+ "!= CONTAINER_DESKTOP ignoring!");
continue;
}
@@ -589,7 +877,7 @@
container = c.getInt(containerIndex);
if (container != LauncherSettings.Favorites.CONTAINER_DESKTOP) {
- Log.e(Launcher.LOG_TAG, "Widget found where container "
+ e(Launcher.LOG_TAG, "Widget found where container "
+ "!= CONTAINER_DESKTOP -- ignoring!");
continue;
}
@@ -599,7 +887,7 @@
break;
}
} catch (Exception e) {
- Log.w(Launcher.LOG_TAG, "Desktop items loading interrupted:", e);
+ w(Launcher.LOG_TAG, "Desktop items loading interrupted:", e);
}
}
} finally {
@@ -699,6 +987,8 @@
* Home screen on orientation change.
*/
void unbind() {
+ // Interrupt the applications loader before setting the adapter to null
+ stopAndWaitForApplicationsLoader();
mApplicationsAdapter = null;
unbindAppDrawables(mApplications);
unbindDrawables(mDesktopItems);
diff --git a/src/com/android/launcher/LauncherProvider.java b/src/com/android/launcher/LauncherProvider.java
index 5cd7a0f..e63ef30 100644
--- a/src/com/android/launcher/LauncherProvider.java
+++ b/src/com/android/launcher/LauncherProvider.java
@@ -24,6 +24,8 @@
import android.content.ComponentName;
import android.content.ContentUris;
import android.content.ContentResolver;
+import android.content.res.XmlResourceParser;
+import android.content.res.TypedArray;
import android.content.pm.PackageManager;
import android.content.pm.ActivityInfo;
import android.database.sqlite.SQLiteOpenHelper;
@@ -33,19 +35,17 @@
import android.database.SQLException;
import android.util.Log;
import android.util.Xml;
+import android.util.AttributeSet;
import android.net.Uri;
import android.text.TextUtils;
import android.os.*;
import android.provider.Settings;
-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 org.xmlpull.v1.XmlPullParser;
import com.android.internal.util.XmlUtils;
import com.android.launcher.LauncherSettings.Favorites;
@@ -162,19 +162,10 @@
}
private static class DatabaseHelper extends SQLiteOpenHelper {
- /**
- * Path to file containing default favorite packages, relative to ANDROID_ROOT.
- */
- private static final String DEFAULT_FAVORITES_PATH = "etc/favorites.xml";
-
private static final String TAG_FAVORITES = "favorites";
private static final String TAG_FAVORITE = "favorite";
- private static final String TAG_PACKAGE = "package";
- private static final String TAG_CLASS = "class";
-
- private static final String ATTRIBUTE_SCREEN = "screen";
- private static final String ATTRIBUTE_X = "x";
- private static final String ATTRIBUTE_Y = "y";
+ private static final String TAG_CLOCK = "clock";
+ private static final String TAG_SEARCH = "search";
private final Context mContext;
private final AppWidgetHost mAppWidgetHost;
@@ -217,7 +208,7 @@
if (!convertDatabase(db)) {
// Populate favorites table with initial favorites
- loadFavorites(db, DEFAULT_FAVORITES_PATH);
+ loadFavorites(db);
}
}
@@ -445,115 +436,122 @@
* Loads the default set of favorite packages from an xml file.
*
* @param db The database to write the values into
- * @param subPath The relative path from ANDROID_ROOT to the file to read
*/
- private int loadFavorites(SQLiteDatabase db, String subPath) {
- FileReader favReader;
-
- // Environment.getRootDirectory() is a fancy way of saying ANDROID_ROOT or "/system".
- final File favFile = new File(Environment.getRootDirectory(), subPath);
- try {
- favReader = new FileReader(favFile);
- } catch (FileNotFoundException e) {
- Log.e(LOG_TAG, "Couldn't find or open favorites file " + favFile);
- return 0;
- }
-
+ private int loadFavorites(SQLiteDatabase db) {
Intent intent = new Intent(Intent.ACTION_MAIN, null);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
ContentValues values = new ContentValues();
PackageManager packageManager = mContext.getPackageManager();
- ActivityInfo info;
int i = 0;
try {
- XmlPullParser parser = Xml.newPullParser();
- parser.setInput(favReader);
-
+ XmlResourceParser parser = mContext.getResources().getXml(R.xml.default_workspace);
+ AttributeSet attrs = Xml.asAttributeSet(parser);
XmlUtils.beginDocument(parser, TAG_FAVORITES);
- while (true) {
- XmlUtils.nextElement(parser);
+ final int depth = parser.getDepth();
- String name = parser.getName();
- if (!TAG_FAVORITE.equals(name)) {
- break;
+ int type;
+ while (((type = parser.next()) != XmlPullParser.END_TAG ||
+ parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
+
+ if (type != XmlPullParser.START_TAG) {
+ continue;
}
- String pkg = parser.getAttributeValue(null, TAG_PACKAGE);
- String cls = parser.getAttributeValue(null, TAG_CLASS);
- try {
- ComponentName cn = new ComponentName(pkg, cls);
- info = packageManager.getActivityInfo(cn, 0);
- intent.setComponent(cn);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- values.put(LauncherSettings.Favorites.INTENT, intent.toURI());
- values.put(LauncherSettings.Favorites.TITLE,
- info.loadLabel(packageManager).toString());
- values.put(LauncherSettings.Favorites.CONTAINER,
- LauncherSettings.Favorites.CONTAINER_DESKTOP);
- values.put(LauncherSettings.Favorites.ITEM_TYPE,
- LauncherSettings.Favorites.ITEM_TYPE_APPLICATION);
- values.put(LauncherSettings.Favorites.SCREEN,
- parser.getAttributeValue(null, ATTRIBUTE_SCREEN));
- values.put(LauncherSettings.Favorites.CELLX,
- parser.getAttributeValue(null, ATTRIBUTE_X));
- values.put(LauncherSettings.Favorites.CELLY,
- parser.getAttributeValue(null, ATTRIBUTE_Y));
- values.put(LauncherSettings.Favorites.SPANX, 1);
- values.put(LauncherSettings.Favorites.SPANY, 1);
- db.insert(TABLE_FAVORITES, null, values);
- i++;
- } catch (PackageManager.NameNotFoundException e) {
- Log.w(LOG_TAG, "Unable to add favorite: " + pkg + "/" + cls, e);
+ boolean added = false;
+ final String name = parser.getName();
+
+ TypedArray a = mContext.obtainStyledAttributes(attrs, R.styleable.Favorite);
+
+ values.clear();
+ values.put(LauncherSettings.Favorites.CONTAINER,
+ LauncherSettings.Favorites.CONTAINER_DESKTOP);
+ values.put(LauncherSettings.Favorites.SCREEN,
+ a.getString(R.styleable.Favorite_screen));
+ values.put(LauncherSettings.Favorites.CELLX,
+ a.getString(R.styleable.Favorite_x));
+ values.put(LauncherSettings.Favorites.CELLY,
+ a.getString(R.styleable.Favorite_y));
+
+ if (TAG_FAVORITE.equals(name)) {
+ added = addShortcut(db, values, a, packageManager, intent);
+ } else if (TAG_SEARCH.equals(name)) {
+ added = addSearchWidget(db, values);
+ } else if (TAG_CLOCK.equals(name)) {
+ added = addClockWidget(db, values);
}
+
+ if (added) i++;
+
+ a.recycle();
}
} catch (XmlPullParserException e) {
Log.w(LOG_TAG, "Got exception parsing favorites.", e);
} catch (IOException e) {
Log.w(LOG_TAG, "Got exception parsing favorites.", e);
}
-
+
+ return i;
+ }
+
+ private boolean addShortcut(SQLiteDatabase db, ContentValues values, TypedArray a,
+ PackageManager packageManager, Intent intent) {
+
+ ActivityInfo info;
+ String packageName = a.getString(R.styleable.Favorite_packageName);
+ String className = a.getString(R.styleable.Favorite_className);
+ try {
+ ComponentName cn = new ComponentName(packageName, className);
+ info = packageManager.getActivityInfo(cn, 0);
+ intent.setComponent(cn);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+ values.put(Favorites.INTENT, intent.toURI());
+ values.put(Favorites.TITLE, info.loadLabel(packageManager).toString());
+ values.put(Favorites.ITEM_TYPE, Favorites.ITEM_TYPE_APPLICATION);
+ values.put(Favorites.SPANX, 1);
+ values.put(Favorites.SPANY, 1);
+ db.insert(TABLE_FAVORITES, null, values);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.w(LOG_TAG, "Unable to add favorite: " + packageName +
+ "/" + className, e);
+ return false;
+ }
+ return true;
+ }
+
+ private boolean addSearchWidget(SQLiteDatabase db, ContentValues values) {
// Add a search box
- values.clear();
- values.put(LauncherSettings.Favorites.CONTAINER,
- LauncherSettings.Favorites.CONTAINER_DESKTOP);
- values.put(LauncherSettings.Favorites.ITEM_TYPE,
- LauncherSettings.Favorites.ITEM_TYPE_WIDGET_SEARCH);
- values.put(LauncherSettings.Favorites.SCREEN, 2);
- values.put(LauncherSettings.Favorites.CELLX, 0);
- values.put(LauncherSettings.Favorites.CELLY, 0);
- values.put(LauncherSettings.Favorites.SPANX, 4);
- values.put(LauncherSettings.Favorites.SPANY, 1);
+ values.put(Favorites.ITEM_TYPE, Favorites.ITEM_TYPE_WIDGET_SEARCH);
+ values.put(Favorites.SPANX, 4);
+ values.put(Favorites.SPANY, 1);
db.insert(TABLE_FAVORITES, null, values);
-
+
+ return true;
+ }
+
+ private boolean addClockWidget(SQLiteDatabase db, ContentValues values) {
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.AnalogAppWidgetProvider"));
-
+
boolean allocatedAppWidgets = false;
-
+
// Try binding to an analog clock widget
try {
int appWidgetId = mAppWidgetHost.allocateAppWidgetId();
-
- 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.APPWIDGET_ID, appWidgetId);
+
+ values.put(Favorites.ITEM_TYPE, Favorites.ITEM_TYPE_WIDGET_CLOCK);
+ values.put(Favorites.SPANX, 2);
+ values.put(Favorites.SPANY, 2);
+ values.put(Favorites.APPWIDGET_ID, appWidgetId);
db.insert(TABLE_FAVORITES, null, values);
-
+
allocatedAppWidgets = true;
} catch (RuntimeException ex) {
Log.e(LOG_TAG, "Problem allocating appWidgetId", ex);
@@ -563,8 +561,8 @@
if (allocatedAppWidgets) {
launchAppWidgetBinder(bindSources, bindTargets);
}
-
- return i;
+
+ return allocatedAppWidgets;
}
}
diff --git a/src/com/android/launcher/LiveFolder.java b/src/com/android/launcher/LiveFolder.java
index 5d727f8..44a283e 100644
--- a/src/com/android/launcher/LiveFolder.java
+++ b/src/com/android/launcher/LiveFolder.java
@@ -90,7 +90,13 @@
if (mLoadingTask != null && mLoadingTask.getStatus() == AsyncTask.Status.RUNNING) {
mLoadingTask.cancel(true);
}
- ((LiveFolderAdapter) mContent.getAdapter()).cleanup();
+
+ // The adapter can be null if onClose() is called before FolderLoadingTask
+ // is done querying the provider
+ final LiveFolderAdapter adapter = (LiveFolderAdapter) mContent.getAdapter();
+ if (adapter != null) {
+ adapter.cleanup();
+ }
}
static class FolderLoadingTask extends AsyncTask<LiveFolderInfo, Void, Cursor> {
diff --git a/src/com/android/launcher/Workspace.java b/src/com/android/launcher/Workspace.java
index bc5347e..359767a 100644
--- a/src/com/android/launcher/Workspace.java
+++ b/src/com/android/launcher/Workspace.java
@@ -26,6 +26,7 @@
import android.graphics.RectF;
import android.graphics.Rect;
import android.graphics.Region;
+import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.VelocityTracker;
@@ -34,6 +35,7 @@
import android.view.ViewGroup;
import android.view.ViewParent;
import android.widget.Scroller;
+import android.widget.TextView;
import android.os.Parcelable;
import android.os.Parcel;
@@ -1240,7 +1242,41 @@
}
}
}
-
+
+ void updateShortcutsForPackage(String packageName) {
+ final int count = getChildCount();
+ for (int i = 0; i < count; i++) {
+ final CellLayout layout = (CellLayout) getChildAt(i);
+ int childCount = layout.getChildCount();
+ for (int j = 0; j < childCount; j++) {
+ final View view = layout.getChildAt(j);
+ Object tag = view.getTag();
+ if (tag instanceof ApplicationInfo) {
+ ApplicationInfo info = (ApplicationInfo) tag;
+ // 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 (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION &&
+ Intent.ACTION_MAIN.equals(intent.getAction()) && name != null &&
+ packageName.equals(name.getPackageName())) {
+
+ final Drawable icon = Launcher.getModel().getApplicationInfoIcon(
+ mLauncher.getPackageManager(), info);
+ if (icon != null && icon != info.icon) {
+ info.icon.setCallback(null);
+ info.icon = Utilities.createIconThumbnail(icon, mContext);
+ info.filtered = true;
+ ((TextView) view).setCompoundDrawablesWithIntrinsicBounds(null,
+ info.icon, null, null);
+ }
+ }
+ }
+ }
+ }
+ }
+
// TODO: remove widgets when appwidgetmanager tells us they're gone
// void removeAppWidgetsForProvider() {
// }