Merge commit 'korg/cupcake'

This commit is contained in:
The Android Open Source Project 2009-03-27 15:31:12 -07:00
commit 2e6a82faa9
64 changed files with 878 additions and 441 deletions

View File

@ -71,6 +71,7 @@
android:clearTaskOnLaunch="true"
android:stateNotNeeded="true"
android:theme="@style/Theme"
android:screenOrientation="nosensor"
android:windowSoftInputMode="stateUnspecified|adjustPan">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 859 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 651 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 954 B

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 982 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 646 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 958 B

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 962 B

After

Width:  |  Height:  |  Size: 833 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 196 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 419 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

View File

@ -66,7 +66,7 @@
android:layout_width="fill_parent"
android:layout_height="fill_parent"
launcher:texture="@drawable/texture_brushed_steel"
launcher:texture="@drawable/pattern_carbon_fiber_dark"
android:scrollbarStyle="outsideInset"
android:drawSelectorOnTop="false"

View File

@ -66,7 +66,7 @@
android:layout_width="fill_parent"
android:layout_height="fill_parent"
launcher:texture="@drawable/texture_brushed_steel"
launcher:texture="@drawable/pattern_carbon_fiber_dark"
android:scrollbarStyle="outsideInset"
android:drawSelectorOnTop="false"

View File

@ -1,29 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
** Copyright 2008, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/title"
android:layout_width="fill_parent"
android:layout_height="?android:attr/listPreferredItemHeight"
android:minHeight="?android:attr/listPreferredItemHeight"
android:textAppearance="?android:attr/textAppearanceLargeInverse"
android:gravity="center_vertical"
android:paddingRight="15dip"
android:paddingLeft="?android:attr/expandableListPreferredItemPaddingLeft" />

View File

@ -1,26 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
**
** Copyright 2008, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<ListView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_marginTop="5dip"
android:cacheColorHint="@null"
android:divider="@android:drawable/divider_horizontal_bright"
android:scrollbars="vertical" />

View File

@ -1,30 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
** Copyright 2008, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/title"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
android:textAppearance="?android:attr/textAppearanceLargeInverse"
android:gravity="center_vertical"
android:drawablePadding="14dip"
android:paddingLeft="?android:attr/expandableListPreferredChildPaddingLeft"
android:paddingRight="15dip" />

View File

@ -19,11 +19,13 @@
android:layout_height="fill_parent"
android:orientation="horizontal"
android:background="@drawable/search_bg"
android:gravity="center_vertical">
android:gravity="center_vertical"
>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingRight="3dip"
android:src="@drawable/google_logo" />
<com.android.launcher.SearchAutoCompleteTextView
@ -31,6 +33,7 @@
android:layout_width="0dip"
android:layout_weight="1"
android:layout_height="wrap_content"
android:layout_marginTop="1dip"
android:hint="@string/search_hint"
android:focusableInTouchMode="false"
android:singleLine="true"
@ -38,16 +41,18 @@
android:completionThreshold="1"
android:inputType="textAutoComplete"
android:imeOptions="actionSearch"
android:lines="1"
/>
<ImageButton android:id="@+id/search_go_btn"
android:layout_marginLeft="1dip"
android:layout_marginLeft="4dip"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@*android:drawable/ic_btn_search"
/>
<ImageButton android:id="@+id/search_voice_btn"
android:layout_marginLeft="2dip"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@android:drawable/ic_btn_speak_now"

View File

@ -54,6 +54,5 @@
<string name="permlab_write_settings">"zápis nastavení a odkazů plochy"</string>
<string name="permdesc_write_settings">"Povoluje aplikaci změnit nastavení a odkazy plochy."</string>
<string name="search_hint">"Vyhledávání Google"</string>
<!-- no translation found for gadget_error_text (8359351016167075858) -->
<skip />
<string name="gadget_error_text">"Problém s načtením widgetu"</string>
</resources>

View File

@ -54,6 +54,5 @@
<string name="permlab_write_settings">"Einstellungen und Shortcuts für Startseite schreiben"</string>
<string name="permdesc_write_settings">"Ermöglicht einer Anwendung, die Einstellungen und Shortcuts auf der Startseite zu ändern."</string>
<string name="search_hint">"Google-Suche"</string>
<!-- no translation found for gadget_error_text (8359351016167075858) -->
<skip />
<string name="gadget_error_text">"Problem beim Laden des Widgets"</string>
</resources>

View File

@ -54,6 +54,5 @@
<string name="permlab_write_settings">"escribir información de accesos directos y de configuración de la página principal"</string>
<string name="permdesc_write_settings">"Permite que una aplicación modifique la configuración y los accesos directos de la página principal."</string>
<string name="search_hint">"Búsqueda de Google"</string>
<!-- no translation found for gadget_error_text (8359351016167075858) -->
<skip />
<string name="gadget_error_text">"Problema al cargar el widget"</string>
</resources>

View File

@ -54,6 +54,5 @@
<string name="permlab_write_settings">"Enregistrer les paramètres de la page d\'accueil et des raccourcis"</string>
<string name="permdesc_write_settings">"Permet à une application de modifier les paramètres et les raccourcis de la page d\'accueil."</string>
<string name="search_hint">"Recherche Google"</string>
<!-- no translation found for gadget_error_text (8359351016167075858) -->
<skip />
<string name="gadget_error_text">"Problème lors du chargement du widget"</string>
</resources>

View File

@ -54,6 +54,5 @@
<string name="permlab_write_settings">"creare impostazioni e scorciatoie in Home"</string>
<string name="permdesc_write_settings">"Consente a un\'applicazione di modificare le impostazioni e le scorciatoie in Home."</string>
<string name="search_hint">"Ricerca Google"</string>
<!-- no translation found for gadget_error_text (8359351016167075858) -->
<skip />
<string name="gadget_error_text">"Errore durante il caricamento del widget"</string>
</resources>

View File

@ -26,20 +26,27 @@
<string name="rename_action">"OK"</string>
<string name="cancel_action">"キャンセル"</string>
<string name="menu_item_add_item">"ホーム画面に追加"</string>
<string name="group_applications">"アプリケーション"</string>
<string name="group_shortcuts">"ショートカット"</string>
<!-- no translation found for group_applications (4118484163419674240) -->
<skip />
<!-- no translation found for group_shortcuts (9133529424900391877) -->
<skip />
<string name="group_search">"検索"</string>
<string name="group_folder">"フォルダ"</string>
<string name="group_live_folders">"ライブフォルダ"</string>
<string name="group_widgets">"ウィジェット"</string>
<string name="group_wallpapers">"壁紙"</string>
<!-- no translation found for group_folder (5143593791798929193) -->
<skip />
<!-- no translation found for group_live_folders (2664945399140647217) -->
<skip />
<!-- no translation found for group_widgets (6704978494073105844) -->
<skip />
<!-- no translation found for group_wallpapers (1568191644272224858) -->
<skip />
<string name="add_folder">"フォルダ"</string>
<string name="add_clock">"時計"</string>
<string name="add_photo_frame">"写真フレーム"</string>
<string name="add_search">"検索"</string>
<string name="out_of_space">"ホーム画面に空きスペースがありません。"</string>
<string name="title_select_shortcut">"ショートカットを選択"</string>
<string name="title_select_live_folder">"ライブフォルダを選択"</string>
<!-- no translation found for title_select_live_folder (3753447798805166749) -->
<skip />
<string name="menu_add">"追加"</string>
<string name="menu_wallpaper">"壁紙"</string>
<string name="menu_search">"検索"</string>
@ -54,6 +61,5 @@
<string name="permlab_write_settings">"ホームの設定とショートカットの書き込み"</string>
<string name="permdesc_write_settings">"ホームの設定とショートカットの変更をアプリケーションに許可します。"</string>
<string name="search_hint">"Google検索"</string>
<!-- no translation found for gadget_error_text (8359351016167075858) -->
<skip />
<string name="gadget_error_text">"ウィジェットを表示できません"</string>
</resources>

View File

@ -54,6 +54,5 @@
<string name="permlab_write_settings">"홈 설정 및 바로가기 쓰기"</string>
<string name="permdesc_write_settings">"응용프로그램이 홈에 있는 설정 및 바로가기를 변경할 수 있습니다."</string>
<string name="search_hint">"Google 검색"</string>
<!-- no translation found for gadget_error_text (8359351016167075858) -->
<skip />
<string name="gadget_error_text">"위젯을 로드하는 중 문제가 발생했습니다."</string>
</resources>

View File

@ -54,6 +54,5 @@
<string name="permlab_write_settings">"skrive skrivebordsinnstillinger og -snarveier"</string>
<string name="permdesc_write_settings">"Lar applikasjonen endre innstillinger og snarveier på skrivebordet."</string>
<string name="search_hint">"Google-søk"</string>
<!-- no translation found for gadget_error_text (8359351016167075858) -->
<skip />
<string name="gadget_error_text">"Problem under lasting av gadget"</string>
</resources>

View File

@ -54,6 +54,5 @@
<string name="permlab_write_settings">"instellingen en snelkoppelingen voor de startpagina schrijven"</string>
<string name="permdesc_write_settings">"Hiermee kan een toepassing de instellingen en snelkoppelingen op de startpagina wijzigen."</string>
<string name="search_hint">"Google Zoeken"</string>
<!-- no translation found for gadget_error_text (8359351016167075858) -->
<skip />
<string name="gadget_error_text">"Probleem bij het laden van widget"</string>
</resources>

View File

@ -54,6 +54,5 @@
<string name="permlab_write_settings">"zapisywanie ustawień i skrótów strony głównej"</string>
<string name="permdesc_write_settings">"Umożliwia aplikacji zmianę ustawień i skrótów strony głównej."</string>
<string name="search_hint">"Szukaj w Google"</string>
<!-- no translation found for gadget_error_text (8359351016167075858) -->
<skip />
<string name="gadget_error_text">"Problem podczas ładowania widżetu"</string>
</resources>

View File

@ -54,6 +54,5 @@
<string name="permlab_write_settings">"записывать ярлыки и настройки главного экрана"</string>
<string name="permdesc_write_settings">"Позволяет приложению изменять настройки и ярлыки на главном экране."</string>
<string name="search_hint">"Поиск Google"</string>
<!-- no translation found for gadget_error_text (8359351016167075858) -->
<skip />
<string name="gadget_error_text">"Не удалось загрузить виджет"</string>
</resources>

View File

@ -54,6 +54,5 @@
<string name="permlab_write_settings">"写入“主页”设置和快捷键"</string>
<string name="permdesc_write_settings">"允许应用程序更改“主页”中的设置和快捷键。"</string>
<string name="search_hint">"Google 搜索"</string>
<!-- no translation found for gadget_error_text (8359351016167075858) -->
<skip />
<string name="gadget_error_text">"载入窗口小部件时出现问题"</string>
</resources>

View File

@ -54,6 +54,5 @@
<string name="permlab_write_settings">"寫入首頁設定和捷徑"</string>
<string name="permdesc_write_settings">"允許應用程式變更首頁中的設定和捷徑。"</string>
<string name="search_hint">"Google 搜尋"</string>
<!-- no translation found for gadget_error_text (8359351016167075858) -->
<skip />
<string name="gadget_error_text">"載入小工具時發生問題"</string>
</resources>

View File

@ -76,4 +76,12 @@
<attr name="texture" format="reference" />
</declare-styleable>
<!-- XML attributes used by default_workspace.xml -->
<declare-styleable name="Favorite">
<attr name="className" format="string" />
<attr name="packageName" format="string" />
<attr name="screen" format="string" />
<attr name="x" format="string" />
<attr name="y" format="string" />
</declare-styleable>
</resources>

View File

@ -49,19 +49,19 @@
<!-- Title of dialog box -->
<string name="menu_item_add_item">Add to Home screen</string>
<!-- Options in "Add to Home" dialog box; Title of the group containing the list of all apps -->
<string name="group_applications">Application</string>
<string name="group_applications">Applications</string>
<!-- Options in "Add to Home" dialog box; Title of the group containing the list of all shortcuts -->
<string name="group_shortcuts">Shortcut</string>
<string name="group_shortcuts">Shortcuts</string>
<!-- Options in "Add to Home" dialog box; Title of the search gadget -->
<string name="group_search">Search</string>
<!-- Options in "Add to Home" dialog box; Title of the folder gadget -->
<string name="group_folder">Folder</string>
<string name="group_folder">New folder</string>
<!-- Options in "Add to Home" dialog box; Title of the group containing the list of all live folders -->
<string name="group_live_folders">Live folder</string>
<string name="group_live_folders">Folders</string>
<!-- Options in "Add to Home" dialog box; Title of the group containing the list of all widgets/gadgets -->
<string name="group_widgets">Widget</string>
<string name="group_widgets">Widgets</string>
<!-- Options in "Add to Home" dialog box; Title of the group containing the list of apps that can set the wallpaper-->
<string name="group_wallpapers">Wallpaper</string>
<string name="group_wallpapers">Wallpapers</string>
<!-- Options in "Add to Home" dialog box; Name of the Folder widget-->
<string name="add_folder">Folder</string>
<!-- Options in "Add to Home" dialog box; Name of the Clock widget-->
@ -76,7 +76,7 @@
<!-- Title of dialog when user is selecting shortcut to add to homescreen -->
<string name="title_select_shortcut">Select shortcut</string>
<!-- Title of dialog when user is selecting live folder to add to homescreen -->
<string name="title_select_live_folder">Select live folder</string>
<string name="title_select_live_folder">Select folder</string>
<!-- Menus items: -->
<skip />

View File

@ -0,0 +1,71 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2009 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<favorites xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher">
<clock
launcher:screen="1"
launcher:x="1"
launcher:y="0" />
<search
launcher:screen="2"
launcher:x="0"
launcher:y="0" />
<favorite
launcher:packageName="com.android.contacts"
launcher:className="com.android.contacts.DialtactsActivity"
launcher:screen="1"
launcher:x="0"
launcher:y="3" />
<favorite
launcher:packageName="com.android.contacts"
launcher:className="com.android.contacts.DialtactsContactsEntryActivity"
launcher:screen="1"
launcher:x="1"
launcher:y="3" />
<favorite
launcher:packageName="com.android.browser"
launcher:className="com.android.browser.BrowserActivity"
launcher:screen="1"
launcher:x="2"
launcher:y="3" />
<favorite
launcher:packageName="com.google.android.apps.maps"
launcher:className="com.google.android.maps.MapsActivity"
launcher:screen="1"
launcher:x="3"
launcher:y="3" />
<favorite
launcher:packageName="com.android.mms"
launcher:className="com.android.mms.ui.ConversationList"
launcher:screen="1"
launcher:x="0"
launcher:y="2" />
<favorite
launcher:packageName="com.android.vending"
launcher:className="com.android.vending.AssetBrowserActivity"
launcher:screen="1"
launcher:x="3"
launcher:y="2" />
</favorites>

View File

@ -31,19 +31,15 @@ import java.util.ArrayList;
* Adapter showing the types of items that can be added to a {@link Workspace}.
*/
public class AddAdapter extends BaseAdapter {
private final Launcher mLauncher;
private final LayoutInflater mInflater;
private final ArrayList<ListItem> mItems = new ArrayList<ListItem>();
public static final int ITEM_APPLICATION = 0;
public static final int ITEM_SHORTCUT = 1;
public static final int ITEM_SEARCH = 2;
public static final int ITEM_APPWIDGET = 3;
public static final int ITEM_LIVE_FOLDER = 4;
public static final int ITEM_FOLDER = 5;
public static final int ITEM_WALLPAPER = 6;
public static final int ITEM_SHORTCUT = 0;
public static final int ITEM_APPWIDGET = 1;
public static final int ITEM_LIVE_FOLDER = 2;
public static final int ITEM_WALLPAPER = 3;
/**
* Specific item in our list.
@ -66,30 +62,20 @@ public class AddAdapter extends BaseAdapter {
public AddAdapter(Launcher launcher) {
super();
mLauncher = launcher;
mInflater = (LayoutInflater) mLauncher.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mInflater = (LayoutInflater) launcher.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
// Create default actions
Resources res = launcher.getResources();
mItems.add(new ListItem(res, R.string.group_applications,
R.drawable.ic_launcher_application, ITEM_APPLICATION));
mItems.add(new ListItem(res, R.string.group_shortcuts,
R.drawable.ic_launcher_empty, ITEM_SHORTCUT));
mItems.add(new ListItem(res, R.string.group_search,
R.drawable.ic_search_widget, ITEM_SEARCH));
R.drawable.ic_launcher_shortcut, ITEM_SHORTCUT));
mItems.add(new ListItem(res, R.string.group_widgets,
R.drawable.ic_launcher_appwidget, ITEM_APPWIDGET));
mItems.add(new ListItem(res, R.string.group_live_folders,
R.drawable.ic_launcher_empty, ITEM_LIVE_FOLDER));
mItems.add(new ListItem(res, R.string.group_folder,
R.drawable.ic_launcher_folder, ITEM_FOLDER));
R.drawable.ic_launcher_folder_live, ITEM_LIVE_FOLDER));
mItems.add(new ListItem(res, R.string.group_wallpapers,
R.drawable.ic_launcher_gallery, ITEM_WALLPAPER));

View File

@ -31,6 +31,7 @@ import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.Intent.ShortcutIconResource;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
@ -46,6 +47,8 @@ import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.MessageQueue;
import android.os.Parcelable;
import android.os.RemoteException;
import android.os.ServiceManager;
@ -57,20 +60,17 @@ import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import android.text.method.TextKeyListener;
import android.util.Log;
import static android.util.Log.*;
import android.view.Display;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.View.OnLongClickListener;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.GridView;
@ -81,6 +81,7 @@ import android.appwidget.AppWidgetProviderInfo;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.LinkedList;
/**
* Default launcher application.
@ -91,6 +92,7 @@ public final class Launcher extends Activity implements View.OnClickListener, On
private static final boolean PROFILE_STARTUP = false;
private static final boolean PROFILE_DRAWER = false;
private static final boolean PROFILE_ROTATE = false;
private static final boolean DEBUG_USER_INTERFACE = false;
private static final int WALLPAPER_SCREENS_SPAN = 2;
@ -112,6 +114,9 @@ public final class Launcher extends Activity implements View.OnClickListener, On
static final String EXTRA_SHORTCUT_DUPLICATE = "duplicate";
static final String EXTRA_CUSTOM_WIDGET = "custom_widget";
static final String SEARCH_WIDGET = "search_widget";
static final int SCREEN_COUNT = 3;
static final int DEFAULT_SCREN = 1;
static final int NUMBER_CELLS_X = 4;
@ -197,6 +202,8 @@ public final class Launcher extends Activity implements View.OnClickListener, On
private Bundle mSavedInstanceState;
private DesktopBinder mBinder;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@ -352,6 +359,19 @@ public final class Launcher extends Activity implements View.OnClickListener, On
super.onPause();
closeDrawer(false);
}
@Override
public Object onRetainNonConfigurationInstance() {
// Flag any binder to stop early before switching
if (mBinder != null) {
mBinder.mTerminate = true;
}
if (PROFILE_ROTATE) {
android.os.Debug.startMethodTracing("/sdcard/launcher-rotate");
}
return null;
}
private boolean acceptFilter() {
final InputMethodManager inputManager = (InputMethodManager)
@ -385,7 +405,8 @@ public final class Launcher extends Activity implements View.OnClickListener, On
intent.putExtra(Contacts.Intents.UI.FILTER_TEXT_EXTRA_KEY, str);
}
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
try {
startActivity(intent);
@ -603,7 +624,7 @@ public final class Launcher extends Activity implements View.OnClickListener, On
Bundle extras = data.getExtras();
int appWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);
Log.d(LOG_TAG, "dumping extras content="+extras.toString());
d(LOG_TAG, "dumping extras content="+extras.toString());
AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
@ -671,7 +692,7 @@ public final class Launcher extends Activity implements View.OnClickListener, On
final int id = resources.getIdentifier(iconResource.resourceName, null, null);
icon = resources.getDrawable(id);
} catch (Exception e) {
Log.w(LOG_TAG, "Could not load shortcut icon: " + extra);
w(LOG_TAG, "Could not load shortcut icon: " + extra);
}
}
}
@ -794,7 +815,7 @@ public final class Launcher extends Activity implements View.OnClickListener, On
try {
mAppWidgetHost.stopListening();
} catch (NullPointerException ex) {
Log.w(LOG_TAG, "problem while stopping AppWidgetHost during Launcher destruction", ex);
w(LOG_TAG, "problem while stopping AppWidgetHost during Launcher destruction", ex);
}
TextKeyListener.getInstance().release();
@ -903,21 +924,36 @@ public final class Launcher extends Activity implements View.OnClickListener, On
}
}
private void updateShortcutsForPackage(String packageName) {
if (packageName != null && packageName.length() > 0) {
mWorkspace.updateShortcutsForPackage(packageName);
}
}
void addAppWidget(Intent data) {
// TODO: catch bad widget exception when sent
int appWidgetId = data.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);
AppWidgetProviderInfo appWidget = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
if (appWidget.configure != null) {
// Launch over to configure widget, if needed
Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_CONFIGURE);
intent.setComponent(appWidget.configure);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
startActivityForResult(intent, REQUEST_CREATE_APPWIDGET);
String customWidget = data.getStringExtra(EXTRA_CUSTOM_WIDGET);
if (SEARCH_WIDGET.equals(customWidget)) {
// We don't need this any more, since this isn't a real app widget.
mAppWidgetHost.deleteAppWidgetId(appWidgetId);
// add the search widget
addSearch();
} else {
// Otherwise just add it
onActivityResult(REQUEST_CREATE_APPWIDGET, Activity.RESULT_OK, data);
AppWidgetProviderInfo appWidget = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
if (appWidget.configure != null) {
// Launch over to configure widget, if needed
Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_CONFIGURE);
intent.setComponent(appWidget.configure);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
startActivityForResult(intent, REQUEST_CREATE_APPWIDGET);
} else {
// Otherwise just add it
onActivityResult(REQUEST_CREATE_APPWIDGET, Activity.RESULT_OK, data);
}
}
}
@ -942,11 +978,32 @@ public final class Launcher extends Activity implements View.OnClickListener, On
}
void addShortcut(Intent intent) {
startActivityForResult(intent, REQUEST_CREATE_SHORTCUT);
// Handle case where user selected "Applications"
String applicationName = getResources().getString(R.string.group_applications);
String shortcutName = intent.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);
if (applicationName != null && applicationName.equals(shortcutName)) {
Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
Intent pickIntent = new Intent(Intent.ACTION_PICK_ACTIVITY);
pickIntent.putExtra(Intent.EXTRA_INTENT, mainIntent);
startActivityForResult(pickIntent, REQUEST_PICK_APPLICATION);
} else {
startActivityForResult(intent, REQUEST_CREATE_SHORTCUT);
}
}
void addLiveFolder(Intent intent) {
startActivityForResult(intent, REQUEST_CREATE_LIVE_FOLDER);
// Handle case where user selected "Folder"
String folderName = getResources().getString(R.string.group_folder);
String shortcutName = intent.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);
if (folderName != null && folderName.equals(shortcutName)) {
addFolder(!mDesktopLocked);
} else {
startActivityForResult(intent, REQUEST_CREATE_LIVE_FOLDER);
}
}
void addFolder(boolean insertAtFirst) {
@ -1008,7 +1065,7 @@ public final class Launcher extends Activity implements View.OnClickListener, On
final int id = resources.getIdentifier(iconResource.resourceName, null, null);
icon = resources.getDrawable(id);
} catch (Exception e) {
Log.w(LOG_TAG, "Could not load live folder icon: " + extra);
w(LOG_TAG, "Could not load live folder icon: " + extra);
}
}
@ -1107,8 +1164,11 @@ public final class Launcher extends Activity implements View.OnClickListener, On
switch (event.getKeyCode()) {
case KeyEvent.KEYCODE_BACK:
mWorkspace.dispatchKeyEvent(event);
closeFolder();
closeDrawer();
if (mDrawer.isOpened()) {
closeDrawer();
} else {
closeFolder();
}
return true;
case KeyEvent.KEYCODE_HOME:
return true;
@ -1163,21 +1223,22 @@ public final class Launcher extends Activity implements View.OnClickListener, On
void onDesktopItemsLoaded() {
if (mDestroyed) return;
android.util.Log.d("Home", "setting grid adapter");
mAllAppsGrid.setAdapter(sModel.getApplicationsAdapter());
bindDesktopItems();
}
/**
* Refreshes the shortcuts shown on the workspace.
*/
private void bindDesktopItems() {
final ArrayList<ItemInfo> shortcuts = sModel.getDesktopItems();
final ArrayList<LauncherAppWidgetInfo> appWidgets = sModel.getDesktopAppWidgets();
if (shortcuts == null || appWidgets == null) {
final ApplicationsAdapter drawerAdapter = sModel.getApplicationsAdapter();
if (shortcuts == null || appWidgets == null || drawerAdapter == null) {
return;
}
mAllAppsGrid.setAdapter(drawerAdapter);
final Workspace workspace = mWorkspace;
int count = workspace.getChildCount();
for (int i = 0; i < count; i++) {
@ -1195,9 +1256,14 @@ android.util.Log.d("Home", "setting grid adapter");
}
});
}
final DesktopBinder binder = new DesktopBinder(this, shortcuts, appWidgets);
binder.startBindingItems();
// Flag any old binder to terminate early
if (mBinder != null) {
mBinder.mTerminate = true;
}
mBinder = new DesktopBinder(this, shortcuts, appWidgets);
mBinder.startBindingItems();
}
private void bindItems(Launcher.DesktopBinder binder,
@ -1250,7 +1316,7 @@ android.util.Log.d("Home", "setting grid adapter");
if (end >= count) {
finishBindDesktopItems();
binder.startBindingAppWidgets();
binder.startBindingAppWidgetsWhenIdle();
} else {
binder.obtainMessage(DesktopBinder.MESSAGE_BIND_ITEMS, i, count).sendToTarget();
}
@ -1296,44 +1362,44 @@ android.util.Log.d("Home", "setting grid adapter");
mDesktopLocked = false;
mDrawer.unlock();
}
private void bindAppWidgets(Launcher.DesktopBinder binder,
ArrayList<LauncherAppWidgetInfo> appWidgets, int start, int count) {
LinkedList<LauncherAppWidgetInfo> appWidgets) {
final Workspace workspace = mWorkspace;
final boolean desktopLocked = mDesktopLocked;
final int end = Math.min(start + DesktopBinder.APPWIDGETS_COUNT, count);
int i = start;
for ( ; i < end; i++) {
final LauncherAppWidgetInfo item = appWidgets.get(i);
if (!appWidgets.isEmpty()) {
final LauncherAppWidgetInfo item = appWidgets.removeFirst();
final int appWidgetId = item.appWidgetId;
final AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
final AppWidgetProviderInfo appWidgetInfo =
mAppWidgetManager.getAppWidgetInfo(appWidgetId);
item.hostView = mAppWidgetHost.createView(this, appWidgetId, appWidgetInfo);
if (LOGD) Log.d(LOG_TAG, String.format("about to setAppWidget for id=%d, info=%s", appWidgetId, appWidgetInfo));
if (LOGD) {
d(LOG_TAG, String.format("about to setAppWidget for id=%d, info=%s",
appWidgetId, appWidgetInfo));
}
item.hostView.setAppWidget(appWidgetId, appWidgetInfo);
item.hostView.setTag(item);
workspace.addInScreen(item.hostView, item.screen, item.cellX,
item.cellY, item.spanX, item.spanY, !desktopLocked);
workspace.requestLayout();
}
workspace.requestLayout();
if (end >= count) {
finishBindDesktopAppWidgets();
if (appWidgets.isEmpty()) {
if (PROFILE_ROTATE) {
android.os.Debug.stopMethodTracing();
}
} else {
binder.obtainMessage(DesktopBinder.MESSAGE_BIND_APPWIDGETS, i, count).sendToTarget();
binder.obtainMessage(DesktopBinder.MESSAGE_BIND_APPWIDGETS).sendToTarget();
}
}
private void finishBindDesktopAppWidgets() {
}
DragController getDragController() {
return mDragLayer;
}
@ -1623,11 +1689,10 @@ android.util.Log.d("Home", "setting grid adapter");
* Displays the shortcut creation dialog and launches, if necessary, the
* appropriate activity.
*/
private class CreateShortcut implements AdapterView.OnItemClickListener,
private class CreateShortcut implements DialogInterface.OnClickListener,
DialogInterface.OnCancelListener {
private AddAdapter mAdapter;
private ListView mList;
Dialog createDialog() {
mWaitingForResult = true;
@ -1635,22 +1700,13 @@ android.util.Log.d("Home", "setting grid adapter");
final AlertDialog.Builder builder = new AlertDialog.Builder(Launcher.this);
builder.setTitle(getString(R.string.menu_item_add_item));
builder.setIcon(0);
mList = (ListView)
View.inflate(Launcher.this, R.layout.create_shortcut_list, null);
mList.setAdapter(mAdapter);
mList.setOnItemClickListener(this);
builder.setView(mList);
builder.setAdapter(mAdapter, this);
builder.setInverseBackgroundForced(true);
AlertDialog dialog = builder.create();
dialog.setOnCancelListener(this);
WindowManager.LayoutParams attributes = dialog.getWindow().getAttributes();
attributes.gravity = Gravity.TOP;
dialog.onWindowAttributesChanged(attributes);
return dialog;
}
@ -1664,74 +1720,94 @@ android.util.Log.d("Home", "setting grid adapter");
dismissDialog(DIALOG_CREATE_SHORTCUT);
}
public void onItemClick(AdapterView parent, View view, int position, long id) {
// handle which item was clicked based on position
// this will launch off pick intent
/**
* Handle the action clicked in the "Add to home" dialog.
*/
public void onClick(DialogInterface dialog, int which) {
Resources res = getResources();
cleanup();
Object tag = view.getTag();
if (tag instanceof AddAdapter.ListItem) {
AddAdapter.ListItem item = (AddAdapter.ListItem) tag;
cleanup();
switch (item.actionTag) {
case AddAdapter.ITEM_APPLICATION: {
Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
Intent pickIntent = new Intent(Intent.ACTION_PICK_ACTIVITY);
pickIntent.putExtra(Intent.EXTRA_INTENT, mainIntent);
startActivityForResult(pickIntent, REQUEST_PICK_APPLICATION);
break;
}
case AddAdapter.ITEM_SHORTCUT: {
Intent shortcutIntent = new Intent(Intent.ACTION_CREATE_SHORTCUT);
Intent pickIntent = new Intent(Intent.ACTION_PICK_ACTIVITY);
pickIntent.putExtra(Intent.EXTRA_INTENT, shortcutIntent);
pickIntent.putExtra(Intent.EXTRA_TITLE,
getText(R.string.title_select_shortcut));
startActivityForResult(pickIntent, REQUEST_PICK_SHORTCUT);
break;
}
switch (which) {
case AddAdapter.ITEM_SHORTCUT: {
// Insert extra item to handle picking application
Bundle bundle = new Bundle();
case AddAdapter.ITEM_SEARCH: {
addSearch();
break;
}
ArrayList<String> shortcutNames = new ArrayList<String>();
shortcutNames.add(res.getString(R.string.group_applications));
bundle.putStringArrayList(Intent.EXTRA_SHORTCUT_NAME, shortcutNames);
case AddAdapter.ITEM_APPWIDGET: {
int appWidgetId = Launcher.this.mAppWidgetHost.allocateAppWidgetId();
Intent pickIntent = new Intent(AppWidgetManager.ACTION_APPWIDGET_PICK);
pickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
startActivityForResult(pickIntent, REQUEST_PICK_APPWIDGET);
break;
}
ArrayList<ShortcutIconResource> shortcutIcons =
new ArrayList<ShortcutIconResource>();
shortcutIcons.add(ShortcutIconResource.fromContext(Launcher.this,
R.drawable.ic_launcher_application));
bundle.putParcelableArrayList(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, shortcutIcons);
case AddAdapter.ITEM_LIVE_FOLDER: {
Intent liveFolderIntent = new Intent(LiveFolders.ACTION_CREATE_LIVE_FOLDER);
Intent pickIntent = new Intent(Intent.ACTION_PICK_ACTIVITY);
pickIntent.putExtra(Intent.EXTRA_INTENT, liveFolderIntent);
pickIntent.putExtra(Intent.EXTRA_TITLE,
getText(R.string.title_select_live_folder));
startActivityForResult(pickIntent, REQUEST_PICK_LIVE_FOLDER);
break;
}
case AddAdapter.ITEM_FOLDER: {
addFolder(!mDesktopLocked);
dismissDialog(DIALOG_CREATE_SHORTCUT);
break;
}
case AddAdapter.ITEM_WALLPAPER: {
startWallpaper();
break;
}
}
Intent pickIntent = new Intent(Intent.ACTION_PICK_ACTIVITY);
pickIntent.putExtra(Intent.EXTRA_INTENT,
new Intent(Intent.ACTION_CREATE_SHORTCUT));
pickIntent.putExtra(Intent.EXTRA_TITLE,
getText(R.string.title_select_shortcut));
pickIntent.putExtras(bundle);
startActivityForResult(pickIntent, REQUEST_PICK_SHORTCUT);
break;
}
case AddAdapter.ITEM_APPWIDGET: {
int appWidgetId = Launcher.this.mAppWidgetHost.allocateAppWidgetId();
Intent pickIntent = new Intent(AppWidgetManager.ACTION_APPWIDGET_PICK);
pickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
// add the search widget
ArrayList<AppWidgetProviderInfo> customInfo =
new ArrayList<AppWidgetProviderInfo>();
AppWidgetProviderInfo info = new AppWidgetProviderInfo();
info.provider = new ComponentName(getPackageName(), "XXX.YYY");
info.label = getString(R.string.group_search);
info.icon = R.drawable.ic_search_widget;
customInfo.add(info);
pickIntent.putParcelableArrayListExtra(
AppWidgetManager.EXTRA_CUSTOM_INFO, customInfo);
ArrayList<Bundle> customExtras = new ArrayList<Bundle>();
Bundle b = new Bundle();
b.putString(EXTRA_CUSTOM_WIDGET, SEARCH_WIDGET);
customExtras.add(b);
pickIntent.putParcelableArrayListExtra(
AppWidgetManager.EXTRA_CUSTOM_EXTRAS, customExtras);
// start the pick activity
startActivityForResult(pickIntent, REQUEST_PICK_APPWIDGET);
break;
}
case AddAdapter.ITEM_LIVE_FOLDER: {
// Insert extra item to handle inserting folder
Bundle bundle = new Bundle();
ArrayList<String> shortcutNames = new ArrayList<String>();
shortcutNames.add(res.getString(R.string.group_folder));
bundle.putStringArrayList(Intent.EXTRA_SHORTCUT_NAME, shortcutNames);
ArrayList<ShortcutIconResource> shortcutIcons =
new ArrayList<ShortcutIconResource>();
shortcutIcons.add(ShortcutIconResource.fromContext(Launcher.this,
R.drawable.ic_launcher_folder));
bundle.putParcelableArrayList(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, shortcutIcons);
Intent pickIntent = new Intent(Intent.ACTION_PICK_ACTIVITY);
pickIntent.putExtra(Intent.EXTRA_INTENT,
new Intent(LiveFolders.ACTION_CREATE_LIVE_FOLDER));
pickIntent.putExtra(Intent.EXTRA_TITLE,
getText(R.string.title_select_live_folder));
pickIntent.putExtras(bundle);
startActivityForResult(pickIntent, REQUEST_PICK_LIVE_FOLDER);
break;
}
case AddAdapter.ITEM_WALLPAPER: {
startWallpaper();
break;
}
}
}
}
@ -1742,23 +1818,47 @@ android.util.Log.d("Home", "setting grid adapter");
private class ApplicationsIntentReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
boolean reloadWorkspace = false;
android.util.Log.d("Home", "application intent received: " + intent.getAction());
android.util.Log.d("Home", " --> " + intent.getData());
if (Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())) {
if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
removeShortcutsForPackage(intent.getData().getSchemeSpecificPart());
} else {
reloadWorkspace = true;
}
final String action = intent.getAction();
final String packageName = intent.getData().getSchemeSpecificPart();
final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
if (LauncherModel.DEBUG_LOADERS) {
d(LauncherModel.LOG_TAG, "application intent received: " + action +
", replacing=" + replacing);
d(LauncherModel.LOG_TAG, " --> " + intent.getData());
}
removeDialog(DIALOG_CREATE_SHORTCUT);
if (!reloadWorkspace) {
android.util.Log.d("Home", " --> loading apps");
sModel.loadApplications(false, Launcher.this, false);
if (!Intent.ACTION_PACKAGE_CHANGED.equals(action)) {
if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
if (!replacing) {
removeShortcutsForPackage(packageName);
if (LauncherModel.DEBUG_LOADERS) {
d(LauncherModel.LOG_TAG, " --> remove package");
}
sModel.removePackage(Launcher.this, packageName);
}
// else, we are replacing the package, so a PACKAGE_ADDED will be sent
// later, we will update the package at this time
} else {
if (!replacing) {
if (LauncherModel.DEBUG_LOADERS) {
d(LauncherModel.LOG_TAG, " --> add package");
}
sModel.addPackage(Launcher.this, packageName);
} else {
if (LauncherModel.DEBUG_LOADERS) {
d(LauncherModel.LOG_TAG, " --> update package " + packageName);
}
sModel.updatePackage(Launcher.this, packageName);
updateShortcutsForPackage(packageName);
}
}
removeDialog(DIALOG_CREATE_SHORTCUT);
} else {
android.util.Log.d("Home", " --> loading workspace");
sModel.loadUserItems(false, Launcher.this, false, true);
if (LauncherModel.DEBUG_LOADERS) {
d(LauncherModel.LOG_TAG, " --> sync package " + packageName);
}
sModel.syncPackage(Launcher.this, packageName);
}
}
}
@ -1865,37 +1965,64 @@ android.util.Log.d("Home", " --> loading workspace");
}
}
private static class DesktopBinder extends Handler {
private static class DesktopBinder extends Handler implements MessageQueue.IdleHandler {
static final int MESSAGE_BIND_ITEMS = 0x1;
static final int MESSAGE_BIND_APPWIDGETS = 0x2;
// Number of items to bind in every pass
static final int ITEMS_COUNT = 6;
static final int APPWIDGETS_COUNT = 1;
private final ArrayList<ItemInfo> mShortcuts;
private final ArrayList<LauncherAppWidgetInfo> mAppWidgets;
private final LinkedList<LauncherAppWidgetInfo> mAppWidgets;
private final WeakReference<Launcher> mLauncher;
public volatile boolean mTerminate = false;
DesktopBinder(Launcher launcher, ArrayList<ItemInfo> shortcuts,
ArrayList<LauncherAppWidgetInfo> appWidgets) {
mLauncher = new WeakReference<Launcher>(launcher);
mShortcuts = shortcuts;
mAppWidgets = appWidgets;
// Sort widgets so active workspace is bound first
final int currentScreen = launcher.mWorkspace.getCurrentScreen();
final int size = appWidgets.size();
mAppWidgets = new LinkedList<LauncherAppWidgetInfo>();
for (int i = 0; i < size; i++) {
LauncherAppWidgetInfo appWidgetInfo = appWidgets.get(i);
if (appWidgetInfo.screen == currentScreen) {
mAppWidgets.addFirst(appWidgetInfo);
} else {
mAppWidgets.addLast(appWidgetInfo);
}
}
}
public void startBindingItems() {
obtainMessage(MESSAGE_BIND_ITEMS, 0, mShortcuts.size()).sendToTarget();
}
public void startBindingAppWidgets() {
obtainMessage(MESSAGE_BIND_APPWIDGETS, 0, mAppWidgets.size()).sendToTarget();
public void startBindingAppWidgetsWhenIdle() {
// Ask for notification when message queue becomes idle
final MessageQueue messageQueue = Looper.myQueue();
messageQueue.addIdleHandler(this);
}
public boolean queueIdle() {
// Queue is idle, so start binding items
startBindingAppWidgets();
return false;
}
public void startBindingAppWidgets() {
obtainMessage(MESSAGE_BIND_APPWIDGETS).sendToTarget();
}
@Override
public void handleMessage(Message msg) {
Launcher launcher = mLauncher.get();
if (launcher == null) {
if (launcher == null || mTerminate) {
return;
}
@ -1905,7 +2032,7 @@ android.util.Log.d("Home", " --> loading workspace");
break;
}
case MESSAGE_BIND_APPWIDGETS: {
launcher.bindAppWidgets(this, mAppWidgets, msg.arg1, msg.arg2);
launcher.bindAppWidgets(this, mAppWidgets);
break;
}
}

View File

@ -28,8 +28,9 @@ import android.content.res.Resources;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.util.Log;
import static android.util.Log.*;
import android.os.Process;
import java.util.ArrayList;
@ -46,13 +47,14 @@ import java.net.URISyntaxException;
* for the Launcher.
*/
public class LauncherModel {
static final boolean DEBUG_LOADERS = true;
static final String LOG_TAG = "HomeLoaders";
private static final int UI_NOTIFICATION_RATE = 4;
private static final int DEFAULT_APPLICATIONS_NUMBER = 42;
private static final long APPLICATION_NOT_RESPONDING_TIMEOUT = 5000;
private static final int INITIAL_ICON_CACHE_CAPACITY = 50;
private static final boolean DEBUG = false;
private static final Collator sCollator = Collator.getInstance();
private boolean mApplicationsLoaded;
@ -101,14 +103,16 @@ public class LauncherModel {
*/
synchronized boolean loadApplications(boolean isLaunching, Launcher launcher,
boolean localeChanged) {
android.util.Log.d("Home", "load applications");
if (DEBUG_LOADERS) d(LOG_TAG, "load applications");
if (isLaunching && mApplicationsLoaded && !localeChanged) {
mApplicationsAdapter = new ApplicationsAdapter(launcher, mApplications);
android.util.Log.d("Home", " --> applications loaded, return");
if (DEBUG_LOADERS) d(LOG_TAG, " --> applications loaded, return");
return false;
}
waitForApplicationsLoader();
stopAndWaitForApplicationsLoader();
if (localeChanged) {
dropApplicationCache();
@ -129,9 +133,9 @@ android.util.Log.d("Home", " --> applications loaded, return");
return true;
}
private synchronized void waitForApplicationsLoader() {
private synchronized void stopAndWaitForApplicationsLoader() {
if (mApplicationsLoader != null && mApplicationsLoader.isRunning()) {
android.util.Log.d("Home", " --> wait for applications loader");
if (DEBUG_LOADERS) d(LOG_TAG, " --> wait for applications loader");
mApplicationsLoader.stop();
// Wait for the currently running thread to finish, this can take a little
@ -145,14 +149,310 @@ android.util.Log.d("Home", " --> applications loaded, return");
}
private synchronized void startApplicationsLoader(Launcher launcher) {
android.util.Log.d("Home", " --> starting applications loader");
waitForApplicationsLoader();
if (DEBUG_LOADERS) d(LOG_TAG, " --> starting applications loader");
stopAndWaitForApplicationsLoader();
mApplicationsLoader = new ApplicationsLoader(launcher);
mApplicationsLoaderThread = new Thread(mApplicationsLoader, "Applications Loader");
mApplicationsLoaderThread.start();
}
synchronized void addPackage(Launcher launcher, String packageName) {
if (mApplicationsLoader != null && mApplicationsLoader.isRunning()) {
startApplicationsLoader(launcher);
return;
}
if (packageName != null && packageName.length() > 0) {
final PackageManager packageManager = launcher.getPackageManager();
final List<ResolveInfo> matches = findActivitiesForPackage(packageManager, packageName);
if (matches.size() > 0) {
final ApplicationsAdapter adapter = mApplicationsAdapter;
final HashMap<ComponentName, ApplicationInfo> cache = mAppInfoCache;
for (ResolveInfo info : matches) {
adapter.setNotifyOnChange(false);
adapter.add(makeAndCacheApplicationInfo(packageManager, cache, info));
}
adapter.sort(new ApplicationInfoComparator());
adapter.notifyDataSetChanged();
}
}
}
synchronized void removePackage(Launcher launcher, String packageName) {
if (mApplicationsLoader != null && mApplicationsLoader.isRunning()) {
dropApplicationCache(); // TODO: this could be optimized
startApplicationsLoader(launcher);
return;
}
if (packageName != null && packageName.length() > 0) {
final ApplicationsAdapter adapter = mApplicationsAdapter;
final List<ApplicationInfo> toRemove = new ArrayList<ApplicationInfo>();
final int count = adapter.getCount();
for (int i = 0; i < count; i++) {
final ApplicationInfo applicationInfo = adapter.getItem(i);
final Intent intent = applicationInfo.intent;
final ComponentName component = intent.getComponent();
if (packageName.equals(component.getPackageName())) {
toRemove.add(applicationInfo);
}
}
final HashMap<ComponentName, ApplicationInfo> cache = mAppInfoCache;
for (ApplicationInfo info : toRemove) {
adapter.setNotifyOnChange(false);
adapter.remove(info);
cache.remove(info.intent.getComponent());
}
if (toRemove.size() > 0) {
adapter.sort(new ApplicationInfoComparator());
adapter.notifyDataSetChanged();
}
}
}
synchronized void updatePackage(Launcher launcher, String packageName) {
if (mApplicationsLoader != null && mApplicationsLoader.isRunning()) {
startApplicationsLoader(launcher);
return;
}
if (packageName != null && packageName.length() > 0) {
final PackageManager packageManager = launcher.getPackageManager();
final ApplicationsAdapter adapter = mApplicationsAdapter;
final List<ResolveInfo> matches = findActivitiesForPackage(packageManager, packageName);
final int count = matches.size();
boolean changed = false;
for (int i = 0; i < count; i++) {
final ResolveInfo info = matches.get(i);
final ApplicationInfo applicationInfo = findIntent(adapter,
info.activityInfo.applicationInfo.packageName, info.activityInfo.name);
if (applicationInfo != null) {
updateAndCacheApplicationInfo(packageManager, info, applicationInfo);
changed = true;
}
}
if (changed) {
adapter.sort(new ApplicationInfoComparator());
adapter.notifyDataSetChanged();
}
}
}
private void updateAndCacheApplicationInfo(PackageManager packageManager, ResolveInfo info,
ApplicationInfo applicationInfo) {
updateApplicationInfoTitleAndIcon(packageManager, info, applicationInfo);
ComponentName componentName = new ComponentName(
info.activityInfo.applicationInfo.packageName, info.activityInfo.name);
mAppInfoCache.put(componentName, applicationInfo);
}
synchronized void syncPackage(Launcher launcher, String packageName) {
if (mApplicationsLoader != null && mApplicationsLoader.isRunning()) {
startApplicationsLoader(launcher);
return;
}
if (packageName != null && packageName.length() > 0) {
final PackageManager packageManager = launcher.getPackageManager();
final List<ResolveInfo> matches = findActivitiesForPackage(packageManager, packageName);
if (matches.size() > 0) {
final ApplicationsAdapter adapter = mApplicationsAdapter;
// Find disabled activities and remove them from the adapter
boolean removed = removeDisabledActivities(packageName, matches, adapter);
// Find enable activities and add them to the adapter
// Also updates existing activities with new labels/icons
boolean added = addEnabledAndUpdateActivities(matches, adapter, launcher);
if (added || removed) {
adapter.sort(new ApplicationInfoComparator());
adapter.notifyDataSetChanged();
}
}
}
}
private static List<ResolveInfo> findActivitiesForPackage(PackageManager packageManager,
String packageName) {
final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
final List<ResolveInfo> apps = packageManager.queryIntentActivities(mainIntent, 0);
final List<ResolveInfo> matches = new ArrayList<ResolveInfo>();
if (apps != null) {
// Find all activities that match the packageName
int count = apps.size();
for (int i = 0; i < count; i++) {
final ResolveInfo info = apps.get(i);
final ActivityInfo activityInfo = info.activityInfo;
if (packageName.equals(activityInfo.packageName)) {
matches.add(info);
}
}
}
return matches;
}
private boolean addEnabledAndUpdateActivities(List<ResolveInfo> matches,
ApplicationsAdapter adapter, Launcher launcher) {
final List<ApplicationInfo> toAdd = new ArrayList<ApplicationInfo>();
final int count = matches.size();
boolean changed = false;
for (int i = 0; i < count; i++) {
final ResolveInfo info = matches.get(i);
final ApplicationInfo applicationInfo = findIntent(adapter,
info.activityInfo.applicationInfo.packageName, info.activityInfo.name);
if (applicationInfo == null) {
toAdd.add(makeAndCacheApplicationInfo(launcher.getPackageManager(),
mAppInfoCache, info));
changed = true;
} else {
updateAndCacheApplicationInfo(launcher.getPackageManager(), info, applicationInfo);
changed = true;
}
}
for (ApplicationInfo info : toAdd) {
adapter.setNotifyOnChange(false);
adapter.add(info);
}
return changed;
}
private boolean removeDisabledActivities(String packageName, List<ResolveInfo> matches,
ApplicationsAdapter adapter) {
final List<ApplicationInfo> toRemove = new ArrayList<ApplicationInfo>();
final int count = adapter.getCount();
boolean changed = false;
for (int i = 0; i < count; i++) {
final ApplicationInfo applicationInfo = adapter.getItem(i);
final Intent intent = applicationInfo.intent;
final ComponentName component = intent.getComponent();
if (packageName.equals(component.getPackageName())) {
if (!findIntent(matches, component)) {
toRemove.add(applicationInfo);
changed = true;
}
}
}
final HashMap<ComponentName, ApplicationInfo> cache = mAppInfoCache;
for (ApplicationInfo info : toRemove) {
adapter.setNotifyOnChange(false);
adapter.remove(info);
cache.remove(info.intent.getComponent());
}
return changed;
}
private static ApplicationInfo findIntent(ApplicationsAdapter adapter, String packageName,
String name) {
final int count = adapter.getCount();
for (int i = 0; i < count; i++) {
final ApplicationInfo applicationInfo = adapter.getItem(i);
final Intent intent = applicationInfo.intent;
final ComponentName component = intent.getComponent();
if (packageName.equals(component.getPackageName()) &&
name.equals(component.getClassName())) {
return applicationInfo;
}
}
return null;
}
private static boolean findIntent(List<ResolveInfo> apps, ComponentName component) {
final String className = component.getClassName();
for (ResolveInfo info : apps) {
final ActivityInfo activityInfo = info.activityInfo;
if (activityInfo.name.equals(className)) {
return true;
}
}
return false;
}
Drawable getApplicationInfoIcon(PackageManager manager, ApplicationInfo info) {
final ResolveInfo resolveInfo = manager.resolveActivity(info.intent, 0);
if (resolveInfo == null) {
return null;
}
ComponentName componentName = new ComponentName(
resolveInfo.activityInfo.applicationInfo.packageName,
resolveInfo.activityInfo.name);
ApplicationInfo application = mAppInfoCache.get(componentName);
if (application == null) {
return resolveInfo.activityInfo.loadIcon(manager);
}
return application.icon;
}
private static ApplicationInfo makeAndCacheApplicationInfo(PackageManager manager,
HashMap<ComponentName, ApplicationInfo> appInfoCache, ResolveInfo info) {
ComponentName componentName = new ComponentName(
info.activityInfo.applicationInfo.packageName,
info.activityInfo.name);
ApplicationInfo application = appInfoCache.get(componentName);
if (application == null) {
application = new ApplicationInfo();
application.container = ItemInfo.NO_ID;
updateApplicationInfoTitleAndIcon(manager, info, application);
application.setActivity(componentName,
Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
appInfoCache.put(componentName, application);
}
return application;
}
private static void updateApplicationInfoTitleAndIcon(PackageManager manager, ResolveInfo info,
ApplicationInfo application) {
application.title = info.loadLabel(manager);
if (application.title == null) {
application.title = info.activityInfo.name;
}
application.icon = info.activityInfo.loadIcon(manager);
application.filtered = false;
}
private class ApplicationsLoader implements Runnable {
private final WeakReference<Launcher> mLauncher;
@ -176,7 +476,7 @@ android.util.Log.d("Home", " --> starting applications loader");
android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
final Launcher launcher = mLauncher.get();
@ -185,6 +485,8 @@ android.util.Log.d("Home", " --> starting applications loader");
if (apps != null && !mStopped) {
final int count = apps.size();
// Can be set to null on the UI thread by the unbind() method
// Do not access without checking for null first
final ApplicationsAdapter applicationList = mApplicationsAdapter;
ChangeNotifier action = new ChangeNotifier(applicationList, true);
@ -192,28 +494,10 @@ android.util.Log.d("Home", " --> starting applications loader");
for (int i = 0; i < count && !mStopped; i++) {
ResolveInfo info = apps.get(i);
ComponentName componentName = new ComponentName(
info.activityInfo.applicationInfo.packageName,
info.activityInfo.name);
ApplicationInfo application = appInfoCache.get(componentName);
if (application == null) {
application = new ApplicationInfo();
application.title = info.loadLabel(manager);
if (application.title == null) {
application.title = info.activityInfo.name;
}
application.setActivity(componentName,
Intent.FLAG_ACTIVITY_NEW_TASK |
Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
application.container = ItemInfo.NO_ID;
application.icon = info.activityInfo.loadIcon(manager);
if (DEBUG) {
Log.d(Launcher.LOG_TAG, "Loaded ApplicationInfo for " + componentName);
}
appInfoCache.put(componentName, application);
}
ApplicationInfo application =
makeAndCacheApplicationInfo(manager, appInfoCache, info);
if (action.add(application)) {
if (action.add(application) && !mStopped) {
launcher.runOnUiThread(action);
action = new ChangeNotifier(applicationList, false);
}
@ -229,7 +513,7 @@ android.util.Log.d("Home", " --> starting applications loader");
}
}
private static class ChangeNotifier implements Runnable, Comparator<ApplicationInfo> {
private static class ChangeNotifier implements Runnable {
private final ApplicationsAdapter mApplicationList;
private final ArrayList<ApplicationInfo> mBuffer;
@ -243,6 +527,8 @@ android.util.Log.d("Home", " --> starting applications loader");
public void run() {
final ApplicationsAdapter applicationList = mApplicationList;
// Can be set to null on the UI thread by the unbind() method
if (applicationList == null) return;
if (mFirst) {
applicationList.setNotifyOnChange(false);
@ -260,7 +546,7 @@ android.util.Log.d("Home", " --> starting applications loader");
buffer.clear();
applicationList.sort(this);
applicationList.sort(new ApplicationInfoComparator());
applicationList.notifyDataSetChanged();
}
@ -269,7 +555,9 @@ android.util.Log.d("Home", " --> starting applications loader");
buffer.add(application);
return buffer.size() >= UI_NOTIFICATION_RATE;
}
}
private static class ApplicationInfoComparator implements Comparator<ApplicationInfo> {
public final int compare(ApplicationInfo a, ApplicationInfo b) {
return sCollator.compare(a.title.toString(), b.title.toString());
}
@ -285,10 +573,10 @@ android.util.Log.d("Home", " --> starting applications loader");
*/
void loadUserItems(boolean isLaunching, Launcher launcher, boolean localeChanged,
boolean loadApplications) {
android.util.Log.d("Home", "loading user items");
if (DEBUG_LOADERS) d(LOG_TAG, "loading user items");
if (isLaunching && isDesktopLoaded()) {
android.util.Log.d("Home", " --> items loaded, return");
if (DEBUG_LOADERS) d(LOG_TAG, " --> items loaded, return");
if (loadApplications) startApplicationsLoader(launcher);
// We have already loaded our data from the DB
launcher.onDesktopItemsLoaded();
@ -306,7 +594,7 @@ android.util.Log.d("Home", " --> items loaded, return");
}
}
android.util.Log.d("Home", " --> starting workspace loader");
if (DEBUG_LOADERS) d(LOG_TAG, " --> starting workspace loader");
mDesktopItemsLoaded = false;
mDesktopItemsLoader = new DesktopItemsLoader(launcher, localeChanged, loadApplications);
mDesktopLoaderThread = new Thread(mDesktopItemsLoader, "Desktop Items Loader");
@ -563,7 +851,7 @@ android.util.Log.d("Home", " --> starting workspace loader");
container = c.getInt(containerIndex);
if (container != LauncherSettings.Favorites.CONTAINER_DESKTOP) {
Log.e(Launcher.LOG_TAG, "Widget found where container "
e(Launcher.LOG_TAG, "Widget found where container "
+ "!= CONTAINER_DESKTOP ignoring!");
continue;
}
@ -589,7 +877,7 @@ android.util.Log.d("Home", " --> starting workspace loader");
container = c.getInt(containerIndex);
if (container != LauncherSettings.Favorites.CONTAINER_DESKTOP) {
Log.e(Launcher.LOG_TAG, "Widget found where container "
e(Launcher.LOG_TAG, "Widget found where container "
+ "!= CONTAINER_DESKTOP -- ignoring!");
continue;
}
@ -599,7 +887,7 @@ android.util.Log.d("Home", " --> starting workspace loader");
break;
}
} catch (Exception e) {
Log.w(Launcher.LOG_TAG, "Desktop items loading interrupted:", e);
w(Launcher.LOG_TAG, "Desktop items loading interrupted:", e);
}
}
} finally {
@ -699,6 +987,8 @@ android.util.Log.d("Home", " --> starting workspace loader");
* Home screen on orientation change.
*/
void unbind() {
// Interrupt the applications loader before setting the adapter to null
stopAndWaitForApplicationsLoader();
mApplicationsAdapter = null;
unbindAppDrawables(mApplications);
unbindDrawables(mDesktopItems);

View File

@ -24,6 +24,8 @@ import android.content.Intent;
import android.content.ComponentName;
import android.content.ContentUris;
import android.content.ContentResolver;
import android.content.res.XmlResourceParser;
import android.content.res.TypedArray;
import android.content.pm.PackageManager;
import android.content.pm.ActivityInfo;
import android.database.sqlite.SQLiteOpenHelper;
@ -33,19 +35,17 @@ import android.database.Cursor;
import android.database.SQLException;
import android.util.Log;
import android.util.Xml;
import android.util.AttributeSet;
import android.net.Uri;
import android.text.TextUtils;
import android.os.*;
import android.provider.Settings;
import java.io.FileReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParser;
import com.android.internal.util.XmlUtils;
import com.android.launcher.LauncherSettings.Favorites;
@ -162,19 +162,10 @@ public class LauncherProvider extends ContentProvider {
}
private static class DatabaseHelper extends SQLiteOpenHelper {
/**
* Path to file containing default favorite packages, relative to ANDROID_ROOT.
*/
private static final String DEFAULT_FAVORITES_PATH = "etc/favorites.xml";
private static final String TAG_FAVORITES = "favorites";
private static final String TAG_FAVORITE = "favorite";
private static final String TAG_PACKAGE = "package";
private static final String TAG_CLASS = "class";
private static final String ATTRIBUTE_SCREEN = "screen";
private static final String ATTRIBUTE_X = "x";
private static final String ATTRIBUTE_Y = "y";
private static final String TAG_CLOCK = "clock";
private static final String TAG_SEARCH = "search";
private final Context mContext;
private final AppWidgetHost mAppWidgetHost;
@ -217,7 +208,7 @@ public class LauncherProvider extends ContentProvider {
if (!convertDatabase(db)) {
// Populate favorites table with initial favorites
loadFavorites(db, DEFAULT_FAVORITES_PATH);
loadFavorites(db);
}
}
@ -445,115 +436,122 @@ public class LauncherProvider extends ContentProvider {
* Loads the default set of favorite packages from an xml file.
*
* @param db The database to write the values into
* @param subPath The relative path from ANDROID_ROOT to the file to read
*/
private int loadFavorites(SQLiteDatabase db, String subPath) {
FileReader favReader;
// Environment.getRootDirectory() is a fancy way of saying ANDROID_ROOT or "/system".
final File favFile = new File(Environment.getRootDirectory(), subPath);
try {
favReader = new FileReader(favFile);
} catch (FileNotFoundException e) {
Log.e(LOG_TAG, "Couldn't find or open favorites file " + favFile);
return 0;
}
private int loadFavorites(SQLiteDatabase db) {
Intent intent = new Intent(Intent.ACTION_MAIN, null);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
ContentValues values = new ContentValues();
PackageManager packageManager = mContext.getPackageManager();
ActivityInfo info;
int i = 0;
try {
XmlPullParser parser = Xml.newPullParser();
parser.setInput(favReader);
XmlResourceParser parser = mContext.getResources().getXml(R.xml.default_workspace);
AttributeSet attrs = Xml.asAttributeSet(parser);
XmlUtils.beginDocument(parser, TAG_FAVORITES);
while (true) {
XmlUtils.nextElement(parser);
final int depth = parser.getDepth();
String name = parser.getName();
if (!TAG_FAVORITE.equals(name)) {
break;
int type;
while (((type = parser.next()) != XmlPullParser.END_TAG ||
parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
if (type != XmlPullParser.START_TAG) {
continue;
}
String pkg = parser.getAttributeValue(null, TAG_PACKAGE);
String cls = parser.getAttributeValue(null, TAG_CLASS);
try {
ComponentName cn = new ComponentName(pkg, cls);
info = packageManager.getActivityInfo(cn, 0);
intent.setComponent(cn);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
values.put(LauncherSettings.Favorites.INTENT, intent.toURI());
values.put(LauncherSettings.Favorites.TITLE,
info.loadLabel(packageManager).toString());
values.put(LauncherSettings.Favorites.CONTAINER,
LauncherSettings.Favorites.CONTAINER_DESKTOP);
values.put(LauncherSettings.Favorites.ITEM_TYPE,
LauncherSettings.Favorites.ITEM_TYPE_APPLICATION);
values.put(LauncherSettings.Favorites.SCREEN,
parser.getAttributeValue(null, ATTRIBUTE_SCREEN));
values.put(LauncherSettings.Favorites.CELLX,
parser.getAttributeValue(null, ATTRIBUTE_X));
values.put(LauncherSettings.Favorites.CELLY,
parser.getAttributeValue(null, ATTRIBUTE_Y));
values.put(LauncherSettings.Favorites.SPANX, 1);
values.put(LauncherSettings.Favorites.SPANY, 1);
db.insert(TABLE_FAVORITES, null, values);
i++;
} catch (PackageManager.NameNotFoundException e) {
Log.w(LOG_TAG, "Unable to add favorite: " + pkg + "/" + cls, e);
boolean added = false;
final String name = parser.getName();
TypedArray a = mContext.obtainStyledAttributes(attrs, R.styleable.Favorite);
values.clear();
values.put(LauncherSettings.Favorites.CONTAINER,
LauncherSettings.Favorites.CONTAINER_DESKTOP);
values.put(LauncherSettings.Favorites.SCREEN,
a.getString(R.styleable.Favorite_screen));
values.put(LauncherSettings.Favorites.CELLX,
a.getString(R.styleable.Favorite_x));
values.put(LauncherSettings.Favorites.CELLY,
a.getString(R.styleable.Favorite_y));
if (TAG_FAVORITE.equals(name)) {
added = addShortcut(db, values, a, packageManager, intent);
} else if (TAG_SEARCH.equals(name)) {
added = addSearchWidget(db, values);
} else if (TAG_CLOCK.equals(name)) {
added = addClockWidget(db, values);
}
if (added) i++;
a.recycle();
}
} catch (XmlPullParserException e) {
Log.w(LOG_TAG, "Got exception parsing favorites.", e);
} catch (IOException e) {
Log.w(LOG_TAG, "Got exception parsing favorites.", e);
}
return i;
}
private boolean addShortcut(SQLiteDatabase db, ContentValues values, TypedArray a,
PackageManager packageManager, Intent intent) {
ActivityInfo info;
String packageName = a.getString(R.styleable.Favorite_packageName);
String className = a.getString(R.styleable.Favorite_className);
try {
ComponentName cn = new ComponentName(packageName, className);
info = packageManager.getActivityInfo(cn, 0);
intent.setComponent(cn);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
values.put(Favorites.INTENT, intent.toURI());
values.put(Favorites.TITLE, info.loadLabel(packageManager).toString());
values.put(Favorites.ITEM_TYPE, Favorites.ITEM_TYPE_APPLICATION);
values.put(Favorites.SPANX, 1);
values.put(Favorites.SPANY, 1);
db.insert(TABLE_FAVORITES, null, values);
} catch (PackageManager.NameNotFoundException e) {
Log.w(LOG_TAG, "Unable to add favorite: " + packageName +
"/" + className, e);
return false;
}
return true;
}
private boolean addSearchWidget(SQLiteDatabase db, ContentValues values) {
// Add a search box
values.clear();
values.put(LauncherSettings.Favorites.CONTAINER,
LauncherSettings.Favorites.CONTAINER_DESKTOP);
values.put(LauncherSettings.Favorites.ITEM_TYPE,
LauncherSettings.Favorites.ITEM_TYPE_WIDGET_SEARCH);
values.put(LauncherSettings.Favorites.SCREEN, 2);
values.put(LauncherSettings.Favorites.CELLX, 0);
values.put(LauncherSettings.Favorites.CELLY, 0);
values.put(LauncherSettings.Favorites.SPANX, 4);
values.put(LauncherSettings.Favorites.SPANY, 1);
values.put(Favorites.ITEM_TYPE, Favorites.ITEM_TYPE_WIDGET_SEARCH);
values.put(Favorites.SPANX, 4);
values.put(Favorites.SPANY, 1);
db.insert(TABLE_FAVORITES, null, values);
return true;
}
private boolean addClockWidget(SQLiteDatabase db, ContentValues values) {
final int[] bindSources = new int[] {
Favorites.ITEM_TYPE_WIDGET_CLOCK,
};
final ArrayList<ComponentName> bindTargets = new ArrayList<ComponentName>();
bindTargets.add(new ComponentName("com.android.alarmclock",
"com.android.alarmclock.AnalogAppWidgetProvider"));
boolean allocatedAppWidgets = false;
// Try binding to an analog clock widget
try {
int appWidgetId = mAppWidgetHost.allocateAppWidgetId();
values.clear();
values.put(LauncherSettings.Favorites.CONTAINER,
LauncherSettings.Favorites.CONTAINER_DESKTOP);
values.put(LauncherSettings.Favorites.ITEM_TYPE,
LauncherSettings.Favorites.ITEM_TYPE_WIDGET_CLOCK);
values.put(LauncherSettings.Favorites.SCREEN, 1);
values.put(LauncherSettings.Favorites.CELLX, 1);
values.put(LauncherSettings.Favorites.CELLY, 0);
values.put(LauncherSettings.Favorites.SPANX, 2);
values.put(LauncherSettings.Favorites.SPANY, 2);
values.put(LauncherSettings.Favorites.APPWIDGET_ID, appWidgetId);
values.put(Favorites.ITEM_TYPE, Favorites.ITEM_TYPE_WIDGET_CLOCK);
values.put(Favorites.SPANX, 2);
values.put(Favorites.SPANY, 2);
values.put(Favorites.APPWIDGET_ID, appWidgetId);
db.insert(TABLE_FAVORITES, null, values);
allocatedAppWidgets = true;
} catch (RuntimeException ex) {
Log.e(LOG_TAG, "Problem allocating appWidgetId", ex);
@ -563,8 +561,8 @@ public class LauncherProvider extends ContentProvider {
if (allocatedAppWidgets) {
launchAppWidgetBinder(bindSources, bindTargets);
}
return i;
return allocatedAppWidgets;
}
}

View File

@ -90,7 +90,13 @@ public class LiveFolder extends Folder {
if (mLoadingTask != null && mLoadingTask.getStatus() == AsyncTask.Status.RUNNING) {
mLoadingTask.cancel(true);
}
((LiveFolderAdapter) mContent.getAdapter()).cleanup();
// The adapter can be null if onClose() is called before FolderLoadingTask
// is done querying the provider
final LiveFolderAdapter adapter = (LiveFolderAdapter) mContent.getAdapter();
if (adapter != null) {
adapter.cleanup();
}
}
static class FolderLoadingTask extends AsyncTask<LiveFolderInfo, Void, Cursor> {

View File

@ -26,6 +26,7 @@ import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Rect;
import android.graphics.Region;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.VelocityTracker;
@ -34,6 +35,7 @@ import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.widget.Scroller;
import android.widget.TextView;
import android.os.Parcelable;
import android.os.Parcel;
@ -1240,7 +1242,41 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag
}
}
}
void updateShortcutsForPackage(String packageName) {
final int count = getChildCount();
for (int i = 0; i < count; i++) {
final CellLayout layout = (CellLayout) getChildAt(i);
int childCount = layout.getChildCount();
for (int j = 0; j < childCount; j++) {
final View view = layout.getChildAt(j);
Object tag = view.getTag();
if (tag instanceof ApplicationInfo) {
ApplicationInfo info = (ApplicationInfo) tag;
// We need to check for ACTION_MAIN otherwise getComponent() might
// return null for some shortcuts (for instance, for shortcuts to
// web pages.)
final Intent intent = info.intent;
final ComponentName name = intent.getComponent();
if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION &&
Intent.ACTION_MAIN.equals(intent.getAction()) && name != null &&
packageName.equals(name.getPackageName())) {
final Drawable icon = Launcher.getModel().getApplicationInfoIcon(
mLauncher.getPackageManager(), info);
if (icon != null && icon != info.icon) {
info.icon.setCallback(null);
info.icon = Utilities.createIconThumbnail(icon, mContext);
info.filtered = true;
((TextView) view).setCompoundDrawablesWithIntrinsicBounds(null,
info.icon, null, null);
}
}
}
}
}
}
// TODO: remove widgets when appwidgetmanager tells us they're gone
// void removeAppWidgetsForProvider() {
// }