diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2008-12-17 18:05:58 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2008-12-17 18:05:58 -0800 |
commit | d097a1880f2339705486d50cd8b33c6088fa9fa5 (patch) | |
tree | 711ec61755822f2bda1d4b2719691db2142ed607 | |
parent | c8f00b61c600927ab404c84686d4472e9b527976 (diff) | |
download | android_packages_apps_Trebuchet-d097a1880f2339705486d50cd8b33c6088fa9fa5.tar.gz android_packages_apps_Trebuchet-d097a1880f2339705486d50cd8b33c6088fa9fa5.tar.bz2 android_packages_apps_Trebuchet-d097a1880f2339705486d50cd8b33c6088fa9fa5.zip |
Code drop from //branches/cupcake/...@124589
47 files changed, 2522 insertions, 454 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 812985191..966848321 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -17,41 +17,59 @@ ** limitations under the License. */ --> -<manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.android.launcher" - android:sharedUserId="android.uid.shared"> +<manifest + xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.launcher" + android:sharedUserId="android.uid.shared"> - <permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" - android:permissionGroup="android.permission-group.SYSTEM_TOOLS" - android:protectionLevel="normal" - android:label="@string/permlab_install_shortcut" - android:description="@string/permdesc_install_shortcut"/> - <permission android:name="com.android.launcher.permission.UNINSTALL_SHORTCUT" - android:permissionGroup="android.permission-group.SYSTEM_TOOLS" - android:protectionLevel="normal" - android:label="@string/permlab_uninstall_shortcut" - android:description="@string/permdesc_uninstall_shortcut"/> + <permission + android:name="com.android.launcher.permission.INSTALL_SHORTCUT" + android:permissionGroup="android.permission-group.SYSTEM_TOOLS" + android:protectionLevel="normal" + android:label="@string/permlab_install_shortcut" + android:description="@string/permdesc_install_shortcut" /> + <permission + android:name="com.android.launcher.permission.UNINSTALL_SHORTCUT" + android:permissionGroup="android.permission-group.SYSTEM_TOOLS" + android:protectionLevel="normal" + android:label="@string/permlab_uninstall_shortcut" + android:description="@string/permdesc_uninstall_shortcut"/> + <permission + android:name="com.android.launcher.permission.READ_SETTINGS" + android:permissionGroup="android.permission-group.SYSTEM_TOOLS" + android:protectionLevel="normal" + android:label="@string/permlab_read_settings" + android:description="@string/permdesc_read_settings"/> + <permission + android:name="com.android.launcher.permission.WRITE_SETTINGS" + android:permissionGroup="android.permission-group.SYSTEM_TOOLS" + android:protectionLevel="normal" + android:label="@string/permlab_write_settings" + android:description="@string/permdesc_write_settings"/> - <uses-permission android:name="android.permission.CALL_PHONE"/> - <uses-permission android:name="android.permission.EXPAND_STATUS_BAR"/> - <uses-permission android:name="android.permission.GET_TASKS"/> + <uses-permission android:name="android.permission.CALL_PHONE" /> + <uses-permission android:name="android.permission.EXPAND_STATUS_BAR" /> + <uses-permission android:name="android.permission.GET_TASKS" /> <uses-permission android:name="android.permission.READ_CONTACTS"/> <uses-permission android:name="android.permission.SET_WALLPAPER" /> <uses-permission android:name="android.permission.SET_WALLPAPER_HINTS" /> - <uses-permission android:name="android.permission.VIBRATE"/> - <uses-permission android:name="android.permission.WRITE_SETTINGS"/> + <uses-permission android:name="android.permission.VIBRATE" /> + <uses-permission android:name="android.permission.WRITE_SETTINGS" /> + <uses-permission android:name="com.android.launcher.permission.READ_SETTINGS" /> + <uses-permission android:name="com.android.launcher.permission.WRITE_SETTINGS" /> <application + android:name="LauncherApplication" android:process="android.process.acore" android:label="@string/application_name" android:icon="@drawable/ic_launcher_home"> - <activity android:name="Launcher" - android:launchMode="singleTask" - android:clearTaskOnLaunch="true" - android:stateNotNeeded="true" - android:theme="@style/Theme" - android:configChanges="mcc|mnc"> + <activity + android:name="Launcher" + android:launchMode="singleTask" + android:clearTaskOnLaunch="true" + android:stateNotNeeded="true" + android:theme="@style/Theme"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.HOME"/> @@ -60,7 +78,8 @@ </intent-filter> </activity> - <activity android:name="WallpaperChooser" + <activity + android:name="WallpaperChooser" android:label="@string/pick_wallpaper" android:icon="@drawable/ic_launcher_gallery"> <intent-filter> @@ -70,21 +89,34 @@ </activity> <!-- Enable system-default search mode for any activity in Home --> - <meta-data android:name="android.app.default_searchable" android:value="*" /> + <meta-data + android:name="android.app.default_searchable" + android:value="*" /> - <receiver android:name=".InstallShortcutReceiver" - android:permission="com.android.launcher.permission.INSTALL_SHORTCUT"> + <!-- Intent received used to install shortcuts from other applications --> + <receiver + android:name=".InstallShortcutReceiver" + android:permission="com.android.launcher.permission.INSTALL_SHORTCUT"> <intent-filter> <action android:name="com.android.launcher.action.INSTALL_SHORTCUT" /> </intent-filter> </receiver> - <receiver android:name=".UninstallShortcutReceiver" - android:permission="com.android.launcher.permission.UNINSTALL_SHORTCUT"> + <!-- Intent received used to uninstall shortcuts from other applications --> + <receiver + android:name=".UninstallShortcutReceiver" + android:permission="com.android.launcher.permission.UNINSTALL_SHORTCUT"> <intent-filter> <action android:name="com.android.launcher.action.UNINSTALL_SHORTCUT" /> </intent-filter> </receiver> + <!-- The settings provider contains Home's data, like the workspace favorites --> + <provider + android:name="LauncherProvider" + android:authorities="com.android.launcher.settings" + android:writePermission="com.android.launcher.permission.WRITE_SETTINGS" + android:readPermission="com.android.launcher.permission.READ_SETTINGS" /> + </application> </manifest> diff --git a/res/drawable/google_logo.png b/res/drawable/google_logo.png Binary files differindex 738abe013..54fd5f961 100644 --- a/res/drawable/google_logo.png +++ b/res/drawable/google_logo.png diff --git a/res/layout-land/application_boxed.xml b/res/layout-land/application_boxed.xml index 3cec8d0be..63d2254b4 100644 --- a/res/layout-land/application_boxed.xml +++ b/res/layout-land/application_boxed.xml @@ -15,15 +15,17 @@ --> <TextView xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/name" android:layout_width="fill_parent" android:layout_height="88dip" - android:paddingTop="6dip" - android:paddingBottom="3dip" + android:paddingTop="5dip" + android:paddingBottom="2dip" android:drawablePadding="0dip" android:textSize="13dip" android:maxLines="2" - android:ellipsize="end" + android:ellipsize="marquee" + android:fadingEdge="horizontal" android:textColor="@color/bright_text_dark_focused" android:gravity="top|center_horizontal" /> diff --git a/res/layout-land/launcher.xml b/res/layout-land/launcher.xml index e93ef31d2..11a81fd8e 100644 --- a/res/layout-land/launcher.xml +++ b/res/layout-land/launcher.xml @@ -16,6 +16,7 @@ <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" @@ -30,9 +31,9 @@ launcher:defaultScreen="1"> - <include layout="@layout/workspace_screen" /> - <include layout="@layout/workspace_screen" /> - <include layout="@layout/workspace_screen" /> + <include android:id="@+id/cell1" layout="@layout/workspace_screen" /> + <include android:id="@+id/cell2" layout="@layout/workspace_screen" /> + <include android:id="@+id/cell3" layout="@layout/workspace_screen" /> </com.android.launcher.Workspace> @@ -42,19 +43,24 @@ android:layout_height="fill_parent" android:orientation="horizontal" - android:bottomOffset="7px" - android:handle="@+id/all_apps" - android:content="@+id/content"> - - <ImageView + androidprv:bottomOffset="7px" + androidprv:handle="@+id/all_apps" + androidprv:content="@+id/content"> + + <com.android.launcher.HandleView android:id="@id/all_apps" + android:layout_width="56dip" + android:layout_height="fill_parent" + + android:background="@drawable/handle" + android:focusable="true" android:clickable="true" + android:scaleType="center" android:src="@drawable/handle_icon" - android:background="@drawable/handle" - android:layout_height="fill_parent" - android:layout_width="56dip" /> + + launcher:direction="vertical" /> <com.android.launcher.AllAppsGridView android:id="@id/content" diff --git a/res/layout-land/live_folder_grid.xml b/res/layout-land/live_folder_grid.xml new file mode 100644 index 000000000..d1b02a4a6 --- /dev/null +++ b/res/layout-land/live_folder_grid.xml @@ -0,0 +1,49 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * 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. + */ +--> + +<com.android.launcher.LiveFolder xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical"> + + <Button + android:id="@+id/close" + android:background="@drawable/box_launcher_top" + android:gravity="left|center_vertical" + android:textSize="14sp" + android:textColor="#404040" + android:textStyle="bold" + android:layout_width="fill_parent" + android:layout_height="wrap_content" /> + + <GridView + android:id="@id/content" + android:layout_width="fill_parent" + android:layout_height="0dip" + android:layout_weight="1" + + android:background="@drawable/box_launcher_bottom" + + android:scrollbarAlwaysDrawVerticalTrack="true" + android:scrollbarStyle="insideInset" + android:drawSelectorOnTop="false" + android:listSelector="@drawable/grid_selector" + + android:verticalSpacing="10dip" + android:numColumns="5" /> + +</com.android.launcher.LiveFolder> diff --git a/res/layout-land/live_folder_icon.xml b/res/layout-land/live_folder_icon.xml new file mode 100644 index 000000000..7b6d58dad --- /dev/null +++ b/res/layout-land/live_folder_icon.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * 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. + */ +--> + +<com.android.launcher.LiveFolderIcon xmlns:android="http://schemas.android.com/apk/res/android" + style="@style/WorkspaceIcon.Landscape" /> diff --git a/res/layout-port/application_boxed.xml b/res/layout-port/application_boxed.xml index 3cec8d0be..63d2254b4 100644 --- a/res/layout-port/application_boxed.xml +++ b/res/layout-port/application_boxed.xml @@ -15,15 +15,17 @@ --> <TextView xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/name" android:layout_width="fill_parent" android:layout_height="88dip" - android:paddingTop="6dip" - android:paddingBottom="3dip" + android:paddingTop="5dip" + android:paddingBottom="2dip" android:drawablePadding="0dip" android:textSize="13dip" android:maxLines="2" - android:ellipsize="end" + android:ellipsize="marquee" + android:fadingEdge="horizontal" android:textColor="@color/bright_text_dark_focused" android:gravity="top|center_horizontal" /> diff --git a/res/layout-port/launcher.xml b/res/layout-port/launcher.xml index 41a1f5b0d..167331e86 100644 --- a/res/layout-port/launcher.xml +++ b/res/layout-port/launcher.xml @@ -16,6 +16,7 @@ <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" @@ -30,9 +31,9 @@ launcher:defaultScreen="1"> - <include layout="@layout/workspace_screen" /> - <include layout="@layout/workspace_screen" /> - <include layout="@layout/workspace_screen" /> + <include android:id="@+id/cell1" layout="@layout/workspace_screen" /> + <include android:id="@+id/cell2" layout="@layout/workspace_screen" /> + <include android:id="@+id/cell3" layout="@layout/workspace_screen" /> </com.android.launcher.Workspace> @@ -41,20 +42,25 @@ android:layout_width="fill_parent" android:layout_height="fill_parent" - android:topOffset="5px" - android:bottomOffset="7px" - android:handle="@+id/all_apps" - android:content="@+id/content"> + androidprv:topOffset="5px" + androidprv:bottomOffset="7px" + androidprv:handle="@+id/all_apps" + androidprv:content="@+id/content"> - <ImageView + <com.android.launcher.HandleView android:id="@id/all_apps" + android:layout_width="fill_parent" + android:layout_height="56dip" + + android:background="@drawable/handle" + android:focusable="true" android:clickable="true" + android:scaleType="center" android:src="@drawable/handle_icon" - android:background="@drawable/handle" - android:layout_width="fill_parent" - android:layout_height="56dip" /> + + launcher:direction="horizontal" /> <com.android.launcher.AllAppsGridView android:id="@id/content" diff --git a/res/layout-port/live_folder_grid.xml b/res/layout-port/live_folder_grid.xml new file mode 100644 index 000000000..ec32d417c --- /dev/null +++ b/res/layout-port/live_folder_grid.xml @@ -0,0 +1,49 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * 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. + */ +--> + +<com.android.launcher.LiveFolder xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical"> + + <Button + android:id="@+id/close" + android:background="@drawable/box_launcher_top" + android:gravity="left|center_vertical" + android:textSize="14sp" + android:textColor="#404040" + android:textStyle="bold" + android:layout_width="fill_parent" + android:layout_height="wrap_content" /> + + <GridView + android:id="@id/content" + android:layout_width="fill_parent" + android:layout_height="0dip" + android:layout_weight="1" + + android:background="@drawable/box_launcher_bottom" + + android:scrollbarAlwaysDrawVerticalTrack="true" + android:scrollbarStyle="insideInset" + android:drawSelectorOnTop="false" + android:listSelector="@drawable/grid_selector" + + android:verticalSpacing="10dip" + android:numColumns="4" /> + +</com.android.launcher.LiveFolder> diff --git a/res/layout-port/live_folder_icon.xml b/res/layout-port/live_folder_icon.xml new file mode 100644 index 000000000..dc711f3cf --- /dev/null +++ b/res/layout-port/live_folder_icon.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * 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. + */ +--> + +<com.android.launcher.LiveFolderIcon xmlns:android="http://schemas.android.com/apk/res/android" + style="@style/WorkspaceIcon.Portrait" /> diff --git a/res/layout/application_list.xml b/res/layout/application_list.xml new file mode 100644 index 000000000..230a95197 --- /dev/null +++ b/res/layout/application_list.xml @@ -0,0 +1,70 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * 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. + */ +--> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="fill_parent" + android:layout_height="?android:attr/listPreferredItemHeight" + + android:paddingLeft="10dip" + + android:orientation="horizontal"> + + <ImageView android:id="@+id/icon" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" + + android:scaleType="center" /> + + <LinearLayout + android:layout_width="0dip" + android:layout_weight="1.0" + android:layout_height="fill_parent" + + android:paddingLeft="8dip" + android:paddingRight="8dip" + + android:orientation="vertical" + android:gravity="center_vertical"> + + <TextView android:id="@+id/name" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + + android:singleLine="true" + android:ellipsize="end" + + android:textAppearance="?android:attr/textAppearanceLarge" /> + + <TextView android:id="@+id/description" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + + android:layout_below="@id/name" + android:layout_alignLeft="@id/name" + + android:singleLine="true" + android:ellipsize="end" + + android:textAppearance="?android:attr/textAppearanceSmall" + android:textColor="?android:attr/textColorSecondary" /> + + </LinearLayout> + +</LinearLayout>
\ No newline at end of file diff --git a/res/layout/live_folder_list.xml b/res/layout/live_folder_list.xml new file mode 100644 index 000000000..1d32f8878 --- /dev/null +++ b/res/layout/live_folder_list.xml @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * 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. + */ +--> + +<com.android.launcher.LiveFolder xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical"> + + <Button + android:id="@+id/close" + android:background="@drawable/box_launcher_top" + android:gravity="left|center_vertical" + android:textSize="14sp" + android:textColor="#404040" + android:textStyle="bold" + android:layout_width="fill_parent" + android:layout_height="wrap_content" /> + + <ListView + android:id="@id/content" + android:layout_width="fill_parent" + android:layout_height="0dip" + android:layout_weight="1" + + android:cacheColorHint="#00000000" + android:background="@drawable/box_launcher_bottom" /> + +</com.android.launcher.LiveFolder> diff --git a/res/layout/widget_search.xml b/res/layout/widget_search.xml index 67ac34582..4343e2792 100644 --- a/res/layout/widget_search.xml +++ b/res/layout/widget_search.xml @@ -34,15 +34,15 @@ android:hint="@string/search_hint" android:focusableInTouchMode="false" android:singleLine="true" - + android:selectAllOnFocus="true" android:completionThreshold="1" /> - <Button - android:id="@+id/go" - android:layout_marginLeft="4dip" + <ImageButton android:id="@+id/search_go_btn" + android:layout_marginLeft="1dip" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:text="@string/go"/> - + android:src="@android:drawable/ic_btn_search" + /> + </com.android.launcher.Search> diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml new file mode 100644 index 000000000..7d3af0791 --- /dev/null +++ b/res/values-de/strings.xml @@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="UTF-8"?> +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="application_name">"Startseite"</string> + <string name="folder_name">"Ordner"</string> + <string name="chooser_wallpaper">"Hintergrund auswählen"</string> + <string name="wallpaper_instructions">"Hintergrund festlegen"</string> + <string name="pick_wallpaper">"Galerie"</string> + <string name="activity_not_found">"Anwendung ist nicht auf dem Telefon installiert."</string> + <!-- no translation found for rename_folder_label (5646236631298452787) --> + <skip /> + <string name="rename_folder_title">"Ordner umbenennen"</string> + <string name="rename_action">"OK"</string> + <string name="cancel_action">"Abbrechen"</string> + <!-- no translation found for menu_item_add_item (6233177331075781114) --> + <skip /> + <string name="group_applications">"Anwendung"</string> + <string name="group_shortcuts">"Verknüpfung"</string> + <!-- no translation found for group_live_folders (3057578584715591220) --> + <skip /> + <string name="group_widgets">"Widget"</string> + <string name="group_wallpapers">"Hintergrund"</string> + <string name="add_folder">"Ordner"</string> + <string name="add_clock">"Uhr"</string> + <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="menu_add">"Hinzufügen"</string> + <string name="menu_wallpaper">"Hintergrund"</string> + <string name="menu_search">"Suchen"</string> + <string name="menu_notifications">"Benachrichtigungen"</string> + <string name="menu_settings">"Einstellungen"</string> + <string name="permlab_install_shortcut">"Verknüpfungen installieren"</string> + <string name="permdesc_install_shortcut">"Ermöglicht einer Anwendung das Hinzufügen von Verknüpfungen ohne Eingriff des Benutzers."</string> + <string name="permlab_uninstall_shortcut">"Verknüpfungen deinstallieren"</string> + <string name="permdesc_uninstall_shortcut">"Ermöglicht einer Anwendung das Entfernen von Verknüpfungen ohne Eingriff des Benutzers."</string> + <!-- no translation found for permlab_read_settings (3452408290738106747) --> + <skip /> + <!-- no translation found for permdesc_read_settings (8377434937176025492) --> + <skip /> + <!-- no translation found for permlab_write_settings (1360567537236705628) --> + <skip /> + <!-- no translation found for permdesc_write_settings (1098648778383349818) --> + <skip /> + <string name="search_hint">"Google-Suche"</string> +</resources> diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml new file mode 100644 index 000000000..11d24bc38 --- /dev/null +++ b/res/values-ja/strings.xml @@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="UTF-8"?> +<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> + <!-- no translation found for rename_folder_label (5646236631298452787) --> + <skip /> + <string name="rename_folder_title">"フォルダ名を変更"</string> + <string name="rename_action">"OK"</string> + <string name="cancel_action">"キャンセル"</string> + <!-- no translation found for menu_item_add_item (6233177331075781114) --> + <skip /> + <string name="group_applications">"アプリケーション"</string> + <string name="group_shortcuts">"ショートカット"</string> + <!-- no translation found for group_live_folders (3057578584715591220) --> + <skip /> + <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="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> + <!-- no translation found for permlab_read_settings (3452408290738106747) --> + <skip /> + <!-- no translation found for permdesc_read_settings (8377434937176025492) --> + <skip /> + <!-- no translation found for permlab_write_settings (1360567537236705628) --> + <skip /> + <!-- no translation found for permdesc_write_settings (1098648778383349818) --> + <skip /> + <string name="search_hint">"Google検索"</string> +</resources> diff --git a/res/values/attrs.xml b/res/values/attrs.xml index caa243849..87f5b788b 100644 --- a/res/values/attrs.xml +++ b/res/values/attrs.xml @@ -17,6 +17,16 @@ --> <resources> + <!-- Orientation of a widget. --> + <attr name="direction"> + <!-- Vertical widget. --> + <enum name="vertical" value="0" /> + <!-- Horizontal widget. --> + <enum name="horizontal" value="1" /> + </attr> + + <skip /> + <!-- Workspace specific attributes. These attributes are used to customize the workspace in XML files. --> <declare-styleable name="Workspace"> @@ -49,12 +59,14 @@ a DeleteZone view in XML files. --> <declare-styleable name="DeleteZone"> <!-- Orientation of the delete zone. --> - <attr name="direction"> - <!-- Vertical delete zone. --> - <enum name="vertical" value="0" /> - <!-- Horizontal delete zone. This is the default value. --> - <enum name="horizontal" value="1" /> - </attr> + <attr name="direction" /> + </declare-styleable> + + <!-- HandleView specific attributes. These attributes are used to customize + a HandleView view in XML files. --> + <declare-styleable name="HandleView"> + <!-- Orientation of the handle. --> + <attr name="direction" /> </declare-styleable> </resources> diff --git a/res/values/strings.xml b/res/values/strings.xml index d2a997a1e..c1d3455ae 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -19,52 +19,66 @@ <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <!-- General --> + <skip /> <!-- Application name --> <string name="application_name">Home</string> <!-- Default folder name --> <string name="folder_name">Folder</string> - <!-- Unused string --> - <string name="all_apps_folder_name">Applications</string> - <!-- Unused string --> - <string name="delete_name">Delete</string> <!-- Title of dialog that appears after user selects Wallpaper from menu --> <string name="chooser_wallpaper">Select wallpaper from</string> <!-- Button label on Wallpaper Gallery screen; user selects this button to set a specific wallpaper --> <string name="wallpaper_instructions">Set wallpaper</string> <!-- Option in "Select wallpaper from" dialog box --> <string name="pick_wallpaper">Wallpaper gallery</string> - <!--Displayed when user selects a shortcut for an app that was uninstalled --> + <!-- Displayed when user selects a shortcut for an app that was uninstalled --> <string name="activity_not_found">Application is not installed on your phone.</string> <!-- Folders --> + <skip /> <!-- Label of Folder name field in Rename folder dialog box --> - <string name="rename_folder_label">Folder name:</string> + <string name="rename_folder_label">Folder name</string> <!-- Title of dialog box --> <string name="rename_folder_title">Rename folder</string> - <!-- Buttons in Rename folder dialog box: --> + <!-- Buttons in Rename folder dialog box --> <string name="rename_action">OK</string> + <!-- Buttons in Rename folder dialog box --> <string name="cancel_action">Cancel</string> <!-- Shortcuts --> + <skip /> <!-- Title of dialog box --> - <string name="menu_item_add_item">Add to Home</string> - <!-- Options in "Add to Home" dialog box: --> + <string name="menu_item_add_item">Add to Home screen</string> + <!-- Options in "Add to Home" dialog box; Title of the group containing the list of all apps --> <string name="group_applications">Application</string> + <!-- Options in "Add to Home" dialog box; Title of the group containing the list of all shortcuts --> <string name="group_shortcuts">Shortcut</string> + <string name="group_live_folders">Live folder</string> + <!-- Options in "Add to Home" dialog box; Title of the group containing the list of all widgets --> <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> + <!-- Options in "Add to Home" dialog box; Name of the Folder widget--> <string name="add_folder">Folder</string> + <!-- Options in "Add to Home" dialog box; Name of the Clock widget--> <string name="add_clock">Clock</string> + <!-- Options in "Add to Home" dialog box; Name of the Picture frame widget--> <string name="add_photo_frame">Picture frame</string> + <!-- Options in "Add to Home" dialog box; Name of the Google Search widget--> <string name="add_search">Search</string> <!-- 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> <!-- Menus items: --> + <skip /> + <!-- Verb, menu item used to add an item on the desktop --> <string name="menu_add">Add</string> + <!-- Noun, menu item used to set the desktop's wallpaper --> <string name="menu_wallpaper">Wallpaper</string> + <!-- Verb, menu item used to initiate a Google Search --> <string name="menu_search">Search</string> + <!-- Noun, menu item used to bring down the notifications shade --> <string name="menu_notifications">Notifications</string> + <!-- Noun, menu item used to show the system settings --> <string name="menu_settings">Settings</string> <!-- Permissions: --> @@ -74,9 +88,18 @@ <string name="permlab_uninstall_shortcut">uninstall shortcuts</string> <string name="permdesc_uninstall_shortcut">Allows an application to remove shortcuts without user intervention.</string> - + <string name="permlab_read_settings">read Home settings and shortcuts</string> + <string name="permdesc_read_settings">Allows an application to read the settings and + shortcuts in Home.</string> + <string name="permlab_write_settings">write Home settings and shortcuts</string> + <string name="permdesc_write_settings">Allows an application to change the settings and + shortcuts in Home.</string> + <!-- Widgets: --> - <string name="go">Search</string> + <skip /> + <!-- This is the hint text shown in the search widget, before text is entered. + This translation SHOULD MATCH the string "search_hint" which is found in + GoogleSearch/res/values/strings.xml --> <string name="search_hint">Google Search</string> </resources> diff --git a/res/values/styles.xml b/res/values/styles.xml index a5aed0169..a3d3e22c7 100644 --- a/res/values/styles.xml +++ b/res/values/styles.xml @@ -26,7 +26,7 @@ <style name="WorkspaceIcon"> <item name="android:textSize">13dip</item> <item name="android:singleLine">true</item> - <item name="android:ellipsize">end</item> + <item name="android:ellipsize">marquee</item> <item name="android:shadowColor">#FF000000</item> <item name="android:shadowRadius">2.0</item> <item name="android:textColor">#FFF</item> diff --git a/src/com/android/launcher/AddAdapter.java b/src/com/android/launcher/AddAdapter.java index 49422c671..8eebe39d9 100644 --- a/src/com/android/launcher/AddAdapter.java +++ b/src/com/android/launcher/AddAdapter.java @@ -28,6 +28,7 @@ import android.view.ViewGroup; 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; @@ -40,9 +41,11 @@ 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_WALLPAPERS = 3; + 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; private final LayoutInflater mInflater; private Launcher mLauncher; @@ -52,7 +55,7 @@ public final class AddAdapter extends BaseExpandableListAdapter { * Abstract class representing one thing that can be added */ public abstract class AddAction implements Runnable { - private final Context mContext; + protected final Context mContext; AddAction(Context context) { mContext = context; @@ -110,8 +113,9 @@ public final class AddAdapter extends BaseExpandableListAdapter { mLabel = info.activityInfo.name; } } + if (mIcon == null) { - mIcon = info.loadIcon(pm); + mIcon = Utilities.createIconThumbnail(info.loadIcon(pm), mContext); } text.setText(mLabel); @@ -126,12 +130,32 @@ public final class AddAdapter extends BaseExpandableListAdapter { 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); } @@ -140,8 +164,8 @@ public final class AddAdapter extends BaseExpandableListAdapter { public void bindView(View view) { TextView text = (TextView) view; text.setText(R.string.add_folder); - text.setCompoundDrawablesWithIntrinsicBounds(getIcon(R.drawable.ic_launcher_folder), - null, null, null); + if (mIcon == null) mIcon = getIcon(R.drawable.ic_launcher_folder); + text.setCompoundDrawablesWithIntrinsicBounds(mIcon, null, null, null); } public void run() { @@ -175,6 +199,8 @@ public final class AddAdapter extends BaseExpandableListAdapter { * Class representing an action that will add a PhotoFrame */ public class CreatePhotoFrameAction extends AddAction { + private Drawable mIcon; + CreatePhotoFrameAction(Context context) { super(context); } @@ -183,8 +209,8 @@ public final class AddAdapter extends BaseExpandableListAdapter { public void bindView(View view) { TextView text = (TextView) view; text.setText(R.string.add_photo_frame); - Drawable icon = getIcon(R.drawable.ic_launcher_gallery); - text.setCompoundDrawablesWithIntrinsicBounds(icon, null, null, null); + if (mIcon == null) mIcon = getIcon(R.drawable.ic_launcher_gallery); + text.setCompoundDrawablesWithIntrinsicBounds(mIcon, null, null, null); } public void run() { @@ -197,6 +223,8 @@ public final class AddAdapter extends BaseExpandableListAdapter { * Class representing an action that will add a Search widget */ public class CreateSearchAction extends AddAction { + private Drawable mIcon; + CreateSearchAction(Context context) { super(context); } @@ -205,8 +233,8 @@ public final class AddAdapter extends BaseExpandableListAdapter { public void bindView(View view) { TextView text = (TextView) view; text.setText(R.string.add_search); - Drawable icon = getIcon(R.drawable.ic_search_gadget); - text.setCompoundDrawablesWithIntrinsicBounds(icon, null, null, null); + if (mIcon == null) mIcon = getIcon(R.drawable.ic_search_gadget); + text.setCompoundDrawablesWithIntrinsicBounds(mIcon, null, null, null); } public void run() { @@ -296,22 +324,27 @@ public final class AddAdapter extends BaseExpandableListAdapter { 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); mLauncher = launcher; mInflater = (LayoutInflater) launcher.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - mGroups = new Group[forFolder ? 2 : 4]; + 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)); @@ -330,6 +363,16 @@ public final class AddAdapter extends BaseExpandableListAdapter { } } + 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(); diff --git a/src/com/android/launcher/ApplicationInfo.java b/src/com/android/launcher/ApplicationInfo.java index ec1c85afc..9bc09507e 100644 --- a/src/com/android/launcher/ApplicationInfo.java +++ b/src/com/android/launcher/ApplicationInfo.java @@ -20,9 +20,7 @@ import android.content.ComponentName; import android.content.ContentValues; import android.content.Intent; import android.graphics.Bitmap; -import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; -import com.android.internal.provider.Settings; /** * Represents a launchable application. An application is made of a name (or title), @@ -63,7 +61,7 @@ class ApplicationInfo extends ItemInfo { Intent.ShortcutIconResource iconResource; ApplicationInfo() { - itemType = Settings.Favorites.ITEM_TYPE_SHORTCUT; + itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT; } public ApplicationInfo(ApplicationInfo info) { @@ -82,7 +80,7 @@ class ApplicationInfo extends ItemInfo { /** * Creates the application intent based on a component name and various launch flags. - * Sets {@link #itemType} to {@link Settings.Favorites#ITEM_TYPE_APPLICATION}. + * Sets {@link #itemType} to {@link LauncherSettings.Favorites#ITEM_TYPE_APPLICATION}. * * @param className the class name of the component representing the intent * @param launchFlags the launch flags @@ -92,7 +90,7 @@ class ApplicationInfo extends ItemInfo { intent.addCategory(Intent.CATEGORY_LAUNCHER); intent.setComponent(className); intent.setFlags(launchFlags); - itemType = Settings.Favorites.ITEM_TYPE_APPLICATION; + itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION; } @Override @@ -100,20 +98,22 @@ class ApplicationInfo extends ItemInfo { super.onAddToDatabase(values); String titleStr = title != null ? title.toString() : null; - values.put(Settings.Favorites.TITLE, titleStr); + values.put(LauncherSettings.Favorites.TITLE, titleStr); String uri = intent != null ? intent.toURI() : null; - values.put(Settings.Favorites.INTENT, uri); + values.put(LauncherSettings.Favorites.INTENT, uri); if (customIcon) { - values.put(Settings.Favorites.ICON_TYPE, Settings.Favorites.ICON_TYPE_BITMAP); - Bitmap bitmap = ((BitmapDrawable) icon).getBitmap(); + values.put(LauncherSettings.Favorites.ICON_TYPE, + LauncherSettings.Favorites.ICON_TYPE_BITMAP); + Bitmap bitmap = ((FastBitmapDrawable) icon).getBitmap(); writeBitmap(values, bitmap); } else { - values.put(Settings.Favorites.ICON_TYPE, Settings.Favorites.ICON_TYPE_RESOURCE); + values.put(LauncherSettings.Favorites.ICON_TYPE, + LauncherSettings.Favorites.ICON_TYPE_RESOURCE); if (iconResource != null) { - values.put(Settings.Favorites.ICON_PACKAGE, iconResource.packageName); - values.put(Settings.Favorites.ICON_RESOURCE, iconResource.resourceName); + values.put(LauncherSettings.Favorites.ICON_PACKAGE, iconResource.packageName); + values.put(LauncherSettings.Favorites.ICON_RESOURCE, iconResource.resourceName); } } } diff --git a/src/com/android/launcher/BubbleTextView.java b/src/com/android/launcher/BubbleTextView.java index 730e08e7d..f2c31e93f 100644 --- a/src/com/android/launcher/BubbleTextView.java +++ b/src/com/android/launcher/BubbleTextView.java @@ -22,7 +22,7 @@ import android.util.AttributeSet; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.RectF; -import android.graphics.Rect; +import android.graphics.drawable.Drawable; import android.text.Layout; /** @@ -38,6 +38,9 @@ public class BubbleTextView extends TextView { private final RectF mRect = new RectF(); private Paint mPaint; + private boolean mBackgroundSizeChanged; + private Drawable mBackground; + public BubbleTextView(Context context) { super(context); init(); @@ -55,13 +58,57 @@ public class BubbleTextView extends TextView { private void init() { setFocusable(true); + mBackground = getBackground(); + setBackgroundDrawable(null); + mBackground.setCallback(this); mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mPaint.setColor(getContext().getResources().getColor(R.color.bubble_dark_background)); } @Override - public void onDraw(Canvas canvas) { + protected boolean setFrame(int left, int top, int right, int bottom) { + if (mLeft != left || mRight != right || mTop != top || mBottom != bottom) { + mBackgroundSizeChanged = true; + } + return super.setFrame(left, top, right, bottom); + } + + @Override + protected boolean verifyDrawable(Drawable who) { + return who == mBackground || super.verifyDrawable(who); + } + + @Override + protected void drawableStateChanged() { + Drawable d = mBackground; + if (d != null && d.isStateful()) { + d.setState(getDrawableState()); + } + super.drawableStateChanged(); + } + + @Override + public void draw(Canvas canvas) { + final Drawable background = mBackground; + if (background != null) { + final int scrollX = mScrollX; + final int scrollY = mScrollY; + + if (mBackgroundSizeChanged) { + background.setBounds(0, 0, mRight - mLeft, mBottom - mTop); + mBackgroundSizeChanged = false; + } + + if ((scrollX | scrollY) == 0) { + background.draw(canvas); + } else { + canvas.translate(scrollX, scrollY); + background.draw(canvas); + canvas.translate(-scrollX, -scrollY); + } + } + final Layout layout = getLayout(); final RectF rect = mRect; final int left = getCompoundPaddingLeft(); @@ -69,10 +116,10 @@ public class BubbleTextView extends TextView { rect.set(left + layout.getLineLeft(0) - PADDING_H, top + layout.getLineTop(0) - PADDING_V, - left + layout.getLineRight(0) + PADDING_H, + 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); - super.onDraw(canvas); + super.draw(canvas); } } diff --git a/src/com/android/launcher/CellLayout.java b/src/com/android/launcher/CellLayout.java index 03cf7fcef..02646bff9 100644 --- a/src/com/android/launcher/CellLayout.java +++ b/src/com/android/launcher/CellLayout.java @@ -105,6 +105,17 @@ public class CellLayout extends ViewGroup { } @Override + public void addView(View child, int index, ViewGroup.LayoutParams params) { + // Generate an id for each view, this assumes we have at most 256x256 cells + // per workspace screen + final LayoutParams cellParams = (LayoutParams) params; + child.setId(((getId() & 0xFF) << 16) | + (cellParams.cellX & 0xFF) << 8 | (cellParams.cellY & 0xFF)); + + super.addView(child, index, params); + } + + @Override public void requestChildFocus(View child, View focused) { super.requestChildFocus(child, focused); if (child != null) { diff --git a/src/com/android/launcher/DeleteZone.java b/src/com/android/launcher/DeleteZone.java index ab2b89136..798cf0de8 100644 --- a/src/com/android/launcher/DeleteZone.java +++ b/src/com/android/launcher/DeleteZone.java @@ -20,7 +20,6 @@ import android.widget.ImageView; import android.content.Context; import android.content.res.TypedArray; import android.util.AttributeSet; -import com.android.internal.provider.Settings; import android.view.View; import android.view.animation.TranslateAnimation; import android.view.animation.Animation; @@ -35,6 +34,8 @@ public class DeleteZone extends ImageView implements DropTarget, DragController. private static final int TRANSITION_DURATION = 250; private static final int ANIMATION_DURATION = 200; + private final int[] mLocation = new int[2]; + private Launcher mLauncher; private boolean mTrashMode; @@ -74,15 +75,16 @@ public class DeleteZone extends ImageView implements DropTarget, DragController. public boolean acceptDrop(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo) { - final ItemInfo item = (ItemInfo) dragInfo; - // Accept anything except items in the all apps folder - return item.container != ItemInfo.NO_ID; + return true; } public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo) { final ItemInfo item = (ItemInfo) dragInfo; + + if (item.container == -1) return; + final LauncherModel model = Launcher.getModel(); - if (item.container == Settings.Favorites.CONTAINER_DESKTOP) { + if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) { model.removeDesktopItem(item); } else { if (source instanceof UserFolder) { @@ -115,7 +117,7 @@ public class DeleteZone extends ImageView implements DropTarget, DragController. public void onDragStart(View v, DragSource source, Object info, int dragAction) { final ItemInfo item = (ItemInfo) info; - if (item != null && item.container != ItemInfo.NO_ID) { + if (item != null) { mTrashMode = true; createAnimations(); final int[] location = mLocation; diff --git a/src/com/android/launcher/FastBitmapDrawable.java b/src/com/android/launcher/FastBitmapDrawable.java new file mode 100644 index 000000000..170f1adc3 --- /dev/null +++ b/src/com/android/launcher/FastBitmapDrawable.java @@ -0,0 +1,73 @@ +/* + * 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.graphics.drawable.Drawable; +import android.graphics.PixelFormat; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.ColorFilter; + +class FastBitmapDrawable extends Drawable { + private Bitmap mBitmap; + + FastBitmapDrawable(Bitmap b) { + mBitmap = b; + } + + @Override + public void draw(Canvas canvas) { + canvas.drawBitmap(mBitmap, 0.0f, 0.0f, null); + } + + @Override + public int getOpacity() { + return PixelFormat.TRANSLUCENT; + } + + @Override + public void setAlpha(int alpha) { + } + + @Override + public void setColorFilter(ColorFilter cf) { + } + + @Override + public int getIntrinsicWidth() { + return mBitmap.getWidth(); + } + + @Override + public int getIntrinsicHeight() { + return mBitmap.getHeight(); + } + + @Override + public int getMinimumWidth() { + return mBitmap.getWidth(); + } + + @Override + public int getMinimumHeight() { + return mBitmap.getHeight(); + } + + public Bitmap getBitmap() { + return mBitmap; + } +} diff --git a/src/com/android/launcher/Folder.java b/src/com/android/launcher/Folder.java index 1a91eb134..bcbccf71b 100644 --- a/src/com/android/launcher/Folder.java +++ b/src/com/android/launcher/Folder.java @@ -21,10 +21,10 @@ import android.util.AttributeSet; import android.view.View; import android.view.View.OnClickListener; import android.widget.AdapterView; -import android.widget.ArrayAdapter; import android.widget.Button; -import android.widget.GridView; import android.widget.LinearLayout; +import android.widget.AbsListView; +import android.widget.ListAdapter; import android.widget.AdapterView.OnItemClickListener; import android.widget.AdapterView.OnItemLongClickListener; @@ -34,7 +34,7 @@ import android.widget.AdapterView.OnItemLongClickListener; public class Folder extends LinearLayout implements DragSource, OnItemLongClickListener, OnItemClickListener, OnClickListener, View.OnLongClickListener { - protected GridView mContent; + protected AbsListView mContent; protected DragController mDragger; protected Launcher mLauncher; @@ -64,7 +64,7 @@ public class Folder extends LinearLayout implements DragSource, OnItemLongClickL protected void onFinishInflate() { super.onFinishInflate(); - mContent = (GridView) findViewById(R.id.content); + mContent = (AbsListView) findViewById(R.id.content); mContent.setOnItemClickListener(this); mContent.setOnItemLongClickListener(this); @@ -83,7 +83,9 @@ public class Folder extends LinearLayout implements DragSource, OnItemLongClickL } public boolean onLongClick(View v) { - return false; + mLauncher.closeFolder(this); + mLauncher.showRenameDialog(mInfo); + return true; } public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { @@ -120,7 +122,7 @@ public class Folder extends LinearLayout implements DragSource, OnItemLongClickL * * @param adapter The list of applications to display in the folder. */ - void setContentAdapter(ArrayAdapter<ApplicationInfo> adapter) { + void setContentAdapter(ListAdapter adapter) { mContent.setAdapter(adapter); } @@ -145,4 +147,9 @@ public class Folder extends LinearLayout implements DragSource, OnItemLongClickL final Workspace workspace = mLauncher.getWorkspace(); workspace.getChildAt(workspace.getCurrentScreen()).requestFocus(); } + + void bind(FolderInfo info) { + mInfo = info; + mCloseButton.setText(info.title); + } } diff --git a/src/com/android/launcher/FolderIcon.java b/src/com/android/launcher/FolderIcon.java index d7c623d5a..667f92ee1 100644 --- a/src/com/android/launcher/FolderIcon.java +++ b/src/com/android/launcher/FolderIcon.java @@ -19,7 +19,6 @@ package com.android.launcher; import android.content.Context; import android.content.res.Resources; import android.graphics.drawable.Drawable; -import com.android.internal.provider.Settings; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.ViewGroup; @@ -65,8 +64,8 @@ public class FolderIcon extends BubbleTextView implements DropTarget { Object dragInfo) { final ItemInfo item = (ItemInfo) dragInfo; final int itemType = item.itemType; - return (itemType == Settings.Favorites.ITEM_TYPE_APPLICATION || - itemType == Settings.Favorites.ITEM_TYPE_SHORTCUT) + return (itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION || + itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) && item.container != mInfo.id; } diff --git a/src/com/android/launcher/FolderInfo.java b/src/com/android/launcher/FolderInfo.java index b226b625a..a58675b0b 100644 --- a/src/com/android/launcher/FolderInfo.java +++ b/src/com/android/launcher/FolderInfo.java @@ -26,4 +26,9 @@ class FolderInfo extends ItemInfo { * Whether this folder has been opened */ boolean opened; + + /** + * The folder name. + */ + CharSequence title; } diff --git a/src/com/android/launcher/HandleView.java b/src/com/android/launcher/HandleView.java new file mode 100644 index 000000000..437d559b7 --- /dev/null +++ b/src/com/android/launcher/HandleView.java @@ -0,0 +1,91 @@ +/* + * 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.ImageView; +import android.content.Context; +import android.content.res.TypedArray; +import android.util.AttributeSet; +import android.view.View; +import android.view.KeyEvent; + +public class HandleView extends ImageView { + private static final int ORIENTATION_HORIZONTAL = 1; + + private Launcher mLauncher; + private int mOrientation = ORIENTATION_HORIZONTAL; + + public HandleView(Context context) { + super(context); + } + + public HandleView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public HandleView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.HandleView, defStyle, 0); + mOrientation = a.getInt(R.styleable.HandleView_direction, ORIENTATION_HORIZONTAL); + a.recycle(); + } + + @Override + public View focusSearch(int direction) { + View newFocus = super.focusSearch(direction); + if (newFocus == null) { + final Workspace workspace = mLauncher.getWorkspace(); + workspace.dispatchUnhandledMove(null, direction); + return (mOrientation == ORIENTATION_HORIZONTAL && direction == FOCUS_DOWN) ? + this : workspace; + } + return newFocus; + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + final boolean handled = super.onKeyDown(keyCode, event); + + if (!handled && !mLauncher.isDrawerDown() && !isDirectionKey(keyCode)) { + return mLauncher.getApplicationsGrid().onKeyDown(keyCode, event); + } + + return handled; + } + + @Override + public boolean onKeyUp(int keyCode, KeyEvent event) { + final boolean handled = super.onKeyUp(keyCode, event); + + if (!handled && !mLauncher.isDrawerDown() && !isDirectionKey(keyCode)) { + return mLauncher.getApplicationsGrid().onKeyUp(keyCode, event); + } + + return handled; + } + + private static boolean isDirectionKey(int keyCode) { + return keyCode == KeyEvent.KEYCODE_DPAD_DOWN || keyCode == KeyEvent.KEYCODE_DPAD_LEFT || + keyCode == KeyEvent.KEYCODE_DPAD_RIGHT || keyCode == KeyEvent.KEYCODE_DPAD_UP; + } + + void setLauncher(Launcher launcher) { + mLauncher = launcher; + } +} diff --git a/src/com/android/launcher/InstallShortcutReceiver.java b/src/com/android/launcher/InstallShortcutReceiver.java index d99e2b483..a1e954a05 100644 --- a/src/com/android/launcher/InstallShortcutReceiver.java +++ b/src/com/android/launcher/InstallShortcutReceiver.java @@ -21,7 +21,6 @@ import android.content.Context; import android.content.Intent; import android.content.ContentResolver; import android.database.Cursor; -import com.android.internal.provider.Settings; public class InstallShortcutReceiver extends BroadcastReceiver { private final int[] mCoordinates = new int[2]; @@ -29,6 +28,15 @@ public class InstallShortcutReceiver extends BroadcastReceiver { public void onReceive(Context context, Intent data) { int screen = Launcher.getScreen(); + if (!installShortcut(context, data, screen)) { + // The target screen is full, let's try the other screens + for (int i = 0; i < Launcher.SCREEN_COUNT; i++) { + if (i != screen && installShortcut(context, data, i)) break; + } + } + } + + private boolean installShortcut(Context context, Intent data, int screen) { if (findEmptyCell(context, mCoordinates, screen)) { CellLayout.CellInfo cell = new CellLayout.CellInfo(); cell.cellX = mCoordinates[0]; @@ -48,7 +56,11 @@ public class InstallShortcutReceiver extends BroadcastReceiver { if (duplicate || !LauncherModel.shortcutExists(context, name, intent)) { Launcher.addShortcut(context, data, cell, true); } + + return true; } + + return false; } private static boolean findEmptyCell(Context context, int[] xy, int screen) { @@ -58,14 +70,16 @@ public class InstallShortcutReceiver extends BroadcastReceiver { boolean[][] occupied = new boolean[xCount][yCount]; final ContentResolver cr = context.getContentResolver(); - Cursor c = cr.query(Settings.Favorites.CONTENT_URI, - new String[] { "cellX", "cellY", "spanX", "spanY" }, "screen=?", + Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI, + new String[] { LauncherSettings.Favorites.CELLX, LauncherSettings.Favorites.CELLY, + LauncherSettings.Favorites.SPANX, LauncherSettings.Favorites.SPANY }, + LauncherSettings.Favorites.SCREEN + "=?", new String[] { String.valueOf(screen) }, null); - final int cellXIndex = c.getColumnIndexOrThrow(Settings.Favorites.CELLX); - final int cellYIndex = c.getColumnIndexOrThrow(Settings.Favorites.CELLY); - final int spanXIndex = c.getColumnIndexOrThrow(Settings.Favorites.SPANX); - final int spanYIndex = c.getColumnIndexOrThrow(Settings.Favorites.SPANY); + 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); try { while (c.moveToNext()) { diff --git a/src/com/android/launcher/ItemInfo.java b/src/com/android/launcher/ItemInfo.java index f2ce23d32..61745dda0 100644 --- a/src/com/android/launcher/ItemInfo.java +++ b/src/com/android/launcher/ItemInfo.java @@ -21,10 +21,8 @@ import java.io.IOException; import android.content.ContentValues; import android.graphics.Bitmap; -import com.android.internal.provider.Settings; import android.util.Log; - /** * Represents an item in the launcher. */ @@ -38,18 +36,18 @@ class ItemInfo { long id = NO_ID; /** - * One of {@link Settings.Favorites#ITEM_TYPE_APPLICATION}, - * {@link Settings.Favorites#ITEM_TYPE_SHORTCUT}, - * {@link Settings.Favorites#ITEM_TYPE_USER_FOLDER}, - * {@link Settings.Favorites#ITEM_TYPE_WIDGET_CLOCK}, - * {@link Settings.Favorites#ITEM_TYPE_WIDGET_SEARCH} or - * {@link Settings.Favorites#ITEM_TYPE_WIDGET_PHOTO_FRAME}, + * 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}, */ int itemType; /** * The id of the container that holds this item. For the desktop, this will be - * {@link Settings.Favorites#CONTAINER_DESKTOP}. For the all applications folder it + * {@link LauncherSettings.Favorites#CONTAINER_DESKTOP}. For the all applications folder it * will be {@link #NO_ID} (since it is not stored in the settings DB). For user folders * it will be the id of the folder. */ @@ -100,13 +98,13 @@ class ItemInfo { * @param values */ void onAddToDatabase(ContentValues values) { - values.put(Settings.Favorites.ITEM_TYPE, itemType); - values.put(Settings.Favorites.CONTAINER, container); - values.put(Settings.Favorites.SCREEN, screen); - values.put(Settings.Favorites.CELLX, cellX); - values.put(Settings.Favorites.CELLY, cellY); - values.put(Settings.Favorites.SPANX, spanX); - values.put(Settings.Favorites.SPANY, spanY); + values.put(LauncherSettings.Favorites.ITEM_TYPE, itemType); + values.put(LauncherSettings.Favorites.CONTAINER, container); + values.put(LauncherSettings.Favorites.SCREEN, screen); + values.put(LauncherSettings.Favorites.CELLX, cellX); + values.put(LauncherSettings.Favorites.CELLY, cellY); + values.put(LauncherSettings.Favorites.SPANX, spanX); + values.put(LauncherSettings.Favorites.SPANY, spanY); } static void writeBitmap(ContentValues values, Bitmap bitmap) { @@ -120,7 +118,7 @@ class ItemInfo { out.flush(); out.close(); - values.put(Settings.Favorites.ICON, out.toByteArray()); + values.put(LauncherSettings.Favorites.ICON, out.toByteArray()); } catch (IOException e) { Log.w("Favorite", "Could not write icon"); } diff --git a/src/com/android/launcher/Launcher.java b/src/com/android/launcher/Launcher.java index 2ae50377c..928f4caec 100644 --- a/src/com/android/launcher/Launcher.java +++ b/src/com/android/launcher/Launcher.java @@ -29,16 +29,15 @@ import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; +import android.content.SharedPreferences; import android.content.pm.PackageManager; -import android.content.res.Configuration; import android.content.res.Resources; +import android.content.res.Configuration; import android.database.ContentObserver; import android.graphics.Bitmap; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.TransitionDrawable; -import android.hardware.SensorListener; -import android.hardware.SensorManager; import android.net.Uri; import android.os.Bundle; import android.os.Handler; @@ -46,15 +45,12 @@ import android.os.IBinder; import android.os.Parcelable; import android.os.RemoteException; import android.os.ServiceManager; -import android.os.SystemClock; -import android.os.SystemProperties; -import android.provider.Contacts; +import android.provider.*; import android.telephony.PhoneNumberUtils; import android.text.Selection; import android.text.SpannableStringBuilder; import android.text.TextUtils; import android.text.method.TextKeyListener; -import android.util.Config; import android.util.Log; import android.view.Display; import android.view.Gravity; @@ -66,14 +62,15 @@ import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; import android.view.View.OnLongClickListener; +import android.view.inputmethod.InputMethodManager; import android.widget.EditText; import android.widget.ExpandableListView; import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; +import android.widget.GridView; import android.app.IWallpaperService; -import com.android.internal.provider.Settings; import com.android.internal.widget.SlidingDrawer; import java.lang.ref.WeakReference; @@ -88,18 +85,8 @@ public final class Launcher extends Activity implements View.OnClickListener, On private static final boolean PROFILE_STARTUP = false; private static final boolean DEBUG_USER_INTERFACE = false; - private static final String USE_OPENGL_BY_DEFAULT = "false"; - private static final boolean REMOVE_SHORTCUT_ON_PACKAGE_REMOVE = false; - // Type: boolean - private static final String PROPERTY_USE_OPENGL = "launcher.opengl"; - // Type: boolean - private static final String PROPERTY_USE_SENSORS = "launcher.sensors"; - - private static final boolean USE_OPENGL = true; - private static final boolean USE_SENSORS = false; - private static final int WALLPAPER_SCREENS_SPAN = 2; private static final int MENU_GROUP_ADD = 1; @@ -112,9 +99,11 @@ public final class Launcher extends Activity implements View.OnClickListener, On private static final int REQUEST_CREATE_SHORTCUT = 1; private static final int REQUEST_CHOOSE_PHOTO = 2; private static final int REQUEST_UPDATE_PHOTO = 3; + private static final int REQUEST_CREATE_LIVE_FOLDER = 4; static final String EXTRA_SHORTCUT_DUPLICATE = "duplicate"; + static final int SCREEN_COUNT = 3; static final int DEFAULT_SCREN = 1; static final int NUMBER_CELLS_X = 4; static final int NUMBER_CELLS_Y = 4; @@ -122,6 +111,11 @@ public final class Launcher extends Activity implements View.OnClickListener, On private static final int DIALOG_CREATE_SHORTCUT = 1; static final int DIALOG_RENAME_FOLDER = 2; + private static final String PREFERENCES = "launcher"; + private static final String KEY_LOCALE = "locale"; + private static final String KEY_MCC = "mcc"; + private static final String KEY_MNC = "mnc"; + // Type: int private static final String RUNTIME_STATE_CURRENT_SCREEN = "launcher.current_screen"; // Type: boolean @@ -165,19 +159,15 @@ public final class Launcher extends Activity implements View.OnClickListener, On private final BroadcastReceiver mApplicationsReceiver = new ApplicationsIntentReceiver(); private final ContentObserver mObserver = new FavoritesChangeObserver(); - private final Handler mHandler = new Handler(); private LayoutInflater mInflater; - private SensorManager mSensorManager; - private SensorHandler mSensorHandler; - private DragLayer mDragLayer; private Workspace mWorkspace; private CellLayout.CellInfo mAddItemCellInfo; private CellLayout.CellInfo mMenuAddInfo; private final int[] mCellCoordinates = new int[2]; - private UserFolderInfo mFolderInfo; + private FolderInfo mFolderInfo; private SlidingDrawer mDrawer; private TransitionDrawable mHandleIcon; @@ -192,11 +182,10 @@ public final class Launcher extends Activity implements View.OnClickListener, On private boolean mRestoring; private boolean mWaitingForResult; + private boolean mLocaleChanged; @Override protected void onCreate(Bundle savedInstanceState) { - dalvik.system.VMRuntime.getRuntime().setMinimumHeapSize(4 * 1024 * 1024); - super.onCreate(savedInstanceState); mInflater = getLayoutInflater(); @@ -204,11 +193,9 @@ public final class Launcher extends Activity implements View.OnClickListener, On android.os.Debug.startMethodTracing("/sdcard/launcher"); } + checkForLocaleChange(); setWallpaperDimension(); - enableSensors(); - enableOpenGL(); - if (sModel == null) { sModel = new LauncherModel(); } @@ -234,6 +221,30 @@ public final class Launcher extends Activity implements View.OnClickListener, On mDefaultKeySsb = new SpannableStringBuilder(); Selection.setSelection(mDefaultKeySsb, 0); } + + private void checkForLocaleChange() { + final SharedPreferences preferences = getSharedPreferences(PREFERENCES, MODE_PRIVATE); + final Configuration configuration = getResources().getConfiguration(); + + final String previousLocale = preferences.getString(KEY_LOCALE, null); + final String locale = configuration.locale.toString(); + + final int previousMcc = preferences.getInt(KEY_MCC, -1); + final int mcc = configuration.mcc; + + final int previousMnc = preferences.getInt(KEY_MNC, -1); + final int mnc = configuration.mnc; + + mLocaleChanged = !locale.equals(previousLocale) || mcc != previousMcc || mnc != previousMnc; + + if (mLocaleChanged) { + final SharedPreferences.Editor editor = preferences.edit(); + editor.putString(KEY_LOCALE, locale); + editor.putInt(KEY_MCC, mcc); + editor.putInt(KEY_MNC, mnc); + editor.commit(); + } + } static int getScreen() { synchronized (sLock) { @@ -248,19 +259,11 @@ public final class Launcher extends Activity implements View.OnClickListener, On } private void startLoaders() { - sModel.loadApplications(true, this); - sModel.loadUserItems(true, this); + sModel.loadApplications(true, this, mLocaleChanged); + sModel.loadUserItems(!mLocaleChanged, this, mLocaleChanged); mRestoring = false; } - @Override - public void onConfigurationChanged(Configuration newConfig) { - super.onConfigurationChanged(newConfig); - - // When MMC/MNC changes, so can applications, so we reload them - sModel.loadApplications(false, Launcher.this); - } - private void setWallpaperDimension() { IBinder binder = ServiceManager.getService(WALLPAPER_SERVICE); IWallpaperService wallpaperService = IWallpaperService.Stub.asInterface(binder); @@ -277,31 +280,6 @@ public final class Launcher extends Activity implements View.OnClickListener, On } } - private void enableSensors() { - //noinspection PointlessBooleanExpression,ConstantConditions - if (USE_SENSORS || "true".equals(SystemProperties.get(PROPERTY_USE_SENSORS, "false"))) { - if (Config.LOGD) { - Log.d(LOG_TAG, "Launcher activating sensors"); - } - mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE); - mSensorHandler = new SensorHandler(); - } - } - - private void enableOpenGL() { - //noinspection PointlessBooleanExpression,ConstantConditions - if (USE_OPENGL && "true".equals(SystemProperties.get(PROPERTY_USE_OPENGL, - USE_OPENGL_BY_DEFAULT))) { - if (Config.LOGD) { - Log.d(LOG_TAG, "Launcher starting in OpenGL"); - } - //requestWindowFeature(Window.FEATURE_OPENGL); - //sOpenGlEnabled = true; - } else { - sOpenGlEnabled = false; - } - } - @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (resultCode == RESULT_OK && mAddItemCellInfo != null) { @@ -315,6 +293,9 @@ public final class Launcher extends Activity implements View.OnClickListener, On case REQUEST_UPDATE_PHOTO: completeUpdatePhotoFrame(data, mAddItemCellInfo); break; + case REQUEST_CREATE_LIVE_FOLDER: + completeAddLiveFolder(data, mAddItemCellInfo, !mDesktopLocked); + break; } } mWaitingForResult = false; @@ -327,19 +308,6 @@ public final class Launcher extends Activity implements View.OnClickListener, On if (mRestoring) { startLoaders(); } - - if (mSensorManager != null) { - mSensorManager.registerListener(mSensorHandler, SensorManager.SENSOR_ACCELEROMETER); - } - } - - @Override - protected void onStop() { - if (mSensorManager != null) { - mSensorManager.unregisterListener(mSensorHandler); - } - - super.onStop(); } @Override @@ -347,6 +315,7 @@ public final class Launcher extends Activity implements View.OnClickListener, On boolean handled = super.onKeyUp(keyCode, event); if (keyCode == KeyEvent.KEYCODE_SEARCH) { handled = mWorkspace.snapToSearch(); + if (handled) closeDrawer(true); } return handled; } @@ -455,7 +424,8 @@ public final class Launcher extends Activity implements View.OnClickListener, On final DeleteZone deleteZone = (DeleteZone) dragLayer.findViewById(R.id.delete_zone); - final ImageView handleIcon = (ImageView) drawer.findViewById(R.id.all_apps); + final HandleView handleIcon = (HandleView) drawer.findViewById(R.id.all_apps); + handleIcon.setLauncher(this); mHandleIcon = (TransitionDrawable) handleIcon.getDrawable(); mHandleIcon.setCrossFadeEnabled(true); @@ -577,7 +547,7 @@ public final class Launcher extends Activity implements View.OnClickListener, On Intent.ShortcutIconResource iconResource = null; if (bitmap != null) { - icon = new BitmapDrawable(Utilities.createBitmapThumbnail(bitmap, context)); + icon = new FastBitmapDrawable(Utilities.createBitmapThumbnail(bitmap, context)); filtered = true; customIcon = true; } else { @@ -608,7 +578,7 @@ public final class Launcher extends Activity implements View.OnClickListener, On info.customIcon = customIcon; info.iconResource = iconResource; - LauncherModel.addItemToDatabase(context, info, Settings.Favorites.CONTAINER_DESKTOP, + LauncherModel.addItemToDatabase(context, info, LauncherSettings.Favorites.CONTAINER_DESKTOP, cellInfo.screen, cellInfo.cellX, cellInfo.cellY, notify); return info; } @@ -630,7 +600,7 @@ public final class Launcher extends Activity implements View.OnClickListener, On final int[] xy = mCellCoordinates; if (!findSlot(cellInfo, xy, info.spanX, info.spanY)) return; - LauncherModel.addItemToDatabase(this, info, Settings.Favorites.CONTAINER_DESKTOP, + LauncherModel.addItemToDatabase(this, info, LauncherSettings.Favorites.CONTAINER_DESKTOP, mWorkspace.getCurrentScreen(), xy[0], xy[1], false); if (!mRestoring) { @@ -746,6 +716,12 @@ public final class Launcher extends Activity implements View.OnClickListener, On mWorkspace.moveToDefaultScreen(); } closeDrawer(); + View v = getWindow().peekDecorView(); + if (v != null && v.getWindowToken() != null) { + InputMethodManager imm = (InputMethodManager)getSystemService( + INPUT_METHOD_SERVICE); + imm.hideSoftInputFromWindow(v.getWindowToken()); + } } else { closeDrawer(false); } @@ -818,6 +794,16 @@ public final class Launcher extends Activity implements View.OnClickListener, On } @Override + public void startSearch(String initialQuery, boolean selectInitialQuery, + Bundle appSearchData, boolean globalSearch) { + if (appSearchData == null) { + appSearchData = new Bundle(); + appSearchData.putString(SearchManager.SOURCE, "launcher-search"); + } + super.startSearch(initialQuery, selectInitialQuery, appSearchData, globalSearch); + } + + @Override public boolean onCreateOptionsMenu(Menu menu) { if (mDesktopLocked) return false; @@ -893,6 +879,10 @@ public final class Launcher extends Activity implements View.OnClickListener, On startActivityForResult(intent, REQUEST_CREATE_SHORTCUT); } + void addLiveFolder(Intent intent) { + startActivityForResult(intent, REQUEST_CREATE_LIVE_FOLDER); + } + void addFolder() { UserFolderInfo folderInfo = new UserFolderInfo(); folderInfo.title = getText(R.string.folder_name); @@ -900,10 +890,10 @@ public final class Launcher extends Activity implements View.OnClickListener, On int cellY = mAddItemCellInfo.cellY; // Update the model - LauncherModel.addItemToDatabase(this, folderInfo, Settings.Favorites.CONTAINER_DESKTOP, + LauncherModel.addItemToDatabase(this, folderInfo, LauncherSettings.Favorites.CONTAINER_DESKTOP, mWorkspace.getCurrentScreen(), cellX, cellY, false); sModel.addDesktopItem(folderInfo); - sModel.addUserFolder(folderInfo); + sModel.addFolder(folderInfo); // Create the view FolderIcon newFolder = FolderIcon.fromXml(R.layout.folder_icon, this, @@ -911,6 +901,68 @@ public final class Launcher extends Activity implements View.OnClickListener, On mWorkspace.addInCurrentScreen(newFolder, cellX, cellY, 1, 1); } + private void completeAddLiveFolder(Intent data, CellLayout.CellInfo cellInfo, + boolean insertAtFirst) { + + cellInfo.screen = mWorkspace.getCurrentScreen(); + final LiveFolderInfo info = addLiveFolder(this, data, cellInfo, false); + + if (!mRestoring) { + sModel.addDesktopItem(info); + + final View view = LiveFolderIcon.fromXml(R.layout.live_folder_icon, this, + (ViewGroup) mWorkspace.getChildAt(mWorkspace.getCurrentScreen()), info); + mWorkspace.addInCurrentScreen(view, cellInfo.cellX, cellInfo.cellY, 1, 1, insertAtFirst); + } else if (sModel.isDesktopLoaded()) { + sModel.addDesktopItem(info); + } + } + + static LiveFolderInfo addLiveFolder(Context context, Intent data, + CellLayout.CellInfo cellInfo, boolean notify) { + + Intent baseIntent = data.getParcelableExtra(LiveFolders.EXTRA_LIVE_FOLDER_BASE_INTENT); + String name = data.getStringExtra(LiveFolders.EXTRA_LIVE_FOLDER_NAME); + + Drawable icon = null; + boolean filtered = false; + Intent.ShortcutIconResource iconResource = null; + + Parcelable extra = data.getParcelableExtra(LiveFolders.EXTRA_LIVE_FOLDER_ICON); + if (extra != null && extra instanceof Intent.ShortcutIconResource) { + try { + iconResource = (Intent.ShortcutIconResource) extra; + final PackageManager packageManager = context.getPackageManager(); + Resources resources = packageManager.getResourcesForApplication( + iconResource.packageName); + final int id = resources.getIdentifier(iconResource.resourceName, null, null); + icon = resources.getDrawable(id); + } catch (Exception e) { + Log.w(LOG_TAG, "Could not load live folder icon: " + extra); + } + } + + if (icon == null) { + icon = context.getResources().getDrawable(R.drawable.ic_launcher_folder); + } + + final LiveFolderInfo info = new LiveFolderInfo(); + info.icon = icon; + info.filtered = filtered; + info.title = name; + info.iconResource = iconResource; + info.uri = data.getData(); + info.baseIntent = baseIntent; + info.displayMode = data.getIntExtra(LiveFolders.EXTRA_LIVE_FOLDER_DISPLAY_MODE, + LiveFolders.DISPLAY_MODE_GRID); + + LauncherModel.addItemToDatabase(context, info, LauncherSettings.Favorites.CONTAINER_DESKTOP, + cellInfo.screen, cellInfo.cellX, cellInfo.cellY, notify); + sModel.addFolder(info); + + return info; + } + void getPhotoForPhotoFrame() { startActivityForResult(createPhotoPickIntent(), REQUEST_CHOOSE_PHOTO); } @@ -935,7 +987,7 @@ public final class Launcher extends Activity implements View.OnClickListener, On if (!findSlot(cellInfo, xy, spanX, spanY)) return; sModel.addDesktopItem(info); - LauncherModel.addItemToDatabase(this, info, Settings.Favorites.CONTAINER_DESKTOP, + LauncherModel.addItemToDatabase(this, info, LauncherSettings.Favorites.CONTAINER_DESKTOP, mWorkspace.getCurrentScreen(), xy[0], xy[1], false); final View view = mInflater.inflate(info.layoutResource, null); @@ -999,7 +1051,7 @@ public final class Launcher extends Activity implements View.OnClickListener, On */ private void registerContentObservers() { ContentResolver resolver = getContentResolver(); - resolver.registerContentObserver(Settings.Favorites.CONTENT_URI, true, mObserver); + resolver.registerContentObserver(LauncherSettings.Favorites.CONTENT_URI, true, mObserver); } @Override @@ -1059,7 +1111,7 @@ public final class Launcher extends Activity implements View.OnClickListener, On private void onFavoritesChanged() { mDesktopLocked = true; mDrawer.lock(); - sModel.loadUserItems(false, this); + sModel.loadUserItems(false, this, false); } void onDesktopItemsLoaded() { @@ -1074,9 +1126,9 @@ public final class Launcher extends Activity implements View.OnClickListener, On final long[] userFolders = mSavedState.getLongArray(RUNTIME_STATE_USER_FOLDERS); if (userFolders != null) { for (long folderId : userFolders) { - final UserFolderInfo info = sModel.findFolderById(folderId); + final FolderInfo info = sModel.findFolderById(folderId); if (info != null) { - openUserFolder(info); + openFolder(info); } } final Folder openFolder = mWorkspace.getOpenFolder(); @@ -1119,19 +1171,27 @@ public final class Launcher extends Activity implements View.OnClickListener, On for (int i = 0; i < count; i++) { final ItemInfo item = shortcuts.get(i); switch (item.itemType) { - case Settings.Favorites.ITEM_TYPE_APPLICATION: - case Settings.Favorites.ITEM_TYPE_SHORTCUT: + case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION: + case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT: final View shortcut = createShortcut((ApplicationInfo) item); workspace.addInScreen(shortcut, item.screen, item.cellX, item.cellY, 1, 1, !mDesktopLocked); break; - case Settings.Favorites.ITEM_TYPE_USER_FOLDER: + case LauncherSettings.Favorites.ITEM_TYPE_USER_FOLDER: final FolderIcon newFolder = FolderIcon.fromXml(R.layout.folder_icon, this, (ViewGroup) mWorkspace.getChildAt(mWorkspace.getCurrentScreen()), ((UserFolderInfo) item)); workspace.addInScreen(newFolder, item.screen, item.cellX, item.cellY, 1, 1, !mDesktopLocked); break; + case LauncherSettings.Favorites.ITEM_TYPE_LIVE_FOLDER: + final FolderIcon newLiveFolder = LiveFolderIcon.fromXml( + R.layout.live_folder_icon, this, + (ViewGroup) mWorkspace.getChildAt(mWorkspace.getCurrentScreen()), + ((LiveFolderInfo) item)); + workspace.addInScreen(newLiveFolder, item.screen, item.cellX, item.cellY, 1, 1, + !mDesktopLocked); + break; default: final Widget widget = (Widget)item; final View view = createWidget(mInflater, widget); @@ -1148,7 +1208,7 @@ public final class Launcher extends Activity implements View.OnClickListener, On final int screen = workspace.getCurrentScreen(); View v = inflater.inflate(widget.layoutResource, (ViewGroup) workspace.getChildAt(screen), false); - if (widget.itemType == Settings.Favorites.ITEM_TYPE_WIDGET_PHOTO_FRAME) { + if (widget.itemType == LauncherSettings.Favorites.ITEM_TYPE_WIDGET_PHOTO_FRAME) { ((ImageView)v).setImageBitmap(widget.photo); } return v; @@ -1169,8 +1229,8 @@ public final class Launcher extends Activity implements View.OnClickListener, On // Open shortcut final Intent intent = ((ApplicationInfo) tag).intent; startActivitySafely(intent); - } else if (tag instanceof UserFolderInfo) { - handleFolderClick((UserFolderInfo) tag); + } else if (tag instanceof FolderInfo) { + handleFolderClick((FolderInfo) tag); } } @@ -1188,7 +1248,7 @@ public final class Launcher extends Activity implements View.OnClickListener, On // Close any open folder closeFolder(); // Open the requested folder - openUserFolder(folderInfo); + openFolder(folderInfo); } else { // Find the open folder... Folder openFolder = mWorkspace.getFolderForTag(folderInfo); @@ -1201,7 +1261,7 @@ public final class Launcher extends Activity implements View.OnClickListener, On // Close any folder open on the current screen closeFolder(); // Pull the folder onto this screen - openUserFolder(folderInfo); + openFolder(folderInfo); } } } @@ -1226,14 +1286,22 @@ public final class Launcher extends Activity implements View.OnClickListener, On * is animated relative to the specified View. If the View is null, no animation * is played. * - * @param tag The UserFolderInfo describing the folder to open. + * @param folderInfo The FolderInfo describing the folder to open. */ - private void openUserFolder(Object tag) { - UserFolder openFolder = UserFolder.fromXml(this); + private void openFolder(FolderInfo folderInfo) { + Folder openFolder; + + if (folderInfo instanceof UserFolderInfo) { + openFolder = UserFolder.fromXml(this); + } else if (folderInfo instanceof LiveFolderInfo) { + openFolder = com.android.launcher.LiveFolder.fromXml(this, folderInfo); + } else { + return; + } + openFolder.setDragger(mDragLayer); openFolder.setLauncher(this); - UserFolderInfo folderInfo = (UserFolderInfo) tag; openFolder.bind(folderInfo); folderInfo.opened = true; @@ -1299,6 +1367,10 @@ public final class Launcher extends Activity implements View.OnClickListener, On return mWorkspace; } + GridView getApplicationsGrid() { + return mAllAppsGrid; + } + @Override protected Dialog onCreateDialog(int id) { switch (id) { @@ -1327,7 +1399,7 @@ public final class Launcher extends Activity implements View.OnClickListener, On } } - void showRenameDialog(UserFolderInfo info) { + void showRenameDialog(FolderInfo info) { mFolderInfo = info; mWaitingForResult = true; showDialog(DIALOG_RENAME_FOLDER); @@ -1384,16 +1456,17 @@ public final class Launcher extends Activity implements View.OnClickListener, On if (mDesktopLocked) { mDrawer.lock(); - sModel.loadUserItems(false, Launcher.this); + sModel.loadUserItems(false, Launcher.this, false); } else { - final FolderIcon folderIcon = (FolderIcon) mWorkspace.getViewForTag(mFolderInfo); + final FolderIcon folderIcon = (FolderIcon) + mWorkspace.getViewForTag(mFolderInfo); if (folderIcon != null) { folderIcon.setText(name); getWorkspace().requestLayout(); } else { mDesktopLocked = true; mDrawer.lock(); - sModel.loadUserItems(false, Launcher.this); + sModel.loadUserItems(false, Launcher.this, false); } } } @@ -1479,7 +1552,7 @@ public final class Launcher extends Activity implements View.OnClickListener, On removeShortcutsForPackage(intent.getData().getSchemeSpecificPart()); } removeDialog(DIALOG_CREATE_SHORTCUT); - sModel.loadApplications(false, Launcher.this); + sModel.loadApplications(false, Launcher.this, false); } } @@ -1488,7 +1561,7 @@ public final class Launcher extends Activity implements View.OnClickListener, On */ private class FavoritesChangeObserver extends ContentObserver { public FavoritesChangeObserver() { - super(mHandler); + super(new Handler()); } @Override @@ -1497,34 +1570,6 @@ public final class Launcher extends Activity implements View.OnClickListener, On } } - private class SensorHandler implements SensorListener { - private long mLastNegativeShake; - private long mLastPositiveShake; - - public void onSensorChanged(int sensor, float[] values) { - if (sensor == SensorManager.SENSOR_ACCELEROMETER) { - float shake = values[0]; - if (shake <= -SensorManager.STANDARD_GRAVITY) { - mLastNegativeShake = SystemClock.uptimeMillis(); - } else if (shake >= SensorManager.STANDARD_GRAVITY) { - mLastPositiveShake = SystemClock.uptimeMillis(); - } - - final long difference = mLastPositiveShake - mLastNegativeShake; - if (difference <= -80 && difference >= -180) { - mWorkspace.scrollLeft(); - mLastNegativeShake = mLastPositiveShake = 0; - } else if (difference >= 80 && difference <= 180) { - mWorkspace.scrollRight(); - mLastNegativeShake = mLastPositiveShake = 0; - } - } - } - - public void onAccuracyChanged(int sensor, int accuracy) { - } - } - /** * Receives intents from other applications to change the wallpaper. */ diff --git a/src/com/android/launcher/LauncherApplication.java b/src/com/android/launcher/LauncherApplication.java new file mode 100644 index 000000000..d71fa19a1 --- /dev/null +++ b/src/com/android/launcher/LauncherApplication.java @@ -0,0 +1,29 @@ +/* + * 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.app.Application; +import dalvik.system.VMRuntime; + +public class LauncherApplication extends Application { + @Override + public void onCreate() { + VMRuntime.getRuntime().setMinimumHeapSize(4 * 1024 * 1024); + + super.onCreate(); + } +} diff --git a/src/com/android/launcher/LauncherModel.java b/src/com/android/launcher/LauncherModel.java index 8375bbe55..0ef2a806b 100644 --- a/src/com/android/launcher/LauncherModel.java +++ b/src/com/android/launcher/LauncherModel.java @@ -30,7 +30,6 @@ import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.drawable.BitmapDrawable; import android.net.Uri; -import com.android.internal.provider.Settings; import android.util.Log; import java.util.ArrayList; @@ -40,6 +39,7 @@ import java.util.List; import java.util.Comparator; import java.lang.ref.WeakReference; import java.text.Collator; +import java.net.URISyntaxException; /** * Maintains in-memory state of the Launcher. It is expected that there should be only one @@ -58,7 +58,7 @@ public class LauncherModel { private boolean mDesktopItemsLoaded; private ArrayList<ItemInfo> mDesktopItems; - private HashMap<Long, UserFolderInfo> mUserFolders; + private HashMap<Long, FolderInfo> mFolders; private ArrayList<ApplicationInfo> mApplications; private ApplicationsAdapter mApplicationsAdapter; @@ -81,13 +81,13 @@ public class LauncherModel { /** * Loads the list of installed applications in mApplications. */ - void loadApplications(boolean isLaunching, Launcher launcher) { - if (isLaunching && mApplicationsLoaded) { + void loadApplications(boolean isLaunching, Launcher launcher, boolean localeChanged) { + if (isLaunching && mApplicationsLoaded && !localeChanged) { mApplicationsAdapter = new ApplicationsAdapter(launcher, mApplications); return; } - if (mApplicationsAdapter == null || isLaunching) { + if (mApplicationsAdapter == null || isLaunching || localeChanged) { mApplicationsAdapter = new ApplicationsAdapter(launcher, mApplications = new ArrayList<ApplicationInfo>(DEFAULT_APPLICATIONS_NUMBER)); } @@ -164,7 +164,7 @@ public class LauncherModel { action.sort(new Comparator<ApplicationInfo>() { public final int compare(ApplicationInfo a, ApplicationInfo b) { - return sCollator.compare(a.title, b.title); + return sCollator.compare(a.title.toString(), b.title.toString()); } }); @@ -221,7 +221,7 @@ public class LauncherModel { * 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) { + void loadUserItems(boolean isLaunching, Launcher launcher, boolean localeChanged) { if (isLaunching && mDesktopItems != null && mDesktopItemsLoaded) { // We have already loaded our data from the DB launcher.onDesktopItemsLoaded(); @@ -240,19 +240,88 @@ public class LauncherModel { } mDesktopItemsLoaded = false; - mDesktopItemsLoader = new DesktopItemsLoader(launcher); + mDesktopItemsLoader = new DesktopItemsLoader(launcher, localeChanged); mDesktopLoader = new Thread(mDesktopItemsLoader, "Desktop Items Loader"); mDesktopLoader.start(); } + private static void updateShortcutLabels(ContentResolver resolver, PackageManager manager) { + final Cursor c = resolver.query(LauncherSettings.Favorites.CONTENT_URI, + new String[] { LauncherSettings.Favorites.ID, LauncherSettings.Favorites.TITLE, + LauncherSettings.Favorites.INTENT, LauncherSettings.Favorites.ITEM_TYPE }, + null, null, null); + + final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ID); + final int intentIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.INTENT); + final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE); + final int titleIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE); + + // boolean changed = false; + + try { + while (c.moveToNext()) { + try { + if (c.getInt(itemTypeIndex) != LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) { + continue; + } + + final String intentUri = c.getString(intentIndex); + if (intentUri != null) { + final Intent shortcut = Intent.getIntent(intentUri); + if (Intent.ACTION_MAIN.equals(shortcut.getAction())) { + final ComponentName name = shortcut.getComponent(); + if (name != null) { + final ActivityInfo activityInfo = manager.getActivityInfo(name, 0); + final String title = c.getString(titleIndex); + String label = getLabel(manager, activityInfo); + + if (title == null || !title.equals(label)) { + final ContentValues values = new ContentValues(); + values.put(LauncherSettings.Favorites.TITLE, label); + + resolver.update(LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION, + values, "_id=?", + new String[] { String.valueOf(c.getLong(idIndex)) }); + + // changed = true; + } + } + } + } + } catch (URISyntaxException e) { + // Ignore + } catch (PackageManager.NameNotFoundException e) { + // Ignore + } + } + } finally { + c.close(); + } + + // if (changed) resolver.notifyChange(Settings.Favorites.CONTENT_URI, null); + } + + private static String getLabel(PackageManager manager, ActivityInfo activityInfo) { + String label = activityInfo.loadLabel(manager).toString(); + if (label == null) { + label = manager.getApplicationLabel(activityInfo.applicationInfo).toString(); + if (label == null) { + label = activityInfo.name; + } + } + return label; + } + private class DesktopItemsLoader implements Runnable { private volatile boolean mStopped; private volatile boolean mRunning; private final WeakReference<Launcher> mLauncher; + private boolean mLocaleChanged; - DesktopItemsLoader(Launcher launcher) { + DesktopItemsLoader(Launcher launcher, boolean localeChanged) { mLauncher = new WeakReference<Launcher>(launcher); + mLocaleChanged = localeChanged; } void stop() { @@ -267,54 +336,61 @@ public class LauncherModel { mRunning = true; final Launcher launcher = mLauncher.get(); + final ContentResolver contentResolver = launcher.getContentResolver(); + final PackageManager manager = launcher.getPackageManager(); + + if (mLocaleChanged) { + updateShortcutLabels(contentResolver, manager); + } mDesktopItems = new ArrayList<ItemInfo>(); - mUserFolders = new HashMap<Long, UserFolderInfo>(); + mFolders = new HashMap<Long, FolderInfo>(); final ArrayList<ItemInfo> desktopItems = mDesktopItems; - final Cursor c = launcher.getContentResolver().query(Settings.Favorites.CONTENT_URI, - null, null, null, null); + final Cursor c = contentResolver.query( + LauncherSettings.Favorites.CONTENT_URI, null, null, null, null); try { - final int idIndex = c.getColumnIndexOrThrow(Settings.Favorites.ID); - final int intentIndex = c.getColumnIndexOrThrow(Settings.Favorites.INTENT); - final int titleIndex = c.getColumnIndexOrThrow(Settings.Favorites.TITLE); - final int iconTypeIndex = c.getColumnIndexOrThrow(Settings.Favorites.ICON_TYPE); - final int iconIndex = c.getColumnIndexOrThrow(Settings.Favorites.ICON); - final int iconPackageIndex = c.getColumnIndexOrThrow(Settings.Favorites.ICON_PACKAGE); - final int iconResourceIndex = c.getColumnIndexOrThrow(Settings.Favorites.ICON_RESOURCE); - final int containerIndex = c.getColumnIndexOrThrow(Settings.Favorites.CONTAINER); - final int itemTypeIndex = c.getColumnIndexOrThrow(Settings.Favorites.ITEM_TYPE); - final int screenIndex = c.getColumnIndexOrThrow(Settings.Favorites.SCREEN); - final int cellXIndex = c.getColumnIndexOrThrow(Settings.Favorites.CELLX); - final int cellYIndex = c.getColumnIndexOrThrow(Settings.Favorites.CELLY); - - final PackageManager manager = launcher.getPackageManager(); + final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ID); + final int intentIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.INTENT); + final int titleIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE); + final int iconTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_TYPE); + final int iconIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON); + final int iconPackageIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_PACKAGE); + 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 screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN); + final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX); + final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY); + final int uriIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.URI); + final int displayModeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.DISPLAY_MODE); ApplicationInfo info; String intentDescription; Widget widgetInfo = null; int container; + long id; + Intent intent; - final HashMap<Long, UserFolderInfo> userFolders = mUserFolders; + final HashMap<Long, FolderInfo> folders = mFolders; while (!mStopped && c.moveToNext()) { try { int itemType = c.getInt(itemTypeIndex); switch (itemType) { - case Settings.Favorites.ITEM_TYPE_APPLICATION: - case Settings.Favorites.ITEM_TYPE_SHORTCUT: + case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION: + case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT: intentDescription = c.getString(intentIndex); - Intent intent; try { intent = Intent.getIntent(intentDescription); } catch (java.net.URISyntaxException e) { continue; } - if (itemType == Settings.Favorites.ITEM_TYPE_APPLICATION) { + if (itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) { info = getApplicationInfo(manager, intent); } else { info = getApplicationInfoShortcut(c, launcher, iconTypeIndex, @@ -338,22 +414,22 @@ public class LauncherModel { info.cellY = c.getInt(cellYIndex); switch (container) { - case Settings.Favorites.CONTAINER_DESKTOP: + case LauncherSettings.Favorites.CONTAINER_DESKTOP: desktopItems.add(info); break; default: // Item is in a user folder UserFolderInfo folderInfo = - findOrMakeFolder(userFolders, container); + findOrMakeUserFolder(folders, container); folderInfo.add(info); break; } } break; - case Settings.Favorites.ITEM_TYPE_USER_FOLDER: + case LauncherSettings.Favorites.ITEM_TYPE_USER_FOLDER: - long id = c.getLong(idIndex); - UserFolderInfo folderInfo = findOrMakeFolder(userFolders, id); + id = c.getLong(idIndex); + UserFolderInfo folderInfo = findOrMakeUserFolder(folders, id); folderInfo.title = c.getString(titleIndex); @@ -365,24 +441,57 @@ public class LauncherModel { folderInfo.cellY = c.getInt(cellYIndex); switch (container) { - case Settings.Favorites.CONTAINER_DESKTOP: - desktopItems.add(folderInfo); - break; - default: + case LauncherSettings.Favorites.CONTAINER_DESKTOP: + desktopItems.add(folderInfo); + break; + } + break; + case LauncherSettings.Favorites.ITEM_TYPE_LIVE_FOLDER: + id = c.getLong(idIndex); + LiveFolderInfo liveFolderInfo = findOrMakeLiveFolder(folders, id); + + intentDescription = c.getString(intentIndex); + intent = null; + if (intentDescription != null) { + try { + intent = Intent.getIntent(intentDescription); + } catch (java.net.URISyntaxException e) { + // Ignore, a live folder might not have a base intent + } + } + + liveFolderInfo.title = c.getString(titleIndex); + liveFolderInfo.id = id; + container = c.getInt(containerIndex); + liveFolderInfo.container = container; + liveFolderInfo.screen = c.getInt(screenIndex); + liveFolderInfo.cellX = c.getInt(cellXIndex); + liveFolderInfo.cellY = c.getInt(cellYIndex); + liveFolderInfo.uri = Uri.parse(c.getString(uriIndex)); + liveFolderInfo.baseIntent = intent; + liveFolderInfo.displayMode = c.getInt(displayModeIndex); + + loadLiveFolderIcon(launcher, c, iconTypeIndex, iconPackageIndex, + iconResourceIndex, liveFolderInfo); + + switch (container) { + case LauncherSettings.Favorites.CONTAINER_DESKTOP: + desktopItems.add(liveFolderInfo); + break; } break; - case Settings.Favorites.ITEM_TYPE_WIDGET_CLOCK: - case Settings.Favorites.ITEM_TYPE_WIDGET_SEARCH: - case Settings.Favorites.ITEM_TYPE_WIDGET_PHOTO_FRAME: + 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 Settings.Favorites.ITEM_TYPE_WIDGET_CLOCK: + case LauncherSettings.Favorites.ITEM_TYPE_WIDGET_CLOCK: widgetInfo = Widget.makeClock(); break; - case Settings.Favorites.ITEM_TYPE_WIDGET_SEARCH: + case LauncherSettings.Favorites.ITEM_TYPE_WIDGET_SEARCH: widgetInfo = Widget.makeSearch(); break; - case Settings.Favorites.ITEM_TYPE_WIDGET_PHOTO_FRAME: + case LauncherSettings.Favorites.ITEM_TYPE_WIDGET_PHOTO_FRAME: widgetInfo = Widget.makePhotoFrame(); byte[] data = c.getBlob(iconIndex); if (data != null) { @@ -394,7 +503,7 @@ public class LauncherModel { if (widgetInfo != null) { container = c.getInt(containerIndex); - if (container != Settings.Favorites.CONTAINER_DESKTOP) { + if (container != LauncherSettings.Favorites.CONTAINER_DESKTOP) { Log.e(Launcher.LOG_TAG, "Widget found where container " + "!= CONTAINER_DESKTOP -- ignoring!"); continue; @@ -432,6 +541,33 @@ public class LauncherModel { } } + private static void loadLiveFolderIcon(Launcher launcher, Cursor c, int iconTypeIndex, + int iconPackageIndex, int iconResourceIndex, LiveFolderInfo liveFolderInfo) { + + int iconType = c.getInt(iconTypeIndex); + switch (iconType) { + case LauncherSettings.Favorites.ICON_TYPE_RESOURCE: + String packageName = c.getString(iconPackageIndex); + String resourceName = c.getString(iconResourceIndex); + PackageManager packageManager = launcher.getPackageManager(); + try { + Resources resources = packageManager.getResourcesForApplication(packageName); + final int id = resources.getIdentifier(resourceName, null, null); + liveFolderInfo.icon = resources.getDrawable(id); + } catch (Exception e) { + liveFolderInfo.icon = + launcher.getResources().getDrawable(R.drawable.ic_launcher_folder); + } + liveFolderInfo.iconResource = new Intent.ShortcutIconResource(); + liveFolderInfo.iconResource.packageName = packageName; + liveFolderInfo.iconResource.resourceName = resourceName; + break; + default: + liveFolderInfo.icon = + launcher.getResources().getDrawable(R.drawable.ic_launcher_folder); + } + } + /** * Finds the user folder defined by the specified id. * @@ -439,28 +575,42 @@ public class LauncherModel { * * @return A UserFolderInfo if the folder exists or null otherwise. */ - UserFolderInfo findFolderById(long id) { - return mUserFolders.get(id); + FolderInfo findFolderById(long id) { + return mFolders.get(id); } - void addUserFolder(UserFolderInfo info) { - mUserFolders.put(info.id, info); + void addFolder(FolderInfo info) { + mFolders.put(info.id, info); } /** * Return an existing UserFolderInfo object if we have encountered this ID previously, or make a * new one. */ - private UserFolderInfo findOrMakeFolder(HashMap<Long, UserFolderInfo> userFolders, long id) { - UserFolderInfo folderInfo; + private UserFolderInfo findOrMakeUserFolder(HashMap<Long, FolderInfo> folders, long id) { // See if a placeholder was created for us already - folderInfo = userFolders.get(id); - if (folderInfo == null) { + FolderInfo folderInfo = folders.get(id); + if (folderInfo == null || !(folderInfo instanceof UserFolderInfo)) { // No placeholder -- create a new instance folderInfo = new UserFolderInfo(); - userFolders.put(id, folderInfo); + folders.put(id, folderInfo); + } + return (UserFolderInfo) folderInfo; + } + + /** + * Return an existing UserFolderInfo object if we have encountered this ID previously, or make a + * new one. + */ + private LiveFolderInfo findOrMakeLiveFolder(HashMap<Long, FolderInfo> folders, long id) { + // See if a placeholder was created for us already + FolderInfo folderInfo = folders.get(id); + if (folderInfo == null || !(folderInfo instanceof LiveFolderInfo)) { + // No placeholder -- create a new instance + folderInfo = new LiveFolderInfo(); + folders.put(id, folderInfo); } - return folderInfo; + return (LiveFolderInfo) folderInfo; } /** @@ -483,8 +633,8 @@ public class LauncherModel { for (int i = 0; i < count; i++) { ItemInfo item = desktopItems.get(i); switch (item.itemType) { - case Settings.Favorites.ITEM_TYPE_APPLICATION: - case Settings.Favorites.ITEM_TYPE_SHORTCUT: + case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION: + case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT: ((ApplicationInfo)item).icon.setCallback(null); } } @@ -562,7 +712,7 @@ public class LauncherModel { if (info.title == null) { info.title = ""; } - info.itemType = Settings.Favorites.ITEM_TYPE_APPLICATION; + info.itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION; return info; } @@ -573,11 +723,11 @@ public class LauncherModel { int iconTypeIndex, int iconPackageIndex, int iconResourceIndex, int iconIndex) { final ApplicationInfo info = new ApplicationInfo(); - info.itemType = Settings.Favorites.ITEM_TYPE_SHORTCUT; + info.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT; int iconType = c.getInt(iconTypeIndex); switch (iconType) { - case Settings.Favorites.ICON_TYPE_RESOURCE: + case LauncherSettings.Favorites.ICON_TYPE_RESOURCE: String packageName = c.getString(iconPackageIndex); String resourceName = c.getString(iconResourceIndex); PackageManager packageManager = launcher.getPackageManager(); @@ -593,10 +743,11 @@ public class LauncherModel { info.iconResource.resourceName = resourceName; info.customIcon = false; break; - case Settings.Favorites.ICON_TYPE_BITMAP: + case LauncherSettings.Favorites.ICON_TYPE_BITMAP: byte[] data = c.getBlob(iconIndex); Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length); - info.icon = new BitmapDrawable(Utilities.createBitmapThumbnail(bitmap, launcher)); + info.icon = new FastBitmapDrawable( + Utilities.createBitmapThumbnail(bitmap, launcher)); info.filtered = true; info.customIcon = true; break; @@ -621,7 +772,7 @@ public class LauncherModel { * @param userFolderInfo */ void removeUserFolder(UserFolderInfo userFolderInfo) { - mUserFolders.remove(userFolderInfo.id); + mFolders.remove(userFolderInfo.id); } /** @@ -652,12 +803,12 @@ public class LauncherModel { final ContentValues values = new ContentValues(); final ContentResolver cr = context.getContentResolver(); - values.put(Settings.Favorites.CONTAINER, item.container); - values.put(Settings.Favorites.CELLX, item.cellX); - values.put(Settings.Favorites.CELLY, item.cellY); - values.put(Settings.Favorites.SCREEN, item.screen); + values.put(LauncherSettings.Favorites.CONTAINER, item.container); + values.put(LauncherSettings.Favorites.CELLX, item.cellX); + values.put(LauncherSettings.Favorites.CELLY, item.cellY); + values.put(LauncherSettings.Favorites.SCREEN, item.screen); - cr.update(Settings.Favorites.getContentUri(item.id, false), values, null, null); + cr.update(LauncherSettings.Favorites.getContentUri(item.id, false), values, null, null); } /** @@ -666,7 +817,7 @@ public class LauncherModel { */ static boolean shortcutExists(Context context, String title, Intent intent) { final ContentResolver cr = context.getContentResolver(); - Cursor c = cr.query(Settings.Favorites.CONTENT_URI, + Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI, new String[] { "title", "intent" }, "title=? and intent=?", new String[] { title, intent.toURI() }, null); boolean result = false; @@ -678,21 +829,32 @@ public class LauncherModel { return result; } - UserFolderInfo getFolderById(Context context, long id) { + FolderInfo getFolderById(Context context, long id) { final ContentResolver cr = context.getContentResolver(); - Cursor c = cr.query(Settings.Favorites.CONTENT_URI, null, "_id=? and itemType=?", - new String[] { String.valueOf(id), - String.valueOf(Settings.Favorites.ITEM_TYPE_USER_FOLDER) }, null); + Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI, null, + "_id=? and itemType=? or itemType=?", + new String[] { String.valueOf(id), + String.valueOf(LauncherSettings.Favorites.ITEM_TYPE_USER_FOLDER), + String.valueOf(LauncherSettings.Favorites.ITEM_TYPE_LIVE_FOLDER) }, null); try { if (c.moveToFirst()) { - final int titleIndex = c.getColumnIndexOrThrow(Settings.Favorites.TITLE); - final int containerIndex = c.getColumnIndexOrThrow(Settings.Favorites.CONTAINER); - final int screenIndex = c.getColumnIndexOrThrow(Settings.Favorites.SCREEN); - final int cellXIndex = c.getColumnIndexOrThrow(Settings.Favorites.CELLX); - final int cellYIndex = c.getColumnIndexOrThrow(Settings.Favorites.CELLY); - - UserFolderInfo folderInfo = findOrMakeFolder(mUserFolders, id); + final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE); + final int titleIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE); + 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); + + FolderInfo folderInfo = null; + switch (c.getInt(itemTypeIndex)) { + case LauncherSettings.Favorites.ITEM_TYPE_USER_FOLDER: + folderInfo = findOrMakeUserFolder(mFolders, id); + break; + case LauncherSettings.Favorites.ITEM_TYPE_LIVE_FOLDER: + folderInfo = findOrMakeLiveFolder(mFolders, id); + break; + } folderInfo.title = c.getString(titleIndex); folderInfo.id = id; @@ -712,18 +874,18 @@ public class LauncherModel { static Widget getPhotoFrameInfo(Context context, int screen, int cellX, int cellY) { final ContentResolver cr = context.getContentResolver(); - Cursor c = cr.query(Settings.Favorites.CONTENT_URI, + 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(Settings.Favorites.ITEM_TYPE_WIDGET_PHOTO_FRAME) }, null); + String.valueOf(LauncherSettings.Favorites.ITEM_TYPE_WIDGET_PHOTO_FRAME) }, null); try { if (c.moveToFirst()) { - final int idIndex = c.getColumnIndexOrThrow(Settings.Favorites.ID); - final int containerIndex = c.getColumnIndexOrThrow(Settings.Favorites.CONTAINER); - final int screenIndex = c.getColumnIndexOrThrow(Settings.Favorites.SCREEN); - final int cellXIndex = c.getColumnIndexOrThrow(Settings.Favorites.CELLX); - final int cellYIndex = c.getColumnIndexOrThrow(Settings.Favorites.CELLY); + 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); @@ -757,8 +919,8 @@ public class LauncherModel { item.onAddToDatabase(values); - Uri result = cr.insert(notify ? Settings.Favorites.CONTENT_URI : - Settings.Favorites.CONTENT_URI_NO_NOTIFICATION, values); + Uri result = cr.insert(notify ? LauncherSettings.Favorites.CONTENT_URI : + LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION, values); if (result != null) { item.id = Integer.parseInt(result.getPathSegments().get(1)); @@ -774,7 +936,7 @@ public class LauncherModel { item.onAddToDatabase(values); - cr.update(Settings.Favorites.getContentUri(item.id, false), values, null, null); + cr.update(LauncherSettings.Favorites.getContentUri(item.id, false), values, null, null); } /** @@ -785,7 +947,7 @@ public class LauncherModel { static void deleteItemFromDatabase(Context context, ItemInfo item) { final ContentResolver cr = context.getContentResolver(); - cr.delete(Settings.Favorites.getContentUri(item.id, false), null, null); + cr.delete(LauncherSettings.Favorites.getContentUri(item.id, false), null, null); } @@ -795,8 +957,8 @@ public class LauncherModel { static void deleteUserFolderContentsFromDatabase(Context context, UserFolderInfo info) { final ContentResolver cr = context.getContentResolver(); - cr.delete(Settings.Favorites.getContentUri(info.id, false), null, null); - cr.delete(Settings.Favorites.CONTENT_URI, Settings.Favorites.CONTAINER + "=" + info.id, + cr.delete(LauncherSettings.Favorites.getContentUri(info.id, false), null, null); + cr.delete(LauncherSettings.Favorites.CONTENT_URI, LauncherSettings.Favorites.CONTAINER + "=" + info.id, null); } } diff --git a/src/com/android/launcher/LauncherProvider.java b/src/com/android/launcher/LauncherProvider.java new file mode 100644 index 000000000..a3e529d32 --- /dev/null +++ b/src/com/android/launcher/LauncherProvider.java @@ -0,0 +1,435 @@ +/* + * 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.ContentProvider; +import android.content.Context; +import android.content.ContentValues; +import android.content.Intent; +import android.content.ComponentName; +import android.content.ContentUris; +import android.content.ContentResolver; +import android.content.pm.PackageManager; +import android.content.pm.ActivityInfo; +import android.database.sqlite.SQLiteOpenHelper; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteQueryBuilder; +import android.database.Cursor; +import android.util.Log; +import android.util.Xml; +import android.net.Uri; +import android.text.TextUtils; +import android.os.*; +import android.provider.Settings; + +import java.io.FileReader; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import com.android.internal.util.XmlUtils; + +public class LauncherProvider extends ContentProvider { + private static final String LOG_TAG = "LauncherSettingsProvider"; + + private static final String DATABASE_NAME = "launcher.db"; + private static final int DATABASE_VERSION = 1; + + static final String AUTHORITY = "com.android.launcher.settings"; + + static final String TABLE_FAVORITES = "favorites"; + static final String PARAMETER_NOTIFY = "notify"; + + private SQLiteOpenHelper mOpenHelper; + + @Override + public boolean onCreate() { + mOpenHelper = new DatabaseHelper(getContext()); + return true; + } + + @Override + public String getType(Uri uri) { + SqlArguments args = new SqlArguments(uri, null, null); + if (TextUtils.isEmpty(args.where)) { + return "vnd.android.cursor.dir/" + args.table; + } else { + return "vnd.android.cursor.item/" + args.table; + } + } + + @Override + public Cursor query(Uri uri, String[] projection, String selection, + String[] selectionArgs, String sortOrder) { + + SqlArguments args = new SqlArguments(uri, selection, selectionArgs); + SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); + qb.setTables(args.table); + + SQLiteDatabase db = mOpenHelper.getReadableDatabase(); + Cursor result = qb.query(db, projection, args.where, args.args, null, null, sortOrder); + result.setNotificationUri(getContext().getContentResolver(), uri); + + return result; + } + + @Override + public Uri insert(Uri uri, ContentValues initialValues) { + SqlArguments args = new SqlArguments(uri); + + SQLiteDatabase db = mOpenHelper.getWritableDatabase(); + final long rowId = db.insert(args.table, null, initialValues); + if (rowId <= 0) return null; + + uri = ContentUris.withAppendedId(uri, rowId); + sendNotify(uri); + + return uri; + } + + @Override + public int bulkInsert(Uri uri, ContentValues[] values) { + SqlArguments args = new SqlArguments(uri); + + SQLiteDatabase db = mOpenHelper.getWritableDatabase(); + db.beginTransaction(); + try { + int numValues = values.length; + for (int i = 0; i < numValues; i++) { + if (db.insert(args.table, null, values[i]) < 0) return 0; + } + db.setTransactionSuccessful(); + } finally { + db.endTransaction(); + } + + sendNotify(uri); + return values.length; + } + + @Override + public int delete(Uri uri, String selection, String[] selectionArgs) { + SqlArguments args = new SqlArguments(uri, selection, selectionArgs); + + SQLiteDatabase db = mOpenHelper.getWritableDatabase(); + int count = db.delete(args.table, args.where, args.args); + if (count > 0) sendNotify(uri); + + return count; + } + + @Override + public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { + SqlArguments args = new SqlArguments(uri, selection, selectionArgs); + + SQLiteDatabase db = mOpenHelper.getWritableDatabase(); + int count = db.update(args.table, values, args.where, args.args); + if (count > 0) sendNotify(uri); + + return count; + } + + private void sendNotify(Uri uri) { + String notify = uri.getQueryParameter(PARAMETER_NOTIFY); + if (notify == null || "true".equals(notify)) { + getContext().getContentResolver().notifyChange(uri, null); + } + } + + private static class DatabaseHelper extends SQLiteOpenHelper { + /** + * Path to file containing default favorite packages, relative to ANDROID_ROOT. + */ + private static final String DEFAULT_FAVORITES_PATH = "etc/favorites.xml"; + + private static final String TAG_FAVORITES = "favorites"; + private static final String TAG_FAVORITE = "favorite"; + private static final String TAG_PACKAGE = "package"; + private static final String TAG_CLASS = "class"; + + private static final String ATTRIBUTE_SCREEN = "screen"; + private static final String ATTRIBUTE_X = "x"; + private static final String ATTRIBUTE_Y = "y"; + + private final Context mContext; + + DatabaseHelper(Context context) { + super(context, DATABASE_NAME, null, DATABASE_VERSION); + mContext = context; + } + + @Override + public void onCreate(SQLiteDatabase db) { + db.execSQL("CREATE TABLE favorites (" + + "_id INTEGER PRIMARY KEY," + + "title TEXT," + + "intent TEXT," + + "container INTEGER," + + "screen INTEGER," + + "cellX INTEGER," + + "cellY INTEGER," + + "spanX INTEGER," + + "spanY INTEGER," + + "itemType INTEGER," + + "isShortcut INTEGER," + + "iconType INTEGER," + + "iconPackage TEXT," + + "iconResource TEXT," + + "icon BLOB," + + "uri TEXT," + + "displayMode INTEGER" + + ");"); + + if (!convertDatabase(db)) { + // Populate favorites table with initial favorites + loadFavorites(db, DEFAULT_FAVORITES_PATH); + } + } + + private boolean convertDatabase(SQLiteDatabase db) { + boolean converted = false; + + final Uri uri = Uri.parse("content://" + Settings.AUTHORITY + + "/favorites?notify=true"); + final ContentResolver resolver = mContext.getContentResolver(); + Cursor cursor = null; + + try { + cursor = resolver.query(uri, null, null, null, null); + } catch (Exception e) { + // Ignore + } + + // We already have a favorites database in the old provider + if (cursor != null && cursor.getCount() > 0) { + try { + converted = copyFromCursor(db, cursor) > 0; + } finally { + cursor.close(); + } + + if (converted) { + resolver.delete(uri, null, null); + } + } + + return converted; + } + + private int copyFromCursor(SQLiteDatabase db, Cursor c) { + final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ID); + final int intentIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.INTENT); + final int titleIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE); + final int iconTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_TYPE); + final int iconIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON); + final int iconPackageIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_PACKAGE); + 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 screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN); + final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX); + final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY); + final int uriIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.URI); + final int displayModeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.DISPLAY_MODE); + + ContentValues[] rows = new ContentValues[c.getCount()]; + int i = 0; + while (c.moveToNext()) { + ContentValues values = new ContentValues(c.getColumnCount()); + values.put(LauncherSettings.Favorites.ID, c.getLong(idIndex)); + values.put(LauncherSettings.Favorites.INTENT, c.getString(intentIndex)); + values.put(LauncherSettings.Favorites.TITLE, c.getString(titleIndex)); + values.put(LauncherSettings.Favorites.ICON_TYPE, c.getInt(iconTypeIndex)); + values.put(LauncherSettings.Favorites.ICON, c.getBlob(iconIndex)); + values.put(LauncherSettings.Favorites.ICON_PACKAGE, c.getString(iconPackageIndex)); + 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.SCREEN, c.getInt(screenIndex)); + values.put(LauncherSettings.Favorites.CELLX, c.getInt(cellXIndex)); + values.put(LauncherSettings.Favorites.CELLY, c.getInt(cellYIndex)); + values.put(LauncherSettings.Favorites.URI, c.getString(uriIndex)); + values.put(LauncherSettings.Favorites.DISPLAY_MODE, c.getInt(displayModeIndex)); + rows[i++] = values; + } + + db.beginTransaction(); + int total = 0; + try { + int numValues = rows.length; + for (i = 0; i < numValues; i++) { + if (db.insert(TABLE_FAVORITES, null, rows[i]) < 0) { + return 0; + } else { + total++; + } + } + db.setTransactionSuccessful(); + } finally { + db.endTransaction(); + } + + return total; + } + + @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"); + + db.execSQL("DROP TABLE IF EXISTS " + TABLE_FAVORITES); + onCreate(db); + } + + + /** + * Loads the default set of favorite packages from an xml file. + * + * @param db The database to write the values into + * @param subPath The relative path from ANDROID_ROOT to the file to read + */ + private int loadFavorites(SQLiteDatabase db, String subPath) { + FileReader favReader; + + // Environment.getRootDirectory() is a fancy way of saying ANDROID_ROOT or "/system". + final File favFile = new File(Environment.getRootDirectory(), subPath); + try { + favReader = new FileReader(favFile); + } catch (FileNotFoundException e) { + Log.e(LOG_TAG, "Couldn't find or open favorites file " + favFile); + return 0; + } + + Intent intent = new Intent(Intent.ACTION_MAIN, null); + intent.addCategory(Intent.CATEGORY_LAUNCHER); + ContentValues values = new ContentValues(); + + PackageManager packageManager = mContext.getPackageManager(); + ActivityInfo info; + int i = 0; + try { + XmlPullParser parser = Xml.newPullParser(); + parser.setInput(favReader); + + XmlUtils.beginDocument(parser, TAG_FAVORITES); + + while (true) { + XmlUtils.nextElement(parser); + + String name = parser.getName(); + if (!TAG_FAVORITE.equals(name)) { + break; + } + + String pkg = parser.getAttributeValue(null, TAG_PACKAGE); + String cls = parser.getAttributeValue(null, TAG_CLASS); + try { + ComponentName cn = new ComponentName(pkg, cls); + info = packageManager.getActivityInfo(cn, 0); + intent.setComponent(cn); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + values.put(LauncherSettings.Favorites.INTENT, intent.toURI()); + values.put(LauncherSettings.Favorites.TITLE, + info.loadLabel(packageManager).toString()); + values.put(LauncherSettings.Favorites.CONTAINER, + LauncherSettings.Favorites.CONTAINER_DESKTOP); + values.put(LauncherSettings.Favorites.ITEM_TYPE, + LauncherSettings.Favorites.ITEM_TYPE_APPLICATION); + values.put(LauncherSettings.Favorites.SCREEN, + parser.getAttributeValue(null, ATTRIBUTE_SCREEN)); + values.put(LauncherSettings.Favorites.CELLX, + parser.getAttributeValue(null, ATTRIBUTE_X)); + values.put(LauncherSettings.Favorites.CELLY, + parser.getAttributeValue(null, ATTRIBUTE_Y)); + values.put(LauncherSettings.Favorites.SPANX, 1); + values.put(LauncherSettings.Favorites.SPANY, 1); + db.insert(TABLE_FAVORITES, null, values); + i++; + } catch (PackageManager.NameNotFoundException e) { + Log.w(LOG_TAG, "Unable to add favorite: " + pkg + "/" + cls, e); + } + } + } catch (XmlPullParserException e) { + Log.w(LOG_TAG, "Got exception parsing favorites.", e); + } 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, + LauncherSettings.Favorites.CONTAINER_DESKTOP); + values.put(LauncherSettings.Favorites.ITEM_TYPE, + LauncherSettings.Favorites.ITEM_TYPE_WIDGET_SEARCH); + values.put(LauncherSettings.Favorites.SCREEN, 2); + values.put(LauncherSettings.Favorites.CELLX, 0); + values.put(LauncherSettings.Favorites.CELLY, 0); + values.put(LauncherSettings.Favorites.SPANX, 4); + values.put(LauncherSettings.Favorites.SPANY, 1); + db.insert(TABLE_FAVORITES, null, values); + + return i; + } + } + + static class SqlArguments { + public final String table; + public final String where; + public final String[] args; + + SqlArguments(Uri url, String where, String[] args) { + if (url.getPathSegments().size() == 1) { + this.table = url.getPathSegments().get(0); + this.where = where; + this.args = args; + } else if (url.getPathSegments().size() != 2) { + throw new IllegalArgumentException("Invalid URI: " + url); + } else if (!TextUtils.isEmpty(where)) { + throw new UnsupportedOperationException("WHERE clause not supported: " + url); + } else { + this.table = url.getPathSegments().get(0); + this.where = "_id=" + ContentUris.parseId(url); + this.args = null; + } + } + + SqlArguments(Uri url) { + if (url.getPathSegments().size() == 1) { + table = url.getPathSegments().get(0); + where = null; + args = null; + } else { + throw new IllegalArgumentException("Invalid URI: " + url); + } + } + } +} diff --git a/src/com/android/launcher/LauncherSettings.java b/src/com/android/launcher/LauncherSettings.java new file mode 100644 index 000000000..c5dfd1ff0 --- /dev/null +++ b/src/com/android/launcher/LauncherSettings.java @@ -0,0 +1,222 @@ +/* + * 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.provider.BaseColumns; +import android.net.Uri; + +/** + * Settings related utilities. + */ +class LauncherSettings { + /** + * Favorites. + */ + static final class Favorites implements BaseColumns { + /** + * The content:// style URL for this table + */ + static final Uri CONTENT_URI = Uri.parse("content://" + + LauncherProvider.AUTHORITY + "/" + LauncherProvider.TABLE_FAVORITES + + "?" + LauncherProvider.PARAMETER_NOTIFY + "=true"); + + /** + * The content:// style URL for this table. When this Uri is used, no notification is + * sent if the content changes. + */ + static final Uri CONTENT_URI_NO_NOTIFICATION = Uri.parse("content://" + + LauncherProvider.AUTHORITY + "/" + LauncherProvider.TABLE_FAVORITES + + "?" + LauncherProvider.PARAMETER_NOTIFY + "=false"); + + /** + * The content:// style URL for a given row, identified by its id. + * + * @param id The row id. + * @param notify True to send a notification is the content changes. + * + * @return The unique content URL for the specified row. + */ + static Uri getContentUri(long id, boolean notify) { + return Uri.parse("content://" + LauncherProvider.AUTHORITY + + "/" + LauncherProvider.TABLE_FAVORITES + "/" + id + "?" + + LauncherProvider.PARAMETER_NOTIFY + "=" + notify); + } + + /** + * The row ID. + * <p>Type: INTEGER</p> + */ + static final String ID = "_id"; + + /** + * Descriptive name of the favorite that can be displayed to the user. + * <P>Type: TEXT</P> + */ + static final String TITLE = "title"; + + /** + * The Intent URL of the favorite, describing what it points to. This + * value is given to {@link android.content.Intent#getIntent} to create + * an Intent that can be launched. + * <P>Type: TEXT</P> + */ + static final String INTENT = "intent"; + + /** + * The container holding the favorite + * <P>Type: INTEGER</P> + */ + static final String CONTAINER = "container"; + + /** + * The icon is a resource identified by a package name and an integer id. + */ + static final int CONTAINER_DESKTOP = -100; + + /** + * The screen holding the favorite (if container is CONTAINER_DESKTOP) + * <P>Type: INTEGER</P> + */ + static final String SCREEN = "screen"; + + /** + * The X coordinate of the cell holding the favorite + * (if container is CONTAINER_DESKTOP or CONTAINER_DOCK) + * <P>Type: INTEGER</P> + */ + static final String CELLX = "cellX"; + + /** + * The Y coordinate of the cell holding the favorite + * (if container is CONTAINER_DESKTOP) + * <P>Type: INTEGER</P> + */ + static final String CELLY = "cellY"; + + /** + * The X span of the cell holding the favorite + * <P>Type: INTEGER</P> + */ + static final String SPANX = "spanX"; + + /** + * The Y span of the cell holding the favorite + * <P>Type: INTEGER</P> + */ + static final String SPANY = "spanY"; + + /** + * The type of the favorite + * + * <P>Type: INTEGER</P> + */ + static final String ITEM_TYPE = "itemType"; + + /** + * The favorite is an application + */ + static final int ITEM_TYPE_APPLICATION = 0; + + /** + * The favorite is an application created shortcut + */ + static final int ITEM_TYPE_SHORTCUT = 1; + + /** + * The favorite is a user created folder + */ + static final int ITEM_TYPE_USER_FOLDER = 2; + + /** + * The favorite is a live folder + */ + static final int ITEM_TYPE_LIVE_FOLDER = 3; + + /** + * The favorite is a clock + */ + static final int ITEM_TYPE_WIDGET_CLOCK = 1000; + + /** + * The favorite is a search widget + */ + static final int ITEM_TYPE_WIDGET_SEARCH = 1001; + + /** + * The favorite is a photo frame + */ + static final int ITEM_TYPE_WIDGET_PHOTO_FRAME = 1002; + + /** + * 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 + * value is 1, it is an application-created shortcut. + * <P>Type: INTEGER</P> + */ + static final String IS_SHORTCUT = "isShortcut"; + + /** + * The icon type. + * <P>Type: INTEGER</P> + */ + static final String ICON_TYPE = "iconType"; + + /** + * The icon is a resource identified by a package name and an integer id. + */ + static final int ICON_TYPE_RESOURCE = 0; + + /** + * The icon is a bitmap. + */ + static final int ICON_TYPE_BITMAP = 1; + + /** + * The icon package name, if icon type is ICON_TYPE_RESOURCE. + * <P>Type: TEXT</P> + */ + static final String ICON_PACKAGE = "iconPackage"; + + /** + * The icon resource id, if icon type is ICON_TYPE_RESOURCE. + * <P>Type: TEXT</P> + */ + static final String ICON_RESOURCE = "iconResource"; + + /** + * The custom icon bitmap, if icon type is ICON_TYPE_BITMAP. + * <P>Type: BLOB</P> + */ + static final String ICON = "icon"; + + /** + * The URI associated with the favorite. It is used, for instance, by + * live folders to find the content provider. + * <P>Type: TEXT</P> + */ + static final String URI = "uri"; + + /** + * The display mode if the item is a live folder. + * <P>Type: INTEGER</P> + * + * @see android.provider.LiveFolders#DISPLAY_MODE_GRID + * @see android.provider.LiveFolders#DISPLAY_MODE_LIST + */ + static final String DISPLAY_MODE = "displayMode"; + } +} diff --git a/src/com/android/launcher/LiveFolder.java b/src/com/android/launcher/LiveFolder.java new file mode 100644 index 000000000..37b98e0f7 --- /dev/null +++ b/src/com/android/launcher/LiveFolder.java @@ -0,0 +1,83 @@ +/* + * 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.content.Intent; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.AdapterView; +import android.net.Uri; +import android.provider.LiveFolders; + +public class LiveFolder extends Folder { + public LiveFolder(Context context, AttributeSet attrs) { + super(context, attrs); + } + + static LiveFolder fromXml(Context context, FolderInfo folderInfo) { + final int layout = isDisplayModeList(folderInfo) ? + R.layout.live_folder_list : R.layout.live_folder_grid; + return (LiveFolder) LayoutInflater.from(context).inflate(layout, null); + } + + private static boolean isDisplayModeList(FolderInfo folderInfo) { + return ((LiveFolderInfo) folderInfo).displayMode == + LiveFolders.DISPLAY_MODE_LIST; + } + + @Override + public void onItemClick(AdapterView parent, View v, int position, long id) { + LiveFolderAdapter.ViewHolder holder = (LiveFolderAdapter.ViewHolder) v.getTag(); + + if (holder.useBaseIntent) { + final Intent baseIntent = ((LiveFolderInfo) mInfo).baseIntent; + if (baseIntent != null) { + final Intent intent = new Intent(baseIntent); + Uri uri = baseIntent.getData(); + uri = uri.buildUpon().appendPath(Long.toString(holder.id)).build(); + intent.setData(uri); + mLauncher.startActivitySafely(intent); + } + } else if (holder.intent != null) { + mLauncher.startActivitySafely(holder.intent); + } + } + + @Override + public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { + return false; + } + + void bind(FolderInfo info) { + super.bind(info); + setContentAdapter(new LiveFolderAdapter(mLauncher, (LiveFolderInfo) info)); + } + + @Override + void onOpen() { + super.onOpen(); + requestFocus(); + } + + @Override + void onClose() { + super.onClose(); + ((LiveFolderAdapter) mContent.getAdapter()).cleanup(); + } +} diff --git a/src/com/android/launcher/LiveFolderAdapter.java b/src/com/android/launcher/LiveFolderAdapter.java new file mode 100644 index 000000000..01db5a639 --- /dev/null +++ b/src/com/android/launcher/LiveFolderAdapter.java @@ -0,0 +1,205 @@ +/* + * 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.CursorAdapter; +import android.widget.TextView; +import android.widget.ImageView; +import android.content.Context; +import android.content.Intent; +import android.content.res.Resources; +import android.content.pm.PackageManager; +import android.view.View; +import android.view.ViewGroup; +import android.view.LayoutInflater; +import android.database.Cursor; +import android.provider.LiveFolders; +import android.graphics.drawable.Drawable; +import android.graphics.BitmapFactory; +import android.graphics.Bitmap; + +import java.net.URISyntaxException; +import java.util.HashMap; +import java.lang.ref.SoftReference; + +class LiveFolderAdapter extends CursorAdapter { + private boolean mIsList; + private LayoutInflater mInflater; + + private final HashMap<String, Drawable> mIcons = new HashMap<String, Drawable>(); + private final HashMap<Long, SoftReference<Drawable>> mCustomIcons = + new HashMap<Long, SoftReference<Drawable>>(); + private final Launcher mLauncher; + + LiveFolderAdapter(Launcher launcher, LiveFolderInfo info) { + super(launcher, query(launcher, info), true); + mIsList = info.displayMode == LiveFolders.DISPLAY_MODE_LIST; + mInflater = LayoutInflater.from(launcher); + mLauncher = launcher; + + mLauncher.startManagingCursor(getCursor()); + } + + private 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) { + View view; + final ViewHolder holder = new ViewHolder(); + + if (!mIsList) { + view = mInflater.inflate(R.layout.application_boxed, parent, false); + } else { + view = mInflater.inflate(R.layout.application_list, parent, false); + holder.description = (TextView) view.findViewById(R.id.description); + holder.icon = (ImageView) view.findViewById(R.id.icon); + } + + holder.name = (TextView) view.findViewById(R.id.name); + + holder.idIndex = cursor.getColumnIndexOrThrow(LiveFolders._ID); + holder.nameIndex = cursor.getColumnIndexOrThrow(LiveFolders.NAME); + holder.descriptionIndex = cursor.getColumnIndex(LiveFolders.DESCRIPTION); + holder.intentIndex = cursor.getColumnIndex(LiveFolders.INTENT); + holder.iconBitmapIndex = cursor.getColumnIndex(LiveFolders.ICON_BITMAP); + holder.iconResourceIndex = cursor.getColumnIndex(LiveFolders.ICON_RESOURCE); + holder.iconPackageIndex = cursor.getColumnIndex(LiveFolders.ICON_PACKAGE); + + view.setTag(holder); + + return view; + } + + public void bindView(View view, Context context, Cursor cursor) { + final ViewHolder holder = (ViewHolder) view.getTag(); + + holder.id = cursor.getLong(holder.idIndex); + final Drawable icon = loadIcon(context, cursor, holder); + + holder.name.setText(cursor.getString(holder.nameIndex)); + + if (!mIsList) { + holder.name.setCompoundDrawablesWithIntrinsicBounds(null, icon, null, null); + } else { + final boolean hasIcon = icon != null; + holder.icon.setVisibility(hasIcon ? View.VISIBLE : View.GONE); + if (hasIcon) holder.icon.setImageDrawable(icon); + + if (holder.descriptionIndex != -1) { + final String description = cursor.getString(holder.descriptionIndex); + if (description != null) { + holder.description.setText(description); + holder.description.setVisibility(View.VISIBLE); + } else { + holder.description.setVisibility(View.GONE); + } + } else { + holder.description.setVisibility(View.GONE); + } + } + + if (holder.intentIndex != -1) { + try { + holder.intent = Intent.getIntent(cursor.getString(holder.intentIndex)); + } catch (URISyntaxException e) { + // Ignore + } + } else { + holder.useBaseIntent = true; + } + } + + private Drawable loadIcon(Context context, Cursor cursor, ViewHolder holder) { + Drawable icon = null; + byte[] data = null; + + if (holder.iconBitmapIndex != -1) { + data = cursor.getBlob(holder.iconBitmapIndex); + } + + if (data != null) { + final SoftReference<Drawable> reference = mCustomIcons.get(holder.id); + if (reference != null) { + icon = reference.get(); + } + + if (icon == null) { + final Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length); + icon = new FastBitmapDrawable(Utilities.createBitmapThumbnail(bitmap, mContext)); + mCustomIcons.put(holder.id, new SoftReference<Drawable>(icon)); + } + } else if (holder.iconResourceIndex != -1 && holder.iconPackageIndex != -1) { + final String resource = cursor.getString(holder.iconResourceIndex); + icon = mIcons.get(resource); + if (icon == null) { + try { + final PackageManager packageManager = context.getPackageManager(); + Resources resources = packageManager.getResourcesForApplication( + cursor.getString(holder.iconPackageIndex)); + final int id = resources.getIdentifier(resource, + null, null); + icon = Utilities.createIconThumbnail(resources.getDrawable(id), mContext); + mIcons.put(resource, icon); + } catch (Exception e) { + // Ignore + } + } + } + + return icon; + } + + void cleanup() { + for (Drawable icon : mIcons.values()) { + icon.setCallback(null); + } + mIcons.clear(); + + for (SoftReference<Drawable> icon : mCustomIcons.values()) { + final Drawable drawable = icon.get(); + if (drawable != null) { + drawable.setCallback(null); + } + } + mCustomIcons.clear(); + + try { + getCursor().close(); + } finally { + mLauncher.stopManagingCursor(getCursor()); + } + } + + static class ViewHolder { + TextView name; + TextView description; + ImageView icon; + + Intent intent; + long id; + boolean useBaseIntent; + + int idIndex; + int nameIndex; + int descriptionIndex = -1; + int intentIndex = -1; + int iconBitmapIndex = -1; + int iconResourceIndex = -1; + int iconPackageIndex = -1; + } +} diff --git a/src/com/android/launcher/LiveFolderIcon.java b/src/com/android/launcher/LiveFolderIcon.java new file mode 100644 index 000000000..33cb0b704 --- /dev/null +++ b/src/com/android/launcher/LiveFolderIcon.java @@ -0,0 +1,76 @@ +/* + * 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.content.res.Resources; +import android.util.AttributeSet; +import android.view.ViewGroup; +import android.view.LayoutInflater; +import android.graphics.drawable.Drawable; + +public class LiveFolderIcon extends FolderIcon { + public LiveFolderIcon(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public LiveFolderIcon(Context context) { + super(context); + } + + static LiveFolderIcon fromXml(int resId, Launcher launcher, ViewGroup group, + LiveFolderInfo folderInfo) { + + LiveFolderIcon icon = (LiveFolderIcon) + LayoutInflater.from(launcher).inflate(resId, group, false); + + final Resources resources = launcher.getResources(); + Drawable d = folderInfo.icon; + if (d == null) { + resources.getDrawable(R.drawable.ic_launcher_folder); + d = Utilities.createIconThumbnail(d, launcher); + folderInfo.filtered = true; + } + icon.setCompoundDrawablesWithIntrinsicBounds(null, d, null, null); + icon.setText(folderInfo.title); + icon.setTag(folderInfo); + icon.setOnClickListener(launcher); + + return icon; + } + + @Override + public boolean acceptDrop(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo) { + return false; + } + + @Override + public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo) { + } + + @Override + public void onDragEnter(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo) { + } + + @Override + public void onDragOver(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo) { + } + + @Override + public void onDragExit(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo) { + } +} diff --git a/src/com/android/launcher/LiveFolderInfo.java b/src/com/android/launcher/LiveFolderInfo.java new file mode 100644 index 000000000..2432cc365 --- /dev/null +++ b/src/com/android/launcher/LiveFolderInfo.java @@ -0,0 +1,75 @@ +/* + * 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.ContentValues; +import android.content.Intent; +import android.graphics.drawable.Drawable; +import android.net.Uri; + +class LiveFolderInfo extends FolderInfo { + + /** + * The base intent, if it exists. + */ + Intent baseIntent; + + /** + * The live folder's content uri. + */ + Uri uri; + + /** + * The live folder's display type. + */ + int displayMode; + + /** + * The live folder icon. + */ + Drawable icon; + + /** + * When set to true, indicates that the icon has been resized. + */ + boolean filtered; + + /** + * Reference to the live folder icon as an application's resource. + */ + Intent.ShortcutIconResource iconResource; + + LiveFolderInfo() { + itemType = LauncherSettings.Favorites.ITEM_TYPE_LIVE_FOLDER; + } + + @Override + void onAddToDatabase(ContentValues values) { + super.onAddToDatabase(values); + values.put(LauncherSettings.Favorites.TITLE, title.toString()); + values.put(LauncherSettings.Favorites.URI, uri.toString()); + if (baseIntent != null) { + values.put(LauncherSettings.Favorites.INTENT, baseIntent.toURI()); + } + values.put(LauncherSettings.Favorites.ICON_TYPE, LauncherSettings.Favorites.ICON_TYPE_RESOURCE); + values.put(LauncherSettings.Favorites.DISPLAY_MODE, displayMode); + if (iconResource != null) { + values.put(LauncherSettings.Favorites.ICON_PACKAGE, iconResource.packageName); + values.put(LauncherSettings.Favorites.ICON_RESOURCE, iconResource.resourceName); + } + } +} diff --git a/src/com/android/launcher/Search.java b/src/com/android/launcher/Search.java index 69e26ac59..b3305279f 100644 --- a/src/com/android/launcher/Search.java +++ b/src/com/android/launcher/Search.java @@ -16,13 +16,19 @@ package com.android.launcher; +import java.util.List; + import android.app.ISearchManager; import android.app.SearchManager; +import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; import android.content.res.Resources; import android.content.res.Resources.NotFoundException; import android.database.Cursor; +import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Bundle; @@ -43,9 +49,9 @@ import android.view.View.OnKeyListener; import android.view.View.OnLongClickListener; import android.widget.AdapterView; import android.widget.AutoCompleteTextView; -import android.widget.Button; import android.widget.CursorAdapter; import android.widget.Filter; +import android.widget.ImageButton; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.SimpleCursorAdapter; @@ -59,7 +65,7 @@ public class Search extends LinearLayout implements OnClickListener, OnKeyListen private final String TAG = "SearchGadget"; private AutoCompleteTextView mSearchText; - private Button mGoButton; + private ImageButton mGoButton; private OnLongClickListener mLongClickListener; // Support for suggestions @@ -69,12 +75,14 @@ public class Search extends LinearLayout implements OnClickListener, OnKeyListen private Uri mSuggestionData = null; private String mSuggestionQuery = null; private int mItemSelected = -1; + + private Rect mTempRect = new Rect(); /** * Used to inflate the Workspace from XML. * * @param context The application's context. - * @param attrs The attribtues set containing the Workspace's customization values. + * @param attrs The attributes set containing the Workspace's customization values. */ public Search(Context context, AttributeSet attrs) { super(context, attrs); @@ -84,7 +92,9 @@ public class Search extends LinearLayout implements OnClickListener, OnKeyListen * Implements OnClickListener (for button) */ public void onClick(View v) { - query(); + if (v == mGoButton) { + query(); + } } private void query() { @@ -92,7 +102,9 @@ public class Search extends LinearLayout implements OnClickListener, OnKeyListen if (TextUtils.getTrimmedLength(mSearchText.getText()) == 0) { return; } - sendLaunchIntent(Intent.ACTION_SEARCH, null, query, null, 0, null, mSearchable); + Bundle appData = new Bundle(); + appData.putString(SearchManager.SOURCE, "launcher-widget"); + sendLaunchIntent(Intent.ACTION_SEARCH, null, query, appData, 0, null, mSearchable); } /** @@ -254,7 +266,7 @@ public class Search extends LinearLayout implements OnClickListener, OnKeyListen mSearchText.setOnKeyListener(this); mSearchText.addTextChangedListener(this); - mGoButton = (Button) findViewById(R.id.go); + mGoButton = (ImageButton) findViewById(R.id.search_go_btn); mGoButton.setOnClickListener(this); mGoButton.setOnKeyListener(this); @@ -296,8 +308,8 @@ public class Search extends LinearLayout implements OnClickListener, OnKeyListen // attach the suggestions adapter mSuggestionsAdapter = new SuggestionsAdapter(mContext, - com.android.internal.R.layout.search_dropdown_item_1line, null, - SuggestionsAdapter.ONE_LINE_FROM, SuggestionsAdapter.ONE_LINE_TO, mSearchable); + com.android.internal.R.layout.search_dropdown_item_2line, null, + SuggestionsAdapter.TWO_LINE_FROM, SuggestionsAdapter.TWO_LINE_TO, mSearchable); mSearchText.setAdapter(mSuggestionsAdapter); } @@ -432,10 +444,14 @@ public class Search extends LinearLayout implements OnClickListener, OnKeyListen /** * 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 + * two-line suggestions, but it does not support icons. */ private static class SuggestionsAdapter extends SimpleCursorAdapter { - public final static String[] ONE_LINE_FROM = { SearchManager.SUGGEST_COLUMN_TEXT_1 }; - public final static int[] ONE_LINE_TO = { com.android.internal.R.id.text1 }; + public final static String[] TWO_LINE_FROM = {SearchManager.SUGGEST_COLUMN_TEXT_1, + SearchManager.SUGGEST_COLUMN_TEXT_2 }; + public final static int[] TWO_LINE_TO = {com.android.internal.R.id.text1, + com.android.internal.R.id.text2}; private final String TAG = "SuggestionsAdapter"; diff --git a/src/com/android/launcher/UninstallShortcutReceiver.java b/src/com/android/launcher/UninstallShortcutReceiver.java index 2d7909e67..e490f9c0f 100644 --- a/src/com/android/launcher/UninstallShortcutReceiver.java +++ b/src/com/android/launcher/UninstallShortcutReceiver.java @@ -21,11 +21,10 @@ import android.content.Context; import android.content.Intent; import android.content.ContentResolver; import android.database.Cursor; +import android.net.Uri; import java.net.URISyntaxException; -import com.android.internal.provider.Settings; - public class UninstallShortcutReceiver extends BroadcastReceiver { public void onReceive(Context context, Intent data) { Intent intent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT); @@ -34,18 +33,23 @@ public class UninstallShortcutReceiver extends BroadcastReceiver { if (intent != null && name != null) { final ContentResolver cr = context.getContentResolver(); - Cursor c = cr.query(Settings.Favorites.CONTENT_URI, - new String[] { "_id", "intent" }, "title=?", new String[]{ name }, null); + Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI, + new String[] { LauncherSettings.Favorites.ID, LauncherSettings.Favorites.INTENT }, + LauncherSettings.Favorites.TITLE + "=?", new String[] { name }, null); + + final int intentIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.INTENT); + final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites._ID); - final int intentIndex = c.getColumnIndexOrThrow(Settings.Favorites.INTENT); - final int idIndex = c.getColumnIndexOrThrow(Settings.Favorites._ID); + boolean changed = false; try { while (c.moveToNext()) { try { if (intent.filterEquals(Intent.getIntent(c.getString(intentIndex)))) { final long id = c.getLong(idIndex); - cr.delete(Settings.Favorites.getContentUri(id, false), null, null); + final Uri uri = LauncherSettings.Favorites.getContentUri(id, false); + cr.delete(uri, null, null); + changed = true; if (!duplicate) { break; } @@ -58,7 +62,7 @@ public class UninstallShortcutReceiver extends BroadcastReceiver { c.close(); } - cr.notifyChange(Settings.Favorites.CONTENT_URI, null); + if (changed) cr.notifyChange(LauncherSettings.Favorites.CONTENT_URI, null); } } } diff --git a/src/com/android/launcher/UserFolder.java b/src/com/android/launcher/UserFolder.java index dee44baa0..1044e969f 100644 --- a/src/com/android/launcher/UserFolder.java +++ b/src/com/android/launcher/UserFolder.java @@ -1,7 +1,6 @@ package com.android.launcher; import android.content.Context; -import com.android.internal.provider.Settings; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; @@ -31,8 +30,8 @@ public class UserFolder extends Folder implements DropTarget { Object dragInfo) { final ItemInfo item = (ItemInfo) dragInfo; final int itemType = item.itemType; - return (itemType == Settings.Favorites.ITEM_TYPE_APPLICATION || - itemType == Settings.Favorites.ITEM_TYPE_SHORTCUT) && item.container != mInfo.id; + return (itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION || + itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) && item.container != mInfo.id; } public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset, Object dragInfo) { @@ -52,13 +51,6 @@ public class UserFolder extends Folder implements DropTarget { } @Override - public boolean onLongClick(View v) { - mLauncher.closeFolder(this); - mLauncher.showRenameDialog((UserFolderInfo) mInfo); - return true; - } - - @Override public void onDropCompleted(View target, boolean success) { if (success) { //noinspection unchecked @@ -68,10 +60,9 @@ public class UserFolder extends Folder implements DropTarget { } } - void bind(UserFolderInfo info) { - mInfo = info; - setContentAdapter(new ApplicationsAdapter(mContext, info.contents)); - mCloseButton.setText(info.title); + void bind(FolderInfo info) { + super.bind(info); + setContentAdapter(new ApplicationsAdapter(mContext, ((UserFolderInfo) info).contents)); } // When the folder opens, we need to refresh the GridView's selection by diff --git a/src/com/android/launcher/UserFolderInfo.java b/src/com/android/launcher/UserFolderInfo.java index 075b89a81..639894e59 100644 --- a/src/com/android/launcher/UserFolderInfo.java +++ b/src/com/android/launcher/UserFolderInfo.java @@ -17,7 +17,6 @@ package com.android.launcher; import android.content.ContentValues; -import com.android.internal.provider.Settings; import java.util.ArrayList; @@ -26,17 +25,12 @@ import java.util.ArrayList; */ class UserFolderInfo extends FolderInfo { /** - * The application name. - */ - CharSequence title; - - /** * The apps and shortcuts */ ArrayList<ApplicationInfo> contents = new ArrayList<ApplicationInfo>(); UserFolderInfo() { - itemType = Settings.Favorites.ITEM_TYPE_USER_FOLDER; + itemType = LauncherSettings.Favorites.ITEM_TYPE_USER_FOLDER; } /** @@ -60,6 +54,6 @@ class UserFolderInfo extends FolderInfo { @Override void onAddToDatabase(ContentValues values) { super.onAddToDatabase(values); - values.put(Settings.Favorites.TITLE, title.toString()); + values.put(LauncherSettings.Favorites.TITLE, title.toString()); } } diff --git a/src/com/android/launcher/Utilities.java b/src/com/android/launcher/Utilities.java index 23738974c..cb8976ca9 100644 --- a/src/com/android/launcher/Utilities.java +++ b/src/com/android/launcher/Utilities.java @@ -18,7 +18,6 @@ package com.android.launcher; import android.graphics.drawable.Drawable; import android.graphics.drawable.PaintDrawable; -import android.graphics.drawable.BitmapDrawable; import android.graphics.Bitmap; import android.graphics.PixelFormat; import android.graphics.Canvas; @@ -97,30 +96,46 @@ final class Utilities { painter.setIntrinsicHeight(height); } - if (width > 0 && height > 0 && (width < iconWidth || height < iconHeight)) { - final float ratio = (float) iconWidth / iconHeight; - - if (iconWidth > iconHeight) { - height = (int) (width / ratio); - } else if (iconHeight > iconWidth) { - width = (int) (height * ratio); + if (width > 0 && height > 0) { + if (width < iconWidth || height < iconHeight) { + final float ratio = (float) iconWidth / iconHeight; + + if (iconWidth > iconHeight) { + height = (int) (width / ratio); + } else if (iconHeight > iconWidth) { + width = (int) (height * ratio); + } + + final Bitmap.Config c = icon.getOpacity() != PixelFormat.OPAQUE ? + Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565; + final Bitmap thumb = Bitmap.createBitmap(sIconWidth, sIconHeight, c); + final Canvas canvas = sCanvas; + canvas.setBitmap(thumb); + // Copy the old bounds to restore them later + // If we were to do oldBounds = icon.getBounds(), + // the call to setBounds() that follows would + // change the same instance and we would lose the + // old bounds + sOldBounds.set(icon.getBounds()); + final int x = (sIconWidth - width) / 2; + final int y = (sIconHeight - height) / 2; + icon.setBounds(x, y, x + width, y + height); + icon.draw(canvas); + icon.setBounds(sOldBounds); + icon = new FastBitmapDrawable(thumb); + } else if (iconWidth < width && iconHeight < height) { + final Bitmap.Config c = Bitmap.Config.ARGB_8888; + final Bitmap thumb = Bitmap.createBitmap(sIconWidth, sIconHeight, c); + final Canvas canvas = sCanvas; + canvas.setBitmap(thumb); + sOldBounds.set(icon.getBounds()); + final int x = (width - iconWidth) / 2; + final int y = (height - iconHeight) / 2; + icon.setBounds(x, y, x + iconWidth, y + iconHeight); + icon.draw(canvas); + icon.setBounds(sOldBounds); + icon = new FastBitmapDrawable(thumb); } - - final Bitmap.Config c = icon.getOpacity() != PixelFormat.OPAQUE ? - Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565; - final Bitmap thumb = Bitmap.createBitmap(sIconWidth, sIconHeight, c); - final Canvas canvas = sCanvas; - canvas.setBitmap(thumb); - // Copy the old bounds to restore them later - // If we were to do oldBounds = icon.getBounds(), - // the call to setBounds() that follows would - // change the same instance and we would lose the - // old bounds - sOldBounds.set(icon.getBounds()); - icon.setBounds((sIconWidth - width) / 2, (sIconHeight - height) / 2, width, height); - icon.draw(canvas); - icon.setBounds(sOldBounds); - icon = new BitmapDrawable(thumb); } return icon; diff --git a/src/com/android/launcher/WallpaperChooser.java b/src/com/android/launcher/WallpaperChooser.java index 268b571db..a4e583e30 100644 --- a/src/com/android/launcher/WallpaperChooser.java +++ b/src/com/android/launcher/WallpaperChooser.java @@ -102,6 +102,7 @@ public class WallpaperChooser extends Activity implements AdapterView.OnItemSele mGallery = (Gallery) findViewById(R.id.gallery); mGallery.setAdapter(new ImageAdapter(this)); mGallery.setOnItemSelectedListener(this); + mGallery.setCallbackDuringFling(false); Button b = (Button) findViewById(R.id.set); b.setOnClickListener(this); diff --git a/src/com/android/launcher/Widget.java b/src/com/android/launcher/Widget.java index b9d8ae676..881252222 100644 --- a/src/com/android/launcher/Widget.java +++ b/src/com/android/launcher/Widget.java @@ -18,7 +18,6 @@ package com.android.launcher; import android.content.ContentValues; import android.graphics.Bitmap; -import com.android.internal.provider.Settings; /** * Represents one instance of a Launcher widget (clock, search, photo frame). @@ -31,7 +30,7 @@ class Widget extends ItemInfo { static Widget makeClock() { Widget w = new Widget(); - w.itemType = Settings.Favorites.ITEM_TYPE_WIDGET_CLOCK; + w.itemType = LauncherSettings.Favorites.ITEM_TYPE_WIDGET_CLOCK; w.spanX = 2; w.spanY = 2; w.layoutResource = R.layout.widget_clock; @@ -40,7 +39,7 @@ class Widget extends ItemInfo { static Widget makePhotoFrame() { Widget w = new Widget(); - w.itemType = Settings.Favorites.ITEM_TYPE_WIDGET_PHOTO_FRAME; + w.itemType = LauncherSettings.Favorites.ITEM_TYPE_WIDGET_PHOTO_FRAME; w.spanX = 2; w.spanY = 2; w.layoutResource = R.layout.widget_photo_frame; @@ -49,7 +48,7 @@ class Widget extends ItemInfo { static Widget makeSearch() { Widget w = new Widget(); - w.itemType = Settings.Favorites.ITEM_TYPE_WIDGET_SEARCH; + w.itemType = LauncherSettings.Favorites.ITEM_TYPE_WIDGET_SEARCH; w.spanX = 4; w.spanY = 1; w.layoutResource = R.layout.widget_search; diff --git a/src/com/android/launcher/Workspace.java b/src/com/android/launcher/Workspace.java index 73cff021e..0ca1b5af6 100644 --- a/src/com/android/launcher/Workspace.java +++ b/src/com/android/launcher/Workspace.java @@ -34,8 +34,6 @@ import android.widget.Scroller; import android.os.Parcelable; import android.os.Parcel; -import com.android.internal.provider.Settings; - import java.util.ArrayList; /** @@ -249,7 +247,7 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag * @param currentScreen */ void setCurrentScreen(int currentScreen) { - mCurrentScreen = Math.max(0, Math.min(currentScreen, getChildCount())); + mCurrentScreen = Math.max(0, Math.min(currentScreen, getChildCount() - 1)); scrollTo(mCurrentScreen * getWidth(), 0); invalidate(); } @@ -426,7 +424,7 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag mScrollY = mScroller.getCurrY(); postInvalidate(); } else if (mNextScreen != INVALID_SCREEN) { - mCurrentScreen = mNextScreen; + mCurrentScreen = Math.max(0, Math.min(mNextScreen, getChildCount() - 1)); Launcher.setScreen(mCurrentScreen); mNextScreen = INVALID_SCREEN; clearChildrenCache(); @@ -784,6 +782,7 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag void snapToScreen(int whichScreen) { enableChildrenCache(); + whichScreen = Math.max(0, Math.min(whichScreen, getChildCount() - 1)); boolean changingScreens = whichScreen != mCurrentScreen; mNextScreen = whichScreen; @@ -861,7 +860,7 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag final ItemInfo info = (ItemInfo)cell.getTag(); CellLayout.LayoutParams lp = (CellLayout.LayoutParams) cell.getLayoutParams(); LauncherModel.moveItemInDatabase(mLauncher, info, - Settings.Favorites.CONTAINER_DESKTOP, mCurrentScreen, lp.cellX, lp.cellY); + LauncherSettings.Favorites.CONTAINER_DESKTOP, mCurrentScreen, lp.cellX, lp.cellY); } } } @@ -885,8 +884,8 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag View view; switch (info.itemType) { - case Settings.Favorites.ITEM_TYPE_APPLICATION: - case Settings.Favorites.ITEM_TYPE_SHORTCUT: + case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION: + case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT: if (info.container == NO_ID) { // Came from all apps -- make a copy info = new ApplicationInfo((ApplicationInfo) info); @@ -894,7 +893,7 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag view = mLauncher.createShortcut(R.layout.application, cellLayout, (ApplicationInfo) info); break; - case Settings.Favorites.ITEM_TYPE_USER_FOLDER: + case LauncherSettings.Favorites.ITEM_TYPE_USER_FOLDER: view = FolderIcon.fromXml(R.layout.folder_icon, mLauncher, (ViewGroup) getChildAt(mCurrentScreen), ((UserFolderInfo) info)); break; @@ -910,7 +909,7 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag final LauncherModel model = Launcher.getModel(); model.addDesktopItem(info); LauncherModel.addOrMoveItemInDatabase(mLauncher, info, - Settings.Favorites.CONTAINER_DESKTOP, mCurrentScreen, lp.cellX, lp.cellY); + LauncherSettings.Favorites.CONTAINER_DESKTOP, mCurrentScreen, lp.cellX, lp.cellY); } public boolean acceptDrop(DragSource source, int x, int y, int xOffset, int yOffset, |