Merge "Introduce scrollbar in widget tray" into ub-launcher3-burnaby
diff --git a/res/drawable-hdpi/ic_launcher_info_active.png b/res/drawable-hdpi/ic_launcher_info_active.png
deleted file mode 100644
index f7a3b68..0000000
--- a/res/drawable-hdpi/ic_launcher_info_active.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_launcher_remove_active.png b/res/drawable-hdpi/ic_launcher_remove_active.png
deleted file mode 100644
index e53de0d..0000000
--- a/res/drawable-hdpi/ic_launcher_remove_active.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_launcher_uninstall_active.png b/res/drawable-hdpi/ic_launcher_uninstall_active.png
deleted file mode 100644
index 22b97ee..0000000
--- a/res/drawable-hdpi/ic_launcher_uninstall_active.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_info_active.png b/res/drawable-mdpi/ic_launcher_info_active.png
deleted file mode 100644
index ea71272..0000000
--- a/res/drawable-mdpi/ic_launcher_info_active.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_remove_active.png b/res/drawable-mdpi/ic_launcher_remove_active.png
deleted file mode 100644
index f36cfdd..0000000
--- a/res/drawable-mdpi/ic_launcher_remove_active.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_uninstall_active.png b/res/drawable-mdpi/ic_launcher_uninstall_active.png
deleted file mode 100644
index e4ee911..0000000
--- a/res/drawable-mdpi/ic_launcher_uninstall_active.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_launcher_info_active.png b/res/drawable-xhdpi/ic_launcher_info_active.png
deleted file mode 100644
index b438f9e..0000000
--- a/res/drawable-xhdpi/ic_launcher_info_active.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_launcher_remove_active.png b/res/drawable-xhdpi/ic_launcher_remove_active.png
deleted file mode 100644
index 14ac79d..0000000
--- a/res/drawable-xhdpi/ic_launcher_remove_active.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_launcher_uninstall_active.png b/res/drawable-xhdpi/ic_launcher_uninstall_active.png
deleted file mode 100644
index 2c19b32..0000000
--- a/res/drawable-xhdpi/ic_launcher_uninstall_active.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_launcher_info_active.png b/res/drawable-xxhdpi/ic_launcher_info_active.png
deleted file mode 100644
index d354dd3..0000000
--- a/res/drawable-xxhdpi/ic_launcher_info_active.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_launcher_remove_active.png b/res/drawable-xxhdpi/ic_launcher_remove_active.png
deleted file mode 100644
index 9df4404..0000000
--- a/res/drawable-xxhdpi/ic_launcher_remove_active.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_launcher_uninstall_active.png b/res/drawable-xxhdpi/ic_launcher_uninstall_active.png
deleted file mode 100644
index db7d339..0000000
--- a/res/drawable-xxhdpi/ic_launcher_uninstall_active.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_launcher_info_active.png b/res/drawable-xxxhdpi/ic_launcher_info_active.png
deleted file mode 100644
index 162e23d..0000000
--- a/res/drawable-xxxhdpi/ic_launcher_info_active.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_launcher_remove_active.png b/res/drawable-xxxhdpi/ic_launcher_remove_active.png
deleted file mode 100644
index c0b8ea2..0000000
--- a/res/drawable-xxxhdpi/ic_launcher_remove_active.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_launcher_uninstall_active.png b/res/drawable-xxxhdpi/ic_launcher_uninstall_active.png
deleted file mode 100644
index 75896f3..0000000
--- a/res/drawable-xxxhdpi/ic_launcher_uninstall_active.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable/info_target_selector.xml b/res/drawable/info_target_selector.xml
deleted file mode 100644
index 51caece..0000000
--- a/res/drawable/info_target_selector.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 2011, 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.
-*/
--->
-
-<transition xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:drawable="@drawable/ic_launcher_info_normal" />
- <item android:drawable="@drawable/ic_launcher_info_active" />
-</transition>
diff --git a/res/drawable/remove_target_selector.xml b/res/drawable/remove_target_selector.xml
deleted file mode 100644
index 9025e8a..0000000
--- a/res/drawable/remove_target_selector.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 2007, 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.
-*/
--->
-
-<transition xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:drawable="@drawable/ic_launcher_remove_normal" />
- <item android:drawable="@drawable/ic_launcher_remove_active" />
-</transition>
diff --git a/res/drawable/uninstall_target_selector.xml b/res/drawable/uninstall_target_selector.xml
deleted file mode 100644
index 175cc20..0000000
--- a/res/drawable/uninstall_target_selector.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 2007, 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.
-*/
--->
-
-<transition xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:drawable="@drawable/ic_launcher_uninstall_normal" />
- <item android:drawable="@drawable/ic_launcher_uninstall_active" />
-</transition>
diff --git a/res/layout-land/launcher.xml b/res/layout-land/launcher.xml
index f0f7bbb..113b319 100644
--- a/res/layout-land/launcher.xml
+++ b/res/layout-land/launcher.xml
@@ -21,7 +21,6 @@
android:id="@+id/launcher"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:background="@drawable/workspace_bg"
android:fitsSystemWindows="true">
<com.android.launcher3.DragLayer
diff --git a/res/layout-port/launcher.xml b/res/layout-port/launcher.xml
index 5a018c5..7202f7b 100644
--- a/res/layout-port/launcher.xml
+++ b/res/layout-port/launcher.xml
@@ -22,7 +22,6 @@
android:id="@+id/launcher"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:background="@drawable/workspace_bg"
android:fitsSystemWindows="true">
<com.android.launcher3.DragLayer
diff --git a/res/layout-sw720dp/launcher.xml b/res/layout-sw720dp/launcher.xml
index a9601af..8a9f3e9 100644
--- a/res/layout-sw720dp/launcher.xml
+++ b/res/layout-sw720dp/launcher.xml
@@ -22,7 +22,6 @@
android:id="@+id/launcher"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:background="@drawable/workspace_bg"
android:fitsSystemWindows="true">
<com.android.launcher3.DragLayer
diff --git a/res/layout/apps_list_view.xml b/res/layout/apps_list_view.xml
index 6f9be05..0404983 100644
--- a/res/layout/apps_list_view.xml
+++ b/res/layout/apps_list_view.xml
@@ -39,6 +39,8 @@
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/apps_search_bar_height"
android:orientation="horizontal"
+ android:descendantFocusability="afterDescendants"
+ android:focusable="true"
android:visibility="invisible" >
</LinearLayout>
diff --git a/res/layout/search_drop_target_bar.xml b/res/layout/search_drop_target_bar.xml
index b0435aa..4737ee1 100644
--- a/res/layout/search_drop_target_bar.xml
+++ b/res/layout/search_drop_target_bar.xml
@@ -36,8 +36,6 @@
<com.android.launcher3.DeleteDropTarget
android:id="@+id/delete_target_text"
style="@style/DropTargetButton"
- android:drawableLeft="@drawable/remove_target_selector"
- android:drawableStart="@drawable/remove_target_selector"
android:text="@string/delete_target_label" />
</FrameLayout>
@@ -50,8 +48,6 @@
<com.android.launcher3.InfoDropTarget
android:id="@+id/info_target_text"
style="@style/DropTargetButton"
- android:drawableLeft="@drawable/info_target_selector"
- android:drawableStart="@drawable/info_target_selector"
android:text="@string/info_target_label" />
</FrameLayout>
@@ -64,8 +60,6 @@
<com.android.launcher3.UninstallDropTarget
android:id="@+id/uninstall_target_text"
style="@style/DropTargetButton"
- android:drawableLeft="@drawable/uninstall_target_selector"
- android:drawableStart="@drawable/uninstall_target_selector"
android:text="@string/delete_target_uninstall_label" />
</FrameLayout>
</LinearLayout>
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 1e89615..a5db2fc 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -20,9 +20,9 @@
<resources>
<!-- The color tints to apply to the text and drag view when hovering
over the delete target or the info target -->
- <color name="delete_target_hover_tint">#DAC1C1C1</color>
- <color name="uninstall_target_hover_tint">#DAF0592B</color>
- <color name="info_target_hover_tint">#DA009688</color>
+ <color name="delete_target_hover_tint">#FFC1C1C1</color>
+ <color name="uninstall_target_hover_tint">#FFF0592B</color>
+ <color name="info_target_hover_tint">#FF009688</color>
<color name="cling_scrim_background">#80000000</color>
<color name="focused_background">#80c6c5c5</color>
diff --git a/src/com/android/launcher3/AlphabeticalAppsList.java b/src/com/android/launcher3/AlphabeticalAppsList.java
index 82aaeb9..b75b3ef 100644
--- a/src/com/android/launcher3/AlphabeticalAppsList.java
+++ b/src/com/android/launcher3/AlphabeticalAppsList.java
@@ -5,14 +5,10 @@
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import com.android.launcher3.compat.AlphabeticIndexCompat;
-import com.android.launcher3.compat.UserHandleCompat;
-import com.android.launcher3.compat.UserManagerCompat;
import com.android.launcher3.model.AppNameComparator;
-import java.text.Collator;
import java.util.ArrayList;
import java.util.Collections;
-import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
@@ -121,10 +117,10 @@
}
/**
- * A callback to notify of changes to the filter.
+ * Callback to notify when the set of adapter items have changed.
*/
- public interface FilterChangedCallback {
- void onFilterChanged();
+ public interface AdapterChangedCallback {
+ void onAdapterItemsChanged();
}
/**
@@ -178,12 +174,20 @@
private static final int MAX_NUM_MERGES_PHONE = 2;
private Context mContext;
+
+ // The set of apps from the system not including predictions
private List<AppInfo> mApps = new ArrayList<>();
+ // The set of filtered apps with the current filter
private List<AppInfo> mFilteredApps = new ArrayList<>();
- private List<AdapterItem> mSectionedFilteredApps = new ArrayList<>();
+ // The current set of adapter items
+ private List<AdapterItem> mAdapterItems = new ArrayList<>();
+ // The set of sections for the apps with the current filter
private List<SectionInfo> mSections = new ArrayList<>();
+ // The set of sections that we allow fast-scrolling to (includes non-merged sections)
private List<FastScrollSectionInfo> mFastScrollerSections = new ArrayList<>();
+ // The set of predicted app component names
private List<ComponentName> mPredictedAppComponents = new ArrayList<>();
+ // The set of predicted apps resolved from the component names and the current set of apps
private List<AppInfo> mPredictedApps = new ArrayList<>();
private HashMap<CharSequence, String> mCachedSectionNames = new HashMap<>();
private RecyclerView.Adapter mAdapter;
@@ -191,20 +195,25 @@
private AlphabeticIndexCompat mIndexer;
private AppNameComparator mAppNameComparator;
private MergeAlgorithm mMergeAlgorithm;
- private FilterChangedCallback mFilterChangedCallback;
+ private AdapterChangedCallback mAdapterChangedCallback;
private int mNumAppsPerRow;
private int mNumPredictedAppsPerRow;
- public AlphabeticalAppsList(Context context, FilterChangedCallback cb, int numAppsPerRow,
- int numPredictedAppsPerRow) {
+ public AlphabeticalAppsList(Context context, int numAppsPerRow, int numPredictedAppsPerRow) {
mContext = context;
mIndexer = new AlphabeticIndexCompat(context);
mAppNameComparator = new AppNameComparator(context);
- mFilterChangedCallback = cb;
setNumAppsPerRow(numAppsPerRow, numPredictedAppsPerRow);
}
/**
+ * Sets the apps updated callback.
+ */
+ public void setAdapterChangedCallback(AdapterChangedCallback cb) {
+ mAdapterChangedCallback = cb;
+ }
+
+ /**
* Sets the number of apps per row. Used only for AppsContainerView.SECTIONED_GRID_COALESCED.
*/
public void setNumAppsPerRow(int numAppsPerRow, int numPredictedAppsPerRow) {
@@ -248,7 +257,7 @@
* Returns the current filtered list of applications broken down into their sections.
*/
public List<AdapterItem> getAdapterItems() {
- return mSectionedFilteredApps;
+ return mAdapterItems;
}
/**
@@ -278,11 +287,7 @@
public void setFilter(Filter f) {
if (mFilter != f) {
mFilter = f;
- onAppsUpdated();
- mAdapter.notifyDataSetChanged();
- if (mFilterChangedCallback != null){
- mFilterChangedCallback.onFilterChanged();
- }
+ updateAdapterItems();
}
}
@@ -294,7 +299,6 @@
mPredictedAppComponents.clear();
mPredictedAppComponents.addAll(apps);
onAppsUpdated();
- mAdapter.notifyDataSetChanged();
}
/**
@@ -311,7 +315,6 @@
mApps.clear();
mApps.addAll(apps);
onAppsUpdated();
- mAdapter.notifyDataSetChanged();
}
/**
@@ -320,10 +323,9 @@
public void addApps(List<AppInfo> apps) {
// We add it in place, in alphabetical order
for (AppInfo info : apps) {
- addApp(info);
+ mApps.add(info);
}
onAppsUpdated();
- mAdapter.notifyDataSetChanged();
}
/**
@@ -335,11 +337,10 @@
if (index != -1) {
mApps.set(index, info);
} else {
- addApp(info);
+ mApps.add(info);
}
}
onAppsUpdated();
- mAdapter.notifyDataSetChanged();
}
/**
@@ -353,7 +354,6 @@
}
}
onAppsUpdated();
- mAdapter.notifyDataSetChanged();
}
/**
@@ -373,34 +373,68 @@
}
/**
- * Implementation to actually add an app to the alphabetic list, but does not notify.
- */
- private void addApp(AppInfo info) {
- int index = Collections.binarySearch(mApps, info, mAppNameComparator.getAppInfoComparator());
- if (index < 0) {
- mApps.add(-(index + 1), info);
- }
- }
-
- /**
* Updates internals when the set of apps are updated.
*/
private void onAppsUpdated() {
// Sort the list of apps
Collections.sort(mApps, mAppNameComparator.getAppInfoComparator());
- // Prepare to update the list of sections, filtered apps, etc.
- mFilteredApps.clear();
- mSections.clear();
- mSectionedFilteredApps.clear();
- mFastScrollerSections.clear();
+ // As a special case for some languages (currently only Simplified Chinese), we may need to
+ // coalesce sections
+ Locale curLocale = mContext.getResources().getConfiguration().locale;
+ TreeMap<String, ArrayList<AppInfo>> sectionMap = null;
+ boolean localeRequiresSectionSorting = curLocale.equals(Locale.SIMPLIFIED_CHINESE);
+ if (localeRequiresSectionSorting) {
+ // Compute the section headers. We use a TreeMap with the section name comparator to
+ // ensure that the sections are ordered when we iterate over it later
+ sectionMap = new TreeMap<>(mAppNameComparator.getSectionNameComparator());
+ for (AppInfo info : mApps) {
+ // Add the section to the cache
+ String sectionName = getAndUpdateCachedSectionName(info.title);
+
+ // Add it to the mapping
+ ArrayList<AppInfo> sectionApps = sectionMap.get(sectionName);
+ if (sectionApps == null) {
+ sectionApps = new ArrayList<>();
+ sectionMap.put(sectionName, sectionApps);
+ }
+ sectionApps.add(info);
+ }
+
+ // Add each of the section apps to the list in order
+ List<AppInfo> allApps = new ArrayList<>(mApps.size());
+ for (Map.Entry<String, ArrayList<AppInfo>> entry : sectionMap.entrySet()) {
+ allApps.addAll(entry.getValue());
+ }
+ mApps = allApps;
+ } else {
+ // Just compute the section headers for use below
+ for (AppInfo info : mApps) {
+ // Add the section to the cache
+ getAndUpdateCachedSectionName(info.title);
+ }
+ }
+
+ // Recompose the set of adapter items from the current set of apps
+ updateAdapterItems();
+ }
+
+ /**
+ * Updates the set of filtered apps with the current filter. At this point, we expect
+ * mCachedSectionNames to have been calculated for the set of all apps in mApps.
+ */
+ private void updateAdapterItems() {
SectionInfo lastSectionInfo = null;
String lastSectionName = null;
FastScrollSectionInfo lastFastScrollerSectionInfo = null;
int position = 0;
int appIndex = 0;
- List<AppInfo> allApps = new ArrayList<>();
+ // Prepare to update the list of sections, filtered apps, etc.
+ mFilteredApps.clear();
+ mFastScrollerSections.clear();
+ mAdapterItems.clear();
+ mSections.clear();
// Process the predicted app components
mPredictedApps.clear();
@@ -421,61 +455,16 @@
if (!mPredictedApps.isEmpty()) {
// Create a new spacer for the prediction bar
AdapterItem sectionItem = AdapterItem.asPredictionBarSpacer(position++);
- mSectionedFilteredApps.add(sectionItem);
+ mAdapterItems.add(sectionItem);
}
}
- // As a special case for some languages (currently only Simplified Chinese), we may need to
- // coalesce sections
- Locale curLocale = mContext.getResources().getConfiguration().locale;
- TreeMap<String, ArrayList<AppInfo>> sectionMap = null;
- boolean localeRequiresSectionSorting = curLocale.equals(Locale.SIMPLIFIED_CHINESE);
- if (localeRequiresSectionSorting) {
- // Compute the section headers. We use a TreeMap with the section name comparator to
- // ensure that the sections are ordered when we iterate over it later
- sectionMap = new TreeMap<>(mAppNameComparator.getSectionNameComparator());
- for (AppInfo info : mApps) {
- // Add the section to the cache
- String sectionName = mCachedSectionNames.get(info.title);
- if (sectionName == null) {
- sectionName = mIndexer.computeSectionName(info.title);
- mCachedSectionNames.put(info.title, sectionName);
- }
-
- // Add it to the mapping
- ArrayList<AppInfo> sectionApps = sectionMap.get(sectionName);
- if (sectionApps == null) {
- sectionApps = new ArrayList<>();
- sectionMap.put(sectionName, sectionApps);
- }
- sectionApps.add(info);
- }
-
- // Add it to the list
- for (Map.Entry<String, ArrayList<AppInfo>> entry : sectionMap.entrySet()) {
- allApps.addAll(entry.getValue());
- }
- } else {
- // Just compute the section headers for use below
- for (AppInfo info : mApps) {
- // Add the section to the cache
- String sectionName = mCachedSectionNames.get(info.title);
- if (sectionName == null) {
- sectionName = mIndexer.computeSectionName(info.title);
- mCachedSectionNames.put(info.title, sectionName);
- }
- }
- // Add it to the list
- allApps.addAll(mApps);
- }
-
// Recreate the filtered and sectioned apps (for convenience for the grid layout) from the
// ordered set of sections
- int numApps = allApps.size();
+ int numApps = mApps.size();
for (int i = 0; i < numApps; i++) {
- AppInfo info = allApps.get(i);
- // The section name was computed above so this should be find
- String sectionName = mCachedSectionNames.get(info.title);
+ AppInfo info = mApps.get(i);
+ String sectionName = getAndUpdateCachedSectionName(info.title);
// Check if we want to retain this app
if (mFilter != null && !mFilter.retainApp(info, sectionName)) {
@@ -494,7 +483,7 @@
// Create a new section item to break the flow of items in the list
if (!hasFilter()) {
AdapterItem sectionItem = AdapterItem.asSectionBreak(position++, lastSectionInfo);
- mSectionedFilteredApps.add(sectionItem);
+ mAdapterItems.add(sectionItem);
}
}
@@ -505,12 +494,21 @@
lastSectionInfo.firstAppItem = appItem;
lastFastScrollerSectionInfo.appItem = appItem;
}
- mSectionedFilteredApps.add(appItem);
+ mAdapterItems.add(appItem);
mFilteredApps.add(info);
}
// Merge multiple sections together as requested by the merge strategy for this device
mergeSections();
+
+ // Refresh the recycler view
+ if (mAdapter != null) {
+ mAdapter.notifyDataSetChanged();
+ }
+
+ if (mAdapterChangedCallback != null) {
+ mAdapterChangedCallback.onAdapterItemsChanged();
+ }
}
/**
@@ -531,20 +529,20 @@
SectionInfo nextSection = mSections.remove(i + 1);
// Remove the next section break
- mSectionedFilteredApps.remove(nextSection.sectionBreakItem);
- int pos = mSectionedFilteredApps.indexOf(section.firstAppItem);
+ mAdapterItems.remove(nextSection.sectionBreakItem);
+ int pos = mAdapterItems.indexOf(section.firstAppItem);
// Point the section for these new apps to the merged section
int nextPos = pos + section.numApps;
for (int j = nextPos; j < (nextPos + nextSection.numApps); j++) {
- AdapterItem item = mSectionedFilteredApps.get(j);
+ AdapterItem item = mAdapterItems.get(j);
item.sectionInfo = section;
item.sectionAppIndex += section.numApps;
}
// Update the following adapter items of the removed section item
- pos = mSectionedFilteredApps.indexOf(nextSection.firstAppItem);
- for (int j = pos; j < mSectionedFilteredApps.size(); j++) {
- AdapterItem item = mSectionedFilteredApps.get(j);
+ pos = mAdapterItems.indexOf(nextSection.firstAppItem);
+ for (int j = pos; j < mAdapterItems.size(); j++) {
+ AdapterItem item = mAdapterItems.get(j);
item.position--;
}
section.numApps += nextSection.numApps;
@@ -560,4 +558,17 @@
}
}
}
+
+ /**
+ * Returns the cached section name for the given title, recomputing and updating the cache if
+ * the title has no cached section name.
+ */
+ private String getAndUpdateCachedSectionName(CharSequence title) {
+ String sectionName = mCachedSectionNames.get(title);
+ if (sectionName == null) {
+ sectionName = mIndexer.computeSectionName(title);
+ mCachedSectionNames.put(title, sectionName);
+ }
+ return sectionName;
+ }
}
diff --git a/src/com/android/launcher3/AppsContainerView.java b/src/com/android/launcher3/AppsContainerView.java
index 5ccb6c6..26a7cd7 100644
--- a/src/com/android/launcher3/AppsContainerView.java
+++ b/src/com/android/launcher3/AppsContainerView.java
@@ -136,7 +136,7 @@
*/
public class AppsContainerView extends BaseContainerView implements DragSource, Insettable,
TextWatcher, TextView.OnEditorActionListener, LauncherTransitionable,
- AlphabeticalAppsList.FilterChangedCallback, AppsGridAdapter.PredictionBarSpacerCallbacks,
+ AlphabeticalAppsList.AdapterChangedCallback, AppsGridAdapter.PredictionBarSpacerCallbacks,
View.OnTouchListener, View.OnClickListener, View.OnLongClickListener,
ViewTreeObserver.OnPreDrawListener {
@@ -183,6 +183,7 @@
private int mContainerInset;
private int mPredictionBarHeight;
private int mLastRecyclerViewScrollPos = -1;
+ private boolean mFocusPredictionBarOnFirstBind;
private CheckLongPressHelper mPredictionIconCheckForLongPress;
private View mPredictionIconUnderTouch;
@@ -209,7 +210,8 @@
mLayoutInflater = LayoutInflater.from(context);
mNumAppsPerRow = grid.appsViewNumCols;
mNumPredictedAppsPerRow = grid.appsViewNumPredictiveCols;
- mApps = new AlphabeticalAppsList(context, this, mNumAppsPerRow, mNumPredictedAppsPerRow);
+ mApps = new AlphabeticalAppsList(context, mNumAppsPerRow, mNumPredictedAppsPerRow);
+ mApps.setAdapterChangedCallback(this);
mAdapter = new AppsGridAdapter(context, mApps, mNumAppsPerRow, this, this, mLauncher, this);
mAdapter.setEmptySearchText(res.getString(R.string.loading_apps_message));
mAdapter.setNumAppsPerRow(mNumAppsPerRow);
@@ -298,7 +300,17 @@
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (v == mContentView && hasFocus) {
- mAppsRecyclerView.requestFocus();
+ if (!mApps.getPredictedApps().isEmpty()) {
+ // If the prediction bar is going to be bound, then defer focusing until
+ // it is first bound
+ if (mPredictionBarView.getChildCount() == 0) {
+ mFocusPredictionBarOnFirstBind = true;
+ } else {
+ mPredictionBarView.requestFocus();
+ }
+ } else {
+ mAppsRecyclerView.requestFocus();
+ }
}
}
});
@@ -387,6 +399,11 @@
icon.setVisibility(View.INVISIBLE);
}
}
+
+ if (mFocusPredictionBarOnFirstBind) {
+ mFocusPredictionBarOnFirstBind = false;
+ mPredictionBarView.requestFocus();
+ }
}
@Override
@@ -670,7 +687,7 @@
}
@Override
- public void onFilterChanged() {
+ public void onAdapterItemsChanged() {
updatePredictionBarVisibility();
}
diff --git a/src/com/android/launcher3/ButtonDropTarget.java b/src/com/android/launcher3/ButtonDropTarget.java
index b8214d1..4cd28c0 100644
--- a/src/com/android/launcher3/ButtonDropTarget.java
+++ b/src/com/android/launcher3/ButtonDropTarget.java
@@ -16,15 +16,20 @@
package com.android.launcher3;
+import android.animation.AnimatorSet;
+import android.animation.FloatArrayEvaluator;
import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Configuration;
+import android.graphics.ColorMatrix;
+import android.graphics.ColorMatrixColorFilter;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
-import android.graphics.drawable.TransitionDrawable;
import android.os.Build;
import android.util.AttributeSet;
import android.view.View;
@@ -56,9 +61,11 @@
protected int mHoverColor = 0;
protected ColorStateList mOriginalTextColor;
- protected TransitionDrawable mDrawable;
+ protected Drawable mDrawable;
- private ObjectAnimator mCurrentColorAnim;
+ private AnimatorSet mCurrentColorAnim;
+ private ColorMatrix mSrcFilter, mDstFilter, mCurrentFilter;
+
public ButtonDropTarget(Context context, AttributeSet attrs) {
this(context, attrs, 0);
@@ -85,21 +92,14 @@
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
protected void setDrawable(int resId) {
- // Get the hover color
- mDrawable = (TransitionDrawable) getCurrentDrawable();
+ // We do not set the drawable in the xml as that inflates two drawables corresponding to
+ // drawableLeft and drawableStart.
+ mDrawable = getResources().getDrawable(resId);
- if (mDrawable == null) {
- // TODO: investigate why this is ever happening. Presently only on one known device.
- mDrawable = (TransitionDrawable) getResources().getDrawable(resId);
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
- setCompoundDrawablesRelativeWithIntrinsicBounds(mDrawable, null, null, null);
- } else {
- setCompoundDrawablesWithIntrinsicBounds(mDrawable, null, null, null);
- }
- }
-
- if (null != mDrawable) {
- mDrawable.setCrossFadeEnabled(true);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ setCompoundDrawablesRelativeWithIntrinsicBounds(mDrawable, null, null, null);
+ } else {
+ setCompoundDrawablesWithIntrinsicBounds(mDrawable, null, null, null);
}
}
@@ -111,16 +111,6 @@
mSearchDropTargetBar = searchDropTargetBar;
}
- protected Drawable getCurrentDrawable() {
- Drawable[] drawables = getCompoundDrawables();
- for (int i = 0; i < drawables.length; ++i) {
- if (drawables[i] != null) {
- return drawables[i];
- }
- }
- return null;
- }
-
@Override
public void onFlingToDelete(DragObject d, PointF vec) { }
@@ -128,10 +118,13 @@
public final void onDragEnter(DragObject d) {
d.dragView.setColor(mHoverColor);
if (Utilities.isLmpOrAbove()) {
- mDrawable.startTransition(DragView.COLOR_CHANGE_DURATION);
animateTextColor(mHoverColor);
} else {
- mDrawable.startTransition(0);
+ if (mCurrentFilter == null) {
+ mCurrentFilter = new ColorMatrix();
+ }
+ DragView.setColorScale(mHoverColor, mCurrentFilter);
+ mDrawable.setColorFilter(new ColorMatrixColorFilter(mCurrentFilter));
setTextColor(mHoverColor);
}
}
@@ -141,12 +134,11 @@
// Do nothing
}
- protected void resetHoverColor() {
+ protected void resetHoverColor() {
if (Utilities.isLmpOrAbove()) {
- mDrawable.reverseTransition(DragView.COLOR_CHANGE_DURATION);
animateTextColor(mOriginalTextColor.getDefaultColor());
} else {
- mDrawable.resetTransition();
+ mDrawable.setColorFilter(null);
setTextColor(mOriginalTextColor);
}
}
@@ -156,8 +148,32 @@
if (mCurrentColorAnim != null) {
mCurrentColorAnim.cancel();
}
- mCurrentColorAnim = ObjectAnimator.ofArgb(this, "textColor", targetColor);
+
+ mCurrentColorAnim = new AnimatorSet();
mCurrentColorAnim.setDuration(DragView.COLOR_CHANGE_DURATION);
+
+ if (mSrcFilter == null) {
+ mSrcFilter = new ColorMatrix();
+ mDstFilter = new ColorMatrix();
+ mCurrentFilter = new ColorMatrix();
+ }
+
+ DragView.setColorScale(getTextColor(), mSrcFilter);
+ DragView.setColorScale(targetColor, mDstFilter);
+ ValueAnimator anim1 = ValueAnimator.ofObject(
+ new FloatArrayEvaluator(mCurrentFilter.getArray()),
+ mSrcFilter.getArray(), mDstFilter.getArray());
+ anim1.addUpdateListener(new AnimatorUpdateListener() {
+
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ mDrawable.setColorFilter(new ColorMatrixColorFilter(mCurrentFilter));
+ invalidate();
+ }
+ });
+
+ mCurrentColorAnim.play(anim1);
+ mCurrentColorAnim.play(ObjectAnimator.ofArgb(this, "textColor", targetColor));
mCurrentColorAnim.start();
}
@@ -172,10 +188,10 @@
}
}
- @Override
+ @Override
public final void onDragStart(DragSource source, Object info, int dragAction) {
mActive = supportsDrop(source, info);
- mDrawable.resetTransition();
+ mDrawable.setColorFilter(null);
if (mCurrentColorAnim != null) {
mCurrentColorAnim.cancel();
mCurrentColorAnim = null;
diff --git a/src/com/android/launcher3/DeleteDropTarget.java b/src/com/android/launcher3/DeleteDropTarget.java
index 08186f5..fa6e74f 100644
--- a/src/com/android/launcher3/DeleteDropTarget.java
+++ b/src/com/android/launcher3/DeleteDropTarget.java
@@ -43,7 +43,7 @@
// Get the hover color
mHoverColor = getResources().getColor(R.color.delete_target_hover_tint);
- setDrawable(R.drawable.remove_target_selector);
+ setDrawable(R.drawable.ic_launcher_remove_normal);
}
public static boolean supportsDrop(Object info) {
diff --git a/src/com/android/launcher3/DragView.java b/src/com/android/launcher3/DragView.java
index 120299e..b332338 100644
--- a/src/com/android/launcher3/DragView.java
+++ b/src/com/android/launcher3/DragView.java
@@ -38,7 +38,7 @@
import java.util.Arrays;
public class DragView extends View {
- public static int COLOR_CHANGE_DURATION = 200;
+ public static int COLOR_CHANGE_DURATION = 120;
@Thunk static float sDragAlpha = 1f;
@@ -249,8 +249,7 @@
m1.setSaturation(0);
ColorMatrix m2 = new ColorMatrix();
- m2.setScale(Color.red(color) / 255f, Color.green(color) / 255f,
- Color.blue(color) / 255f, Color.alpha(color) / 255f);
+ setColorScale(color, m2);
m1.postConcat(m2);
if (Utilities.isLmpOrAbove()) {
@@ -355,4 +354,9 @@
mDragLayer.removeView(DragView.this);
}
}
+
+ public static void setColorScale(int color, ColorMatrix target) {
+ target.setScale(Color.red(color) / 255f, Color.green(color) / 255f,
+ Color.blue(color) / 255f, Color.alpha(color) / 255f);
+ }
}
diff --git a/src/com/android/launcher3/FocusHelper.java b/src/com/android/launcher3/FocusHelper.java
index c77d416..678ed0f 100644
--- a/src/com/android/launcher3/FocusHelper.java
+++ b/src/com/android/launcher3/FocusHelper.java
@@ -314,12 +314,14 @@
// with the hotseat.
if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN && !profile.isVerticalBarLayout()) {
matrix = FocusLogic.createSparseMatrix(iconLayout, hotseatLayout, true /* horizontal */,
- hotseat.getAllAppsButtonRank(), false /* all apps icon is ignored */);
+ hotseat.getAllAppsButtonRank(),
+ !hotseat.hasIcons() /* ignore all apps icon, unless there are no other icons */);
countY = countY + 1;
} else if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT &&
profile.isVerticalBarLayout()) {
matrix = FocusLogic.createSparseMatrix(iconLayout, hotseatLayout, false /* horizontal */,
- hotseat.getAllAppsButtonRank(), false /* all apps icon is ignored */);
+ hotseat.getAllAppsButtonRank(),
+ !hotseat.hasIcons() /* ignore all apps icon, unless there are no other icons */);
countX = countX + 1;
} else if (keyCode == KeyEvent.KEYCODE_DEL || keyCode == KeyEvent.KEYCODE_FORWARD_DEL) {
workspace.removeWorkspaceItem(v);
diff --git a/src/com/android/launcher3/FolderInfo.java b/src/com/android/launcher3/FolderInfo.java
index 930f911..aea21c9 100644
--- a/src/com/android/launcher3/FolderInfo.java
+++ b/src/com/android/launcher3/FolderInfo.java
@@ -92,7 +92,7 @@
}
public void setTitle(CharSequence title) {
- this.title = Utilities.trim(title);
+ this.title = title;
for (int i = 0; i < listeners.size(); i++) {
listeners.get(i).onTitleChanged(title);
}
diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java
index b614bc6..b8337b6 100644
--- a/src/com/android/launcher3/Hotseat.java
+++ b/src/com/android/launcher3/Hotseat.java
@@ -65,6 +65,13 @@
}
/**
+ * Returns whether there are other icons than the all apps button in the hotseat.
+ */
+ public boolean hasIcons() {
+ return mContent.getShortcutsAndWidgets().getChildCount() > 1;
+ }
+
+ /**
* Registers the specified listener on the cell layout of the hotseat.
*/
@Override
@@ -98,25 +105,6 @@
return rank == mAllAppsButtonRank;
}
- /** This returns the coordinates of an app in a given cell, relative to the DragLayer */
- Rect getCellCoordinates(int cellX, int cellY) {
- Rect coords = new Rect();
- mContent.cellToRect(cellX, cellY, 1, 1, coords);
- int[] hotseatInParent = new int[2];
- Utilities.getDescendantCoordRelativeToParent(this, mLauncher.getDragLayer(),
- hotseatInParent, false);
- coords.offset(hotseatInParent[0], hotseatInParent[1]);
-
- // Center the icon
- int cWidth = mContent.getShortcutsAndWidgets().getCellContentWidth();
- int cHeight = mContent.getShortcutsAndWidgets().getCellContentHeight();
- int cellPaddingX = (int) Math.max(0, ((coords.width() - cWidth) / 2f));
- int cellPaddingY = (int) Math.max(0, ((coords.height() - cHeight) / 2f));
- coords.offset(cellPaddingX, cellPaddingY);
-
- return coords;
- }
-
@Override
protected void onFinishInflate() {
super.onFinishInflate();
diff --git a/src/com/android/launcher3/IconCache.java b/src/com/android/launcher3/IconCache.java
index a387579..8b5f747 100644
--- a/src/com/android/launcher3/IconCache.java
+++ b/src/com/android/launcher3/IconCache.java
@@ -35,6 +35,7 @@
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.os.Handler;
+import android.os.SystemClock;
import android.text.TextUtils;
import android.util.Log;
@@ -46,7 +47,6 @@
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.Thunk;
-import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
@@ -71,6 +71,8 @@
private static final int LOW_RES_SCALE_FACTOR = 8;
+ private static final Object ICON_UPDATE_TOKEN = new Object();
+
@Thunk static class CacheEntry {
public Bitmap icon;
public CharSequence title;
@@ -223,13 +225,32 @@
new String[] {packageName + "/%", Long.toString(userSerial)});
}
+ public void updateDbIcons() {
+ // Remove all active icon update tasks.
+ mWorkerHandler.removeCallbacksAndMessages(ICON_UPDATE_TOKEN);
+
+ mIconDb.updateSystemStateString(mContext);
+ for (UserHandleCompat user : mUserManager.getUserProfiles()) {
+ // Query for the set of apps
+ final List<LauncherActivityInfoCompat> apps = mLauncherApps.getActivityList(null, user);
+ // Fail if we don't have any apps
+ // TODO: Fix this. Only fail for the current user.
+ if (apps == null || apps.isEmpty()) {
+ return;
+ }
+
+ // Update icon cache. This happens in segments and {@link #onPackageIconsUpdated}
+ // is called by the icon cache when the job is complete.
+ updateDBIcons(user, apps);
+ }
+ }
+
/**
* Updates the persistent DB, such that only entries corresponding to {@param apps} remain in
* the DB and are updated.
* @return The set of packages for which icons have updated.
*/
- public HashSet<String> updateDBIcons(UserHandleCompat user, List<LauncherActivityInfoCompat> apps) {
- mIconDb.updateSystemStateString(mContext);
+ private void updateDBIcons(UserHandleCompat user, List<LauncherActivityInfoCompat> apps) {
long userSerial = mUserManager.getSerialNumberForUser(user);
PackageManager pm = mContext.getPackageManager();
HashMap<String, PackageInfo> pkgInfoMap = new HashMap<String, PackageInfo>();
@@ -257,7 +278,7 @@
final int systemStateIndex = c.getColumnIndex(IconDB.COLUMN_SYSTEM_STATE);
HashSet<Integer> itemsToRemove = new HashSet<Integer>();
- HashSet<String> updatedPackages = new HashSet<String>();
+ Stack<LauncherActivityInfoCompat> appsToUpdate = new Stack<>();
while (c.moveToNext()) {
String cn = c.getString(indexComponent);
@@ -281,14 +302,9 @@
}
if (app == null) {
itemsToRemove.add(c.getInt(rowIndex));
- continue;
+ } else {
+ appsToUpdate.add(app);
}
- ContentValues values = updateCacheAndGetContentValues(app, true);
- mIconDb.getWritableDatabase().update(IconDB.TABLE_NAME, values,
- IconDB.COLUMN_COMPONENT + " = ? AND " + IconDB.COLUMN_USER + " = ?",
- new String[] {cn, Long.toString(userSerial)});
-
- updatedPackages.add(component.getPackageName());
}
c.close();
if (!itemsToRemove.isEmpty()) {
@@ -298,11 +314,12 @@
}
// Insert remaining apps.
- if (!componentMap.isEmpty()) {
- mWorkerHandler.post(new SerializedIconAdditionTask(userSerial, pkgInfoMap,
- componentMap.values()));
+ if (!componentMap.isEmpty() || !appsToUpdate.isEmpty()) {
+ Stack<LauncherActivityInfoCompat> appsToAdd = new Stack<>();
+ appsToAdd.addAll(componentMap.values());
+ new SerializedIconUpdateTask(userSerial, pkgInfoMap,
+ appsToAdd, appsToUpdate).scheduleNext();
}
- return updatedPackages;
}
private void addIconToDBAndMemCache(LauncherActivityInfoCompat app, PackageInfo info,
@@ -684,25 +701,46 @@
}
/**
- * A runnable that adds icons in the DB for the provided LauncherActivityInfoCompat list.
- * Items are added one at a time, to that the worker thread does not get blocked.
+ * A runnable that updates invalid icons and adds missing icons in the DB for the provided
+ * LauncherActivityInfoCompat list. Items are updated/added one at a time, so that the
+ * worker thread doesn't get blocked.
*/
- private class SerializedIconAdditionTask implements Runnable {
+ private class SerializedIconUpdateTask implements Runnable {
private final long mUserSerial;
private final HashMap<String, PackageInfo> mPkgInfoMap;
private final Stack<LauncherActivityInfoCompat> mAppsToAdd;
+ private final Stack<LauncherActivityInfoCompat> mAppsToUpdate;
+ private final HashSet<String> mUpdatedPackages = new HashSet<String>();
- private SerializedIconAdditionTask(long userSerial, HashMap<String, PackageInfo> pkgInfoMap,
- Collection<LauncherActivityInfoCompat> appsToAdd) {
+ private SerializedIconUpdateTask(long userSerial, HashMap<String, PackageInfo> pkgInfoMap,
+ Stack<LauncherActivityInfoCompat> appsToAdd,
+ Stack<LauncherActivityInfoCompat> appsToUpdate) {
mUserSerial = userSerial;
mPkgInfoMap = pkgInfoMap;
- mAppsToAdd = new Stack<LauncherActivityInfoCompat>();
- mAppsToAdd.addAll(appsToAdd);
+ mAppsToAdd = appsToAdd;
+ mAppsToUpdate = appsToUpdate;
}
@Override
public void run() {
- if (!mAppsToAdd.isEmpty()) {
+ if (!mAppsToUpdate.isEmpty()) {
+ LauncherActivityInfoCompat app = mAppsToUpdate.pop();
+ String cn = app.getComponentName().flattenToString();
+ ContentValues values = updateCacheAndGetContentValues(app, true);
+ mIconDb.getWritableDatabase().update(IconDB.TABLE_NAME, values,
+ IconDB.COLUMN_COMPONENT + " = ? AND " + IconDB.COLUMN_USER + " = ?",
+ new String[] {cn, Long.toString(mUserSerial)});
+ mUpdatedPackages.add(app.getComponentName().getPackageName());
+
+ if (mAppsToUpdate.isEmpty() && !mUpdatedPackages.isEmpty()) {
+ // No more app to update. Notify model.
+ LauncherAppState.getInstance().getModel().onPackageIconsUpdated(
+ mUpdatedPackages, mUserManager.getUserForSerialNumber(mUserSerial));
+ }
+
+ // Let it run one more time.
+ scheduleNext();
+ } else if (!mAppsToAdd.isEmpty()) {
LauncherActivityInfoCompat app = mAppsToAdd.pop();
PackageInfo info = mPkgInfoMap.get(app.getComponentName().getPackageName());
if (info != null) {
@@ -710,10 +748,15 @@
addIconToDBAndMemCache(app, info, mUserSerial);
}
}
+
+ if (!mAppsToAdd.isEmpty()) {
+ scheduleNext();
+ }
}
- if (!mAppsToAdd.isEmpty()) {
- mWorkerHandler.post(this);
- }
+ }
+
+ public void scheduleNext() {
+ mWorkerHandler.postAtTime(this, ICON_UPDATE_TOKEN, SystemClock.uptimeMillis() + 1);
}
}
diff --git a/src/com/android/launcher3/InfoDropTarget.java b/src/com/android/launcher3/InfoDropTarget.java
index f3383cc..0f139fa 100644
--- a/src/com/android/launcher3/InfoDropTarget.java
+++ b/src/com/android/launcher3/InfoDropTarget.java
@@ -41,7 +41,7 @@
// Get the hover color
mHoverColor = getResources().getColor(R.color.info_target_hover_tint);
- setDrawable(R.drawable.info_target_selector);
+ setDrawable(R.drawable.ic_launcher_info_normal);
}
public static void startDetailsActivityForInfo(Object info, Launcher launcher) {
diff --git a/src/com/android/launcher3/InstallShortcutReceiver.java b/src/com/android/launcher3/InstallShortcutReceiver.java
index 115598f..448cc1d 100644
--- a/src/com/android/launcher3/InstallShortcutReceiver.java
+++ b/src/com/android/launcher3/InstallShortcutReceiver.java
@@ -156,6 +156,16 @@
queuePendingShortcutInfo(info, context);
}
+ public static ShortcutInfo fromShortcutIntent(Context context, Intent data) {
+ PendingInstallShortcutInfo info = new PendingInstallShortcutInfo(data, context);
+ if (info.launchIntent == null || info.label == null) {
+ if (DBG) Log.e(TAG, "Invalid install shortcut intent");
+ return null;
+ }
+ info = convertToLauncherActivityIfPossible(info);
+ return info.getShortcutInfo();
+ }
+
static void queueInstallShortcut(LauncherActivityInfoCompat info, Context context) {
queuePendingShortcutInfo(new PendingInstallShortcutInfo(info, context), context);
}
@@ -215,30 +225,6 @@
}
/**
- * Returns true if the intent is a valid launch intent for a shortcut.
- * This is used to identify shortcuts which are different from the ones exposed by the
- * applications' manifest file.
- *
- * When DISABLE_ALL_APPS is true, shortcuts exposed via the app's manifest should never be
- * duplicated or removed(unless the app is un-installed).
- *
- * @param launchIntent The intent that will be launched when the shortcut is clicked.
- */
- static boolean isValidShortcutLaunchIntent(Intent launchIntent) {
- if (launchIntent != null
- && Intent.ACTION_MAIN.equals(launchIntent.getAction())
- && launchIntent.getComponent() != null
- && launchIntent.getCategories() != null
- && launchIntent.getCategories().size() == 1
- && launchIntent.hasCategory(Intent.CATEGORY_LAUNCHER)
- && launchIntent.getExtras() == null
- && TextUtils.isEmpty(launchIntent.getDataString())) {
- return false;
- }
- return true;
- }
-
- /**
* Ensures that we have a valid, non-null name. If the provided name is null, we will return
* the application name instead.
*/
@@ -428,7 +414,7 @@
// Already an activity target
return original;
}
- if (isValidShortcutLaunchIntent(original.launchIntent)
+ if (!Utilities.isLauncherAppTarget(original.launchIntent)
|| !original.user.equals(UserHandleCompat.myUserHandle())) {
// We can only convert shortcuts which point to a main activity in the current user.
return original;
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 59ca978..a305d10 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -55,6 +55,7 @@
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.graphics.Rect;
+import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.AsyncTask;
@@ -157,6 +158,10 @@
private static final int REQUEST_BIND_APPWIDGET = 11;
private static final int REQUEST_RECONFIGURE_APPWIDGET = 12;
+ private static final int WORKSPACE_BACKGROUND_GRADIENT = 0;
+ private static final int WORKSPACE_BACKGROUND_TRANSPARENT = 1;
+ private static final int WORKSPACE_BACKGROUND_BLACK = 2;
+
/**
* IntentStarter uses request codes starting with this. This must be greater than all activity
* request codes used internally.
@@ -806,7 +811,7 @@
}
boolean isWidgetDrop = (requestCode == REQUEST_PICK_APPWIDGET ||
- requestCode == REQUEST_CREATE_APPWIDGET || requestCode == REQUEST_CREATE_SHORTCUT);
+ requestCode == REQUEST_CREATE_APPWIDGET);
final boolean workspaceLocked = isWorkspaceLocked();
// We have special handling for widgets
@@ -1042,8 +1047,9 @@
}
}
- // Background was set to gradient in onPause(), restore to black if in all apps.
- setWorkspaceBackground(mState == State.WORKSPACE);
+ // Background was set to gradient in onPause(), restore to transparent if in all apps.
+ setWorkspaceBackground(mState == State.WORKSPACE ? WORKSPACE_BACKGROUND_TRANSPARENT
+ : WORKSPACE_BACKGROUND_GRADIENT);
mPaused = false;
if (mRestoring || mOnResumeNeedsLoad) {
@@ -1550,14 +1556,13 @@
int[] touchXY = mPendingAddInfo.dropPos;
CellLayout layout = getCellLayout(container, screenId);
- boolean foundCellSpan = false;
-
- ShortcutInfo info = mModel.infoFromShortcutIntent(this, data);
+ ShortcutInfo info = InstallShortcutReceiver.fromShortcutIntent(this, data);
if (info == null) {
return;
}
final View view = createShortcut(info);
+ boolean foundCellSpan = false;
// First we check if we already know the exact location where we want to add this item.
if (cellX >= 0 && cellY >= 0) {
cellXY[0] = cellX;
@@ -3296,9 +3301,17 @@
return (mState == State.WIDGETS) || (mOnResumeState == State.WIDGETS);
}
- private void setWorkspaceBackground(boolean workspace) {
- mLauncherView.setBackground(workspace ?
- mWorkspaceBackgroundDrawable : null);
+ private void setWorkspaceBackground(int background) {
+ switch (background) {
+ case WORKSPACE_BACKGROUND_TRANSPARENT:
+ getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
+ break;
+ case WORKSPACE_BACKGROUND_BLACK:
+ getWindow().setBackgroundDrawable(null);
+ break;
+ default:
+ getWindow().setBackgroundDrawable(mWorkspaceBackgroundDrawable);
+ }
}
protected void changeWallpaperVisiblity(boolean visible) {
@@ -3308,7 +3321,7 @@
if (wpflags != curflags) {
getWindow().setFlags(wpflags, WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER);
}
- setWorkspaceBackground(visible);
+ setWorkspaceBackground(visible ? WORKSPACE_BACKGROUND_GRADIENT : WORKSPACE_BACKGROUND_BLACK);
}
@Override
diff --git a/src/com/android/launcher3/LauncherBackupAgentHelper.java b/src/com/android/launcher3/LauncherBackupAgentHelper.java
index 5f7173f..e607a0f 100644
--- a/src/com/android/launcher3/LauncherBackupAgentHelper.java
+++ b/src/com/android/launcher3/LauncherBackupAgentHelper.java
@@ -94,6 +94,7 @@
// TODO: Update the backup set to include rank.
if (mHelper.restoredBackupVersion <= 2) {
LauncherAppState.getLauncherProvider().updateFolderItemsRank();
+ LauncherAppState.getLauncherProvider().convertShortcutsToLauncherActivities();
}
} else {
if (VERBOSE) Log.v(TAG, "Nothing was restored, clearing DB");
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 5002538..1b92602 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -969,7 +969,8 @@
break;
}
- folderInfo.title = Utilities.trim(c.getString(titleIndex));
+ // Do not trim the folder label, as is was set by the user.
+ folderInfo.title = c.getString(titleIndex);
folderInfo.id = id;
folderInfo.container = c.getInt(containerIndex);
folderInfo.screenId = c.getInt(screenIndex);
@@ -2026,7 +2027,7 @@
"constructing info for partially restored package",
true);
info = getRestoredItemInfo(c, titleIndex, intent,
- promiseType, useLowResIcon);
+ promiseType);
intent = getRestoredItemIntent(c, context, intent);
} else {
// Don't restore items for other profiles.
@@ -2111,7 +2112,8 @@
id = c.getLong(idIndex);
FolderInfo folderInfo = findOrMakeFolder(sBgFolders, id);
- folderInfo.title = Utilities.trim(c.getString(titleIndex));
+ // Do not trim the folder label, as is was set by the user.
+ folderInfo.title = c.getString(titleIndex);
folderInfo.id = id;
container = c.getInt(containerIndex);
folderInfo.container = container;
@@ -2755,7 +2757,7 @@
return;
}
}
- updateAllAppsIconsCache();
+ mIconCache.updateDbIcons();
synchronized (LoaderTask.this) {
if (mStopped) {
return;
@@ -2881,68 +2883,6 @@
}
}
- private void updateAllAppsIconsCache() {
- final ArrayList<AppInfo> updatedApps = new ArrayList<>();
-
- for (UserHandleCompat user : mUserManager.getUserProfiles()) {
- // Query for the set of apps
- final List<LauncherActivityInfoCompat> apps = mLauncherApps.getActivityList(null, user);
- // Fail if we don't have any apps
- // TODO: Fix this. Only fail for the current user.
- if (apps == null || apps.isEmpty()) {
- return;
- }
-
- // Update icon cache
- HashSet<String> updatedPackages = mIconCache.updateDBIcons(user, apps);
-
- // If any package icon has changed (app was updated while launcher was dead),
- // update the corresponding shortcuts.
- if (!updatedPackages.isEmpty()) {
- final ArrayList<ShortcutInfo> updatedShortcuts = new ArrayList<>();
- synchronized (sBgLock) {
- for (ItemInfo info : sBgItemsIdMap) {
- if (info instanceof ShortcutInfo && user.equals(info.user)
- && info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
- ShortcutInfo si = (ShortcutInfo) info;
- ComponentName cn = si.getTargetComponent();
- if (cn != null && updatedPackages.contains(cn.getPackageName())) {
- si.updateIcon(mIconCache);
- updatedShortcuts.add(si);
- }
- }
- }
- mBgAllAppsList.updateIconsAndLabels(updatedPackages, user, updatedApps);
- }
-
- if (!updatedShortcuts.isEmpty()) {
- final UserHandleCompat userFinal = user;
- mHandler.post(new Runnable() {
-
- public void run() {
- Callbacks cb = getCallback();
- if (cb != null) {
- cb.bindShortcutsChanged(updatedShortcuts,
- new ArrayList<ShortcutInfo>(), userFinal);
- }
- }
- });
- }
- }
- }
- if (!updatedApps.isEmpty()) {
- mHandler.post(new Runnable() {
-
- public void run() {
- Callbacks cb = getCallback();
- if (cb != null) {
- cb.bindAppsUpdated(updatedApps);
- }
- }
- });
- }
- }
-
public void dumpState() {
synchronized (sBgLock) {
Log.d(TAG, "mLoaderTask.mContext=" + mContext);
@@ -2953,6 +2893,58 @@
}
}
+ /**
+ * Called when the icons for packages have been updated in the icon cache.
+ */
+ public void onPackageIconsUpdated(HashSet<String> updatedPackages, UserHandleCompat user) {
+ final Callbacks callbacks = getCallback();
+ final ArrayList<AppInfo> updatedApps = new ArrayList<>();
+ final ArrayList<ShortcutInfo> updatedShortcuts = new ArrayList<>();
+
+ // If any package icon has changed (app was updated while launcher was dead),
+ // update the corresponding shortcuts.
+ synchronized (sBgLock) {
+ for (ItemInfo info : sBgItemsIdMap) {
+ if (info instanceof ShortcutInfo && user.equals(info.user)
+ && info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
+ ShortcutInfo si = (ShortcutInfo) info;
+ ComponentName cn = si.getTargetComponent();
+ if (cn != null && updatedPackages.contains(cn.getPackageName())) {
+ si.updateIcon(mIconCache);
+ updatedShortcuts.add(si);
+ }
+ }
+ }
+ mBgAllAppsList.updateIconsAndLabels(updatedPackages, user, updatedApps);
+ }
+
+ if (!updatedShortcuts.isEmpty()) {
+ final UserHandleCompat userFinal = user;
+ mHandler.post(new Runnable() {
+
+ public void run() {
+ Callbacks cb = getCallback();
+ if (cb != null && callbacks == cb) {
+ cb.bindShortcutsChanged(updatedShortcuts,
+ new ArrayList<ShortcutInfo>(), userFinal);
+ }
+ }
+ });
+ }
+
+ if (!updatedApps.isEmpty()) {
+ mHandler.post(new Runnable() {
+
+ public void run() {
+ Callbacks cb = getCallback();
+ if (cb != null && callbacks == cb) {
+ cb.bindAppsUpdated(updatedApps);
+ }
+ }
+ });
+ }
+ }
+
void enqueuePackageUpdated(PackageUpdatedTask task) {
sWorker.post(task);
}
@@ -3410,10 +3402,10 @@
* to a package that is not yet installed on the system.
*/
public ShortcutInfo getRestoredItemInfo(Cursor cursor, int titleIndex, Intent intent,
- int promiseType, boolean useLowResIcon) {
+ int promiseType) {
final ShortcutInfo info = new ShortcutInfo();
info.user = UserHandleCompat.myUserHandle();
- mIconCache.getTitleAndIcon(info, intent, info.user, useLowResIcon);
+ mIconCache.getTitleAndIcon(info, intent, info.user, false /* useLowResIcon */);
if ((promiseType & ShortcutInfo.FLAG_RESTORED_ICON) != 0) {
String title = (cursor != null) ? cursor.getString(titleIndex) : null;
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index 8bc8988..8fef32d 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -65,7 +65,7 @@
private static final String TAG = "Launcher.LauncherProvider";
private static final boolean LOGD = false;
- private static final int DATABASE_VERSION = 25;
+ private static final int DATABASE_VERSION = 26;
static final String OLD_AUTHORITY = "com.android.launcher2.settings";
static final String AUTHORITY = ProviderConfig.AUTHORITY;
@@ -378,6 +378,11 @@
mOpenHelper.updateFolderItemsRank(mOpenHelper.getWritableDatabase(), false);
}
+ public void convertShortcutsToLauncherActivities() {
+ mOpenHelper.convertShortcutsToLauncherActivities(mOpenHelper.getWritableDatabase());
+ }
+
+
public void deleteDatabase() {
// Are you sure? (y/n)
final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
@@ -623,10 +628,12 @@
}
}
case 23:
- convertShortcutsToLauncherActivities(db);
+ // No-op
case 24:
ManagedProfileHeuristic.markExistingUsersForNoFolderCreation(mContext);
- case 25: {
+ case 25:
+ convertShortcutsToLauncherActivities(db);
+ case 26: {
// DB Upgraded successfully
return;
}
diff --git a/src/com/android/launcher3/UninstallDropTarget.java b/src/com/android/launcher3/UninstallDropTarget.java
index 0fc8f32..4199390 100644
--- a/src/com/android/launcher3/UninstallDropTarget.java
+++ b/src/com/android/launcher3/UninstallDropTarget.java
@@ -28,7 +28,7 @@
// Get the hover color
mHoverColor = getResources().getColor(R.color.uninstall_target_hover_tint);
- setDrawable(R.drawable.uninstall_target_selector);
+ setDrawable(R.drawable.ic_launcher_uninstall_normal);
}
@Override
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index 1f8a6f2..9f47e13 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -45,12 +45,15 @@
import android.graphics.drawable.PaintDrawable;
import android.os.Build;
import android.os.Process;
+import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
import android.util.SparseArray;
import android.view.View;
import android.widget.Toast;
+import junit.framework.Assert;
+
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
@@ -58,8 +61,6 @@
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import junit.framework.Assert;
-
/**
* Various utilities shared amongst the Launcher's classes.
*/
@@ -650,4 +651,22 @@
Assert.assertTrue(LauncherModel.sWorkerThread.getThreadId() == Process.myTid());
}
}
+
+ /**
+ * Returns true if the intent is a valid launch intent for a launcher activity of an app.
+ * This is used to identify shortcuts which are different from the ones exposed by the
+ * applications' manifest file.
+ *
+ * @param launchIntent The intent that will be launched when the shortcut is clicked.
+ */
+ public static boolean isLauncherAppTarget(Intent launchIntent) {
+ return launchIntent != null
+ && Intent.ACTION_MAIN.equals(launchIntent.getAction())
+ && launchIntent.getComponent() != null
+ && launchIntent.getCategories() != null
+ && launchIntent.getCategories().size() == 1
+ && launchIntent.hasCategory(Intent.CATEGORY_LAUNCHER)
+ && launchIntent.getExtras() == null
+ && TextUtils.isEmpty(launchIntent.getDataString());
+ }
}