Merge commit 'remotes/korg/cupcake' into merge
@@ -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)
|
||||
|
||||
|
||||
@@ -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"/>
|
||||
|
||||
|
After Width: | Height: | Size: 918 B |
|
Before Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 480 B |
|
Before Width: | Height: | Size: 580 B |
|
Before Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 196 B |
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 6.6 KiB |
|
Before Width: | Height: | Size: 79 KiB |
|
Before Width: | Height: | Size: 97 KiB After Width: | Height: | Size: 70 KiB |
|
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 5.3 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 667 B |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 5.7 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 695 B |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 669 B |
|
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 87 KiB After Width: | Height: | Size: 62 KiB |
|
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 578 B |
|
Before Width: | Height: | Size: 53 KiB |
|
Before Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 45 KiB |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 1.5 KiB |
@@ -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"
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
android:paddingTop="5dip"
|
||||
android:paddingBottom="2dip"
|
||||
android:drawablePadding="0dip"
|
||||
|
||||
|
||||
android:textSize="13dip"
|
||||
android:maxLines="2"
|
||||
android:ellipsize="marquee"
|
||||
|
||||
@@ -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"
|
||||
/>
|
||||
@@ -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" />
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||