Merge commit 'remotes/korg/cupcake' into merge

This commit is contained in:
Jean-Baptiste Queru
2009-03-17 16:08:48 -07:00
83 changed files with 2095 additions and 1092 deletions
+1 -1
View File
@@ -17,7 +17,7 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := user eng development
LOCAL_MODULE_TAGS := user
LOCAL_SRC_FILES := $(call all-subdir-java-files)
+4 -2
View File
@@ -20,7 +20,8 @@
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.launcher"
android:sharedUserId="android.uid.shared">
android:sharedUserId="android.uid.shared"
android:sharedUserLabel="@string/application_name">
<permission
android:name="com.android.launcher.permission.INSTALL_SHORTCUT"
@@ -69,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"/>
Binary file not shown.

After

Width:  |  Height:  |  Size: 918 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 480 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 580 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 196 B

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 97 KiB

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 667 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 695 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 669 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 87 KiB

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 578 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

+6 -7
View File
@@ -16,7 +16,6 @@
<com.android.launcher.DragLayer
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher"
android:id="@+id/drag_layer"
@@ -37,15 +36,15 @@
</com.android.launcher.Workspace>
<com.android.internal.widget.SlidingDrawer
<SlidingDrawer
android:id="@+id/drawer"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal"
androidprv:bottomOffset="7px"
androidprv:handle="@+id/all_apps"
androidprv:content="@+id/content">
android:bottomOffset="7dip"
android:handle="@+id/all_apps"
android:content="@+id/content">
<com.android.launcher.HandleView
android:id="@id/all_apps"
@@ -67,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"
@@ -81,7 +80,7 @@
android:verticalSpacing="10dip"
android:numColumns="5" />
</com.android.internal.widget.SlidingDrawer>
</SlidingDrawer>
<com.android.launcher.DeleteZone
android:id="@+id/delete_zone"
+1 -1
View File
@@ -22,7 +22,7 @@
android:paddingTop="5dip"
android:paddingBottom="2dip"
android:drawablePadding="0dip"
android:textSize="13dip"
android:maxLines="2"
android:ellipsize="marquee"
+7 -8
View File
@@ -16,7 +16,6 @@
<com.android.launcher.DragLayer
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher"
android:id="@+id/drag_layer"
@@ -37,15 +36,15 @@
</com.android.launcher.Workspace>
<com.android.internal.widget.SlidingDrawer
<SlidingDrawer
android:id="@+id/drawer"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
androidprv:topOffset="5px"
androidprv:bottomOffset="7px"
androidprv:handle="@+id/all_apps"
androidprv:content="@+id/content">
android:topOffset="5dip"
android:bottomOffset="7dip"
android:handle="@+id/all_apps"
android:content="@+id/content">
<com.android.launcher.HandleView
android:id="@id/all_apps"
@@ -67,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"
@@ -81,7 +80,7 @@
android:verticalSpacing="10dip"
android:numColumns="4" />
</com.android.internal.widget.SlidingDrawer>
</SlidingDrawer>
<com.android.launcher.DeleteZone
android:id="@+id/delete_zone"
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2008 The Android Open Source Project
<!-- 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.
@@ -14,9 +14,12 @@
limitations under the License.
-->
<AnalogClock xmlns:android="http://schemas.android.com/apk/res/android"
android:dial="@drawable/clock_dial"
android:hand_hour="@drawable/clock_hour"
android:hand_minute="@drawable/clock_minute"
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="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="15dip"
android:paddingRight="15dip" />
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2008 The Android Open Source Project
<!-- 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.
@@ -14,9 +14,16 @@
limitations under the License.
-->
<com.android.launcher.PhotoFrame xmlns:android="http://schemas.android.com/apk/res/android"
android:scaleType="center"
android:cropToPadding="true"
android:background="@drawable/picture_frame"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="10dip"
android:paddingBottom="10dip"
android:paddingLeft="20dip"
android:paddingRight="20dip"
android:gravity="center"
android:background="@drawable/bg_appwidget_error"
android:textAppearance="?android:attr/textAppearanceMediumInverse"
android:textColor="@color/appwidget_error_color"
android:text="@string/gadget_error_text"
/>
+2 -3
View File
@@ -17,11 +17,10 @@
** limitations under the License.
*/
-->
<ExpandableListView xmlns:android="http://schemas.android.com/apk/res/android"
<ListView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_marginTop="5px"
android:layout_marginTop="5dip"
android:cacheColorHint="@null"
android:childDivider="@android:drawable/divider_horizontal_bright"
android:divider="@android:drawable/divider_horizontal_bright"
android:scrollbars="vertical" />
+9 -2
View File
@@ -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|textSearchString"
android:inputType="textAutoComplete"
android:imeOptions="actionSearch"
/>
<ImageButton android:id="@+id/search_go_btn"
@@ -46,4 +47,10 @@
android:src="@*android:drawable/ic_btn_search"
/>
<ImageButton android:id="@+id/search_voice_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@android:drawable/ic_btn_speak_now"
/>
</com.android.launcher.Search>
+6
View File
@@ -28,6 +28,8 @@
<string name="menu_item_add_item">"Přidat na plochu"</string>
<string name="group_applications">"Aplikace"</string>
<string name="group_shortcuts">"Zástupce"</string>
<string name="group_search">"Hledat"</string>
<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_wallpapers">"Tapeta"</string>
@@ -36,6 +38,8 @@
<string name="add_photo_frame">"Rámeček fotografie"</string>
<string name="add_search">"Vyhledávání"</string>
<string name="out_of_space">"Na této ploše již není místo."</string>
<string name="title_select_shortcut">"Vyberte zástupce"</string>
<string name="title_select_live_folder">"Vyberte složku Live"</string>
<string name="menu_add">"Přidat"</string>
<string name="menu_wallpaper">"Tapeta"</string>
<string name="menu_search">"Hledat"</string>
@@ -50,4 +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>
<!-- no translation found for gadget_error_text (8359351016167075858) -->
<skip />
</resources>
+6
View File
@@ -28,6 +28,8 @@
<string name="menu_item_add_item">"Zur Startseite hinzufügen"</string>
<string name="group_applications">"Anwendung"</string>
<string name="group_shortcuts">"Verknüpfung"</string>
<string name="group_search">"Suchen"</string>
<string name="group_folder">"Ordner"</string>
<string name="group_live_folders">"Live-Ordner"</string>
<string name="group_widgets">"Widget"</string>
<string name="group_wallpapers">"Hintergrund"</string>
@@ -36,6 +38,8 @@
<string name="add_photo_frame">"Bildrahmen"</string>
<string name="add_search">"Suchen"</string>
<string name="out_of_space">"Auf der Startseite ist kein Platz mehr vorhanden."</string>
<string name="title_select_shortcut">"Tastenkürzel auswählen"</string>
<string name="title_select_live_folder">"Live-Ordner auswählen"</string>
<string name="menu_add">"Hinzufügen"</string>
<string name="menu_wallpaper">"Hintergrund"</string>
<string name="menu_search">"Suchen"</string>
@@ -50,4 +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>
<!-- no translation found for gadget_error_text (8359351016167075858) -->
<skip />
</resources>
+13 -7
View File
@@ -17,9 +17,9 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="application_name">"Página principal"</string>
<string name="folder_name">"Carpeta"</string>
<string name="chooser_wallpaper">"Seleccionar papel tapiz de"</string>
<string name="wallpaper_instructions">"Establecer papel tapiz"</string>
<string name="pick_wallpaper">"Galería de papel tapiz"</string>
<string name="chooser_wallpaper">"Seleccionar fondo de pantalla de"</string>
<string name="wallpaper_instructions">"Establecer fondo de pantalla"</string>
<string name="pick_wallpaper">"Galería de fondo de pantalla"</string>
<string name="activity_not_found">"La aplicación no está instalada en el teléfono."</string>
<string name="rename_folder_label">"Nombre de carpeta"</string>
<string name="rename_folder_title">"Cambiar nombre de carpeta"</string>
@@ -28,19 +28,23 @@
<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">"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_wallpapers">"Papel tapiz"</string>
<string name="group_wallpapers">"Fondo de pantalla"</string>
<string name="add_folder">"Carpeta"</string>
<string name="add_clock">"Reloj"</string>
<string name="add_photo_frame">"Picture frame"</string>
<string name="add_search">"Búsqueda de Google"</string>
<string name="out_of_space">"No queda espacio en esta pantalla de página principal."</string>
<string name="title_select_shortcut">"Seleccionar acceso directo"</string>
<string name="title_select_live_folder">"Seleccionar carpeta activa"</string>
<string name="menu_add">"Añadir"</string>
<string name="menu_wallpaper">"Papel tapiz"</string>
<string name="menu_search">"Búsqueda de Google"</string>
<string name="menu_wallpaper">"Fondo de pantalla"</string>
<string name="menu_search">"Buscar con Google"</string>
<string name="menu_notifications">"Notificaciones"</string>
<string name="menu_settings">"Configuración"</string>
<string name="menu_settings">"Ajustes"</string>
<string name="permlab_install_shortcut">"instalar accesos directos"</string>
<string name="permdesc_install_shortcut">"Permite que una aplicación añada accesos directos sin intervención del usuario."</string>
<string name="permlab_uninstall_shortcut">"desinstalar accesos directos"</string>
@@ -50,4 +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>
<!-- no translation found for gadget_error_text (8359351016167075858) -->
<skip />
</resources>
+13 -7
View File
@@ -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>
@@ -28,14 +28,18 @@
<string name="menu_item_add_item">"Ajouter à l\'écran d\'accueil"</string>
<string name="group_applications">"Application"</string>
<string name="group_shortcuts">"Raccourci"</string>
<string name="group_live_folders">"Dossier live"</string>
<string name="group_search">"Recherche"</string>
<string name="group_folder">"Dossier"</string>
<string name="group_live_folders">"Dossier actif"</string>
<string name="group_widgets">"Widget"</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 dossier actif"</string>
<string name="menu_add">"Ajouter"</string>
<string name="menu_wallpaper">"Arrière-plan"</string>
<string name="menu_search">"Rechercher"</string>
@@ -45,9 +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>
<!-- no translation found for gadget_error_text (8359351016167075858) -->
<skip />
</resources>
+15 -9
View File
@@ -27,7 +27,9 @@
<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_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_wallpapers">"Sfondo"</string>
@@ -36,18 +38,22 @@
<string name="add_photo_frame">"Cornice immagini"</string>
<string name="add_search">"Ricerca"</string>
<string name="out_of_space">"Spazio nella schermata Home esaurito."</string>
<string name="title_select_shortcut">"Seleziona collegamento"</string>
<string name="title_select_live_folder">"Seleziona cartella dinamica"</string>
<string name="menu_add">"Aggiungi"</string>
<string name="menu_wallpaper">"Sfondo"</string>
<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>
<!-- no translation found for gadget_error_text (8359351016167075858) -->
<skip />
</resources>
+10 -4
View File
@@ -28,6 +28,8 @@
<string name="menu_item_add_item">"ホーム画面に追加"</string>
<string name="group_applications">"アプリケーション"</string>
<string name="group_shortcuts">"ショートカット"</string>
<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>
@@ -35,19 +37,23 @@
<string name="add_clock">"時計"</string>
<string name="add_photo_frame">"写真フレーム"</string>
<string name="add_search">"検索"</string>
<string name="out_of_space">"このホーム画面に空きスペースがありません。"</string>
<string name="out_of_space">"ホーム画面に空きスペースがありません。"</string>
<string name="title_select_shortcut">"ショートカットを選択"</string>
<string name="title_select_live_folder">"ライブフォルダを選択"</string>
<string name="menu_add">"追加"</string>
<string name="menu_wallpaper">"壁紙"</string>
<string name="menu_search">"検索"</string>
<string name="menu_notifications">"通知"</string>
<string name="menu_settings">"設定"</string>
<string name="permlab_install_shortcut">"ショートカットのインストール"</string>
<string name="permdesc_install_shortcut">"ユーザー操作なしでショートカットをアプリケーションで追加できるようにします。"</string>
<string name="permdesc_install_shortcut">"ユーザー操作なしでショートカットの追加をアプリケーションに許可します。"</string>
<string name="permlab_uninstall_shortcut">"ショートカットのアンインストール"</string>
<string name="permdesc_uninstall_shortcut">"ユーザー操作なしでショートカットをアプリケーションで削除できるようにします。"</string>
<string name="permlab_read_settings">"ホーム設定とショートカットの読み取り"</string>
<string name="permdesc_uninstall_shortcut">"ユーザー操作なしでショートカットの削除をアプリケーションに許可します。"</string>
<string name="permlab_read_settings">"ホーム設定とショートカットの読み取り"</string>
<string name="permdesc_read_settings">"ホームの設定とショートカットの読み取りをアプリケーションに許可します。"</string>
<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 />
</resources>
+59
View File
@@ -0,0 +1,59 @@
<?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.
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="application_name">"홈"</string>
<string name="folder_name">"폴더"</string>
<string name="chooser_wallpaper">"배경화면 선택"</string>
<string name="wallpaper_instructions">"배경화면 설정"</string>
<string name="pick_wallpaper">"배경화면 갤러리"</string>
<string name="activity_not_found">"전화기에 설치되어 있지 않은 응용프로그램입니다."</string>
<string name="rename_folder_label">"폴더 이름"</string>
<string name="rename_folder_title">"폴더 이름 바꾸기"</string>
<string name="rename_action">"확인"</string>
<string name="cancel_action">"취소"</string>
<string name="menu_item_add_item">"홈 화면에 추가"</string>
<string name="group_applications">"응용프로그램"</string>
<string name="group_shortcuts">"바로가기"</string>
<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>
<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>
<string name="menu_add">"추가"</string>
<string name="menu_wallpaper">"배경화면"</string>
<string name="menu_search">"검색"</string>
<string name="menu_notifications">"알림"</string>
<string name="menu_settings">"설정"</string>
<string name="permlab_install_shortcut">"바로가기 설치"</string>
<string name="permdesc_install_shortcut">"응용프로그램이 사용자의 작업 없이 바로가기를 추가할 수 있도록 합니다."</string>
<string name="permlab_uninstall_shortcut">"바로가기 제거"</string>
<string name="permdesc_uninstall_shortcut">"응용프로그램이 사용자의 작업 없이 바로가기를 제거할 수 있도록 합니다."</string>
<string name="permlab_read_settings">"홈 설정 및 바로가기 읽기"</string>
<string name="permdesc_read_settings">"응용프로그램이 홈에 있는 설정 및 바로가기를 읽을 수 있습니다."</string>
<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 />
</resources>
+59
View File
@@ -0,0 +1,59 @@
<?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.
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="application_name">"Hjem"</string>
<string name="folder_name">"Mappe"</string>
<string name="chooser_wallpaper">"Velg bakgrunnsbilde fra"</string>
<string name="wallpaper_instructions">"Velg bakgrunnsbilde"</string>
<string name="pick_wallpaper">"Bildegalleri"</string>
<string name="activity_not_found">"Applikasjonen er ikke installert."</string>
<string name="rename_folder_label">"Mappenavn"</string>
<string name="rename_folder_title">"Gi nytt navn til mappe"</string>
<string name="rename_action">"OK"</string>
<string name="cancel_action">"Avbryt"</string>
<string name="menu_item_add_item">"Legg til skrivebord"</string>
<string name="group_applications">"Applikasjon"</string>
<string name="group_shortcuts">"Snarvei"</string>
<string name="group_search">"Søk"</string>
<string name="group_folder">"Mappe"</string>
<string name="group_live_folders">"Aktiv mappe"</string>
<string name="group_widgets">"Skrivebordselement"</string>
<string name="group_wallpapers">"Bakgrunnsbilde"</string>
<string name="add_folder">"Mappe"</string>
<string name="add_clock">"Klokke"</string>
<string name="add_photo_frame">"Bilderamme"</string>
<string name="add_search">"Søk"</string>
<string name="out_of_space">"Ikke nok plass på skrivebordet."</string>
<string name="title_select_shortcut">"Velg snarvei"</string>
<string name="title_select_live_folder">"Velg aktiv mappe"</string>
<string name="menu_add">"Legg til"</string>
<string name="menu_wallpaper">"Bakgrunnsbilde"</string>
<string name="menu_search">"Søk"</string>
<string name="menu_notifications">"Varslinger"</string>
<string name="menu_settings">"Innstillinger"</string>
<string name="permlab_install_shortcut">"installere snarveier"</string>
<string name="permdesc_install_shortcut">"Lar applikasjonen legge til snarveier uten å involvere brukeren."</string>
<string name="permlab_uninstall_shortcut">"avinstallere snarveier"</string>
<string name="permdesc_uninstall_shortcut">"Lar applikasjonen fjerne snarveier uten å involvere brukeren."</string>
<string name="permlab_read_settings">"lese skrivebordsinnstillinger og -snarveier"</string>
<string name="permdesc_read_settings">"Lar applikasjonen lese innstillinger og snarveier fra skrivebordet."</string>
<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 />
</resources>
+7 -1
View File
@@ -28,6 +28,8 @@
<string name="menu_item_add_item">"Toevoegen aan startpagina"</string>
<string name="group_applications">"Toepassing"</string>
<string name="group_shortcuts">"Snelkoppeling"</string>
<string name="group_search">"Zoeken"</string>
<string name="group_folder">"Map"</string>
<string name="group_live_folders">"Live map"</string>
<string name="group_widgets">"Widget"</string>
<string name="group_wallpapers">"Achtergrond"</string>
@@ -36,6 +38,8 @@
<string name="add_photo_frame">"Fotolijstje"</string>
<string name="add_search">"Zoeken"</string>
<string name="out_of_space">"Er is geen ruimte meer op dit startscherm."</string>
<string name="title_select_shortcut">"Snelkoppeling selecteren"</string>
<string name="title_select_live_folder">"Live map selecteren"</string>
<string name="menu_add">"Toevoegen"</string>
<string name="menu_wallpaper">"Achtergrond"</string>
<string name="menu_search">"Zoeken"</string>
@@ -49,5 +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="search_hint">"Google Zoeken"</string>
<!-- no translation found for gadget_error_text (8359351016167075858) -->
<skip />
</resources>
+9 -3
View File
@@ -15,7 +15,7 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="application_name">"Strona główna"</string>
<string name="application_name">"Sieć"</string>
<string name="folder_name">"Folder"</string>
<string name="chooser_wallpaper">"Wybierz tapetę"</string>
<string name="wallpaper_instructions">"Ustaw tapetę"</string>
@@ -28,14 +28,18 @@
<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_live_folders">"Folder Live"</string>
<string name="group_search">"Wyszukiwarka"</string>
<string name="group_folder">"Folder"</string>
<string name="group_live_folders">"Folder aktywny"</string>
<string name="group_widgets">"Widget"</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>
<string name="menu_add">"Dodaj"</string>
<string name="menu_wallpaper">"Tapeta"</string>
<string name="menu_search">"Szukaj"</string>
@@ -50,4 +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>
<!-- no translation found for gadget_error_text (8359351016167075858) -->
<skip />
</resources>
+6
View File
@@ -28,6 +28,8 @@
<string name="menu_item_add_item">"Добавление на главный экран"</string>
<string name="group_applications">"Приложение"</string>
<string name="group_shortcuts">"Ярлык"</string>
<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>
@@ -36,6 +38,8 @@
<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>
<string name="menu_add">"Добавить"</string>
<string name="menu_wallpaper">"Фоновый рисунок"</string>
<string name="menu_search">"Искать"</string>
@@ -50,4 +54,6 @@
<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 />
</resources>
+6
View File
@@ -28,6 +28,8 @@
<string name="menu_item_add_item">"添加到“主页”屏幕"</string>
<string name="group_applications">"应用程序"</string>
<string name="group_shortcuts">"快捷键"</string>
<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>
@@ -36,6 +38,8 @@
<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>
<string name="menu_add">"添加"</string>
<string name="menu_wallpaper">"壁纸"</string>
<string name="menu_search">"搜索"</string>
@@ -50,4 +54,6 @@
<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 />
</resources>
+6
View File
@@ -28,6 +28,8 @@
<string name="menu_item_add_item">"新增至首頁畫面"</string>
<string name="group_applications">"應用程式"</string>
<string name="group_shortcuts">"捷徑"</string>
<string name="group_search">"搜尋"</string>
<string name="group_folder">"資料夾"</string>
<string name="group_live_folders">"使用中的資料夾"</string>
<string name="group_widgets">"Widget"</string>
<string name="group_wallpapers">"桌布"</string>
@@ -36,6 +38,8 @@
<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>
<string name="menu_add">"新增"</string>
<string name="menu_wallpaper">"桌布"</string>
<string name="menu_search">"搜尋"</string>
@@ -50,4 +54,6 @@
<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 />
</resources>
+7
View File
@@ -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>
+2
View File
@@ -22,4 +22,6 @@
<color name="grid_dark_background">#EB191919</color>
<color name="bubble_dark_background">#B2191919</color>
<color name="delete_color_filter">#A5FF0000</color>
<color name="appwidget_error_color">#fccc</color>
</resources>
+15 -2
View File
@@ -52,8 +52,13 @@
<string name="group_applications">Application</string>
<!-- Options in "Add to Home" dialog box; Title of the group containing the list of all shortcuts -->
<string name="group_shortcuts">Shortcut</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>
<!-- 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 apps that can set the wallpaper-->
<string name="group_wallpapers">Wallpaper</string>
@@ -68,6 +73,11 @@
<!-- Error message when user has filled a home screen, possibly not used -->
<string name="out_of_space">No more room on this Home screen.</string>
<!-- 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>
<!-- Menus items: -->
<skip />
<!-- Verb, menu item used to add an item on the desktop -->
@@ -101,5 +111,8 @@
This translation SHOULD MATCH the string "search_hint" which is found in
GoogleSearch/res/values/strings.xml -->
<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 widget</string>
</resources>
+76 -421
View File
@@ -16,456 +16,111 @@
package com.android.launcher;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
import android.widget.BaseExpandableListAdapter;
import android.graphics.drawable.Drawable;
import android.provider.LiveFolders;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Shows a list of all the items that can be added to the workspace.
* Adapter showing the types of items that can be added to a {@link Workspace}.
*/
public final class AddAdapter extends BaseExpandableListAdapter {
private static final int GROUP_APPLICATIONS = 0;
private static final int GROUP_SHORTCUTS = 1;
private static final int GROUP_WIDGETS = 2;
private static final int GROUP_LIVE_FOLDERS = 3;
private static final int GROUP_WALLPAPERS = 4;
private final Intent mCreateShortcutIntent;
private final Intent mCreateLiveFolderIntent;
private Intent mSetWallpaperIntent;
public class AddAdapter extends BaseAdapter {
private final Launcher mLauncher;
private final LayoutInflater mInflater;
private Launcher mLauncher;
private Group[] mGroups;
/**
* Abstract class representing one thing that can be added
*/
public abstract class AddAction implements Runnable {
protected final Context mContext;
AddAction(Context context) {
mContext = context;
}
Drawable getIcon(int resource) {
return mContext.getResources().getDrawable(resource);
}
public abstract void bindView(View v);
}
/**
* Class representing an action that will create set the wallpaper.
*/
public class SetWallpaperAction extends CreateShortcutAction {
SetWallpaperAction(Context context, ResolveInfo info) {
super(context, info);
}
public void run() {
Intent intent = new Intent(mSetWallpaperIntent);
ActivityInfo activityInfo = mInfo.activityInfo;
intent.setComponent(new ComponentName(activityInfo.applicationInfo.packageName,
activityInfo.name));
mLauncher.startActivity(intent);
}
}
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;
/**
* Class representing an action that will create a specific type
* of shortcut
* Specific item in our list.
*/
public class CreateShortcutAction extends AddAction {
public class ListItem {
public final CharSequence text;
public final Drawable image;
public final int actionTag;
ResolveInfo mInfo;
private CharSequence mLabel;
private Drawable mIcon;
CreateShortcutAction(Context context, ResolveInfo info) {
super(context);
mInfo = info;
}
@Override
public void bindView(View view) {
ResolveInfo info = mInfo;
TextView text = (TextView) view;
PackageManager pm = mLauncher.getPackageManager();
if (mLabel == null) {
mLabel = info.loadLabel(pm);
if (mLabel == null) {
mLabel = info.activityInfo.name;
}
public ListItem(Resources res, int textResourceId, int imageResourceId, int actionTag) {
text = res.getString(textResourceId);
if (imageResourceId != -1) {
image = res.getDrawable(imageResourceId);
} else {
image = null;
}
if (mIcon == null) {
mIcon = Utilities.createIconThumbnail(info.loadIcon(pm), mContext);
}
text.setText(mLabel);
text.setCompoundDrawablesWithIntrinsicBounds(mIcon, null, null, null);
}
public void run() {
Intent intent = new Intent(mCreateShortcutIntent);
ActivityInfo activityInfo = mInfo.activityInfo;
intent.setComponent(new ComponentName(activityInfo.applicationInfo.packageName,
activityInfo.name));
mLauncher.addShortcut(intent);
}
}
/**
* Class representing an action that will create a specific type
* of live folder
*/
public class CreateLiveFolderAction extends CreateShortcutAction {
CreateLiveFolderAction(Context context, ResolveInfo info) {
super(context, info);
}
@Override
public void run() {
Intent intent = new Intent(mCreateLiveFolderIntent);
ActivityInfo activityInfo = mInfo.activityInfo;
intent.setComponent(new ComponentName(activityInfo.applicationInfo.packageName,
activityInfo.name));
mLauncher.addLiveFolder(intent);
}
}
/**
* Class representing an action that will add a folder
*/
public class CreateFolderAction extends AddAction {
private Drawable mIcon;
CreateFolderAction(Context context) {
super(context);
}
@Override
public void bindView(View view) {
TextView text = (TextView) view;
text.setText(R.string.add_folder);
if (mIcon == null) mIcon = getIcon(R.drawable.ic_launcher_folder);
text.setCompoundDrawablesWithIntrinsicBounds(mIcon, null, null, null);
}
public void run() {
mLauncher.addFolder();
}
}
/**
* Class representing an action that will add a folder
*/
public class CreateClockAction extends AddAction {
CreateClockAction(Context context) {
super(context);
}
@Override
public void bindView(View view) {
TextView text = (TextView) view;
text.setText(R.string.add_clock);
Drawable icon = getIcon(R.drawable.ic_launcher_alarmclock);
text.setCompoundDrawablesWithIntrinsicBounds(icon, null, null, null);
}
public void run() {
mLauncher.addClock();
}
}
/**
* Class representing an action that will add a PhotoFrame
*/
public class CreatePhotoFrameAction extends AddAction {
private Drawable mIcon;
CreatePhotoFrameAction(Context context) {
super(context);
}
@Override
public void bindView(View view) {
TextView text = (TextView) view;
text.setText(R.string.add_photo_frame);
if (mIcon == null) mIcon = getIcon(R.drawable.ic_launcher_gallery);
text.setCompoundDrawablesWithIntrinsicBounds(mIcon, null, null, null);
}
public void run() {
mLauncher.getPhotoForPhotoFrame();
}
}
/**
* Class representing an action that will add a Search widget
*/
public class CreateSearchAction extends AddAction {
private Drawable mIcon;
CreateSearchAction(Context context) {
super(context);
}
@Override
public void bindView(View view) {
TextView text = (TextView) view;
text.setText(R.string.add_search);
if (mIcon == null) mIcon = getIcon(R.drawable.ic_search_gadget);
text.setCompoundDrawablesWithIntrinsicBounds(mIcon, null, null, null);
}
public void run() {
mLauncher.addSearch();
this.actionTag = actionTag;
}
}
private class Group {
private String mName;
private ArrayList<AddAction> mList;
Group(String name) {
mName = name;
mList = new ArrayList<AddAction>();
}
void add(AddAction action) {
mList.add(action);
}
int size() {
return mList.size();
}
String getName() {
return mName;
}
void run(int position) {
mList.get(position).run();
}
void bindView(int childPosition, View view) {
mList.get(childPosition).bindView(view);
}
public Object get(int childPosition) {
return mList.get(childPosition);
}
}
private class ApplicationsGroup extends Group {
private final Launcher mLauncher;
private final ArrayList<ApplicationInfo> mApplications;
ApplicationsGroup(Launcher launcher, String name) {
super(name);
mLauncher = launcher;
mApplications = Launcher.getModel().getApplications();
}
@Override
int size() {
return mApplications == null ? 0 : mApplications.size();
}
@Override
void add(AddAction action) {
}
@Override
void run(int position) {
final ApplicationInfo info = mApplications.get(position);
mLauncher.addApplicationShortcut(info);
}
@Override
void bindView(int childPosition, View view) {
TextView text = (TextView) view.findViewById(R.id.title);
final ApplicationInfo info = mApplications.get(childPosition);
text.setText(info.title);
if (!info.filtered) {
info.icon = Utilities.createIconThumbnail(info.icon, mLauncher);
info.filtered = true;
}
text.setCompoundDrawablesWithIntrinsicBounds(info.icon, null, null, null);
}
@Override
public Object get(int childPosition) {
return mApplications.get(childPosition);
}
}
public AddAdapter(Launcher launcher, boolean forFolder) {
mCreateShortcutIntent = new Intent(Intent.ACTION_CREATE_SHORTCUT);
mCreateShortcutIntent.setComponent(null);
mCreateLiveFolderIntent = new Intent(LiveFolders.ACTION_CREATE_LIVE_FOLDER);
mCreateLiveFolderIntent.setComponent(null);
mSetWallpaperIntent = new Intent(Intent.ACTION_SET_WALLPAPER);
mSetWallpaperIntent.setComponent(null);
public AddAdapter(Launcher launcher) {
super();
mLauncher = launcher;
mInflater = (LayoutInflater) launcher.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mInflater = (LayoutInflater) mLauncher.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));
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));
mItems.add(new ListItem(res, R.string.group_wallpapers,
R.drawable.ic_launcher_gallery, ITEM_WALLPAPER));
mGroups = new Group[forFolder ? 2 : 5];
final Group[] groups = mGroups;
groups[GROUP_APPLICATIONS] = new ApplicationsGroup(mLauncher,
mLauncher.getString(R.string.group_applications));
groups[GROUP_SHORTCUTS] = new Group(mLauncher.getString(R.string.group_shortcuts));
groups[GROUP_LIVE_FOLDERS] = new Group(mLauncher.getString(R.string.group_live_folders));
}
if (!forFolder) {
groups[GROUP_WALLPAPERS] = new Group(mLauncher.getString(R.string.group_wallpapers));
groups[GROUP_SHORTCUTS].add(new CreateFolderAction(launcher));
groups[GROUP_WIDGETS] = new Group(mLauncher.getString(R.string.group_widgets));
final Group widgets = groups[GROUP_WIDGETS];
widgets.add(new CreateClockAction(launcher));
widgets.add(new CreatePhotoFrameAction(launcher));
widgets.add(new CreateSearchAction(launcher));
public View getView(int position, View convertView, ViewGroup parent) {
ListItem item = (ListItem) getItem(position);
if (convertView == null) {
convertView = mInflater.inflate(R.layout.add_list_item, parent, false);
}
PackageManager packageManager = launcher.getPackageManager();
List<ResolveInfo> list = findTargetsForIntent(mCreateShortcutIntent, packageManager);
if (list != null && list.size() > 0) {
int count = list.size();
final Group shortcuts = groups[GROUP_SHORTCUTS];
for (int i = 0; i < count; i++) {
ResolveInfo resolveInfo = list.get(i);
shortcuts.add(new CreateShortcutAction(launcher, resolveInfo));
}
}
list = findTargetsForIntent(mCreateLiveFolderIntent, packageManager);
if (list != null && list.size() > 0) {
int count = list.size();
final Group shortcuts = groups[GROUP_LIVE_FOLDERS];
for (int i = 0; i < count; i++) {
ResolveInfo resolveInfo = list.get(i);
shortcuts.add(new CreateLiveFolderAction(launcher, resolveInfo));
}
}
list = findTargetsForIntent(mSetWallpaperIntent, packageManager);
if (list != null && list.size() > 0) {
int count = list.size();
final Group shortcuts = groups[GROUP_WALLPAPERS];
for (int i = 0; i < count; i++) {
ResolveInfo resolveInfo = list.get(i);
shortcuts.add(new SetWallpaperAction(launcher, resolveInfo));
}
}
TextView textView = (TextView) convertView;
textView.setTag(item);
textView.setText(item.text);
textView.setCompoundDrawablesWithIntrinsicBounds(item.image, null, null, null);
return convertView;
}
private List<ResolveInfo> findTargetsForIntent(Intent intent, PackageManager packageManager) {
List<ResolveInfo> list = packageManager.queryIntentActivities(intent,
PackageManager.MATCH_DEFAULT_ONLY);
if (list != null) {
int count = list.size();
if (count > 1) {
// Only display the first matches that are either of equal
// priority or have asked to be default options.
ResolveInfo firstInfo = list.get(0);
for (int i=1; i<count; i++) {
ResolveInfo resolveInfo = list.get(i);
if (firstInfo.priority != resolveInfo.priority ||
firstInfo.isDefault != resolveInfo.isDefault) {
while (i < count) {
list.remove(i);
count--;
}
}
}
Collections.sort(list, new ResolveInfo.DisplayNameComparator(packageManager));
}
}
return list;
public int getCount() {
return mItems.size();
}
public int getGroupCount() {
return mGroups.length;
public Object getItem(int position) {
return mItems.get(position);
}
public int getChildrenCount(int groupPosition) {
return mGroups[groupPosition].size();
}
public Object getGroup(int groupPosition) {
return mGroups[groupPosition].getName();
}
public Object getChild(int groupPosition, int childPosition) {
return mGroups[groupPosition].get(childPosition);
}
public long getGroupId(int groupPosition) {
return groupPosition;
}
public long getChildId(int groupPosition, int childPosition) {
return (groupPosition << 16) | childPosition;
}
public boolean hasStableIds() {
return true;
}
public View getGroupView(int groupPosition, boolean isExpanded,
View convertView, ViewGroup parent) {
View view;
if (convertView == null) {
view = mInflater.inflate(R.layout.create_shortcut_group_item, parent, false);
} else {
view = convertView;
}
((TextView) view).setText(mGroups[groupPosition].getName());
return view;
}
public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
View convertView, ViewGroup parent) {
View view;
if (convertView == null) {
view = mInflater.inflate(R.layout.create_shortcut_list_item, parent, false);
} else {
view = convertView;
}
mGroups[groupPosition].bindView(childPosition, view);
return view;
}
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
void performAction(int groupPosition, int childPosition) {
mGroups[groupPosition].run(childPosition);
public long getItemId(int position) {
return position;
}
}
+48 -1
View File
@@ -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);
+14 -5
View File
@@ -40,6 +40,9 @@ public class BubbleTextView extends TextView {
private boolean mBackgroundSizeChanged;
private Drawable mBackground;
private float mCornerRadius;
private float mPaddingH;
private float mPaddingV;
public BubbleTextView(Context context) {
super(context);
@@ -64,6 +67,12 @@ public class BubbleTextView extends TextView {
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(getContext().getResources().getColor(R.color.bubble_dark_background));
final float scale = getContext().getResources().getDisplayMetrics().density;
mCornerRadius = CORNER_RADIUS * scale;
mPaddingH = PADDING_H * scale;
//noinspection PointlessArithmeticExpression
mPaddingV = PADDING_V * scale;
}
@Override
@@ -114,11 +123,11 @@ public class BubbleTextView extends TextView {
final int left = getCompoundPaddingLeft();
final int top = getExtendedPaddingTop();
rect.set(left + layout.getLineLeft(0) - PADDING_H,
top + layout.getLineTop(0) - PADDING_V,
Math.min(left + layout.getLineRight(0) + PADDING_H, mScrollX + mRight - mLeft),
top + layout.getLineBottom(0) + PADDING_V);
canvas.drawRoundRect(rect, CORNER_RADIUS, CORNER_RADIUS, mPaint);
rect.set(left + layout.getLineLeft(0) - mPaddingH,
top + layout.getLineTop(0) - mPaddingV,
Math.min(left + layout.getLineRight(0) + mPaddingH, mScrollX + mRight - mLeft),
top + layout.getLineBottom(0) + mPaddingV);
canvas.drawRoundRect(rect, mCornerRadius, mCornerRadius, mPaint);
super.draw(canvas);
}
+137 -30
View File
@@ -56,6 +56,8 @@ public class CellLayout extends ViewGroup {
private RectF mDragRect = new RectF();
private boolean mDirtyTag;
public CellLayout(Context context) {
this(context, null);
}
@@ -157,6 +159,7 @@ public class CellLayout extends ViewGroup {
cellInfo.spanY = lp.cellVSpan;
cellInfo.valid = true;
found = true;
mDirtyTag = false;
break;
}
}
@@ -181,10 +184,12 @@ public class CellLayout extends ViewGroup {
cellInfo.valid = cellXY[0] >= 0 && cellXY[1] >= 0 && cellXY[0] < xCount &&
cellXY[1] < yCount && !occupied[cellXY[0]][cellXY[1]];
if (cellInfo.valid) {
findIntersectingVacantCells(cellInfo, cellXY[0], cellXY[1],
xCount, yCount, occupied);
}
// Instead of finding the interesting vacant cells here, wait until a
// caller invokes getTag() to retrieve the result. Finding the vacant
// cells is a bit expensive and can generate many new objects, it's
// therefore better to defer it until we know we actually need it.
mDirtyTag = true;
}
setTag(cellInfo);
} else if (action == MotionEvent.ACTION_UP) {
@@ -194,12 +199,31 @@ public class CellLayout extends ViewGroup {
cellInfo.spanX = 0;
cellInfo.spanY = 0;
cellInfo.valid = false;
mDirtyTag = false;
setTag(cellInfo);
}
return false;
}
@Override
public CellInfo getTag() {
final CellInfo info = (CellInfo) super.getTag();
if (mDirtyTag && info.valid) {
final boolean portrait = mPortrait;
final int xCount = portrait ? mShortAxisCells : mLongAxisCells;
final int yCount = portrait ? mLongAxisCells : mShortAxisCells;
final boolean[][] occupied = mOccupied;
findOccupiedCells(xCount, yCount, occupied);
findIntersectingVacantCells(info, info.cellX, info.cellY, xCount, yCount, occupied);
mDirtyTag = false;
}
return info;
}
private static void findIntersectingVacantCells(CellInfo cellInfo, int x, int y,
int xCount, int yCount, boolean[][] occupied) {
@@ -207,14 +231,15 @@ public class CellLayout extends ViewGroup {
cellInfo.maxVacantSpanXSpanY = Integer.MIN_VALUE;
cellInfo.maxVacantSpanY = Integer.MIN_VALUE;
cellInfo.maxVacantSpanYSpanX = Integer.MIN_VALUE;
cellInfo.vacantCells = new ArrayList<CellInfo.VacantCell>();
cellInfo.clearVacantCells();
if (occupied[x][y]) {
return;
}
Rect current = new Rect(x, y, x, y);
findVacantCell(current, xCount, yCount, occupied, cellInfo);
cellInfo.current.set(x, y, x, y);
findVacantCell(cellInfo.current, xCount, yCount, occupied, cellInfo);
}
private static void findVacantCell(Rect current, int xCount, int yCount, boolean[][] occupied,
@@ -256,7 +281,7 @@ public class CellLayout extends ViewGroup {
}
private static void addVacantCell(Rect current, CellInfo cellInfo) {
CellInfo.VacantCell cell = new CellInfo.VacantCell();
CellInfo.VacantCell cell = CellInfo.VacantCell.acquire();
cell.cellX = current.left;
cell.cellY = current.top;
cell.spanX = current.right - current.left + 1;
@@ -317,10 +342,9 @@ public class CellLayout extends ViewGroup {
cellInfo.maxVacantSpanXSpanY = Integer.MIN_VALUE;
cellInfo.maxVacantSpanY = Integer.MIN_VALUE;
cellInfo.maxVacantSpanYSpanX = Integer.MIN_VALUE;
cellInfo.vacantCells = new ArrayList<CellInfo.VacantCell>();
cellInfo.screen = mCellInfo.screen;
Rect current = new Rect();
Rect current = cellInfo.current;
for (int x = 0; x < xCount; x++) {
for (int y = 0; y < yCount; y++) {
@@ -333,16 +357,10 @@ public class CellLayout extends ViewGroup {
}
cellInfo.valid = cellInfo.vacantCells.size() > 0;
if (cellInfo.valid) {
int[] xy = new int[2];
if (cellInfo.findCellForSpan(xy, 1, 1)) {
cellInfo.cellX = xy[0];
cellInfo.cellY = xy[1];
cellInfo.spanY = 1;
cellInfo.spanX = 1;
}
}
// Assume the caller will perform their own cell searching, otherwise we
// risk causing an unnecessary rebuild after findCellForSpan()
return cellInfo;
}
@@ -634,6 +652,26 @@ public class CellLayout extends ViewGroup {
dragRect.set(x, y, x + width, y + height);
}
/**
* Computes the required horizontal and vertical cell spans to always
* fit the given rectangle.
*
* @param width Width in pixels
* @param height Height in pixels
*/
public int[] rectToCell(int width, int height) {
// Always assume we're working with the smallest span to make sure we
// reserve enough space in both orientations.
int actualWidth = mCellWidth + mWidthGap;
int actualHeight = mCellHeight + mHeightGap;
int smallerSize = Math.min(actualWidth, actualHeight);
// Always round up to next largest cell
int spanX = (width + smallerSize) / smallerSize;
int spanY = (height + smallerSize) / smallerSize;
return new int[] { spanX, spanY };
}
/**
* Find the first vacant cell, if there is one.
@@ -811,12 +849,54 @@ out: for (int i = x; i < x + spanX - 1 && x < xCount; i++) {
}
static final class CellInfo implements ContextMenu.ContextMenuInfo {
/**
* See View.AttachInfo.InvalidateInfo for futher explanations about
* the recycling mechanism. In this case, we recycle the vacant cells
* instances because up to several hundreds can be instanciated when
* the user long presses an empty cell.
*/
static final class VacantCell {
int cellX;
int cellY;
int spanX;
int spanY;
// We can create up to 523 vacant cells on a 4x4 grid, 100 seems
// like a reasonable compromise given the size of a VacantCell and
// the fact that the user is not likely to touch an empty 4x4 grid
// very often
private static final int POOL_LIMIT = 100;
private static final Object sLock = new Object();
private static int sAcquiredCount = 0;
private static VacantCell sRoot;
private VacantCell next;
static VacantCell acquire() {
synchronized (sLock) {
if (sRoot == null) {
return new VacantCell();
}
VacantCell info = sRoot;
sRoot = info.next;
sAcquiredCount--;
return info;
}
}
void release() {
synchronized (sLock) {
if (sAcquiredCount < POOL_LIMIT) {
sAcquiredCount++;
next = sRoot;
sRoot = this;
}
}
}
@Override
public String toString() {
return "VacantCell[x=" + cellX + ", y=" + cellY + ", spanX=" + spanX +
@@ -832,17 +912,27 @@ out: for (int i = x; i < x + spanX - 1 && x < xCount; i++) {
int screen;
boolean valid;
ArrayList<VacantCell> vacantCells;
final ArrayList<VacantCell> vacantCells = new ArrayList<VacantCell>(VacantCell.POOL_LIMIT);
int maxVacantSpanX;
int maxVacantSpanXSpanY;
int maxVacantSpanY;
int maxVacantSpanYSpanX;
final Rect current = new Rect();
private void clearVacantCells() {
final ArrayList<VacantCell> list = vacantCells;
final int count = list.size();
for (int i = 0; i < count; i++) list.get(i).release();
list.clear();
}
void findVacantCellsFromOccupied(boolean[] occupied, int xCount, int yCount) {
if (cellX < 0 || cellY < 0) {
maxVacantSpanX = maxVacantSpanXSpanY = Integer.MIN_VALUE;
maxVacantSpanY = maxVacantSpanYSpanX = Integer.MIN_VALUE;
vacantCells = new ArrayList<VacantCell>();
clearVacantCells();
return;
}
@@ -855,26 +945,40 @@ out: for (int i = x; i < x + spanX - 1 && x < xCount; i++) {
CellLayout.findIntersectingVacantCells(this, cellX, cellY, xCount, yCount, unflattened);
}
/**
* This method can be called only once! Calling #findVacantCellsFromOccupied will
* restore the ability to call this method.
*
* Finds the upper-left coordinate of the first rectangle in the grid that can
* hold a cell of the specified dimensions.
*
* @param cellXY The array that will contain the position of a vacant cell if such a cell
* can be found.
* @param spanX The horizontal span of the cell we want to find.
* @param spanY The vertical span of the cell we want to find.
*
* @return True if a vacant cell of the specified dimension was found, false otherwise.
*/
boolean findCellForSpan(int[] cellXY, int spanX, int spanY) {
if (vacantCells == null) {
return false;
}
final ArrayList<VacantCell> list = vacantCells;
final int count = list.size();
boolean found = false;
if (this.spanX >= spanX && this.spanY >= spanY) {
cellXY[0] = cellX;
cellXY[1] = cellY;
return true;
found = true;
}
final ArrayList<VacantCell> list = vacantCells;
final int count = list.size();
// Look for an exact match first
for (int i = 0; i < count; i++) {
VacantCell cell = list.get(i);
if (cell.spanX == spanX && cell.spanY == spanY) {
cellXY[0] = cell.cellX;
cellXY[1] = cell.cellY;
return true;
found = true;
break;
}
}
@@ -884,11 +988,14 @@ out: for (int i = x; i < x + spanX - 1 && x < xCount; i++) {
if (cell.spanX >= spanX && cell.spanY >= spanY) {
cellXY[0] = cell.cellX;
cellXY[1] = cell.cellY;
return true;
found = true;
break;
}
}
return false;
clearVacantCells();
return found;
}
@Override
+11 -1
View File
@@ -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 LauncherAppWidgetInfo) {
model.removeDesktopAppWidget((LauncherAppWidgetInfo) item);
} else {
model.removeDesktopItem(item);
}
} else {
if (source instanceof UserFolder) {
final UserFolder userFolder = (UserFolder) source;
@@ -97,6 +101,12 @@ public class DeleteZone extends ImageView implements DropTarget, DragController.
final UserFolderInfo userFolderInfo = (UserFolderInfo)item;
LauncherModel.deleteUserFolderContentsFromDatabase(mLauncher, userFolderInfo);
model.removeUserFolder(userFolderInfo);
} else if (item instanceof LauncherAppWidgetInfo) {
final LauncherAppWidgetInfo launcherAppWidgetInfo = (LauncherAppWidgetInfo) item;
final LauncherAppWidgetHost appWidgetHost = mLauncher.getAppWidgetHost();
if (appWidgetHost != null) {
appWidgetHost.deleteAppWidgetId(launcherAppWidgetInfo.appWidgetId);
}
}
LauncherModel.deleteItemFromDatabase(mLauncher, item);
}
+30 -27
View File
@@ -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);
}
@@ -320,40 +330,33 @@ public class DragLayer extends FrameLayout implements DragController {
break;
case MotionEvent.ACTION_MOVE:
if (Launcher.sOpenGlEnabled) {
mLastMotionX = x;
mLastMotionY = y;
final int scrollX = mScrollX;
final int scrollY = mScrollY;
invalidate();
} else {
final int scrollX = mScrollX;
final int scrollY = mScrollY;
final float touchX = mTouchOffsetX;
final float touchY = mTouchOffsetY;
final float touchX = mTouchOffsetX;
final float touchY = mTouchOffsetY;
final int offsetX = mBitmapOffsetX;
final int offsetY = mBitmapOffsetY;
final int offsetX = mBitmapOffsetX;
final int offsetY = mBitmapOffsetY;
int left = (int) (scrollX + mLastMotionX - touchX - offsetX);
int top = (int) (scrollY + mLastMotionY - touchY - offsetY);
int left = (int) (scrollX + mLastMotionX - touchX - offsetX);
int top = (int) (scrollY + mLastMotionY - touchY - offsetY);
final Bitmap dragBitmap = mDragBitmap;
final int width = dragBitmap.getWidth();
final int height = dragBitmap.getHeight();
final Bitmap dragBitmap = mDragBitmap;
final int width = dragBitmap.getWidth();
final int height = dragBitmap.getHeight();
final Rect rect = mRect;
rect.set(left - 1, top - 1, left + width + 1, top + height + 1);
final Rect rect = mRect;
rect.set(left - 1, top - 1, left + width + 1, top + height + 1);
mLastMotionX = x;
mLastMotionY = y;
mLastMotionX = x;
mLastMotionY = y;
left = (int) (scrollX + x - touchX - offsetX);
top = (int) (scrollY + y - touchY - offsetY);
left = (int) (scrollX + x - touchX - offsetX);
top = (int) (scrollY + y - touchY - offsetY);
rect.union(left - 1, top - 1, left + width + 1, top + height + 1);
invalidate(rect);
}
rect.union(left - 1, top - 1, left + width + 1, top + height + 1);
invalidate(rect);
final int[] coordinates = mDropCoordinates;
DropTarget dropTarget = findDropTarget((int) x, (int) y, coordinates);
+2 -4
View File
@@ -38,10 +38,8 @@ class ItemInfo {
/**
* One of {@link LauncherSettings.Favorites#ITEM_TYPE_APPLICATION},
* {@link LauncherSettings.Favorites#ITEM_TYPE_SHORTCUT},
* {@link LauncherSettings.Favorites#ITEM_TYPE_USER_FOLDER},
* {@link LauncherSettings.Favorites#ITEM_TYPE_WIDGET_CLOCK},
* {@link LauncherSettings.Favorites#ITEM_TYPE_WIDGET_SEARCH} or
* {@link LauncherSettings.Favorites#ITEM_TYPE_WIDGET_PHOTO_FRAME},
* {@link LauncherSettings.Favorites#ITEM_TYPE_USER_FOLDER}, or
* {@link LauncherSettings.Favorites#ITEM_TYPE_APPWIDGET}.
*/
int itemType;
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,39 @@
/*
* 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.
*/
package com.android.launcher;
import android.appwidget.AppWidgetHost;
import android.appwidget.AppWidgetHostView;
import android.appwidget.AppWidgetProviderInfo;
import android.content.Context;
/**
* Specific {@link AppWidgetHost} that creates our {@link LauncherAppWidgetHostView}
* which correctly captures all long-press events. This ensures that users can
* always pick up and move widgets.
*/
public class LauncherAppWidgetHost extends AppWidgetHost {
public LauncherAppWidgetHost(Context context, int hostId) {
super(context, hostId);
}
@Override
protected AppWidgetHostView onCreateView(Context context, int appWidgetId,
AppWidgetProviderInfo appWidget) {
return new LauncherAppWidgetHostView(context);
}
}
@@ -0,0 +1,101 @@
/*
* 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.
*/
package com.android.launcher;
import android.appwidget.AppWidgetHostView;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
/**
* {@inheritDoc}
*/
public class LauncherAppWidgetHostView extends AppWidgetHostView {
private boolean mHasPerformedLongPress;
private CheckForLongPress mPendingCheckForLongPress;
private LayoutInflater mInflater;
public LauncherAppWidgetHostView(Context context) {
super(context);
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
@Override
protected View getErrorView() {
return mInflater.inflate(R.layout.appwidget_error, this, false);
}
public boolean onInterceptTouchEvent(MotionEvent ev) {
// Consume any touch events for ourselves after longpress is triggered
if (mHasPerformedLongPress) {
mHasPerformedLongPress = false;
return true;
}
// Watch for longpress events at this level to make sure
// users can always pick up this widget
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN: {
postCheckForLongClick();
break;
}
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
return false;
}
class CheckForLongPress implements Runnable {
private int mOriginalWindowAttachCount;
public void run() {
if ((mParent != null) && hasWindowFocus()
&& mOriginalWindowAttachCount == getWindowAttachCount()
&& !mHasPerformedLongPress) {
if (performLongClick()) {
mHasPerformedLongPress = true;
}
}
}
public void rememberWindowAttachCount() {
mOriginalWindowAttachCount = getWindowAttachCount();
}
}
private void postCheckForLongClick() {
mHasPerformedLongPress = false;
if (mPendingCheckForLongPress == null) {
mPendingCheckForLongPress = new CheckForLongPress();
}
mPendingCheckForLongPress.rememberWindowAttachCount();
postDelayed(mPendingCheckForLongPress, ViewConfiguration.getLongPressTimeout());
}
}
@@ -0,0 +1,53 @@
/*
* 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.
*/
package com.android.launcher;
import android.appwidget.AppWidgetHostView;
import android.content.ContentValues;
/**
* Represents a widget, which just contains an identifier.
*/
class LauncherAppWidgetInfo extends ItemInfo {
/**
* Identifier for this widget when talking with {@link AppWidgetManager} for updates.
*/
int appWidgetId;
/**
* View that holds this widget after it's been created. This view isn't created
* until Launcher knows it's needed.
*/
AppWidgetHostView hostView = null;
LauncherAppWidgetInfo(int appWidgetId) {
itemType = LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET;
this.appWidgetId = appWidgetId;
}
@Override
void onAddToDatabase(ContentValues values) {
super.onAddToDatabase(values);
values.put(LauncherSettings.Favorites.APPWIDGET_ID, appWidgetId);
}
@Override
public String toString() {
return Integer.toString(appWidgetId);
}
}
+216 -140
View File
@@ -33,7 +33,6 @@ import android.util.Log;
import android.os.Process;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Comparator;
@@ -44,33 +43,41 @@ import java.net.URISyntaxException;
/**
* Maintains in-memory state of the Launcher. It is expected that there should be only one
* LauncherModel object held in a static. Also provide APIs for updating the database state
* for the Launcher
* for the Launcher.
*/
public class LauncherModel {
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 final Collator sCollator = Collator.getInstance();
private static final boolean DEBUG = false;
private static final Collator sCollator = Collator.getInstance();
private boolean mApplicationsLoaded;
private boolean mDesktopItemsLoaded;
private ArrayList<ItemInfo> mDesktopItems;
private ArrayList<LauncherAppWidgetInfo> mDesktopAppWidgets;
private HashMap<Long, FolderInfo> mFolders;
private ArrayList<ApplicationInfo> mApplications;
private ApplicationsAdapter mApplicationsAdapter;
private ApplicationsLoader mApplicationsLoader;
private DesktopItemsLoader mDesktopItemsLoader;
private Thread mLoader;
private Thread mDesktopLoader;
private Thread mApplicationsLoaderThread;
private Thread mDesktopLoaderThread;
void abortLoaders() {
private final HashMap<ComponentName, ApplicationInfo> mAppInfoCache =
new HashMap<ComponentName, ApplicationInfo>(INITIAL_ICON_CACHE_CAPACITY);
synchronized void abortLoaders() {
if (mApplicationsLoader != null && mApplicationsLoader.isRunning()) {
mApplicationsLoader.stop();
mApplicationsLoaded = false;
}
if (mDesktopItemsLoader != null && mDesktopItemsLoader.isRunning()) {
mDesktopItemsLoader.stop();
mDesktopItemsLoaded = false;
@@ -78,41 +85,72 @@ public class LauncherModel {
}
/**
* Loads the list of installed applications in mApplications.
* Drop our cache of components to their lables & icons. We do
* this from Launcher when applications are added/removed. It's a
* bit overkill, but it's a rare operation anyway.
*/
void loadApplications(boolean isLaunching, Launcher launcher, boolean localeChanged) {
synchronized void dropApplicationCache() {
mAppInfoCache.clear();
}
/**
* Loads the list of installed applications in mApplications.
*
* @return true if the applications loader must be started
* (see startApplicationsLoader()), false otherwise.
*/
synchronized boolean loadApplications(boolean isLaunching, Launcher launcher,
boolean localeChanged) {
android.util.Log.d("Home", "load applications");
if (isLaunching && mApplicationsLoaded && !localeChanged) {
mApplicationsAdapter = new ApplicationsAdapter(launcher, mApplications);
return;
android.util.Log.d("Home", " --> applications loaded, return");
return false;
}
waitForApplicationsLoader();
if (localeChanged) {
dropApplicationCache();
}
if (mApplicationsAdapter == null || isLaunching || localeChanged) {
mApplicationsAdapter = new ApplicationsAdapter(launcher,
mApplications = new ArrayList<ApplicationInfo>(DEFAULT_APPLICATIONS_NUMBER));
}
if (mApplicationsLoader != null && mApplicationsLoader.isRunning()) {
mApplicationsLoader.stop();
// Wait for the currently running thread to finish, this can take a little
// time but it should be well below the timeout limit
try {
mLoader.join(APPLICATION_NOT_RESPONDING_TIMEOUT);
} catch (InterruptedException e) {
// Empty
}
mApplications = new ArrayList<ApplicationInfo>(DEFAULT_APPLICATIONS_NUMBER);
mApplicationsAdapter = new ApplicationsAdapter(launcher, mApplications);
}
mApplicationsLoaded = false;
if (!isLaunching) {
startApplicationsLoader(launcher);
return false;
}
return true;
}
private synchronized void waitForApplicationsLoader() {
if (mApplicationsLoader != null && mApplicationsLoader.isRunning()) {
android.util.Log.d("Home", " --> wait for applications loader");
mApplicationsLoader.stop();
// Wait for the currently running thread to finish, this can take a little
// time but it should be well below the timeout limit
try {
mApplicationsLoaderThread.join(APPLICATION_NOT_RESPONDING_TIMEOUT);
} catch (InterruptedException e) {
// EMpty
}
}
}
private void startApplicationsLoader(Launcher launcher) {
private synchronized void startApplicationsLoader(Launcher launcher) {
android.util.Log.d("Home", " --> starting applications loader");
waitForApplicationsLoader();
mApplicationsLoader = new ApplicationsLoader(launcher);
mLoader = new Thread(mApplicationsLoader, "Applications Loader");
mLoader.start();
mApplicationsLoaderThread = new Thread(mApplicationsLoader, "Applications Loader");
mApplicationsLoaderThread.start();
}
private class ApplicationsLoader implements Runnable {
@@ -149,36 +187,39 @@ public class LauncherModel {
final int count = apps.size();
final ApplicationsAdapter applicationList = mApplicationsAdapter;
ChangeNotifier action = new ChangeNotifier(applicationList);
ChangeNotifier action = new ChangeNotifier(applicationList, true);
final HashMap<ComponentName, ApplicationInfo> appInfoCache = mAppInfoCache;
for (int i = 0; i < count && !mStopped; i++) {
ApplicationInfo application = new ApplicationInfo();
ResolveInfo info = apps.get(i);
application.title = info.loadLabel(manager);
if (application.title == null) {
application.title = info.activityInfo.name;
}
application.setActivity(new ComponentName(
ComponentName componentName = new ComponentName(
info.activityInfo.applicationInfo.packageName,
info.activityInfo.name),
Intent.FLAG_ACTIVITY_NEW_TASK |
Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
application.icon = info.activityInfo.loadIcon(manager);
application.container = ItemInfo.NO_ID;
action.add(application);
}
action.sort(new Comparator<ApplicationInfo>() {
public final int compare(ApplicationInfo a, ApplicationInfo b) {
return sCollator.compare(a.title.toString(), b.title.toString());
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);
}
});
if (!mStopped) {
launcher.runOnUiThread(action);
if (action.add(application)) {
launcher.runOnUiThread(action);
action = new ChangeNotifier(applicationList, false);
}
}
launcher.runOnUiThread(action);
}
if (!mStopped) {
@@ -188,51 +229,66 @@ public class LauncherModel {
}
}
private static class ChangeNotifier implements Runnable {
private static class ChangeNotifier implements Runnable, Comparator<ApplicationInfo> {
private final ApplicationsAdapter mApplicationList;
private ArrayList<ApplicationInfo> mBuffer;
private final ArrayList<ApplicationInfo> mBuffer;
ChangeNotifier(ApplicationsAdapter applicationList) {
private boolean mFirst = true;
ChangeNotifier(ApplicationsAdapter applicationList, boolean first) {
mApplicationList = applicationList;
mFirst = first;
mBuffer = new ArrayList<ApplicationInfo>(UI_NOTIFICATION_RATE);
}
public void run() {
final ArrayList<ApplicationInfo> buffer = mBuffer;
final ApplicationsAdapter applicationList = mApplicationList;
if (mFirst) {
applicationList.setNotifyOnChange(false);
applicationList.clear();
mFirst = false;
}
final ArrayList<ApplicationInfo> buffer = mBuffer;
final int count = buffer.size();
applicationList.clear();
for (int i = 0; i < count; i++) {
applicationList.setNotifyOnChange(false);
applicationList.add(buffer.get(i));
}
applicationList.notifyDataSetChanged();
buffer.clear();
applicationList.sort(this);
applicationList.notifyDataSetChanged();
}
void add(ApplicationInfo application) {
mBuffer.add(application);
boolean add(ApplicationInfo application) {
final ArrayList<ApplicationInfo> buffer = mBuffer;
buffer.add(application);
return buffer.size() >= UI_NOTIFICATION_RATE;
}
void sort(Comparator<ApplicationInfo> comparator) {
Collections.sort(mBuffer, comparator);
public final int compare(ApplicationInfo a, ApplicationInfo b) {
return sCollator.compare(a.title.toString(), b.title.toString());
}
}
boolean isDesktopLoaded() {
return mDesktopItems != null && mDesktopItemsLoaded;
return mDesktopItems != null && mDesktopAppWidgets != null && mDesktopItemsLoaded;
}
/**
* Loads all of the items on the desktop, in folders, or in the dock.
* These can be apps, shortcuts or widgets
*/
void loadUserItems(boolean isLaunching, Launcher launcher, boolean localeChanged,
boolean loadApplications) {
android.util.Log.d("Home", "loading user items");
if (isLaunching && mDesktopItems != null && mDesktopItemsLoaded) {
if (isLaunching && isDesktopLoaded()) {
android.util.Log.d("Home", " --> items loaded, return");
if (loadApplications) startApplicationsLoader(launcher);
// We have already loaded our data from the DB
launcher.onDesktopItemsLoaded();
@@ -244,16 +300,17 @@ public class LauncherModel {
// Wait for the currently running thread to finish, this can take a little
// time but it should be well below the timeout limit
try {
mDesktopLoader.join(APPLICATION_NOT_RESPONDING_TIMEOUT);
mDesktopLoaderThread.join(APPLICATION_NOT_RESPONDING_TIMEOUT);
} catch (InterruptedException e) {
// Empty
}
}
android.util.Log.d("Home", " --> starting workspace loader");
mDesktopItemsLoaded = false;
mDesktopItemsLoader = new DesktopItemsLoader(launcher, localeChanged, loadApplications);
mDesktopLoader = new Thread(mDesktopItemsLoader, "Desktop Items Loader");
mDesktopLoader.start();
mDesktopLoaderThread = new Thread(mDesktopItemsLoader, "Desktop Items Loader");
mDesktopLoaderThread.start();
}
private static void updateShortcutLabels(ContentResolver resolver, PackageManager manager) {
@@ -272,7 +329,8 @@ public class LauncherModel {
try {
while (c.moveToNext()) {
try {
if (c.getInt(itemTypeIndex) != LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
if (c.getInt(itemTypeIndex) !=
LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
continue;
}
@@ -357,9 +415,11 @@ public class LauncherModel {
}
mDesktopItems = new ArrayList<ItemInfo>();
mDesktopAppWidgets = new ArrayList<LauncherAppWidgetInfo>();
mFolders = new HashMap<Long, FolderInfo>();
final ArrayList<ItemInfo> desktopItems = mDesktopItems;
final ArrayList<LauncherAppWidgetInfo> desktopAppWidgets = mDesktopAppWidgets;
final Cursor c = contentResolver.query(
LauncherSettings.Favorites.CONTENT_URI, null, null, null, null);
@@ -374,15 +434,19 @@ public class LauncherModel {
final int iconResourceIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_RESOURCE);
final int containerIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CONTAINER);
final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE);
final int appWidgetIdIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.APPWIDGET_ID);
final int screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);
final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);
final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);
final int spanXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANX);
final int spanYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANY);
final int uriIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.URI);
final int displayModeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.DISPLAY_MODE);
ApplicationInfo info;
String intentDescription;
Widget widgetInfo = null;
Widget widgetInfo;
LauncherAppWidgetInfo appWidgetInfo;
int container;
long id;
Intent intent;
@@ -494,41 +558,44 @@ public class LauncherModel {
break;
}
break;
case LauncherSettings.Favorites.ITEM_TYPE_WIDGET_CLOCK:
case LauncherSettings.Favorites.ITEM_TYPE_WIDGET_SEARCH:
case LauncherSettings.Favorites.ITEM_TYPE_WIDGET_PHOTO_FRAME:
switch (itemType) {
case LauncherSettings.Favorites.ITEM_TYPE_WIDGET_CLOCK:
widgetInfo = Widget.makeClock();
break;
case LauncherSettings.Favorites.ITEM_TYPE_WIDGET_SEARCH:
widgetInfo = Widget.makeSearch();
break;
case LauncherSettings.Favorites.ITEM_TYPE_WIDGET_PHOTO_FRAME:
widgetInfo = Widget.makePhotoFrame();
byte[] data = c.getBlob(iconIndex);
if (data != null) {
widgetInfo.photo =
BitmapFactory.decodeByteArray(data, 0, data.length);
}
break;
widgetInfo = Widget.makeSearch();
container = c.getInt(containerIndex);
if (container != LauncherSettings.Favorites.CONTAINER_DESKTOP) {
Log.e(Launcher.LOG_TAG, "Widget found where container "
+ "!= CONTAINER_DESKTOP ignoring!");
continue;
}
if (widgetInfo != null) {
container = c.getInt(containerIndex);
if (container != LauncherSettings.Favorites.CONTAINER_DESKTOP) {
Log.e(Launcher.LOG_TAG, "Widget found where container "
+ "!= CONTAINER_DESKTOP -- ignoring!");
continue;
}
widgetInfo.id = c.getLong(idIndex);
widgetInfo.screen = c.getInt(screenIndex);
widgetInfo.container = container;
widgetInfo.cellX = c.getInt(cellXIndex);
widgetInfo.cellY = c.getInt(cellYIndex);
widgetInfo.id = c.getLong(idIndex);
widgetInfo.screen = c.getInt(screenIndex);
widgetInfo.container = container;
widgetInfo.cellX = c.getInt(cellXIndex);
widgetInfo.cellY = c.getInt(cellYIndex);
desktopItems.add(widgetInfo);
desktopItems.add(widgetInfo);
break;
case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
// Read all Launcher-specific widget details
int appWidgetId = c.getInt(appWidgetIdIndex);
appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId);
appWidgetInfo.id = c.getLong(idIndex);
appWidgetInfo.screen = c.getInt(screenIndex);
appWidgetInfo.cellX = c.getInt(cellXIndex);
appWidgetInfo.cellY = c.getInt(cellYIndex);
appWidgetInfo.spanX = c.getInt(spanXIndex);
appWidgetInfo.spanY = c.getInt(spanYIndex);
container = c.getInt(containerIndex);
if (container != LauncherSettings.Favorites.CONTAINER_DESKTOP) {
Log.e(Launcher.LOG_TAG, "Widget found where container "
+ "!= CONTAINER_DESKTOP -- ignoring!");
continue;
}
appWidgetInfo.container = c.getInt(containerIndex);
desktopAppWidgets.add(appWidgetInfo);
break;
}
} catch (Exception e) {
@@ -578,7 +645,7 @@ public class LauncherModel {
break;
default:
liveFolderInfo.icon =
launcher.getResources().getDrawable(R.drawable.ic_launcher_folder);
launcher.getResources().getDrawable(R.drawable.ic_launcher_folder);
}
}
@@ -586,7 +653,7 @@ public class LauncherModel {
* Finds the user folder defined by the specified id.
*
* @param id The id of the folder to look for.
*
*
* @return A UserFolderInfo if the folder exists or null otherwise.
*/
FolderInfo findFolderById(long id) {
@@ -635,8 +702,10 @@ public class LauncherModel {
mApplicationsAdapter = null;
unbindAppDrawables(mApplications);
unbindDrawables(mDesktopItems);
unbindAppWidgetHostViews(mDesktopAppWidgets);
unbindCachedIconDrawables();
}
/**
* Remove the callback for the cached drawables or we leak the previous
* Home screen on orientation change.
@@ -650,11 +719,12 @@ public class LauncherModel {
case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
((ApplicationInfo)item).icon.setCallback(null);
break;
}
}
}
}
/**
* Remove the callback for the cached drawables or we leak the previous
* Home screen on orientation change.
@@ -669,31 +739,54 @@ public class LauncherModel {
}
/**
* @return The current list of applications
* Remove any {@link LauncherAppWidgetHostView} references in our widgets.
*/
public ArrayList<ApplicationInfo> getApplications() {
return mApplications;
private void unbindAppWidgetHostViews(ArrayList<LauncherAppWidgetInfo> appWidgets) {
if (appWidgets != null) {
final int count = appWidgets.size();
for (int i = 0; i < count; i++) {
LauncherAppWidgetInfo launcherInfo = appWidgets.get(i);
launcherInfo.hostView = null;
}
}
}
/**
* Remove the callback for the cached drawables or we leak the previous
* Home screen on orientation change.
*/
private void unbindCachedIconDrawables() {
for (ApplicationInfo appInfo : mAppInfoCache.values()) {
appInfo.icon.setCallback(null);
}
}
/**
* @return The current list of applications
*/
public ApplicationsAdapter getApplicationsAdapter() {
ApplicationsAdapter getApplicationsAdapter() {
return mApplicationsAdapter;
}
/**
* @return The current list of desktop items
*/
public ArrayList<ItemInfo> getDesktopItems() {
ArrayList<ItemInfo> getDesktopItems() {
return mDesktopItems;
}
/**
* @return The current list of desktop items
*/
ArrayList<LauncherAppWidgetInfo> getDesktopAppWidgets() {
return mDesktopAppWidgets;
}
/**
* Add an item to the desktop
* @param info
*/
public void addDesktopItem(ItemInfo info) {
void addDesktopItem(ItemInfo info) {
// TODO: write to DB; also check that folder has been added to folders list
mDesktopItems.add(info);
}
@@ -702,11 +795,25 @@ public class LauncherModel {
* Remove an item from the desktop
* @param info
*/
public void removeDesktopItem(ItemInfo info) {
void removeDesktopItem(ItemInfo info) {
// TODO: write to DB; figure out if we should remove folder from folders list
mDesktopItems.remove(info);
}
/**
* Add a widget to the desktop
*/
void addDesktopAppWidget(LauncherAppWidgetInfo info) {
mDesktopAppWidgets.add(info);
}
/**
* Remove a widget from the desktop
*/
void removeDesktopAppWidget(LauncherAppWidgetInfo info) {
mDesktopAppWidgets.remove(info);
}
/**
* Make an ApplicationInfo object for an application
*/
@@ -886,37 +993,6 @@ public class LauncherModel {
return null;
}
static Widget getPhotoFrameInfo(Context context, int screen, int cellX, int cellY) {
final ContentResolver cr = context.getContentResolver();
Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI,
null, "screen=? and cellX=? and cellY=? and itemType=?",
new String[] { String.valueOf(screen), String.valueOf(cellX), String.valueOf(cellY),
String.valueOf(LauncherSettings.Favorites.ITEM_TYPE_WIDGET_PHOTO_FRAME) }, null);
try {
if (c.moveToFirst()) {
final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ID);
final int containerIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CONTAINER);
final int screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);
final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);
final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);
Widget widgetInfo = Widget.makePhotoFrame();
widgetInfo.id = c.getLong(idIndex);
widgetInfo.screen = c.getInt(screenIndex);
widgetInfo.container = c.getInt(containerIndex);
widgetInfo.cellX = c.getInt(cellXIndex);
widgetInfo.cellY = c.getInt(cellYIndex);
return widgetInfo;
}
} finally {
c.close();
}
return null;
}
/**
* Add an item to the database in a specified container. Sets the container, screen, cellX and
* cellY fields of the item. Also assigns an ID to the item.
@@ -972,7 +1048,7 @@ public class LauncherModel {
final ContentResolver cr = context.getContentResolver();
cr.delete(LauncherSettings.Favorites.getContentUri(info.id, false), null, null);
cr.delete(LauncherSettings.Favorites.CONTENT_URI, LauncherSettings.Favorites.CONTAINER + "=" + info.id,
null);
cr.delete(LauncherSettings.Favorites.CONTENT_URI,
LauncherSettings.Favorites.CONTAINER + "=" + info.id, null);
}
}
+204 -22
View File
@@ -16,6 +16,7 @@
package com.android.launcher;
import android.appwidget.AppWidgetHost;
import android.content.ContentProvider;
import android.content.Context;
import android.content.ContentValues;
@@ -29,6 +30,7 @@ import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder;
import android.database.Cursor;
import android.database.SQLException;
import android.util.Log;
import android.util.Xml;
import android.net.Uri;
@@ -40,18 +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 = 1;
private static final int DATABASE_VERSION = 3;
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";
@@ -168,14 +177,18 @@ public class LauncherProvider extends ContentProvider {
private static final String ATTRIBUTE_Y = "y";
private final Context mContext;
private final AppWidgetHost mAppWidgetHost;
DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
mContext = context;
mAppWidgetHost = new AppWidgetHost(context, Launcher.APPWIDGET_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," +
@@ -187,6 +200,7 @@ public class LauncherProvider extends ContentProvider {
"spanX INTEGER," +
"spanY INTEGER," +
"itemType INTEGER," +
"appWidgetId INTEGER NOT NULL DEFAULT -1," +
"isShortcut INTEGER," +
"iconType INTEGER," +
"iconPackage TEXT," +
@@ -196,6 +210,11 @@ public class LauncherProvider extends ContentProvider {
"displayMode INTEGER" +
");");
// Database was just created, so wipe any previous widgets
if (mAppWidgetHost != null) {
mAppWidgetHost.deleteHost();
}
if (!convertDatabase(db)) {
// Populate favorites table with initial favorites
loadFavorites(db, DEFAULT_FAVORITES_PATH);
@@ -203,10 +222,11 @@ 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 +
"/favorites?notify=true");
"/old_favorites?notify=true");
final ContentResolver resolver = mContext.getContentResolver();
Cursor cursor = null;
@@ -228,6 +248,12 @@ public class LauncherProvider extends ContentProvider {
resolver.delete(uri, null, null);
}
}
if (converted) {
// Convert widgets from this import into widgets
if (LOGD) Log.d(LOG_TAG, "converted and now triggering widget upgrade");
convertWidgets(db);
}
return converted;
}
@@ -261,6 +287,7 @@ public class LauncherProvider extends ContentProvider {
values.put(LauncherSettings.Favorites.ICON_RESOURCE, c.getString(iconResourceIndex));
values.put(LauncherSettings.Favorites.CONTAINER, c.getInt(containerIndex));
values.put(LauncherSettings.Favorites.ITEM_TYPE, c.getInt(itemTypeIndex));
values.put(LauncherSettings.Favorites.APPWIDGET_ID, -1);
values.put(LauncherSettings.Favorites.SCREEN, c.getInt(screenIndex));
values.put(LauncherSettings.Favorites.CELLX, c.getInt(cellXIndex));
values.put(LauncherSettings.Favorites.CELLY, c.getInt(cellYIndex));
@@ -290,14 +317,130 @@ public class LauncherProvider extends ContentProvider {
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.w(LOG_TAG, "Upgrading database from version " + oldVersion + " to " +
newVersion + ", which will destroy all old data");
if (LOGD) Log.d(LOG_TAG, "onUpgrade triggered");
int version = oldVersion;
if (version < 3) {
// upgrade 1,2 -> 3 added appWidgetId column
db.beginTransaction();
try {
// Insert new column for holding appWidgetIds
db.execSQL("ALTER TABLE favorites " +
"ADD COLUMN appWidgetId INTEGER NOT NULL DEFAULT -1;");
db.setTransactionSuccessful();
version = 3;
} catch (SQLException ex) {
// Old version remains, which means we wipe old data
Log.e(LOG_TAG, ex.getMessage(), ex);
} finally {
db.endTransaction();
}
// Convert existing widgets only if table upgrade was successful
if (version == 3) {
convertWidgets(db);
}
}
if (version != DATABASE_VERSION) {
Log.w(LOG_TAG, "Destroying all old data.");
db.execSQL("DROP TABLE IF EXISTS " + TABLE_FAVORITES);
onCreate(db);
}
}
/**
* Upgrade existing clock and photo frame widgets into their new widget
* equivalents. This method allocates appWidgetIds, and then hands off to
* LauncherAppWidgetBinder 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.AnalogAppWidgetProvider"));
bindTargets.add(new ComponentName("com.android.camera",
"com.android.camera.PhotoAppWidgetProvider"));
final String selectWhere = buildOrWhereString(Favorites.ITEM_TYPE, bindSources);
Cursor c = null;
boolean allocatedAppWidgets = 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 appWidgetId
try {
int appWidgetId = mAppWidgetHost.allocateAppWidgetId();
if (LOGD) Log.d(LOG_TAG, "allocated appWidgetId="+appWidgetId+" for favoriteId="+favoriteId);
values.clear();
values.put(LauncherSettings.Favorites.APPWIDGET_ID, appWidgetId);
// Original widgets might not have valid spans when upgrading
values.put(LauncherSettings.Favorites.SPANX, 2);
values.put(LauncherSettings.Favorites.SPANY, 2);
db.execSQL("DROP TABLE IF EXISTS " + TABLE_FAVORITES);
onCreate(db);
String updateWhere = Favorites._ID + "=" + favoriteId;
db.update(TABLE_FAVORITES, values, updateWhere, null);
allocatedAppWidgets = true;
} catch (RuntimeException ex) {
Log.e(LOG_TAG, "Problem allocating appWidgetId", ex);
}
}
db.setTransactionSuccessful();
} catch (SQLException ex) {
Log.w(LOG_TAG, "Problem while allocating appWidgetIds for existing widgets", ex);
} finally {
db.endTransaction();
if (c != null) {
c.close();
}
}
// If any appWidgetIds allocated, then launch over to binder
if (allocatedAppWidgets) {
launchAppWidgetBinder(bindSources, bindTargets);
}
}
/**
* Launch the widget 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_APPWIDGET permission.
*/
private void launchAppWidgetBinder(int[] bindSources, ArrayList<ComponentName> bindTargets) {
final Intent intent = new Intent();
intent.setComponent(new ComponentName("com.android.settings",
"com.android.settings.LauncherAppWidgetBinder"));
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.
*
@@ -370,20 +513,7 @@ public class LauncherProvider extends ContentProvider {
} catch (IOException e) {
Log.w(LOG_TAG, "Got exception parsing favorites.", e);
}
// Add a clock
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);
db.insert(TABLE_FAVORITES, null, values);
// Add a search box
values.clear();
values.put(LauncherSettings.Favorites.CONTAINER,
@@ -396,11 +526,63 @@ public class LauncherProvider extends ContentProvider {
values.put(LauncherSettings.Favorites.SPANX, 4);
values.put(LauncherSettings.Favorites.SPANY, 1);
db.insert(TABLE_FAVORITES, null, 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);
db.insert(TABLE_FAVORITES, null, values);
allocatedAppWidgets = true;
} catch (RuntimeException ex) {
Log.e(LOG_TAG, "Problem allocating appWidgetId", ex);
}
// If any appWidgetIds allocated, then launch over to binder
if (allocatedAppWidgets) {
launchAppWidgetBinder(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;
+14 -1
View File
@@ -24,7 +24,8 @@ import android.net.Uri;
*/
class LauncherSettings {
/**
* Favorites.
* Favorites. When changing these values, be sure to update
* {@link com.android.settings.LauncherAppWidgetBinder} as needed.
*/
static final class Favorites implements BaseColumns {
/**
@@ -146,6 +147,11 @@ class LauncherSettings {
*/
static final int ITEM_TYPE_LIVE_FOLDER = 3;
/**
* The favorite is a widget
*/
static final int ITEM_TYPE_APPWIDGET = 4;
/**
* The favorite is a clock
*/
@@ -161,6 +167,13 @@ class LauncherSettings {
*/
static final int ITEM_TYPE_WIDGET_PHOTO_FRAME = 1002;
/**
* The appWidgetId of the widget
*
* <P>Type: INTEGER</P>
*/
static final String APPWIDGET_ID = "appWidgetId";
/**
* Indicates whether this favorite is an application-created shortcut or not.
* If the value is 0, the favorite is not an application-created shortcut, if the
+46 -1
View File
@@ -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();
}
}
}
}
@@ -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) {
@@ -178,10 +179,13 @@ class LiveFolderAdapter extends CursorAdapter {
}
mCustomIcons.clear();
try {
getCursor().close();
} finally {
mLauncher.stopManagingCursor(getCursor());
final Cursor cursor = getCursor();
if (cursor != null) {
try {
cursor.close();
} finally {
mLauncher.stopManagingCursor(cursor);
}
}
}
-42
View File
@@ -1,42 +0,0 @@
/*
* 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.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageView;
/**
* Desktop widget that holds a user folder
*
*/
public class PhotoFrame extends ImageView implements OnClickListener {
public PhotoFrame(Context context, AttributeSet attrs) {
super(context, attrs);
setClickable(true);
setOnClickListener(this);
setWillNotCacheDrawing(true);
}
public void onClick(View v) {
((Launcher) mContext).updatePhotoFrame((Widget) getTag());
}
}
+102 -12
View File
@@ -16,8 +16,6 @@
package com.android.launcher;
import java.util.List;
import android.app.ISearchManager;
import android.app.SearchManager;
import android.content.ActivityNotFoundException;
@@ -62,10 +60,11 @@ import android.widget.AdapterView.OnItemSelectedListener;
public class Search extends LinearLayout implements OnClickListener, OnKeyListener,
OnLongClickListener, TextWatcher, OnItemClickListener, OnItemSelectedListener {
private final String TAG = "SearchGadget";
private final String TAG = "SearchWidget";
private AutoCompleteTextView mSearchText;
private ImageButton mGoButton;
private ImageButton mVoiceButton;
private OnLongClickListener mLongClickListener;
// Support for suggestions
@@ -76,7 +75,11 @@ public class Search extends LinearLayout implements OnClickListener, OnKeyListen
private String mSuggestionQuery = null;
private int mItemSelected = -1;
// For voice searching
private Intent mVoiceSearchIntent;
private Rect mTempRect = new Rect();
private boolean mRestoreFocus = false;
/**
* Used to inflate the Workspace from XML.
@@ -86,6 +89,10 @@ public class Search extends LinearLayout implements OnClickListener, OnKeyListen
*/
public Search(Context context, AttributeSet attrs) {
super(context, attrs);
mVoiceSearchIntent = new Intent(android.speech.RecognizerIntent.ACTION_WEB_SEARCH);
mVoiceSearchIntent.putExtra(android.speech.RecognizerIntent.EXTRA_LANGUAGE_MODEL,
android.speech.RecognizerIntent.LANGUAGE_MODEL_WEB_SEARCH);
}
/**
@@ -94,6 +101,14 @@ public class Search extends LinearLayout implements OnClickListener, OnKeyListen
public void onClick(View v) {
if (v == mGoButton) {
query();
} else if (v == mVoiceButton) {
try {
getContext().startActivity(mVoiceSearchIntent);
} catch (ActivityNotFoundException ex) {
// Should not happen, since we check the availability of
// voice search before showing the button. But just in case...
Log.w(TAG, "Could not find voice search activity");
}
}
}
@@ -154,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)
*/
@@ -206,7 +240,7 @@ public class Search extends LinearLayout implements OnClickListener, OnKeyListen
return true;
}
}
} else if (v == mGoButton) {
} else if (v == mGoButton || v == mVoiceButton) {
boolean handled = false;
if (!event.isSystem() &&
(keyCode != KeyEvent.KEYCODE_DPAD_UP) &&
@@ -243,7 +277,14 @@ public class Search extends LinearLayout implements OnClickListener, OnKeyListen
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
requestFocusFromTouch();
// Request focus unless the user tapped on the voice search button
final int x = (int) ev.getX();
final int y = (int) ev.getY();
final Rect frame = mTempRect;
mVoiceButton.getHitRect(frame);
if (!frame.contains(x, y)) {
requestFocusFromTouch();
}
return super.onInterceptTouchEvent(ev);
}
@@ -268,26 +309,29 @@ public class Search extends LinearLayout implements OnClickListener, OnKeyListen
mSearchText.addTextChangedListener(this);
mGoButton = (ImageButton) findViewById(R.id.search_go_btn);
mVoiceButton = (ImageButton) findViewById(R.id.search_voice_btn);
mGoButton.setOnClickListener(this);
mVoiceButton.setOnClickListener(this);
mGoButton.setOnKeyListener(this);
mVoiceButton.setOnKeyListener(this);
mSearchText.setOnLongClickListener(this);
mGoButton.setOnLongClickListener(this);
mVoiceButton.setOnLongClickListener(this);
// disable the button since we start out w/empty input
mGoButton.setEnabled(false);
mGoButton.setFocusable(false);
configureSearchableInfo();
configureSuggestions();
configureVoiceSearchButton();
}
/** The rest of the class deals with providing search suggestions */
/**
* Set up the suggestions provider mechanism
* Read the searchable info from the search manager
*/
private void configureSuggestions() {
// get SearchableInfo
private void configureSearchableInfo() {
ISearchManager sms;
SearchableInfo searchable;
sms = ISearchManager.Stub.asInterface(ServiceManager.getService(Context.SEARCH_SERVICE));
@@ -303,6 +347,36 @@ public class Search extends LinearLayout implements OnClickListener, OnKeyListen
return;
}
mSearchable = searchable;
}
/**
* If appropriate & available, configure voice search
*
* Note: Because the home screen search widget is always web search, we only check for
* getVoiceSearchLaunchWebSearch() modes. We don't support the alternate form of app-specific
* voice search.
*/
private void configureVoiceSearchButton() {
boolean voiceSearchVisible = false;
if (mSearchable.getVoiceSearchEnabled() && mSearchable.getVoiceSearchLaunchWebSearch()) {
// Enable the voice search button if there is an activity that can handle it
PackageManager pm = getContext().getPackageManager();
ResolveInfo ri = pm.resolveActivity(mVoiceSearchIntent,
PackageManager.MATCH_DEFAULT_ONLY);
voiceSearchVisible = ri != null;
}
// finally, set visible state of voice search button, as appropriate
mVoiceButton.setVisibility(voiceSearchVisible ? View.VISIBLE : View.GONE);
}
/** The rest of the class deals with providing search suggestions */
/**
* Set up the suggestions provider mechanism
*/
private void configureSuggestions() {
// get SearchableInfo
mSearchText.setOnItemClickListener(this);
mSearchText.setOnItemSelectedListener(this);
@@ -314,6 +388,18 @@ public class Search extends LinearLayout implements OnClickListener, OnKeyListen
mSearchText.setAdapter(mSuggestionsAdapter);
}
/**
* 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
*/
@@ -443,7 +529,11 @@ public class Search extends LinearLayout implements OnClickListener, OnKeyListen
" returned exception" + e.toString());
}
}
SearchAutoCompleteTextView getSearchInputField() {
return (SearchAutoCompleteTextView) mSearchText;
}
/**
* This class provides the filtering-based interface to suggestions providers.
* It is hardwired in a couple of places to support GoogleSearch - for example, it supports
@@ -0,0 +1,106 @@
/*
* 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.content.res.Configuration;
import android.os.Handler;
import android.os.Message;
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 {
private boolean mShowKeyboard;
private Handler mLoseFocusHandler = new Handler() {
public void handleMessage(Message msg) {
if (msg.what == 1 && !hasFocus()) {
// Hide the soft keyboard when the search widget loses the focus
InputMethodManager.peekInstance().hideSoftInputFromWindow(getWindowToken(), 0);
}
}
};
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;
// If we don't immediately gain focus, we want to hide the IME.
mLoseFocusHandler.sendEmptyMessage(1);
}
if (getWindowToken() != null) {
final WindowManager manager = (WindowManager)
getContext().getSystemService(Context.WINDOW_SERVICE);
manager.updateViewLayout(getRootView(), lp);
if (mShowKeyboard) {
if (getContext().getResources().getConfiguration().hardKeyboardHidden ==
Configuration.HARDKEYBOARDHIDDEN_YES) {
InputMethodManager inputManager = (InputMethodManager)
getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
inputManager.showSoftInput(this, 0);
}
mShowKeyboard = false;
}
}
}
@Override
public void onWindowFocusChanged(boolean hasWindowFocus) {
super.onWindowFocusChanged(hasWindowFocus);
// See Workspace#focusOnSearch()
setFocusableInTouchMode(false);
}
void showKeyboardOnNextFocus() {
mShowKeyboard = true;
}
}
@@ -50,7 +50,6 @@ public class WallpaperChooser extends Activity implements AdapterView.OnItemSele
R.drawable.wallpaper_path_small,
R.drawable.wallpaper_sunrise_small,
R.drawable.wallpaper_mountain_small,
R.drawable.wallpaper_ripples_small,
R.drawable.wallpaper_road_small,
R.drawable.wallpaper_jellyfish_small,
R.drawable.wallpaper_zanzibar_small,
@@ -61,14 +60,13 @@ public class WallpaperChooser extends Activity implements AdapterView.OnItemSele
};
private static final Integer[] IMAGE_IDS = {
R.drawable.wallpaper_lake,
com.android.internal.R.drawable.default_wallpaper,
R.drawable.wallpaper_sunset,
R.drawable.wallpaper_beach,
R.drawable.wallpaper_snow_leopard,
R.drawable.wallpaper_path,
R.drawable.wallpaper_sunrise,
R.drawable.wallpaper_mountain,
R.drawable.wallpaper_ripples,
R.drawable.wallpaper_road,
R.drawable.wallpaper_jellyfish,
R.drawable.wallpaper_zanzibar,
@@ -123,9 +121,6 @@ public class WallpaperChooser extends Activity implements AdapterView.OnItemSele
final String[] extras = resources.getStringArray(R.array.extra_wallpapers);
final String packageName = getApplication().getPackageName();
final ArrayList<Integer> images = mImages;
final ArrayList<Integer> thumbs = mThumbs;
for (String extra : extras) {
int res = resources.getIdentifier(extra, "drawable", packageName);
if (res != 0) {
@@ -133,8 +128,8 @@ public class WallpaperChooser extends Activity implements AdapterView.OnItemSele
"drawable", packageName);
if (thumbRes != 0) {
images.add(res);
thumbs.add(res);
mThumbs.add(thumbRes);
mImages.add(res);
}
}
}
@@ -148,7 +143,7 @@ public class WallpaperChooser extends Activity implements AdapterView.OnItemSele
public void onItemSelected(AdapterView parent, View v, int position, long id) {
final ImageView view = mImageView;
Bitmap b = BitmapFactory.decodeResource(getResources(), IMAGE_IDS[position], mOptions);
Bitmap b = BitmapFactory.decodeResource(getResources(), mImages.get(position), mOptions);
view.setImageBitmap(b);
// Help the GC
+1 -29
View File
@@ -20,32 +20,11 @@ import android.content.ContentValues;
import android.graphics.Bitmap;
/**
* Represents one instance of a Launcher widget (clock, search, photo frame).
*
* Represents one instance of a Launcher widget, such as search.
*/
class Widget extends ItemInfo {
int layoutResource;
Bitmap photo;
static Widget makeClock() {
Widget w = new Widget();
w.itemType = LauncherSettings.Favorites.ITEM_TYPE_WIDGET_CLOCK;
w.spanX = 2;
w.spanY = 2;
w.layoutResource = R.layout.widget_clock;
return w;
}
static Widget makePhotoFrame() {
Widget w = new Widget();
w.itemType = LauncherSettings.Favorites.ITEM_TYPE_WIDGET_PHOTO_FRAME;
w.spanX = 2;
w.spanY = 2;
w.layoutResource = R.layout.widget_photo_frame;
return w;
}
static Widget makeSearch() {
Widget w = new Widget();
w.itemType = LauncherSettings.Favorites.ITEM_TYPE_WIDGET_SEARCH;
@@ -54,11 +33,4 @@ class Widget extends ItemInfo {
w.layoutResource = R.layout.widget_search;
return w;
}
@Override
void onAddToDatabase(ContentValues values) {
super.onAddToDatabase(values);
writeBitmap(values, photo);
}
}
+98 -9
View File
@@ -17,12 +17,15 @@
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;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Rect;
import android.graphics.Region;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.VelocityTracker;
@@ -89,6 +92,13 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
private boolean mAllowLongPress;
private boolean mLocked;
private int mTouchSlop;
final Rect mDrawerBounds = new Rect();
final Rect mClipBounds = new Rect();
int mDrawerContentHeight;
int mDrawerContentWidth;
/**
* Used to inflate the Workspace from XML.
*
@@ -126,6 +136,8 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
mPaint = new Paint();
mPaint.setDither(false);
mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
}
/**
@@ -433,6 +445,29 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
@Override
protected void dispatchDraw(Canvas canvas) {
boolean restore = false;
// 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;
}
} else if (mLauncher.isDrawerMoving()) {
restore = true;
canvas.save(Canvas.CLIP_SAVE_FLAG);
final View view = mLauncher.getDrawerHandle();
final int top = view.getTop() + view.getHeight();
canvas.clipRect(mScrollX, top, mScrollX + mDrawerContentWidth,
top + mDrawerContentHeight, Region.Op.DIFFERENCE);
}
float x = mScrollX * mWallpaperOffset;
if (x + mWallpaperWidth < mRight - mLeft) {
x = mRight - mLeft - mWallpaperWidth;
@@ -464,6 +499,10 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
}
}
}
if (restore) {
canvas.restore();
}
}
@Override
@@ -626,8 +665,8 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
*/
final int xDiff = (int) Math.abs(x - mLastMotionX);
final int yDiff = (int) Math.abs(y - mLastMotionY);
final int touchSlop = ViewConfiguration.getTouchSlop();
final int touchSlop = mTouchSlop;
boolean xMoved = xDiff > touchSlop;
boolean yMoved = yDiff > touchSlop;
@@ -669,6 +708,7 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
// Release the drag
clearChildrenCache();
mTouchState = TOUCH_STATE_REST;
mAllowLongPress = false;
break;
}
@@ -835,11 +875,16 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
}
void addApplicationShortcut(ApplicationInfo info, CellLayout.CellInfo cellInfo) {
addApplicationShortcut(info, cellInfo, false);
}
void addApplicationShortcut(ApplicationInfo info, CellLayout.CellInfo cellInfo,
boolean insertAtFirst) {
final CellLayout layout = (CellLayout) getChildAt(cellInfo.screen);
final int[] result = new int[2];
layout.cellToPoint(cellInfo.cellX, cellInfo.cellY, result);
onDropExternal(result[0], result[1], info, layout);
onDropExternal(result[0], result[1], info, layout, insertAtFirst);
}
public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo) {
@@ -878,6 +923,11 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
}
private void onDropExternal(int x, int y, Object dragInfo, CellLayout cellLayout) {
onDropExternal(x, y, dragInfo, cellLayout, false);
}
private void onDropExternal(int x, int y, Object dragInfo, CellLayout cellLayout,
boolean insertAtFirst) {
// Drag from somewhere else
ItemInfo info = (ItemInfo) dragInfo;
@@ -901,7 +951,7 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
throw new IllegalStateException("Unknown item type: " + info.itemType);
}
cellLayout.addView(view);
cellLayout.addView(view, insertAtFirst ? 0 : -1);
view.setOnLongClickListener(mLongClickListener);
cellLayout.onDropChild(view, x, y);
CellLayout.LayoutParams lp = (CellLayout.LayoutParams) view.getLayoutParams();
@@ -979,12 +1029,12 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
/**
* Find a search widget on the given screen
*/
private View findSearchWidget(CellLayout screen) {
private Search findSearchWidget(CellLayout screen) {
final int count = screen.getChildCount();
for (int i = 0; i < count; i++) {
View v = screen.getChildAt(i);
if (v instanceof Search) {
return v;
return (Search) v;
}
}
return null;
@@ -995,9 +1045,30 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
* if there is one. Also clears the current search selection so we don't
*/
private boolean focusOnSearch(int screen) {
CellLayout currentScreen = (CellLayout)getChildAt(screen);
Search searchWidget = (Search)findSearchWidget(currentScreen);
CellLayout currentScreen = (CellLayout) getChildAt(screen);
final Search searchWidget = findSearchWidget(currentScreen);
if (searchWidget != null) {
// This is necessary when focus on search is requested from the menu
// If the workspace was not in touch mode before the menu is invoked
// and the user clicks "Search" by touching the menu item, the following
// happens:
//
// - We request focus from touch on the search widget
// - The search widget gains focus
// - The window focus comes back to Home's window
// - The touch mode change is propagated to Home's window
// - The search widget is not focusable in touch mode and ViewRoot
// clears its focus
//
// Forcing focusable in touch mode ensures the search widget will
// keep the focus no matter what happens.
//
// Note: the search input field disables focusable in touch mode
// after the window gets the focus back, see SearchAutoCompleteTextView
final SearchAutoCompleteTextView input = searchWidget.getSearchInputField();
input.setFocusableInTouchMode(true);
input.showKeyboardOnNextFocus();
if (isInTouchMode()) {
searchWidget.requestFocusFromTouch();
} else {
@@ -1124,6 +1195,14 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
public boolean allowLongPress() {
return mAllowLongPress;
}
/**
* Set true to allow long-press events to be triggered, usually checked by
* {@link Launcher} to accept or block dpad-initiated long-presses.
*/
public void setAllowLongPress(boolean allowLongPress) {
mAllowLongPress = allowLongPress;
}
void removeShortcutsForPackage(String packageName) {
final ArrayList<View> childrenToRemove = new ArrayList<View>();
@@ -1138,7 +1217,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);
@@ -1155,6 +1240,10 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
}
}
}
// TODO: remove widgets when appwidgetmanager tells us they're gone
// void removeAppWidgetsForProvider() {
// }
void moveToDefaultScreen() {
snapToScreen(mDefaultScreen);